Documentation
¶
Overview ¶
Package atomic implements advanced, type-safe atomic primitives designed for high-performance concurrent applications.
The core philosophy of this package is to provide the safety and convenience of generics while maintaining the extreme performance characteristics of the native sync/atomic package. It addresses common pain points in Go's concurrency model, such as mandatory type assertions for atomic.Value and the risk of storing or retrieving unexpected zero-values in shared state.
ARCHITECTURE & INTERNALS ¶
The package is built around three main components: Value[T], Map[K], MapTyped[K, V], and the Cast[T] utility.
1. High-Performance Value Container (Value[T])
The Value[T] implementation uses a tiered access model to minimize overhead:
Data Flow (Nominal Case - No Defaults): User -> Store(T) -> atomic.Value.Store(any) User <- Load() <- atomic.Value.Load() <- (Type Assertion) -> User
Data Flow (With Defaults Configured): User -> Store(val T) | +-> Is val empty/zero? (using Cast[T]) | +-- Yes --> atomic.Value.Store(DefaultStoreValue) | +-- No ---> atomic.Value.Store(val)
Internal Performance Optimization (Short-Circuiting): To avoid the overhead of zero-value detection (which may require reflection for complex types), the structure maintains internal atomic flags (bl, bs). If no default value is set, the logic bypasses the entire Cast/IsEmpty subsystem, resulting in performance identical to native code.
2. Specialized Atomic Maps (MapAny and MapTyped)
These components wrap sync.Map to provide type safety without the need for external mutexes. They implement a "self-healing" mechanism during iteration: if the Range function encounters an entry whose key or value has been corrupted (e.g. by an external agent injecting an invalid type directly into the underlying sync.Map), the entry is automatically evicted to ensure the integrity of the typed view.
3. Zero-Value Detection Engine (Cast & IsEmpty)
The Cast function provides a highly optimized alternative to reflect.DeepEqual for detecting uninitialized state. It uses a type switch for all Go scalar types (integers, floats, strings, bools) to perform direct comparisons. For structs and complex types, it falls back to reflect.Value.IsZero(), which is significantly faster than comparing two full objects.
QUICK START ¶
Basic type-safe atomic value:
v := atomic.NewValue[string]()
v.Store("hello")
msg := v.Load() // "hello", no type assertion needed
Atomic value with default "safe" state:
v := atomic.NewValueDefault[int](10, 20) fmt.Println(v.Load()) // Prints 10 (load default) v.Store(0) // Triggers store default (20) fmt.Println(v.Load()) // Prints 20
Type-safe concurrent map:
m := atomic.NewMapTyped[string, int]()
m.Store("key", 42)
val, ok := m.Load("key") // (42, true)
USE CASES ¶
1. Lifecycle Management: Storing a context.Context or a CancelFunc in a structure where you want to ensure that a call to Load() never returns nil, but instead returns a Background context or a no-op function.
2. Configuration Hot-Reloading: Safely swapping complex configuration structs between goroutines while ensuring that any invalid (empty) configuration received from a source is automatically replaced by a known-good default.
3. High-Concurrency Counters & Metrics: Using MapTyped to track per-user or per-service metrics without the performance penalty of a global mutex or the verbosity of sync.Map type assertions.
TECHNICAL CONSTRAINTS & CONTRACTS ¶
- Immutability: Users should avoid modifying objects after they have been stored in an atomic container.
- Writer Contract: Functions stored as values must not retain references to provided buffers to prevent data races.
- Performance: To achieve nanosecond-level latency, prefer NewValue() over NewValueDefault() unless the default value logic is strictly required by the business logic.
Package atomic provides type-safe wrappers around sync/atomic operations.
This file defines the public interfaces and factory functions for the package. The design focuses on providing the convenience of Go generics while maintaining the strict performance requirements of low-level atomic primitives.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Cast ¶
Cast attempts to safely convert any value to the target type M while performing a zero-value validation.
This function is a core component of the atomic package's safety mechanism. It returns the converted value and true if successful, or the zero value of M and false if:
- The source interface is nil.
- The source value cannot be asserted to type M.
- The source value is the "zero value" or "empty value" for its type.
PERFORMANCE DESIGN ¶
To avoid the massive overhead of reflect.DeepEqual (which was identified as a major bottleneck), Cast uses a tiered evaluation strategy designed for nanosecond-level latency:
- Immediate exit for nil interfaces to avoid any further processing cost.
- Native Go type assertion (src.(M)). This is the fastest way to check type compatibility.
- Specialized Type Switching: For all Go scalar types (integers, strings, floats, bools), it performs direct comparisons against zero constants. This bypasses reflection entirely.
- Reflection Fallback: For complex types (structs, slices, maps, channels, functions, pointers), it uses reflect.Value.IsZero(), which is the modern, recommended way to check for zero-state without the recursive cost of DeepEqual.
Parameters:
- src: The source value of any type to be converted and validated.
Returns:
- model: The converted value of type M, or the zero value of M on failure.
- casted: A boolean indicating if the cast was successful AND the value is not empty.
func IsEmpty ¶
IsEmpty checks if the source value is nil, zero, or cannot be cast to type M.
This is a convenience wrapper around Cast[M] used primarily for input validation in Store operations. It returns true if the value is considered "vacant" or "invalid" for the given type M.
OPTIMIZATION ¶
It performs a direct nil check before invoking the more complex Cast logic to maximize performance for nil inputs, which are common in concurrent state management.
Types ¶
type Map ¶
type Map[K comparable] interface { // Len returns the number of entries currently stored in the map. // This is an O(1) operation maintained via atomic increments/decrements. Len() uint64 // Load retrieves the value for a key. Returns (nil, false) if the key is not found. Load(key K) (value any, ok bool) // Store sets the value for a key. If the key already exists, the value is updated. Store(key K, value any) // LoadOrStore returns the existing value for the key if present. // Otherwise, it stores and returns the given value. // The 'loaded' result is true if the value was loaded, false if stored. LoadOrStore(key K, value any) (actual any, loaded bool) // LoadAndDelete deletes the value for a key, returning the previous value if any. // The 'loaded' result is true if the key was present in the map. LoadAndDelete(key K) (value any, loaded bool) // Delete removes the value for a key from the map. Delete(key K) // Swap exchanges the value for a key and returns the previous value. // The 'loaded' result is true if the key was previously present. Swap(key K, value any) (previous any, loaded bool) // CompareAndSwap performs a CAS operation on a map entry. // It only updates the value if the current value matches 'old'. CompareAndSwap(key K, old, new any) bool // CompareAndDelete deletes the entry if the current value matches 'old'. CompareAndDelete(key K, old any) (deleted bool) // Range iterates over the map. The function 'f' is called for each key/value pair. // If 'f' returns false, iteration stops. // Range also performs a "self-healing" check: any key found with an invalid type // is automatically evicted from the map. Range(f func(key K, value any) bool) }
Map provides a thread-safe map with a fixed key type and arbitrary value types (any). It is a type-safe wrapper around sync.Map that adds a constant-time length counter.
Implementation Note: The keys must satisfy the 'comparable' constraint as required by Go maps. While values are 'any', the Map implementation ensures that keys are correctly typed during iteration and internal operations.
func NewMapAny ¶
func NewMapAny[K comparable]() Map[K]
NewMapAny creates a thread-safe map with a specific key type K and arbitrary values. It initializes the atomic length counter and the underlying sync.Map.
type MapTyped ¶
type MapTyped[K comparable, V any] interface { // Len returns the number of entries currently stored in the map. Len() uint64 // Load retrieves the typed value for a key. Load(key K) (value V, ok bool) // Store sets the typed value for a key. Store(key K, value V) // LoadOrStore returns the existing typed value or stores the new one. LoadOrStore(key K, value V) (actual V, loaded bool) // LoadAndDelete deletes the typed value for a key. LoadAndDelete(key K) (value V, loaded bool) // Delete removes the typed value for a key. Delete(key K) // Swap exchanges the typed value for a key and returns the previous value. Swap(key K, value V) (previous V, loaded bool) // CompareAndSwap performs a typed CAS operation. CompareAndSwap(key K, old, new V) bool // CompareAndDelete performs a typed conditional delete. CompareAndDelete(key K, old V) (deleted bool) // Range iterates over typed entries. // Range performs a "self-healing" check: any value found that cannot be cast // to type V is automatically evicted from the map. Range(f func(key K, value V) bool) }
MapTyped provides a fully type-safe thread-safe map for both keys and values. It extends the Map[K] interface by enforcing a specific type V for all values.
func NewMapTyped ¶
func NewMapTyped[K comparable, V any]() MapTyped[K, V]
NewMapTyped creates a fully type-safe thread-safe map for keys of type K and values of type V.
type Value ¶
type Value[T any] interface { // SetDefaultLoad configures the value to be returned by Load() if the underlying // storage is uninitialized or contains a zero-value (as defined by the Cast utility). // Calling this method enables the validation path for Load() and Swap() operations. SetDefaultLoad(def T) // SetDefaultStore configures a value that will be automatically stored by Store(), // Swap(), and CompareAndSwap() if the user attempts to store a zero-value of type T. // This ensures that the container never transitions to an "empty" state. SetDefaultStore(def T) // Load atomically retrieves the current value. // If a default load value is set and the current value is empty, the default is returned. Load() (val T) // Store atomically updates the current value. // If a default store value is set and 'val' is empty, the default is stored instead. Store(val T) // Swap atomically stores a new value and returns the previous one. // It respects both SetDefaultLoad and SetDefaultStore configurations. Swap(new T) (old T) // CompareAndSwap performs an atomic compare-and-swap operation. // It only succeeds if the current value matches 'old'. If a default store value // is configured, it is applied to both 'old' and 'new' before comparison. CompareAndSwap(old, new T) (swapped bool) }
Value provides a type-safe interface for atomic operations on a single value of type T. It acts as a generic-aware container that eliminates the need for manual type assertions when working with sync/atomic.Value.
Features:
- Full type safety for Load, Store, Swap, and CAS operations.
- Optional default values for Load() when the container is empty.
- Optional default values for Store() to prevent storing zero-values.
- Tiered performance model that bypasses validation logic when defaults are not set.
Thread Safety: All methods are safe for concurrent use by multiple goroutines without additional locking.
func NewValue ¶
NewValue initializes and returns a new high-performance atomic container for type T.
Performance Note: This constructor creates a Value instance optimized for speed. Until SetDefaultLoad or SetDefaultStore are called, the implementation uses a "fast path" that skips all validation logic, matching the performance of sync/atomic.Value.
func NewValueDefault ¶
NewValueDefault creates an atomic box with pre-configured default values for both Load and Store operations.
Note: Using this constructor immediately enables the validation logic path, which involves type casting and zero-value detection.