fix(go.sum): update ResolveSpec dependency to v1.0.87
This commit is contained in:
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
© 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
|
||||
ISC License
|
||||
|
||||
Modified by htemelski-redis
|
||||
Removed the treshold, adapted it to work with float64
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
// AtomicMax is a thread-safe max container
|
||||
// - hasValue indicator true if a value was equal to or greater than threshold
|
||||
// - optional threshold for minimum accepted max value
|
||||
// - if threshold is not used, initialization-free
|
||||
// - —
|
||||
// - wait-free CompareAndSwap mechanic
|
||||
type AtomicMax struct {
|
||||
|
||||
// value is current max
|
||||
value atomic.Float64
|
||||
// whether [AtomicMax.Value] has been invoked
|
||||
// with value equal or greater to threshold
|
||||
hasValue atomic.Bool
|
||||
}
|
||||
|
||||
// NewAtomicMax returns a thread-safe max container
|
||||
// - if threshold is not used, AtomicMax is initialization-free
|
||||
func NewAtomicMax() (atomicMax *AtomicMax) {
|
||||
m := AtomicMax{}
|
||||
m.value.Store((-math.MaxFloat64))
|
||||
return &m
|
||||
}
|
||||
|
||||
// Value updates the container with a possible max value
|
||||
// - isNewMax is true if:
|
||||
// - — value is equal to or greater than any threshold and
|
||||
// - — invocation recorded the first 0 or
|
||||
// - — a new max
|
||||
// - upon return, Max and Max1 are guaranteed to reflect the invocation
|
||||
// - the return order of concurrent Value invocations is not guaranteed
|
||||
// - Thread-safe
|
||||
func (m *AtomicMax) Value(value float64) (isNewMax bool) {
|
||||
// -math.MaxFloat64 as max case
|
||||
var hasValue0 = m.hasValue.Load()
|
||||
if value == (-math.MaxFloat64) {
|
||||
if !hasValue0 {
|
||||
isNewMax = m.hasValue.CompareAndSwap(false, true)
|
||||
}
|
||||
return // -math.MaxFloat64 as max: isNewMax true for first 0 writer
|
||||
}
|
||||
|
||||
// check against present value
|
||||
var current = m.value.Load()
|
||||
if isNewMax = value > current; !isNewMax {
|
||||
return // not a new max return: isNewMax false
|
||||
}
|
||||
|
||||
// store the new max
|
||||
for {
|
||||
|
||||
// try to write value to *max
|
||||
if isNewMax = m.value.CompareAndSwap(current, value); isNewMax {
|
||||
if !hasValue0 {
|
||||
// may be rarely written multiple times
|
||||
// still faster than CompareAndSwap
|
||||
m.hasValue.Store(true)
|
||||
}
|
||||
return // new max written return: isNewMax true
|
||||
}
|
||||
if current = m.value.Load(); current >= value {
|
||||
return // no longer a need to write return: isNewMax false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Max returns current max and value-present flag
|
||||
// - hasValue true indicates that value reflects a Value invocation
|
||||
// - hasValue false: value is zero-value
|
||||
// - Thread-safe
|
||||
func (m *AtomicMax) Max() (value float64, hasValue bool) {
|
||||
if hasValue = m.hasValue.Load(); !hasValue {
|
||||
return
|
||||
}
|
||||
value = m.value.Load()
|
||||
return
|
||||
}
|
||||
|
||||
// Max1 returns current maximum whether zero-value or set by Value
|
||||
// - threshold is ignored
|
||||
// - Thread-safe
|
||||
func (m *AtomicMax) Max1() (value float64) { return m.value.Load() }
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package util
|
||||
|
||||
/*
|
||||
© 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
|
||||
ISC License
|
||||
|
||||
Modified by htemelski-redis
|
||||
Adapted from the modified atomic_max, but with inverted logic
|
||||
*/
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
// AtomicMin is a thread-safe Min container
|
||||
// - hasValue indicator true if a value was equal to or greater than threshold
|
||||
// - optional threshold for minimum accepted Min value
|
||||
// - —
|
||||
// - wait-free CompareAndSwap mechanic
|
||||
type AtomicMin struct {
|
||||
|
||||
// value is current Min
|
||||
value atomic.Float64
|
||||
// whether [AtomicMin.Value] has been invoked
|
||||
// with value equal or greater to threshold
|
||||
hasValue atomic.Bool
|
||||
}
|
||||
|
||||
// NewAtomicMin returns a thread-safe Min container
|
||||
// - if threshold is not used, AtomicMin is initialization-free
|
||||
func NewAtomicMin() (atomicMin *AtomicMin) {
|
||||
m := AtomicMin{}
|
||||
m.value.Store(math.MaxFloat64)
|
||||
return &m
|
||||
}
|
||||
|
||||
// Value updates the container with a possible Min value
|
||||
// - isNewMin is true if:
|
||||
// - — value is equal to or greater than any threshold and
|
||||
// - — invocation recorded the first 0 or
|
||||
// - — a new Min
|
||||
// - upon return, Min and Min1 are guaranteed to reflect the invocation
|
||||
// - the return order of concurrent Value invocations is not guaranteed
|
||||
// - Thread-safe
|
||||
func (m *AtomicMin) Value(value float64) (isNewMin bool) {
|
||||
// math.MaxFloat64 as Min case
|
||||
var hasValue0 = m.hasValue.Load()
|
||||
if value == math.MaxFloat64 {
|
||||
if !hasValue0 {
|
||||
isNewMin = m.hasValue.CompareAndSwap(false, true)
|
||||
}
|
||||
return // math.MaxFloat64 as Min: isNewMin true for first 0 writer
|
||||
}
|
||||
|
||||
// check against present value
|
||||
var current = m.value.Load()
|
||||
if isNewMin = value < current; !isNewMin {
|
||||
return // not a new Min return: isNewMin false
|
||||
}
|
||||
|
||||
// store the new Min
|
||||
for {
|
||||
|
||||
// try to write value to *Min
|
||||
if isNewMin = m.value.CompareAndSwap(current, value); isNewMin {
|
||||
if !hasValue0 {
|
||||
// may be rarely written multiple times
|
||||
// still faster than CompareAndSwap
|
||||
m.hasValue.Store(true)
|
||||
}
|
||||
return // new Min written return: isNewMin true
|
||||
}
|
||||
if current = m.value.Load(); current <= value {
|
||||
return // no longer a need to write return: isNewMin false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Min returns current min and value-present flag
|
||||
// - hasValue true indicates that value reflects a Value invocation
|
||||
// - hasValue false: value is zero-value
|
||||
// - Thread-safe
|
||||
func (m *AtomicMin) Min() (value float64, hasValue bool) {
|
||||
if hasValue = m.hasValue.Load(); !hasValue {
|
||||
return
|
||||
}
|
||||
value = m.value.Load()
|
||||
return
|
||||
}
|
||||
|
||||
// Min1 returns current Minimum whether zero-value or set by Value
|
||||
// - threshold is ignored
|
||||
// - Thread-safe
|
||||
func (m *AtomicMin) Min1() (value float64) { return m.value.Load() }
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ParseFloat parses a Redis RESP3 float reply into a Go float64,
|
||||
// handling "inf", "-inf", "nan" per Redis conventions.
|
||||
func ParseStringToFloat(s string) (float64, error) {
|
||||
switch s {
|
||||
case "inf":
|
||||
return math.Inf(1), nil
|
||||
case "-inf":
|
||||
return math.Inf(-1), nil
|
||||
case "nan", "-nan":
|
||||
return math.NaN(), nil
|
||||
}
|
||||
return strconv.ParseFloat(s, 64)
|
||||
}
|
||||
|
||||
// MustParseFloat is like ParseFloat but panics on parse errors.
|
||||
func MustParseFloat(s string) float64 {
|
||||
f, err := ParseStringToFloat(s)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("redis: failed to parse float %q: %v", s, err))
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// SafeIntToInt32 safely converts an int to int32, returning an error if overflow would occur.
|
||||
func SafeIntToInt32(value int, fieldName string) (int32, error) {
|
||||
if value > math.MaxInt32 {
|
||||
return 0, fmt.Errorf("redis: %s value %d exceeds maximum allowed value %d", fieldName, value, math.MaxInt32)
|
||||
}
|
||||
if value < math.MinInt32 {
|
||||
return 0, fmt.Errorf("redis: %s value %d is below minimum allowed value %d", fieldName, value, math.MinInt32)
|
||||
}
|
||||
return int32(value), nil
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
//go:build appengine
|
||||
|
||||
package util
|
||||
|
||||
func BytesToString(b []byte) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func StringToBytes(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package util
|
||||
|
||||
import "strconv"
|
||||
|
||||
func Atoi(b []byte) (int, error) {
|
||||
return strconv.Atoi(BytesToString(b))
|
||||
}
|
||||
|
||||
func ParseInt(b []byte, base int, bitSize int) (int64, error) {
|
||||
return strconv.ParseInt(BytesToString(b), base, bitSize)
|
||||
}
|
||||
|
||||
func ParseUint(b []byte, base int, bitSize int) (uint64, error) {
|
||||
return strconv.ParseUint(BytesToString(b), base, bitSize)
|
||||
}
|
||||
|
||||
func ParseFloat(b []byte, bitSize int) (float64, error) {
|
||||
return strconv.ParseFloat(BytesToString(b), bitSize)
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package util
|
||||
|
||||
func ToPtr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
//go:build !appengine
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// BytesToString converts byte slice to string.
|
||||
func BytesToString(b []byte) string {
|
||||
return unsafe.String(unsafe.SliceData(b), len(b))
|
||||
}
|
||||
|
||||
// StringToBytes converts string to byte slice.
|
||||
func StringToBytes(s string) []byte {
|
||||
return unsafe.Slice(unsafe.StringData(s), len(s))
|
||||
}
|
||||
Reference in New Issue
Block a user