Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
538 lines
14 KiB
538 lines
14 KiB
// 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 number // import "go.opentelemetry.io/otel/metric/number" |
|
|
|
//go:generate stringer -type=Kind |
|
|
|
import ( |
|
"fmt" |
|
"math" |
|
"sync/atomic" |
|
|
|
"go.opentelemetry.io/otel/internal" |
|
) |
|
|
|
// Kind describes the data type of the Number. |
|
type Kind int8 |
|
|
|
const ( |
|
// Int64Kind means that the Number stores int64. |
|
Int64Kind Kind = iota |
|
// Float64Kind means that the Number stores float64. |
|
Float64Kind |
|
) |
|
|
|
// Zero returns a zero value for a given Kind |
|
func (k Kind) Zero() Number { |
|
switch k { |
|
case Int64Kind: |
|
return NewInt64Number(0) |
|
case Float64Kind: |
|
return NewFloat64Number(0.) |
|
default: |
|
return Number(0) |
|
} |
|
} |
|
|
|
// Minimum returns the minimum representable value |
|
// for a given Kind |
|
func (k Kind) Minimum() Number { |
|
switch k { |
|
case Int64Kind: |
|
return NewInt64Number(math.MinInt64) |
|
case Float64Kind: |
|
return NewFloat64Number(-1. * math.MaxFloat64) |
|
default: |
|
return Number(0) |
|
} |
|
} |
|
|
|
// Maximum returns the maximum representable value |
|
// for a given Kind |
|
func (k Kind) Maximum() Number { |
|
switch k { |
|
case Int64Kind: |
|
return NewInt64Number(math.MaxInt64) |
|
case Float64Kind: |
|
return NewFloat64Number(math.MaxFloat64) |
|
default: |
|
return Number(0) |
|
} |
|
} |
|
|
|
// Number represents either an integral or a floating point value. It |
|
// needs to be accompanied with a source of Kind that describes |
|
// the actual type of the value stored within Number. |
|
type Number uint64 |
|
|
|
// - constructors |
|
|
|
// NewNumberFromRaw creates a new Number from a raw value. |
|
func NewNumberFromRaw(r uint64) Number { |
|
return Number(r) |
|
} |
|
|
|
// NewInt64Number creates an integral Number. |
|
func NewInt64Number(i int64) Number { |
|
return NewNumberFromRaw(internal.Int64ToRaw(i)) |
|
} |
|
|
|
// NewFloat64Number creates a floating point Number. |
|
func NewFloat64Number(f float64) Number { |
|
return NewNumberFromRaw(internal.Float64ToRaw(f)) |
|
} |
|
|
|
// NewNumberSignChange returns a number with the same magnitude and |
|
// the opposite sign. `kind` must describe the kind of number in `nn`. |
|
func NewNumberSignChange(kind Kind, nn Number) Number { |
|
switch kind { |
|
case Int64Kind: |
|
return NewInt64Number(-nn.AsInt64()) |
|
case Float64Kind: |
|
return NewFloat64Number(-nn.AsFloat64()) |
|
} |
|
return nn |
|
} |
|
|
|
// - as x |
|
|
|
// AsNumber gets the Number. |
|
func (n *Number) AsNumber() Number { |
|
return *n |
|
} |
|
|
|
// AsRaw gets the uninterpreted raw value. Might be useful for some |
|
// atomic operations. |
|
func (n *Number) AsRaw() uint64 { |
|
return uint64(*n) |
|
} |
|
|
|
// AsInt64 assumes that the value contains an int64 and returns it as |
|
// such. |
|
func (n *Number) AsInt64() int64 { |
|
return internal.RawToInt64(n.AsRaw()) |
|
} |
|
|
|
// AsFloat64 assumes that the measurement value contains a float64 and |
|
// returns it as such. |
|
func (n *Number) AsFloat64() float64 { |
|
return internal.RawToFloat64(n.AsRaw()) |
|
} |
|
|
|
// - as x atomic |
|
|
|
// AsNumberAtomic gets the Number atomically. |
|
func (n *Number) AsNumberAtomic() Number { |
|
return NewNumberFromRaw(n.AsRawAtomic()) |
|
} |
|
|
|
// AsRawAtomic gets the uninterpreted raw value atomically. Might be |
|
// useful for some atomic operations. |
|
func (n *Number) AsRawAtomic() uint64 { |
|
return atomic.LoadUint64(n.AsRawPtr()) |
|
} |
|
|
|
// AsInt64Atomic assumes that the number contains an int64 and returns |
|
// it as such atomically. |
|
func (n *Number) AsInt64Atomic() int64 { |
|
return atomic.LoadInt64(n.AsInt64Ptr()) |
|
} |
|
|
|
// AsFloat64Atomic assumes that the measurement value contains a |
|
// float64 and returns it as such atomically. |
|
func (n *Number) AsFloat64Atomic() float64 { |
|
return internal.RawToFloat64(n.AsRawAtomic()) |
|
} |
|
|
|
// - as x ptr |
|
|
|
// AsRawPtr gets the pointer to the raw, uninterpreted raw |
|
// value. Might be useful for some atomic operations. |
|
func (n *Number) AsRawPtr() *uint64 { |
|
return (*uint64)(n) |
|
} |
|
|
|
// AsInt64Ptr assumes that the number contains an int64 and returns a |
|
// pointer to it. |
|
func (n *Number) AsInt64Ptr() *int64 { |
|
return internal.RawPtrToInt64Ptr(n.AsRawPtr()) |
|
} |
|
|
|
// AsFloat64Ptr assumes that the number contains a float64 and returns a |
|
// pointer to it. |
|
func (n *Number) AsFloat64Ptr() *float64 { |
|
return internal.RawPtrToFloat64Ptr(n.AsRawPtr()) |
|
} |
|
|
|
// - coerce |
|
|
|
// CoerceToInt64 casts the number to int64. May result in |
|
// data/precision loss. |
|
func (n *Number) CoerceToInt64(kind Kind) int64 { |
|
switch kind { |
|
case Int64Kind: |
|
return n.AsInt64() |
|
case Float64Kind: |
|
return int64(n.AsFloat64()) |
|
default: |
|
// you get what you deserve |
|
return 0 |
|
} |
|
} |
|
|
|
// CoerceToFloat64 casts the number to float64. May result in |
|
// data/precision loss. |
|
func (n *Number) CoerceToFloat64(kind Kind) float64 { |
|
switch kind { |
|
case Int64Kind: |
|
return float64(n.AsInt64()) |
|
case Float64Kind: |
|
return n.AsFloat64() |
|
default: |
|
// you get what you deserve |
|
return 0 |
|
} |
|
} |
|
|
|
// - set |
|
|
|
// SetNumber sets the number to the passed number. Both should be of |
|
// the same kind. |
|
func (n *Number) SetNumber(nn Number) { |
|
*n.AsRawPtr() = nn.AsRaw() |
|
} |
|
|
|
// SetRaw sets the number to the passed raw value. Both number and the |
|
// raw number should represent the same kind. |
|
func (n *Number) SetRaw(r uint64) { |
|
*n.AsRawPtr() = r |
|
} |
|
|
|
// SetInt64 assumes that the number contains an int64 and sets it to |
|
// the passed value. |
|
func (n *Number) SetInt64(i int64) { |
|
*n.AsInt64Ptr() = i |
|
} |
|
|
|
// SetFloat64 assumes that the number contains a float64 and sets it |
|
// to the passed value. |
|
func (n *Number) SetFloat64(f float64) { |
|
*n.AsFloat64Ptr() = f |
|
} |
|
|
|
// - set atomic |
|
|
|
// SetNumberAtomic sets the number to the passed number |
|
// atomically. Both should be of the same kind. |
|
func (n *Number) SetNumberAtomic(nn Number) { |
|
atomic.StoreUint64(n.AsRawPtr(), nn.AsRaw()) |
|
} |
|
|
|
// SetRawAtomic sets the number to the passed raw value |
|
// atomically. Both number and the raw number should represent the |
|
// same kind. |
|
func (n *Number) SetRawAtomic(r uint64) { |
|
atomic.StoreUint64(n.AsRawPtr(), r) |
|
} |
|
|
|
// SetInt64Atomic assumes that the number contains an int64 and sets |
|
// it to the passed value atomically. |
|
func (n *Number) SetInt64Atomic(i int64) { |
|
atomic.StoreInt64(n.AsInt64Ptr(), i) |
|
} |
|
|
|
// SetFloat64Atomic assumes that the number contains a float64 and |
|
// sets it to the passed value atomically. |
|
func (n *Number) SetFloat64Atomic(f float64) { |
|
atomic.StoreUint64(n.AsRawPtr(), internal.Float64ToRaw(f)) |
|
} |
|
|
|
// - swap |
|
|
|
// SwapNumber sets the number to the passed number and returns the old |
|
// number. Both this number and the passed number should be of the |
|
// same kind. |
|
func (n *Number) SwapNumber(nn Number) Number { |
|
old := *n |
|
n.SetNumber(nn) |
|
return old |
|
} |
|
|
|
// SwapRaw sets the number to the passed raw value and returns the old |
|
// raw value. Both number and the raw number should represent the same |
|
// kind. |
|
func (n *Number) SwapRaw(r uint64) uint64 { |
|
old := n.AsRaw() |
|
n.SetRaw(r) |
|
return old |
|
} |
|
|
|
// SwapInt64 assumes that the number contains an int64, sets it to the |
|
// passed value and returns the old int64 value. |
|
func (n *Number) SwapInt64(i int64) int64 { |
|
old := n.AsInt64() |
|
n.SetInt64(i) |
|
return old |
|
} |
|
|
|
// SwapFloat64 assumes that the number contains an float64, sets it to |
|
// the passed value and returns the old float64 value. |
|
func (n *Number) SwapFloat64(f float64) float64 { |
|
old := n.AsFloat64() |
|
n.SetFloat64(f) |
|
return old |
|
} |
|
|
|
// - swap atomic |
|
|
|
// SwapNumberAtomic sets the number to the passed number and returns |
|
// the old number atomically. Both this number and the passed number |
|
// should be of the same kind. |
|
func (n *Number) SwapNumberAtomic(nn Number) Number { |
|
return NewNumberFromRaw(atomic.SwapUint64(n.AsRawPtr(), nn.AsRaw())) |
|
} |
|
|
|
// SwapRawAtomic sets the number to the passed raw value and returns |
|
// the old raw value atomically. Both number and the raw number should |
|
// represent the same kind. |
|
func (n *Number) SwapRawAtomic(r uint64) uint64 { |
|
return atomic.SwapUint64(n.AsRawPtr(), r) |
|
} |
|
|
|
// SwapInt64Atomic assumes that the number contains an int64, sets it |
|
// to the passed value and returns the old int64 value atomically. |
|
func (n *Number) SwapInt64Atomic(i int64) int64 { |
|
return atomic.SwapInt64(n.AsInt64Ptr(), i) |
|
} |
|
|
|
// SwapFloat64Atomic assumes that the number contains an float64, sets |
|
// it to the passed value and returns the old float64 value |
|
// atomically. |
|
func (n *Number) SwapFloat64Atomic(f float64) float64 { |
|
return internal.RawToFloat64(atomic.SwapUint64(n.AsRawPtr(), internal.Float64ToRaw(f))) |
|
} |
|
|
|
// - add |
|
|
|
// AddNumber assumes that this and the passed number are of the passed |
|
// kind and adds the passed number to this number. |
|
func (n *Number) AddNumber(kind Kind, nn Number) { |
|
switch kind { |
|
case Int64Kind: |
|
n.AddInt64(nn.AsInt64()) |
|
case Float64Kind: |
|
n.AddFloat64(nn.AsFloat64()) |
|
} |
|
} |
|
|
|
// AddRaw assumes that this number and the passed raw value are of the |
|
// passed kind and adds the passed raw value to this number. |
|
func (n *Number) AddRaw(kind Kind, r uint64) { |
|
n.AddNumber(kind, NewNumberFromRaw(r)) |
|
} |
|
|
|
// AddInt64 assumes that the number contains an int64 and adds the |
|
// passed int64 to it. |
|
func (n *Number) AddInt64(i int64) { |
|
*n.AsInt64Ptr() += i |
|
} |
|
|
|
// AddFloat64 assumes that the number contains a float64 and adds the |
|
// passed float64 to it. |
|
func (n *Number) AddFloat64(f float64) { |
|
*n.AsFloat64Ptr() += f |
|
} |
|
|
|
// - add atomic |
|
|
|
// AddNumberAtomic assumes that this and the passed number are of the |
|
// passed kind and adds the passed number to this number atomically. |
|
func (n *Number) AddNumberAtomic(kind Kind, nn Number) { |
|
switch kind { |
|
case Int64Kind: |
|
n.AddInt64Atomic(nn.AsInt64()) |
|
case Float64Kind: |
|
n.AddFloat64Atomic(nn.AsFloat64()) |
|
} |
|
} |
|
|
|
// AddRawAtomic assumes that this number and the passed raw value are |
|
// of the passed kind and adds the passed raw value to this number |
|
// atomically. |
|
func (n *Number) AddRawAtomic(kind Kind, r uint64) { |
|
n.AddNumberAtomic(kind, NewNumberFromRaw(r)) |
|
} |
|
|
|
// AddInt64Atomic assumes that the number contains an int64 and adds |
|
// the passed int64 to it atomically. |
|
func (n *Number) AddInt64Atomic(i int64) { |
|
atomic.AddInt64(n.AsInt64Ptr(), i) |
|
} |
|
|
|
// AddFloat64Atomic assumes that the number contains a float64 and |
|
// adds the passed float64 to it atomically. |
|
func (n *Number) AddFloat64Atomic(f float64) { |
|
for { |
|
o := n.AsFloat64Atomic() |
|
if n.CompareAndSwapFloat64(o, o+f) { |
|
break |
|
} |
|
} |
|
} |
|
|
|
// - compare and swap (atomic only) |
|
|
|
// CompareAndSwapNumber does the atomic CAS operation on this |
|
// number. This number and passed old and new numbers should be of the |
|
// same kind. |
|
func (n *Number) CompareAndSwapNumber(on, nn Number) bool { |
|
return atomic.CompareAndSwapUint64(n.AsRawPtr(), on.AsRaw(), nn.AsRaw()) |
|
} |
|
|
|
// CompareAndSwapRaw does the atomic CAS operation on this |
|
// number. This number and passed old and new raw values should be of |
|
// the same kind. |
|
func (n *Number) CompareAndSwapRaw(or, nr uint64) bool { |
|
return atomic.CompareAndSwapUint64(n.AsRawPtr(), or, nr) |
|
} |
|
|
|
// CompareAndSwapInt64 assumes that this number contains an int64 and |
|
// does the atomic CAS operation on it. |
|
func (n *Number) CompareAndSwapInt64(oi, ni int64) bool { |
|
return atomic.CompareAndSwapInt64(n.AsInt64Ptr(), oi, ni) |
|
} |
|
|
|
// CompareAndSwapFloat64 assumes that this number contains a float64 and |
|
// does the atomic CAS operation on it. |
|
func (n *Number) CompareAndSwapFloat64(of, nf float64) bool { |
|
return atomic.CompareAndSwapUint64(n.AsRawPtr(), internal.Float64ToRaw(of), internal.Float64ToRaw(nf)) |
|
} |
|
|
|
// - compare |
|
|
|
// CompareNumber compares two Numbers given their kind. Both numbers |
|
// should have the same kind. This returns: |
|
// 0 if the numbers are equal |
|
// -1 if the subject `n` is less than the argument `nn` |
|
// +1 if the subject `n` is greater than the argument `nn` |
|
func (n *Number) CompareNumber(kind Kind, nn Number) int { |
|
switch kind { |
|
case Int64Kind: |
|
return n.CompareInt64(nn.AsInt64()) |
|
case Float64Kind: |
|
return n.CompareFloat64(nn.AsFloat64()) |
|
default: |
|
// you get what you deserve |
|
return 0 |
|
} |
|
} |
|
|
|
// CompareRaw compares two numbers, where one is input as a raw |
|
// uint64, interpreting both values as a `kind` of number. |
|
func (n *Number) CompareRaw(kind Kind, r uint64) int { |
|
return n.CompareNumber(kind, NewNumberFromRaw(r)) |
|
} |
|
|
|
// CompareInt64 assumes that the Number contains an int64 and performs |
|
// a comparison between the value and the other value. It returns the |
|
// typical result of the compare function: -1 if the value is less |
|
// than the other, 0 if both are equal, 1 if the value is greater than |
|
// the other. |
|
func (n *Number) CompareInt64(i int64) int { |
|
this := n.AsInt64() |
|
if this < i { |
|
return -1 |
|
} else if this > i { |
|
return 1 |
|
} |
|
return 0 |
|
} |
|
|
|
// CompareFloat64 assumes that the Number contains a float64 and |
|
// performs a comparison between the value and the other value. It |
|
// returns the typical result of the compare function: -1 if the value |
|
// is less than the other, 0 if both are equal, 1 if the value is |
|
// greater than the other. |
|
// |
|
// Do not compare NaN values. |
|
func (n *Number) CompareFloat64(f float64) int { |
|
this := n.AsFloat64() |
|
if this < f { |
|
return -1 |
|
} else if this > f { |
|
return 1 |
|
} |
|
return 0 |
|
} |
|
|
|
// - relations to zero |
|
|
|
// IsPositive returns true if the actual value is greater than zero. |
|
func (n *Number) IsPositive(kind Kind) bool { |
|
return n.compareWithZero(kind) > 0 |
|
} |
|
|
|
// IsNegative returns true if the actual value is less than zero. |
|
func (n *Number) IsNegative(kind Kind) bool { |
|
return n.compareWithZero(kind) < 0 |
|
} |
|
|
|
// IsZero returns true if the actual value is equal to zero. |
|
func (n *Number) IsZero(kind Kind) bool { |
|
return n.compareWithZero(kind) == 0 |
|
} |
|
|
|
// - misc |
|
|
|
// Emit returns a string representation of the raw value of the |
|
// Number. A %d is used for integral values, %f for floating point |
|
// values. |
|
func (n *Number) Emit(kind Kind) string { |
|
switch kind { |
|
case Int64Kind: |
|
return fmt.Sprintf("%d", n.AsInt64()) |
|
case Float64Kind: |
|
return fmt.Sprintf("%f", n.AsFloat64()) |
|
default: |
|
return "" |
|
} |
|
} |
|
|
|
// AsInterface returns the number as an interface{}, typically used |
|
// for Kind-correct JSON conversion. |
|
func (n *Number) AsInterface(kind Kind) interface{} { |
|
switch kind { |
|
case Int64Kind: |
|
return n.AsInt64() |
|
case Float64Kind: |
|
return n.AsFloat64() |
|
default: |
|
return math.NaN() |
|
} |
|
} |
|
|
|
// - private stuff |
|
|
|
func (n *Number) compareWithZero(kind Kind) int { |
|
switch kind { |
|
case Int64Kind: |
|
return n.CompareInt64(0) |
|
case Float64Kind: |
|
return n.CompareFloat64(0.) |
|
default: |
|
// you get what you deserve |
|
return 0 |
|
} |
|
}
|
|
|