// Copyright The OpenTelemetry Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.package attribute // import "go.opentelemetry.io/otel/attribute"import ()type (// Set is the representation for a distinct attribute set. It manages an // immutable set of attributes, with an internal cache for storing // attribute encodings. // // This type supports the Equivalent method of comparison using values of // type Distinct.Setstruct {equivalentDistinct }// Distinct wraps a variable-size array of KeyValue, constructed with keys // in sorted order. This can be used as a map key or for equality checking // between Sets.Distinctstruct {ifaceinterface{} }// Sortable implements sort.Interface, used for sorting KeyValue. This is // an exported type to support a memory optimization. A pointer to one of // these is needed for the call to sort.Stable(), which the caller may // provide in order to avoid an allocation. See NewSetWithSortable().Sortable []KeyValue)var (// keyValueType is used in computeDistinctReflect.keyValueType = reflect.TypeOf(KeyValue{})// emptySet is returned for empty attribute sets.emptySet = &Set{equivalent: Distinct{iface: [0]KeyValue{}, }, }// sortables is a pool of Sortables used to create Sets with a user does // not provide one.sortables = sync.Pool{New: func() interface{} { returnnew(Sortable) }, })// EmptySet returns a reference to a Set with no elements.//// This is a convenience provided for optimized calling utility.func () *Set {returnemptySet}// reflectValue abbreviates reflect.ValueOf(d).func ( Distinct) () reflect.Value {returnreflect.ValueOf(.iface)}// Valid returns true if this value refers to a valid Set.func ( Distinct) () bool {return .iface != nil}// Len returns the number of attributes in this set.func ( *Set) () int {if == nil || !.equivalent.Valid() {return0 }return .equivalent.reflectValue().Len()}// Get returns the KeyValue at ordered position idx in this set.func ( *Set) ( int) (KeyValue, bool) {if == nil || !.equivalent.Valid() {returnKeyValue{}, false } := .equivalent.reflectValue()if >= 0 && < .Len() {// Note: The Go compiler successfully avoids an allocation for // the interface{} conversion here:return .Index().Interface().(KeyValue), true }returnKeyValue{}, false}// Value returns the value of a specified key in this set.func ( *Set) ( Key) (Value, bool) {if == nil || !.equivalent.Valid() {returnValue{}, false } := .equivalent.reflectValue() := .Len() := sort.Search(, func( int) bool {return .Index().Interface().(KeyValue).Key >= })if >= {returnValue{}, false } := .Index().Interface().(KeyValue)if == .Key {return .Value, true }returnValue{}, false}// HasValue tests whether a key is defined in this set.func ( *Set) ( Key) bool {if == nil {returnfalse } , := .Value()return}// Iter returns an iterator for visiting the attributes in this set.func ( *Set) () Iterator {returnIterator{storage: ,idx: -1, }}// ToSlice returns the set of attributes belonging to this set, sorted, where// keys appear no more than once.func ( *Set) () []KeyValue { := .Iter()return .ToSlice()}// Equivalent returns a value that may be used as a map key. The Distinct type// guarantees that the result will equal the equivalent. Distinct value of any// attribute set with the same elements as this, where sets are made unique by// choosing the last value in the input for any given key.func ( *Set) () Distinct {if == nil || !.equivalent.Valid() {returnemptySet.equivalent }return .equivalent}// Equals returns true if the argument set is equivalent to this set.func ( *Set) ( *Set) bool {return .Equivalent() == .Equivalent()}// Encoded returns the encoded form of this set, according to encoder.func ( *Set) ( Encoder) string {if == nil || == nil {return"" }return .Encode(.Iter())}func () Set {returnSet{equivalent: emptySet.equivalent, }}// NewSet returns a new Set. See the documentation for// NewSetWithSortableFiltered for more details.//// Except for empty sets, this method adds an additional allocation compared// with calls that include a Sortable.func ( ...KeyValue) Set {// Check for empty set.iflen() == 0 {returnempty() } := sortables.Get().(*Sortable) , := NewSetWithSortableFiltered(, , nil)sortables.Put()return}// NewSetWithSortable returns a new Set. See the documentation for// NewSetWithSortableFiltered for more details.//// This call includes a Sortable option as a memory optimization.func ( []KeyValue, *Sortable) Set {// Check for empty set.iflen() == 0 {returnempty() } , := NewSetWithSortableFiltered(, , nil)return}// NewSetWithFiltered returns a new Set. See the documentation for// NewSetWithSortableFiltered for more details.//// This call includes a Filter to include/exclude attribute keys from the// return value. Excluded keys are returned as a slice of attribute values.func ( []KeyValue, Filter) (Set, []KeyValue) {// Check for empty set.iflen() == 0 {returnempty(), nil } := sortables.Get().(*Sortable) , := NewSetWithSortableFiltered(, , )sortables.Put()return , }// NewSetWithSortableFiltered returns a new Set.//// Duplicate keys are eliminated by taking the last value. This// re-orders the input slice so that unique last-values are contiguous// at the end of the slice.//// This ensures the following://// - Last-value-wins semantics// - Caller sees the reordering, but doesn't lose values// - Repeated call preserve last-value wins.//// Note that methods are defined on Set, although this returns Set. Callers// can avoid memory allocations by://// - allocating a Sortable for use as a temporary in this method// - allocating a Set for storing the return value of this constructor.//// The result maintains a cache of encoded attributes, by attribute.EncoderID.// This value should not be copied after its first use.//// The second []KeyValue return value is a list of attributes that were// excluded by the Filter (if non-nil).func ( []KeyValue, *Sortable, Filter) (Set, []KeyValue) {// Check for empty set.iflen() == 0 {returnempty(), nil } * = // Stable sort so the following de-duplication can implement // last-value-wins semantics.sort.Stable() * = nil := len() - 1 := - 1// The requirements stated above require that the stable // result be placed in the end of the input slice, while // overwritten values are swapped to the beginning. // // De-duplicate with last-value-wins semantics. Preserve // duplicate values at the beginning of the input slice.for ; >= 0; -- {if [].Key == [].Key {continue } -- [], [] = [], [] }if != nil {returnfilterSet([:], ) }returnSet{equivalent: computeDistinct([:]), }, nil}// filterSet reorders kvs so that included keys are contiguous at the end of// the slice, while excluded keys precede the included keys.func ( []KeyValue, Filter) (Set, []KeyValue) {var []KeyValue// Move attributes that do not match the filter so they're adjacent before // calling computeDistinct(). := len()// Swap indistinct keys forward and distinct keys toward the // end of the slice. := len() - 1for ; >= 0; -- {if ([]) { -- [], [] = [], []continue } } = [:]returnSet{equivalent: computeDistinct([:]), }, }// Filter returns a filtered copy of this Set. See the documentation for// NewSetWithSortableFiltered for more details.func ( *Set) ( Filter) (Set, []KeyValue) {if == nil {returnSet{equivalent: .equivalent, }, nil }// Note: This could be refactored to avoid the temporary slice // allocation, if it proves to be expensive.returnfilterSet(.ToSlice(), )}// computeDistinct returns a Distinct using either the fixed- or// reflect-oriented code path, depending on the size of the input. The input// slice is assumed to already be sorted and de-duplicated.func ( []KeyValue) Distinct { := computeDistinctFixed()if == nil { = computeDistinctReflect() }returnDistinct{iface: , }}// computeDistinctFixed computes a Distinct for small slices. It returns nil// if the input is too large for this code path.func ( []KeyValue) interface{} {switchlen() {case1: := new([1]KeyValue)copy((*)[:], )return *case2: := new([2]KeyValue)copy((*)[:], )return *case3: := new([3]KeyValue)copy((*)[:], )return *case4: := new([4]KeyValue)copy((*)[:], )return *case5: := new([5]KeyValue)copy((*)[:], )return *case6: := new([6]KeyValue)copy((*)[:], )return *case7: := new([7]KeyValue)copy((*)[:], )return *case8: := new([8]KeyValue)copy((*)[:], )return *case9: := new([9]KeyValue)copy((*)[:], )return *case10: := new([10]KeyValue)copy((*)[:], )return *default:returnnil }}// computeDistinctReflect computes a Distinct using reflection, works for any// size input.func ( []KeyValue) interface{} { := reflect.New(reflect.ArrayOf(len(), keyValueType)).Elem()for , := range { *(.Index().Addr().Interface().(*KeyValue)) = }return .Interface()}// MarshalJSON returns the JSON encoding of the Set.func ( *Set) () ([]byte, error) {returnjson.Marshal(.equivalent.iface)}// MarshalLog is the marshaling function used by the logging system to represent this exporter.func ( Set) () interface{} { := make(map[string]string)for , := range .ToSlice() { [string(.Key)] = .Value.Emit() }return}// Len implements sort.Interface.func ( *Sortable) () int {returnlen(*)}// Swap implements sort.Interface.func ( *Sortable) (, int) { (*)[], (*)[] = (*)[], (*)[]}// Less implements sort.Interface.func ( *Sortable) (, int) bool {return (*)[].Key < (*)[].Key}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.