mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-03-09 08:59:30 +00:00
Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
412 lines
11 KiB
Go
412 lines
11 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package attribute // import "go.opentelemetry.io/otel/attribute"
|
|
|
|
import (
|
|
"cmp"
|
|
"encoding/json"
|
|
"reflect"
|
|
"slices"
|
|
"sort"
|
|
)
|
|
|
|
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 be ensures equivalence stability: comparisons
|
|
// will return the save value across versions. For this reason, Distinct
|
|
// should always be used as a map key instead of a Set.
|
|
Distinct struct {
|
|
iface interface{}
|
|
}
|
|
|
|
// 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 EmptySet() *Set {
|
|
return emptySet
|
|
}
|
|
|
|
// reflectValue abbreviates reflect.ValueOf(d).
|
|
func (d Distinct) reflectValue() reflect.Value {
|
|
return reflect.ValueOf(d.iface)
|
|
}
|
|
|
|
// Valid returns true if this value refers to a valid Set.
|
|
func (d Distinct) Valid() bool {
|
|
return d.iface != nil
|
|
}
|
|
|
|
// Len returns the number of attributes in this set.
|
|
func (l *Set) Len() int {
|
|
if l == nil || !l.equivalent.Valid() {
|
|
return 0
|
|
}
|
|
return l.equivalent.reflectValue().Len()
|
|
}
|
|
|
|
// Get returns the KeyValue at ordered position idx in this set.
|
|
func (l *Set) Get(idx int) (KeyValue, bool) {
|
|
if l == nil || !l.equivalent.Valid() {
|
|
return KeyValue{}, false
|
|
}
|
|
value := l.equivalent.reflectValue()
|
|
|
|
if idx >= 0 && idx < value.Len() {
|
|
// Note: The Go compiler successfully avoids an allocation for
|
|
// the interface{} conversion here:
|
|
return value.Index(idx).Interface().(KeyValue), true
|
|
}
|
|
|
|
return KeyValue{}, false
|
|
}
|
|
|
|
// Value returns the value of a specified key in this set.
|
|
func (l *Set) Value(k Key) (Value, bool) {
|
|
if l == nil || !l.equivalent.Valid() {
|
|
return Value{}, false
|
|
}
|
|
rValue := l.equivalent.reflectValue()
|
|
vlen := rValue.Len()
|
|
|
|
idx := sort.Search(vlen, func(idx int) bool {
|
|
return rValue.Index(idx).Interface().(KeyValue).Key >= k
|
|
})
|
|
if idx >= vlen {
|
|
return Value{}, false
|
|
}
|
|
keyValue := rValue.Index(idx).Interface().(KeyValue)
|
|
if k == keyValue.Key {
|
|
return keyValue.Value, true
|
|
}
|
|
return Value{}, false
|
|
}
|
|
|
|
// HasValue tests whether a key is defined in this set.
|
|
func (l *Set) HasValue(k Key) bool {
|
|
if l == nil {
|
|
return false
|
|
}
|
|
_, ok := l.Value(k)
|
|
return ok
|
|
}
|
|
|
|
// Iter returns an iterator for visiting the attributes in this set.
|
|
func (l *Set) Iter() Iterator {
|
|
return Iterator{
|
|
storage: l,
|
|
idx: -1,
|
|
}
|
|
}
|
|
|
|
// ToSlice returns the set of attributes belonging to this set, sorted, where
|
|
// keys appear no more than once.
|
|
func (l *Set) ToSlice() []KeyValue {
|
|
iter := l.Iter()
|
|
return iter.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 (l *Set) Equivalent() Distinct {
|
|
if l == nil || !l.equivalent.Valid() {
|
|
return emptySet.equivalent
|
|
}
|
|
return l.equivalent
|
|
}
|
|
|
|
// Equals returns true if the argument set is equivalent to this set.
|
|
func (l *Set) Equals(o *Set) bool {
|
|
return l.Equivalent() == o.Equivalent()
|
|
}
|
|
|
|
// Encoded returns the encoded form of this set, according to encoder.
|
|
func (l *Set) Encoded(encoder Encoder) string {
|
|
if l == nil || encoder == nil {
|
|
return ""
|
|
}
|
|
|
|
return encoder.Encode(l.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 NewSet(kvs ...KeyValue) Set {
|
|
s, _ := NewSetWithFiltered(kvs, nil)
|
|
return s
|
|
}
|
|
|
|
// 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 NewSetWithSortable(kvs []KeyValue, _ *Sortable) Set {
|
|
s, _ := NewSetWithFiltered(kvs, nil)
|
|
return s
|
|
}
|
|
|
|
// 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 NewSetWithFiltered(kvs []KeyValue, filter Filter) (Set, []KeyValue) {
|
|
// Check for empty set.
|
|
if len(kvs) == 0 {
|
|
return empty(), nil
|
|
}
|
|
|
|
// Stable sort so the following de-duplication can implement
|
|
// last-value-wins semantics.
|
|
slices.SortStableFunc(kvs, func(a, b KeyValue) int {
|
|
return cmp.Compare(a.Key, b.Key)
|
|
})
|
|
|
|
position := len(kvs) - 1
|
|
offset := position - 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 ; offset >= 0; offset-- {
|
|
if kvs[offset].Key == kvs[position].Key {
|
|
continue
|
|
}
|
|
position--
|
|
kvs[offset], kvs[position] = kvs[position], kvs[offset]
|
|
}
|
|
kvs = kvs[position:]
|
|
|
|
if filter != nil {
|
|
if div := filteredToFront(kvs, filter); div != 0 {
|
|
return Set{equivalent: computeDistinct(kvs[div:])}, kvs[:div]
|
|
}
|
|
}
|
|
return Set{equivalent: computeDistinct(kvs)}, 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 NewSetWithSortableFiltered(kvs []KeyValue, _ *Sortable, filter Filter) (Set, []KeyValue) {
|
|
return NewSetWithFiltered(kvs, filter)
|
|
}
|
|
|
|
// 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(slice []KeyValue, keep Filter) int {
|
|
n := len(slice)
|
|
j := n
|
|
for i := n - 1; i >= 0; i-- {
|
|
if keep(slice[i]) {
|
|
j--
|
|
slice[i], slice[j] = slice[j], slice[i]
|
|
}
|
|
}
|
|
return j
|
|
}
|
|
|
|
// Filter returns a filtered copy of this Set. See the documentation for
|
|
// NewSetWithSortableFiltered for more details.
|
|
func (l *Set) Filter(re Filter) (Set, []KeyValue) {
|
|
if re == nil {
|
|
return *l, nil
|
|
}
|
|
|
|
// Iterate in reverse to the first attribute that will be filtered out.
|
|
n := l.Len()
|
|
first := n - 1
|
|
for ; first >= 0; first-- {
|
|
kv, _ := l.Get(first)
|
|
if !re(kv) {
|
|
break
|
|
}
|
|
}
|
|
|
|
// No attributes will be dropped, return the immutable Set l and nil.
|
|
if first < 0 {
|
|
return *l, 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.
|
|
slice := l.ToSlice()
|
|
|
|
// Don't re-iterate the slice if only slice[0] is filtered.
|
|
if first == 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(slice[1:])}, slice[:1]
|
|
}
|
|
|
|
// Move the filtered slice[first] to the front (preserving order).
|
|
kv := slice[first]
|
|
copy(slice[1:first+1], slice[:first])
|
|
slice[0] = kv
|
|
|
|
// Do not re-evaluate re(slice[first+1:]).
|
|
div := filteredToFront(slice[1:first+1], re) + 1
|
|
return Set{equivalent: computeDistinct(slice[div:])}, slice[:div]
|
|
}
|
|
|
|
// 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(kvs []KeyValue) Distinct {
|
|
iface := computeDistinctFixed(kvs)
|
|
if iface == nil {
|
|
iface = computeDistinctReflect(kvs)
|
|
}
|
|
return Distinct{
|
|
iface: iface,
|
|
}
|
|
}
|
|
|
|
// computeDistinctFixed computes a Distinct for small slices. It returns nil
|
|
// if the input is too large for this code path.
|
|
func computeDistinctFixed(kvs []KeyValue) interface{} {
|
|
switch len(kvs) {
|
|
case 1:
|
|
return [1]KeyValue(kvs)
|
|
case 2:
|
|
return [2]KeyValue(kvs)
|
|
case 3:
|
|
return [3]KeyValue(kvs)
|
|
case 4:
|
|
return [4]KeyValue(kvs)
|
|
case 5:
|
|
return [5]KeyValue(kvs)
|
|
case 6:
|
|
return [6]KeyValue(kvs)
|
|
case 7:
|
|
return [7]KeyValue(kvs)
|
|
case 8:
|
|
return [8]KeyValue(kvs)
|
|
case 9:
|
|
return [9]KeyValue(kvs)
|
|
case 10:
|
|
return [10]KeyValue(kvs)
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// computeDistinctReflect computes a Distinct using reflection, works for any
|
|
// size input.
|
|
func computeDistinctReflect(kvs []KeyValue) interface{} {
|
|
at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem()
|
|
for i, keyValue := range kvs {
|
|
*(at.Index(i).Addr().Interface().(*KeyValue)) = keyValue
|
|
}
|
|
return at.Interface()
|
|
}
|
|
|
|
// MarshalJSON returns the JSON encoding of the Set.
|
|
func (l *Set) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(l.equivalent.iface)
|
|
}
|
|
|
|
// MarshalLog is the marshaling function used by the logging system to represent this Set.
|
|
func (l Set) MarshalLog() interface{} {
|
|
kvs := make(map[string]string)
|
|
for _, kv := range l.ToSlice() {
|
|
kvs[string(kv.Key)] = kv.Value.Emit()
|
|
}
|
|
return kvs
|
|
}
|
|
|
|
// Len implements sort.Interface.
|
|
func (l *Sortable) Len() int {
|
|
return len(*l)
|
|
}
|
|
|
|
// Swap implements sort.Interface.
|
|
func (l *Sortable) Swap(i, j int) {
|
|
(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
|
|
}
|
|
|
|
// Less implements sort.Interface.
|
|
func (l *Sortable) Less(i, j int) bool {
|
|
return (*l)[i].Key < (*l)[j].Key
|
|
}
|