Documentation
¶
Overview ¶
Package adt provides "atomic data types" as strongly-typed generic helpers for simple atomic operations (including sync.Map, sync.Pool, and a typed value).
Index ¶
- Constants
- func AccessorsWithLock[T any](getter fn.Future[T], setter fn.Handler[T]) (fn.Future[T], fn.Handler[T])
- func AccessorsWithReadLock[T any](getter fn.Future[T], setter fn.Handler[T]) (fn.Future[T], fn.Handler[T])
- func CompareAndSwap[T comparable, A AtomicValue[T]](a A, oldVal, newVal T) bool
- func Lock(mtx *sync.Mutex) *sync.Mutex
- func LockR(m *sync.RWMutex) *sync.RWMutex
- func LockW(m *sync.RWMutex) *sync.RWMutex
- func LocksHeld(mtxs []*sync.Mutex) []*sync.Mutex
- func Reset[T intish.Numbers, A AtomicValue[T]](a A) T
- func SafeSet[T comparable, A AtomicValue[T]](atom A, value T)
- func With(mtx *sync.Mutex)
- func WithAll(locks []*sync.Mutex)
- func WithR(m *sync.RWMutex)
- func WithW(m *sync.RWMutex)
- type Atomic
- type AtomicValue
- type Element
- func (el *Element[T]) Drop()
- func (el *Element[T]) Get() (*T, bool)
- func (el *Element[T]) Next() *Element[T]
- func (el *Element[T]) Ok() bool
- func (el *Element[T]) Pop() *T
- func (el *Element[T]) Previous() *Element[T]
- func (el *Element[T]) Ref() T
- func (el *Element[T]) RefOk() (T, bool)
- func (el *Element[T]) Set(v *T) *Element[T]
- func (el *Element[T]) Unset() (out *T, ok bool)
- func (el *Element[T]) Value() *T
- type List
- type Map
- func (mp *Map[K, V]) Check(key K) bool
- func (mp *Map[K, V]) Delete(key K)
- func (mp *Map[K, V]) Ensure(key K)
- func (mp *Map[K, V]) EnsureDefault(key K, constr func() V) V
- func (mp *Map[K, V]) EnsureSet(i dt.Pair[K, V]) bool
- func (mp *Map[K, V]) EnsureStore(k K, v V) bool
- func (mp *Map[K, V]) Get(key K) V
- func (mp *Map[K, V]) Iterator() iter.Seq2[K, V]
- func (mp *Map[K, V]) Keys() *fun.Stream[K]
- func (mp *Map[K, V]) Len() int
- func (mp *Map[K, V]) Load(key K) (V, bool)
- func (mp *Map[K, V]) MarshalJSON() ([]byte, error)
- func (mp *Map[K, V]) Range(fn func(K, V) bool)
- func (mp *Map[K, V]) Set(it dt.Pair[K, V])
- func (mp *Map[K, V]) Store(k K, v V)
- func (mp *Map[K, V]) Stream() *fun.Stream[dt.Pair[K, V]]
- func (mp *Map[K, V]) Swap(k K, v V) (V, bool)
- func (mp *Map[K, V]) UnmarshalJSON(in []byte) error
- func (mp *Map[K, V]) Values() *fun.Stream[V]
- type Once
- type Pool
- type Synchronized
- func (s *Synchronized[T]) Get() T
- func (s *Synchronized[T]) Load() T
- func (s *Synchronized[T]) Set(in T)
- func (s *Synchronized[T]) Store(in T)
- func (s *Synchronized[T]) String() string
- func (s *Synchronized[T]) Swap(newVal T) (old T)
- func (s *Synchronized[T]) Using(op func())
- func (s *Synchronized[T]) With(in func(obj T))
Constants ¶
const ( // ErrOperationOnDetachedElements is used as the value for panics when attempting to manipulate add to elements that are not connected to a list. ErrOperationOnDetachedElements = ers.Error("impossible operation: detached elements") // ErrOperationOnAttachedElements is used as a panic value when attempting to attach elements that already belong to a list to a different list. ErrOperationOnAttachedElements = ers.Error("operation impacts elements attached to another list") // probably a bug in // ErrOperationOnRootElement is used as a panic when attempting to read the value or performing an // operation that is impossible to perform on the root object. ErrOperationOnRootElement = ers.Error("operation not permissible on the sentinel node ") // probably a bug in the list implementation )
Variables ¶
This section is empty.
Functions ¶
func AccessorsWithLock ¶ added in v0.10.5
func AccessorsWithLock[T any](getter fn.Future[T], setter fn.Handler[T]) (fn.Future[T], fn.Handler[T])
AccessorsWithLock takes a getter/setter pair and configures both with a shared mutex: all read/write operations are fully synchronized with regards to eachother.
func AccessorsWithReadLock ¶ added in v0.10.5
func AccessorsWithReadLock[T any](getter fn.Future[T], setter fn.Handler[T]) (fn.Future[T], fn.Handler[T])
AccessorsWithReadLock takes a getter/setter pair and configures them with a rw-mutex: the getter (Future) uses the read lock, while the setter is write-locked.
func CompareAndSwap ¶
func CompareAndSwap[T comparable, A AtomicValue[T]](a A, oldVal, newVal T) bool
CompareAndSwap exposes the CompareAndSwap option for atomics that store values of comparable types. Only supports the Atomic and Synchronized types, as well as any type that implement a CompareAndSwap method for old/new values of T. Panics for all other types.
func Lock ¶ added in v0.10.0
Lock takes the lock, locks it, and then returns it.
This, in combination With() makes it possible to have a single statement for managing a mutex in a defer, given the evaluation time of defer arguments, as in:
mtx := &sync.Mutex{}
defer adt.With(adt.Lock(mtx))
func LockR ¶ added in v0.12.0
LockR takes an RWMutex locks it in read-mode and returns it to be unlocked WithR.
func LockW ¶ added in v0.12.0
LockW takes a RWMutex, locks as a write, and returns it to be unlocked by WithW.
func LocksHeld ¶ added in v0.13.0
LocksHeld acquires all of the locks in the slice, and returns them, for use with the adt.WithAll function. If some of the locks are held, all locks are released the operation sleeps for a short period of time (upto 3ms) and then attempts to acquire the locks again. Retries attempt to acquire the locks in different orders to avoid implicit dependencies on lock order.
func Reset ¶ added in v0.10.2
func Reset[T intish.Numbers, A AtomicValue[T]](a A) T
Reset sets the atomic, for an atomic value that holds a number, to 0, and returns the previously stored value.
func SafeSet ¶
func SafeSet[T comparable, A AtomicValue[T]](atom A, value T)
SafeSet sets the atomic to the given value only if the value is not the Zero value for that type.
func With ¶ added in v0.10.0
With takes a lock as an argument and then releases the lock when it executes.
This, in combination with Lock makes it possible to have a single statement for managing a mutex in a defer, given the evaluation time of defer arguments, as in:
mtx := &sync.Mutex{}
defer adt.With(adt.Lock(mtx))
func WithAll ¶ added in v0.13.0
WithAll releases all of the non-nill locks in slice of mutexes, and can be used with adt.LocksHeld in a defer statement.
Types ¶
type Atomic ¶
type Atomic[T any] struct { // contains filtered or unexported fields }
Atomic is a very simple atomic Get/Set operation, providing a generic type-safe implementation wrapping sync/atomic.Value. The primary caveat is that interface types are not compatible with adt.Atomic as a result of the standard library's underlying atomic type. To store interface objects atomically you can wrap the object in a function, using ft.Wrapper.
func NewAtomic ¶
NewAtomic creates a new Atomic Get/Set value with the initial value already set. This is a helper for creating a new atomic with a default value set.
func (*Atomic[T]) Get ¶
func (a *Atomic[T]) Get() T
Get resolves the atomic value, returning the zero value of the type T if the value is unset.
func (*Atomic[T]) Load ¶ added in v0.10.2
func (a *Atomic[T]) Load() T
Load returns the value stored in the atomic. It mirrors the standard library's interface for atomics.
type AtomicValue ¶ added in v0.9.0
type AtomicValue[T any] interface { Load() T Store(T) Swap(T) T }
AtomicValue describes the public interface of the Atomic type. Use this definition to compose atomic types into other interfaces.
type Element ¶ added in v0.13.0
type Element[T any] struct { // contains filtered or unexported fields }
Element is a container for an item in a doubly linked list.
func (*Element[T]) Drop ¶ added in v0.13.0
func (el *Element[T]) Drop()
Drop removes this element from its list, discarding the value it contained. This operation is safe for concurrent access and is equivalent to calling Pop() and ignoring the result.
func (*Element[T]) Get ¶ added in v0.13.0
Get returns the value stored in this element and a boolean indicating whether the element contains a valid value. Returns (nil, false) if the element is nil or contains no value. Safe for concurrent access.
func (*Element[T]) Next ¶ added in v0.13.0
Next returns the next element in the list, or nil if this is the last element. Safe to call on nil elements, which will return nil.
func (*Element[T]) Ok ¶ added in v0.13.0
Ok returns true if this element contains a valid value, false otherwise. Safe to call on nil elements, which will return false.
func (*Element[T]) Pop ¶ added in v0.13.0
func (el *Element[T]) Pop() *T
Pop removes this element from its list and returns the value it contained. Returns nil if the element was already detached or contained no value. This operation is safe for concurrent access.
func (*Element[T]) Previous ¶ added in v0.13.0
Previous returns the previous element in the list, or nil if this is the first element. Safe to call on nil elements, which will return nil.
func (*Element[T]) Ref ¶ added in v0.13.0
func (el *Element[T]) Ref() T
Ref returns the value stored in this element by dereferencing the pointer. Panics if the element is nil or contains no value.
func (*Element[T]) RefOk ¶ added in v0.13.0
RefOk returns the value stored in this element and a boolean indicating success. Returns the zero value and false if the element is nil or contains no value.
func (*Element[T]) Set ¶ added in v0.13.0
Set stores the given value in this element and returns the element for method chaining. Panics if called on a root/sentinel element. This operation is safe for concurrent access.
type List ¶ added in v0.13.0
type List[T any] struct { // contains filtered or unexported fields }
List is a container type for a doublly-linked list that supports appending and prepending elements, as well as inserting elements in the middle of the list. These lists are safe for concurrent access, and operations only require exclusive access to, at most 3 nodes in the list. Becaues the list tracks it's length centrally, calls to Len() are efficient and safe.
func (*List[T]) Head ¶ added in v0.13.0
Head returns the first element in the list, or nil if the list is empty.
func (*List[T]) Len ¶ added in v0.13.0
Len returns the current number of elements in the list. This operation is efficient and safe for concurrent access as the length is tracked atomically.
func (*List[T]) PopBack ¶ added in v0.13.0
func (l *List[T]) PopBack() *T
PopBack removes and returns the value from the last element in the list. Returns nil if the list is empty.
func (*List[T]) PopFront ¶ added in v0.13.0
func (l *List[T]) PopFront() *T
PopFront removes and returns the value from the first element in the list. Returns nil if the list is empty.
func (*List[T]) PushBack ¶ added in v0.13.0
func (l *List[T]) PushBack(v *T)
PushBack appends a new element containing the given value to the end of the list. Thise is safe for concurrent access and only requires locking the adjoining nodes.
type Map ¶
type Map[K comparable, V any] struct { // Default handles construction and pools objects in // the map for the Ensure and Get operations which must // construct zero-value items. No configuration or // construction is necessary; however, callers can modify the // default value constructed as needed. Default Pool[V] // contains filtered or unexported fields }
Map provides a wrapper around the standard library's sync.Map type with key/value types enforced by generics. Additional helpers support adding multiple items to the map, while Stream and StoreFrom provide compatibility with streams.
func (*Map[K, V]) Check ¶ added in v0.10.0
Check returns true if the key exists in the map or false otherwise.
func (*Map[K, V]) Delete ¶
func (mp *Map[K, V]) Delete(key K)
Delete removes a key--and its corresponding value--from the map, if it exists.
func (*Map[K, V]) Ensure ¶
func (mp *Map[K, V]) Ensure(key K)
Ensure adds a key to the map if it does not already exist, using the default value. The default value, is taken from the pool, which has a configurable constructor if you want a different default value.
func (*Map[K, V]) EnsureDefault ¶
func (mp *Map[K, V]) EnsureDefault(key K, constr func() V) V
EnsureDefault is similar to EnsureStore and Ensure, but provides the default value as a function that produces a value rather than the value directly. The returned value is *always* the value of the key, which is either the value from the map or the value produced by the function.
The constructor function is *always* called, even when the key exists in the map. Unlike Get and Ensure which have similar semantics and roles, the value produced by function does not participate in the default object pool.
func (*Map[K, V]) EnsureSet ¶ added in v0.8.5
EnsureSet has the same semantics as EnsureStore, but takes a dt.Pair object.
func (*Map[K, V]) EnsureStore ¶ added in v0.8.5
EnsureStore takes a value and returns true if the value was stored in the map.
func (*Map[K, V]) Get ¶
func (mp *Map[K, V]) Get(key K) V
Get retrieves the value from the map at the given value. If the key is not present in the map a default value is created and added to the map.
func (*Map[K, V]) Keys ¶ added in v0.8.5
Keys returns a stream that renders all of the keys in the map.
This operation relies on a the underlying Range stream, and advances lazily through the Range operation as callers advance the stream. Be aware that this produces a stream that does not reflect any particular atomic of the underlying map.
func (*Map[K, V]) Len ¶
Len counts and reports on the number of items in the map. This is provided by iterating and counting the values in the map, and has O(n) performance.
Len uses a range function and therefore does not reflect a specific snapshot of the map at any time if keys are being deleted while Len is running. Len will never report a number that is larger than the total number of items in the map while Len is running, but the number of items in the map may be smaller at the beginning and/or the end than reported.
func (*Map[K, V]) Load ¶
Load retrieves the value from the map. The semantics are the same as for maps in go: if the value does not exist it always returns the zero value for the type, while the second value indicates if the key was present in the map.
func (*Map[K, V]) MarshalJSON ¶
MarshalJSON produces a JSON form of the map, using a Range function to iterate through the values in the map. Range functions do not reflect a specific snapshot of the map if the map is being modified while being marshaled: keys will only appear at most once but order or which version of a value is not defined.
func (*Map[K, V]) Range ¶
Range provides a method for iterating over the values in the map, with a similar API as the standard library's sync.Map. The function is called once on every key in the map. When the range function returns false the iteration stops.
Range functions do not reflect a specific snapshot of the map if the map is being modified while being marshaled: keys will only appear at most once but order or which version of a value is not defined.
func (*Map[K, V]) Store ¶
func (mp *Map[K, V]) Store(k K, v V)
Store adds a key and value to the map, replacing any existing values as needed.
func (*Map[K, V]) Stream ¶ added in v0.12.0
Stream returns a stream that produces a sequence of pair objects.
This operation relies on a the underlying Range stream, and advances lazily through the Range operation as callers advance the stream. Be aware that this produces a stream that does not reflect any particular atomic state of the underlying map.
func (*Map[K, V]) Swap ¶
Swap exchanges the value (v) stored in the map under the key (k) for the current value stored under that key.
func (*Map[K, V]) UnmarshalJSON ¶
UnmarshalJSON takes a json sequence and adds the values to the map. This does not remove or reset the values in the map, and other operations may interleave during this operation.
func (*Map[K, V]) Values ¶ added in v0.8.5
Values returns a stream that renders all of the values in the map.
This operation relies on a the underlying Range iterator, and advances lazily through the Range operation as callers advance the stream. Be aware that this produces a stream that does not reflect any particular atomic of the underlying map.
type Once ¶ added in v0.9.0
type Once[T any] struct { // contains filtered or unexported fields }
Once provides a mnemonic form of sync.Once, caching and returning a value after the Do() function is called.
Panics are only thrown when the underlying constructor is called (and it panics.) Nil constructors are ignored and subsequent attempts to access the value will return the zero value for the return type.
func NewOnce ¶ added in v0.10.0
NewOnce creates a Once object and initializes it with the function provided. This is optional and this function can be later overridden by Set() or Do(). When the operation is complete, the Once value is populated and the .Resolve() method will return the value.
func (*Once[T]) Call ¶ added in v0.12.0
func (o *Once[T]) Call(ctor func() T) T
Call has the same semantics Do but returns the value produced by the constructor function.
func (*Once[T]) Called ¶ added in v0.10.0
Called returns true if the Once object has been called or is currently running, and false otherwise.
func (*Once[T]) Defined ¶ added in v0.10.0
Defined returns true when the function has been set. Use only for observational purpsoses. Though the value is stored in an atomic, it does reflect the state of the underlying operation.
func (*Once[T]) Do ¶ added in v0.9.0
func (o *Once[T]) Do(ctor func() T)
Do runs the function provided, and caches the results. All subsequent calls to Do or Resolve() are noops. If multiple callers use Do/Resolve at the same time, like sync.Once.Do none will return until return until the first operation completes.
Functions passed to Do should return values that are safe for concurrent access: while the Do/Resolve operations are synchronized, the return value from Do is responsible for its own synchronization.
func (*Once[T]) Resolve ¶ added in v0.10.0
func (o *Once[T]) Resolve() T
Resolve runs the stored, if and only if it hasn't been run function and returns its output. If the constructor hasn't been populated, as with Set(), then Resolve() will return the zero value for T. Once the function has run, Resolve will continue to return the cached value.
type Pool ¶
type Pool[T any] struct { // contains filtered or unexported fields }
Pool is an ergonomic wrapper around sync.Pool that provides some additional functionality: generic type interface, a default clean up hook to modify (optionally) the object before returning it to the pool.
Additionally, the Make() method attaches an object finalizer to the object produced by the pool that returns the object to the pool rather than garbage collect it. This is likely to be less efficient than return the objects to the pool using defer functions, but may be more ergonomic in some situations.
Pool can be used with default construction; however, you should set the Constructor before calling Get() or Make() on the pool.
func DefaultBufferPool ¶ added in v0.10.4
DefaultBufferPool creates a pool of byte slices with a maximum size of 64kb. All other slices are discarded. These are the same settings as used by the fmt package's buffer pool.
The type of the pooled object is dt.Slice[byte], a simple type alias for Go's slice type with convenience methods for common slice operations. You can use these values interchangeably with vanilla byte slices, as you need and wish.
func MakeBufferPool ¶ added in v0.10.4
MakeBufferPool constructs a pool of byte slices. New slices are allocated with the specified minimum capacity, and are always resliced to be 0 length before reentering the pool. Slices that are larger than the specified maximum do not reenter the pool.
Min/Max values less than 0 are ignored, and the highest value is always used as the max the lowest as the min, regardless of position. MakeBufferPool panics with an invariant violation if the max capacity value is zero.
The type of the pooled object is dt.Slice[byte], a simple type alias for Go's slice type with convenience methods for common slice operations. You can use these values interchangeably with vanilla byte slices, as you need and wish.
func MakeBytesBufferPool ¶ added in v0.10.4
MakeBytesBufferPool configures a pool of *bytes.Buffers. Buffers are always reset before reentering the pool, and are pre-allocated with the specified capacity. Negative initial capcity values are ignored.
func (*Pool[T]) FinalizeSetup ¶ added in v0.10.4
func (p *Pool[T]) FinalizeSetup()
FinalizeSetup prevents future calls from setting the constructor or cleanup hooks. Once a pool's setup has been finalized it cannot be unset: future attempts to set the constructor or cleanup hook result in a panic and invariant violation. FinalizeSetup is safe to cull multiple times and from different go routines.
func (*Pool[T]) Get ¶
func (p *Pool[T]) Get() T
Get returns an object from the pool or constructs a default object according to the constructor.
func (*Pool[T]) Make ¶
func (p *Pool[T]) Make() T
Make gets an object out of the sync.Pool, and attaches a finalizer that returns the item to the pool when the object would be garbage collected.
Finalizer hooks are not automatically cleared by the Put() operation, so objects retrieved with Make should not be passed manually to Put().
func (*Pool[T]) Put ¶
func (p *Pool[T]) Put(in T)
Put returns an object in the pool, calling the cleanuphook if set. Put *always* clears the object's finalizer before calling the cleanuphook or returning it to the pool.
func (*Pool[T]) SetCleanupHook ¶
func (p *Pool[T]) SetCleanupHook(in func(T) T)
SetCleanupHook sets a function to be called on every object renetering the pool. By default, the cleanup function is a noop, and if the input function is nil, it is not set.
func (*Pool[T]) SetConstructor ¶
func (p *Pool[T]) SetConstructor(in func() T)
SetConstructor overrides the default constructor (which makes an object with a Zero value by default) for Get/Make operations.
type Synchronized ¶ added in v0.8.7
type Synchronized[T any] struct { // contains filtered or unexported fields }
Synchronized wraps an arbitrary type with a lock, and provides a functional interface for interacting with that type. In general Synchronize is ideal for container and interface types which are not safe for concurrent use, when either `adt.Map`, `adt.Atomic` are not appropriate.
func NewSynchronized ¶ added in v0.8.7
func NewSynchronized[T any](in T) *Synchronized[T]
NewSynchronized constructs a new synchronized object that wraps the input type.
func (*Synchronized[T]) Get ¶ added in v0.8.9
func (s *Synchronized[T]) Get() T
Get returns the underlying protected object.
func (*Synchronized[T]) Load ¶ added in v0.10.2
func (s *Synchronized[T]) Load() T
Load returns the underlyting protected object.
func (*Synchronized[T]) Set ¶ added in v0.8.7
func (s *Synchronized[T]) Set(in T)
Set overrides the current value of the protected object.
func (*Synchronized[T]) Store ¶ added in v0.10.2
func (s *Synchronized[T]) Store(in T)
Store replaces the value of the protected with the new provided value.
func (*Synchronized[T]) String ¶ added in v0.8.9
func (s *Synchronized[T]) String() string
String implements fmt.Stringer using this type.
func (*Synchronized[T]) Swap ¶ added in v0.8.9
func (s *Synchronized[T]) Swap(newVal T) (old T)
Swap sets the locked value to the new value and returns the old.
func (*Synchronized[T]) Using ¶ added in v0.10.0
func (s *Synchronized[T]) Using(op func())
Using runs the provided operation while holding the lock, but without providing access to the locked value.
func (*Synchronized[T]) With ¶ added in v0.8.7
func (s *Synchronized[T]) With(in func(obj T))
With runs the input function within the lock, to mutate the object.