Source File
set.go
Belonging Package
go.opentelemetry.io/otel/attribute
// Copyright The OpenTelemetry Authors// SPDX-License-Identifier: Apache-2.0package 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 will remain comparable for backwards compatibility. The// equivalence of Sets across versions is not guaranteed to be stable.// Prior versions may find two Sets to be equal or not when compared// directly (i.e. ==), but subsequent versions may not. Users should use// the Equals method to ensure stable equivalence checking.//// Users should also use the Distinct returned from Equivalent as a map key// instead of a Set directly. In addition to that type providing guarantees// on stable equivalence, it may also provide performance improvements.Set struct {equivalent Distinct}// Distinct is a unique identifier of a Set.//// Distinct is designed to ensure equivalence stability: comparisons will// return the same value across versions. For this reason, Distinct should// always be used as a map key instead of a Set.Distinct struct {iface any}// Sortable implements sort.Interface, used for sorting KeyValue.//// Deprecated: This type is no longer used. It was added as a performance// optimization for Go < 1.21 that is no longer needed (Go < 1.21 is no// longer supported by the module).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{},},})// EmptySet returns a reference to a Set with no elements.//// This is a convenience provided for optimized calling utility.func () *Set {return emptySet}// reflectValue abbreviates reflect.ValueOf(d).func ( Distinct) () reflect.Value {return reflect.ValueOf(.iface)}// Valid reports whether 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() {return 0}return .equivalent.reflectValue().Len()}// Get returns the KeyValue at ordered position idx in this set.func ( *Set) ( int) (KeyValue, bool) {if == nil || !.equivalent.Valid() {return KeyValue{}, false}:= .equivalent.reflectValue()if >= 0 && < .Len() {// Note: The Go compiler successfully avoids an allocation for// the interface{} conversion here:return .Index().Interface().(KeyValue), true}return KeyValue{}, false}// Value returns the value of a specified key in this set.func ( *Set) ( Key) (Value, bool) {if == nil || !.equivalent.Valid() {return Value{}, false}:= .equivalent.reflectValue():= .Len():= sort.Search(, func( int) bool {return .Index().Interface().(KeyValue).Key >=})if >= {return Value{}, false}:= .Index().Interface().(KeyValue)if == .Key {return .Value, true}return Value{}, false}// HasValue reports whether a key is defined in this set.func ( *Set) ( Key) bool {if == nil {return false}, := .Value()return}// Iter returns an iterator for visiting the attributes in this set.func ( *Set) () Iterator {return Iterator{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() {return emptySet.equivalent}return .equivalent}// Equals reports whether 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 empty() Set {return Set{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 {, := NewSetWithFiltered(, nil)return}// NewSetWithSortable returns a new Set. See the documentation for// NewSetWithSortableFiltered for more details.//// This call includes a Sortable option as a memory optimization.//// Deprecated: Use [NewSet] instead.func ( []KeyValue, *Sortable) Set {, := NewSetWithFiltered(, 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.if len() == 0 {return empty(), nil}// Stable sort so the following de-duplication can implement// last-value-wins semantics.slices.SortStableFunc(, func(, KeyValue) int {return cmp.Compare(.Key, .Key)}):= 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 {if := filteredToFront(, ); != 0 {return Set{equivalent: computeDistinct([:])}, [:]}}return Set{equivalent: computeDistinct()}, nil}// 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).//// Deprecated: Use [NewSetWithFiltered] instead.func ( []KeyValue, *Sortable, Filter) (Set, []KeyValue) {return NewSetWithFiltered(, )}// filteredToFront filters slice in-place using keep function. All KeyValues that need to// be removed are moved to the front. All KeyValues that need to be kept are// moved (in-order) to the back. The index for the first KeyValue to be kept is// returned.func filteredToFront( []KeyValue, Filter) int {:= len():=for := - 1; >= 0; -- {if ([]) {--[], [] = [], []}}return}// Filter returns a filtered copy of this Set. See the documentation for// NewSetWithSortableFiltered for more details.func ( *Set) ( Filter) (Set, []KeyValue) {if == nil {return *, nil}// Iterate in reverse to the first attribute that will be filtered out.:= .Len():= - 1for ; >= 0; -- {, := .Get()if !() {break}}// No attributes will be dropped, return the immutable Set l and nil.if < 0 {return *, nil}// Copy now that we know we need to return a modified set.//// Do not do this in-place on the underlying storage of *Set l. Sets are// immutable and filtering should not change this.:= .ToSlice()// Don't re-iterate the slice if only slice[0] is filtered.if == 0 {// It is safe to assume len(slice) >= 1 given we found at least one// attribute above that needs to be filtered out.return Set{equivalent: computeDistinct([1:])}, [:1]}// Move the filtered slice[first] to the front (preserving order).:= []copy([1:+1], [:])[0] =// Do not re-evaluate re(slice[first+1:]).:= filteredToFront([1:+1], ) + 1return Set{equivalent: computeDistinct([:])}, [:]}// 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 computeDistinct( []KeyValue) Distinct {:= computeDistinctFixed()if == nil {= computeDistinctReflect()}return Distinct{iface: ,}}// computeDistinctFixed computes a Distinct for small slices. It returns nil// if the input is too large for this code path.func computeDistinctFixed( []KeyValue) any {switch len() {case 1:return [1]KeyValue()case 2:return [2]KeyValue()case 3:return [3]KeyValue()case 4:return [4]KeyValue()case 5:return [5]KeyValue()case 6:return [6]KeyValue()case 7:return [7]KeyValue()case 8:return [8]KeyValue()case 9:return [9]KeyValue()case 10:return [10]KeyValue()default:return nil}}// computeDistinctReflect computes a Distinct using reflection, works for any// size input.func computeDistinctReflect( []KeyValue) any {:= 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) {return json.Marshal(.equivalent.iface)}// MarshalLog is the marshaling function used by the logging system to represent this Set.func ( Set) () any {:= make(map[string]string)for , := range .ToSlice() {[string(.Key)] = .Value.Emit()}return}// Len implements sort.Interface.func ( *Sortable) () int {return len(*)}// Swap implements sort.Interface.func ( *Sortable) (, int) {(*)[], (*)[] = (*)[], (*)[]}// Less implements sort.Interface.func ( *Sortable) (, int) bool {return (*)[].Key < (*)[].Key}
![]() |
The pages are generated with Golds v0.8.2. (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 @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |