gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

set.go (12034B)


      1 // Copyright The OpenTelemetry Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package attribute // import "go.opentelemetry.io/otel/attribute"
     16 
     17 import (
     18 	"encoding/json"
     19 	"reflect"
     20 	"sort"
     21 	"sync"
     22 )
     23 
     24 type (
     25 	// Set is the representation for a distinct attribute set. It manages an
     26 	// immutable set of attributes, with an internal cache for storing
     27 	// attribute encodings.
     28 	//
     29 	// This type supports the Equivalent method of comparison using values of
     30 	// type Distinct.
     31 	Set struct {
     32 		equivalent Distinct
     33 	}
     34 
     35 	// Distinct wraps a variable-size array of KeyValue, constructed with keys
     36 	// in sorted order. This can be used as a map key or for equality checking
     37 	// between Sets.
     38 	Distinct struct {
     39 		iface interface{}
     40 	}
     41 
     42 	// Filter supports removing certain attributes from attribute sets. When
     43 	// the filter returns true, the attribute will be kept in the filtered
     44 	// attribute set. When the filter returns false, the attribute is excluded
     45 	// from the filtered attribute set, and the attribute instead appears in
     46 	// the removed list of excluded attributes.
     47 	Filter func(KeyValue) bool
     48 
     49 	// Sortable implements sort.Interface, used for sorting KeyValue. This is
     50 	// an exported type to support a memory optimization. A pointer to one of
     51 	// these is needed for the call to sort.Stable(), which the caller may
     52 	// provide in order to avoid an allocation. See NewSetWithSortable().
     53 	Sortable []KeyValue
     54 )
     55 
     56 var (
     57 	// keyValueType is used in computeDistinctReflect.
     58 	keyValueType = reflect.TypeOf(KeyValue{})
     59 
     60 	// emptySet is returned for empty attribute sets.
     61 	emptySet = &Set{
     62 		equivalent: Distinct{
     63 			iface: [0]KeyValue{},
     64 		},
     65 	}
     66 
     67 	// sortables is a pool of Sortables used to create Sets with a user does
     68 	// not provide one.
     69 	sortables = sync.Pool{
     70 		New: func() interface{} { return new(Sortable) },
     71 	}
     72 )
     73 
     74 // EmptySet returns a reference to a Set with no elements.
     75 //
     76 // This is a convenience provided for optimized calling utility.
     77 func EmptySet() *Set {
     78 	return emptySet
     79 }
     80 
     81 // reflectValue abbreviates reflect.ValueOf(d).
     82 func (d Distinct) reflectValue() reflect.Value {
     83 	return reflect.ValueOf(d.iface)
     84 }
     85 
     86 // Valid returns true if this value refers to a valid Set.
     87 func (d Distinct) Valid() bool {
     88 	return d.iface != nil
     89 }
     90 
     91 // Len returns the number of attributes in this set.
     92 func (l *Set) Len() int {
     93 	if l == nil || !l.equivalent.Valid() {
     94 		return 0
     95 	}
     96 	return l.equivalent.reflectValue().Len()
     97 }
     98 
     99 // Get returns the KeyValue at ordered position idx in this set.
    100 func (l *Set) Get(idx int) (KeyValue, bool) {
    101 	if l == nil || !l.equivalent.Valid() {
    102 		return KeyValue{}, false
    103 	}
    104 	value := l.equivalent.reflectValue()
    105 
    106 	if idx >= 0 && idx < value.Len() {
    107 		// Note: The Go compiler successfully avoids an allocation for
    108 		// the interface{} conversion here:
    109 		return value.Index(idx).Interface().(KeyValue), true
    110 	}
    111 
    112 	return KeyValue{}, false
    113 }
    114 
    115 // Value returns the value of a specified key in this set.
    116 func (l *Set) Value(k Key) (Value, bool) {
    117 	if l == nil || !l.equivalent.Valid() {
    118 		return Value{}, false
    119 	}
    120 	rValue := l.equivalent.reflectValue()
    121 	vlen := rValue.Len()
    122 
    123 	idx := sort.Search(vlen, func(idx int) bool {
    124 		return rValue.Index(idx).Interface().(KeyValue).Key >= k
    125 	})
    126 	if idx >= vlen {
    127 		return Value{}, false
    128 	}
    129 	keyValue := rValue.Index(idx).Interface().(KeyValue)
    130 	if k == keyValue.Key {
    131 		return keyValue.Value, true
    132 	}
    133 	return Value{}, false
    134 }
    135 
    136 // HasValue tests whether a key is defined in this set.
    137 func (l *Set) HasValue(k Key) bool {
    138 	if l == nil {
    139 		return false
    140 	}
    141 	_, ok := l.Value(k)
    142 	return ok
    143 }
    144 
    145 // Iter returns an iterator for visiting the attributes in this set.
    146 func (l *Set) Iter() Iterator {
    147 	return Iterator{
    148 		storage: l,
    149 		idx:     -1,
    150 	}
    151 }
    152 
    153 // ToSlice returns the set of attributes belonging to this set, sorted, where
    154 // keys appear no more than once.
    155 func (l *Set) ToSlice() []KeyValue {
    156 	iter := l.Iter()
    157 	return iter.ToSlice()
    158 }
    159 
    160 // Equivalent returns a value that may be used as a map key. The Distinct type
    161 // guarantees that the result will equal the equivalent. Distinct value of any
    162 // attribute set with the same elements as this, where sets are made unique by
    163 // choosing the last value in the input for any given key.
    164 func (l *Set) Equivalent() Distinct {
    165 	if l == nil || !l.equivalent.Valid() {
    166 		return emptySet.equivalent
    167 	}
    168 	return l.equivalent
    169 }
    170 
    171 // Equals returns true if the argument set is equivalent to this set.
    172 func (l *Set) Equals(o *Set) bool {
    173 	return l.Equivalent() == o.Equivalent()
    174 }
    175 
    176 // Encoded returns the encoded form of this set, according to encoder.
    177 func (l *Set) Encoded(encoder Encoder) string {
    178 	if l == nil || encoder == nil {
    179 		return ""
    180 	}
    181 
    182 	return encoder.Encode(l.Iter())
    183 }
    184 
    185 func empty() Set {
    186 	return Set{
    187 		equivalent: emptySet.equivalent,
    188 	}
    189 }
    190 
    191 // NewSet returns a new Set. See the documentation for
    192 // NewSetWithSortableFiltered for more details.
    193 //
    194 // Except for empty sets, this method adds an additional allocation compared
    195 // with calls that include a Sortable.
    196 func NewSet(kvs ...KeyValue) Set {
    197 	// Check for empty set.
    198 	if len(kvs) == 0 {
    199 		return empty()
    200 	}
    201 	srt := sortables.Get().(*Sortable)
    202 	s, _ := NewSetWithSortableFiltered(kvs, srt, nil)
    203 	sortables.Put(srt)
    204 	return s
    205 }
    206 
    207 // NewSetWithSortable returns a new Set. See the documentation for
    208 // NewSetWithSortableFiltered for more details.
    209 //
    210 // This call includes a Sortable option as a memory optimization.
    211 func NewSetWithSortable(kvs []KeyValue, tmp *Sortable) Set {
    212 	// Check for empty set.
    213 	if len(kvs) == 0 {
    214 		return empty()
    215 	}
    216 	s, _ := NewSetWithSortableFiltered(kvs, tmp, nil)
    217 	return s
    218 }
    219 
    220 // NewSetWithFiltered returns a new Set. See the documentation for
    221 // NewSetWithSortableFiltered for more details.
    222 //
    223 // This call includes a Filter to include/exclude attribute keys from the
    224 // return value. Excluded keys are returned as a slice of attribute values.
    225 func NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
    226 	// Check for empty set.
    227 	if len(kvs) == 0 {
    228 		return empty(), nil
    229 	}
    230 	srt := sortables.Get().(*Sortable)
    231 	s, filtered := NewSetWithSortableFiltered(kvs, srt, filter)
    232 	sortables.Put(srt)
    233 	return s, filtered
    234 }
    235 
    236 // NewSetWithSortableFiltered returns a new Set.
    237 //
    238 // Duplicate keys are eliminated by taking the last value.  This
    239 // re-orders the input slice so that unique last-values are contiguous
    240 // at the end of the slice.
    241 //
    242 // This ensures the following:
    243 //
    244 // - Last-value-wins semantics
    245 // - Caller sees the reordering, but doesn't lose values
    246 // - Repeated call preserve last-value wins.
    247 //
    248 // Note that methods are defined on Set, although this returns Set. Callers
    249 // can avoid memory allocations by:
    250 //
    251 // - allocating a Sortable for use as a temporary in this method
    252 // - allocating a Set for storing the return value of this constructor.
    253 //
    254 // The result maintains a cache of encoded attributes, by attribute.EncoderID.
    255 // This value should not be copied after its first use.
    256 //
    257 // The second []KeyValue return value is a list of attributes that were
    258 // excluded by the Filter (if non-nil).
    259 func NewSetWithSortableFiltered(kvs []KeyValue, tmp *Sortable, filter Filter) (Set, []KeyValue) {
    260 	// Check for empty set.
    261 	if len(kvs) == 0 {
    262 		return empty(), nil
    263 	}
    264 
    265 	*tmp = kvs
    266 
    267 	// Stable sort so the following de-duplication can implement
    268 	// last-value-wins semantics.
    269 	sort.Stable(tmp)
    270 
    271 	*tmp = nil
    272 
    273 	position := len(kvs) - 1
    274 	offset := position - 1
    275 
    276 	// The requirements stated above require that the stable
    277 	// result be placed in the end of the input slice, while
    278 	// overwritten values are swapped to the beginning.
    279 	//
    280 	// De-duplicate with last-value-wins semantics.  Preserve
    281 	// duplicate values at the beginning of the input slice.
    282 	for ; offset >= 0; offset-- {
    283 		if kvs[offset].Key == kvs[position].Key {
    284 			continue
    285 		}
    286 		position--
    287 		kvs[offset], kvs[position] = kvs[position], kvs[offset]
    288 	}
    289 	if filter != nil {
    290 		return filterSet(kvs[position:], filter)
    291 	}
    292 	return Set{
    293 		equivalent: computeDistinct(kvs[position:]),
    294 	}, nil
    295 }
    296 
    297 // filterSet reorders kvs so that included keys are contiguous at the end of
    298 // the slice, while excluded keys precede the included keys.
    299 func filterSet(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
    300 	var excluded []KeyValue
    301 
    302 	// Move attributes that do not match the filter so they're adjacent before
    303 	// calling computeDistinct().
    304 	distinctPosition := len(kvs)
    305 
    306 	// Swap indistinct keys forward and distinct keys toward the
    307 	// end of the slice.
    308 	offset := len(kvs) - 1
    309 	for ; offset >= 0; offset-- {
    310 		if filter(kvs[offset]) {
    311 			distinctPosition--
    312 			kvs[offset], kvs[distinctPosition] = kvs[distinctPosition], kvs[offset]
    313 			continue
    314 		}
    315 	}
    316 	excluded = kvs[:distinctPosition]
    317 
    318 	return Set{
    319 		equivalent: computeDistinct(kvs[distinctPosition:]),
    320 	}, excluded
    321 }
    322 
    323 // Filter returns a filtered copy of this Set. See the documentation for
    324 // NewSetWithSortableFiltered for more details.
    325 func (l *Set) Filter(re Filter) (Set, []KeyValue) {
    326 	if re == nil {
    327 		return Set{
    328 			equivalent: l.equivalent,
    329 		}, nil
    330 	}
    331 
    332 	// Note: This could be refactored to avoid the temporary slice
    333 	// allocation, if it proves to be expensive.
    334 	return filterSet(l.ToSlice(), re)
    335 }
    336 
    337 // computeDistinct returns a Distinct using either the fixed- or
    338 // reflect-oriented code path, depending on the size of the input. The input
    339 // slice is assumed to already be sorted and de-duplicated.
    340 func computeDistinct(kvs []KeyValue) Distinct {
    341 	iface := computeDistinctFixed(kvs)
    342 	if iface == nil {
    343 		iface = computeDistinctReflect(kvs)
    344 	}
    345 	return Distinct{
    346 		iface: iface,
    347 	}
    348 }
    349 
    350 // computeDistinctFixed computes a Distinct for small slices. It returns nil
    351 // if the input is too large for this code path.
    352 func computeDistinctFixed(kvs []KeyValue) interface{} {
    353 	switch len(kvs) {
    354 	case 1:
    355 		ptr := new([1]KeyValue)
    356 		copy((*ptr)[:], kvs)
    357 		return *ptr
    358 	case 2:
    359 		ptr := new([2]KeyValue)
    360 		copy((*ptr)[:], kvs)
    361 		return *ptr
    362 	case 3:
    363 		ptr := new([3]KeyValue)
    364 		copy((*ptr)[:], kvs)
    365 		return *ptr
    366 	case 4:
    367 		ptr := new([4]KeyValue)
    368 		copy((*ptr)[:], kvs)
    369 		return *ptr
    370 	case 5:
    371 		ptr := new([5]KeyValue)
    372 		copy((*ptr)[:], kvs)
    373 		return *ptr
    374 	case 6:
    375 		ptr := new([6]KeyValue)
    376 		copy((*ptr)[:], kvs)
    377 		return *ptr
    378 	case 7:
    379 		ptr := new([7]KeyValue)
    380 		copy((*ptr)[:], kvs)
    381 		return *ptr
    382 	case 8:
    383 		ptr := new([8]KeyValue)
    384 		copy((*ptr)[:], kvs)
    385 		return *ptr
    386 	case 9:
    387 		ptr := new([9]KeyValue)
    388 		copy((*ptr)[:], kvs)
    389 		return *ptr
    390 	case 10:
    391 		ptr := new([10]KeyValue)
    392 		copy((*ptr)[:], kvs)
    393 		return *ptr
    394 	default:
    395 		return nil
    396 	}
    397 }
    398 
    399 // computeDistinctReflect computes a Distinct using reflection, works for any
    400 // size input.
    401 func computeDistinctReflect(kvs []KeyValue) interface{} {
    402 	at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem()
    403 	for i, keyValue := range kvs {
    404 		*(at.Index(i).Addr().Interface().(*KeyValue)) = keyValue
    405 	}
    406 	return at.Interface()
    407 }
    408 
    409 // MarshalJSON returns the JSON encoding of the Set.
    410 func (l *Set) MarshalJSON() ([]byte, error) {
    411 	return json.Marshal(l.equivalent.iface)
    412 }
    413 
    414 // MarshalLog is the marshaling function used by the logging system to represent this exporter.
    415 func (l Set) MarshalLog() interface{} {
    416 	kvs := make(map[string]string)
    417 	for _, kv := range l.ToSlice() {
    418 		kvs[string(kv.Key)] = kv.Value.Emit()
    419 	}
    420 	return kvs
    421 }
    422 
    423 // Len implements sort.Interface.
    424 func (l *Sortable) Len() int {
    425 	return len(*l)
    426 }
    427 
    428 // Swap implements sort.Interface.
    429 func (l *Sortable) Swap(i, j int) {
    430 	(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
    431 }
    432 
    433 // Less implements sort.Interface.
    434 func (l *Sortable) Less(i, j int) bool {
    435 	return (*l)[i].Key < (*l)[j].Key
    436 }