maps

package
v0.0.0-...-622fb6d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 2, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package maps provides generic map utilities, including a case-insensitive map implementation.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoDefaultValue = errors.New("no default value for this key")

ErrNoDefaultValue is returned by the default value function when it cannot or chooses not to provide a default value for a given key. When this error is returned, the defaultMap will not add the key to the map and will behave as if the key simply doesn't exist.

Functions

func ToGoMap

func ToGoMap[K comparable, V any](m Map[Key[K], V]) map[K]V

ToGoMap converts an amp-common Map to a standard Go map. It extracts all key-value pairs from the Map and returns them in a native Go map[K]V.

Returns nil if the input map is nil. The iteration order is non-deterministic for standard maps and follows insertion order for ordered maps.

Example:

ampMap := NewHashMap[Key[string], int](hashing.Sha256)
ampMap.Add(Key[string]{Key: "a"}, 1)

goMap := ToGoMap(ampMap)
// goMap is now map[string]int{"a": 1}

Types

type CaseInsensitiveMap

type CaseInsensitiveMap[V any] struct {
	// contains filtered or unexported fields
}

CaseInsensitiveMap is a map that allows both case-sensitive and case-insensitive key lookups. It maintains the original casing of keys while also supporting case-insensitive retrieval. The zero value is not ready to use; use NewCaseInsensitiveMap to create instances.

Example:

m := maps.NewCaseInsensitiveMap(map[string]string{"Content-Type": "application/json"})
key, val, ok := m.Get("content-type", false) // case-insensitive: returns "Content-Type", "application/json", true
key, val, ok := m.Get("Content-Type", true)  // case-sensitive: returns "Content-Type", "application/json", true

func NewCaseInsensitiveMap

func NewCaseInsensitiveMap[V any](from map[string]V) *CaseInsensitiveMap[V]

NewCaseInsensitiveMap creates a new CaseInsensitiveMap initialized with the provided key-value pairs. Pass nil or an empty map to create an empty map.

func (*CaseInsensitiveMap[V]) Add

func (s *CaseInsensitiveMap[V]) Add(key string, value V)

Add adds a key-value pair to the map. If a key with different casing already exists, it removes the old entry first and adds the new one with the provided casing. This ensures only one entry per case-insensitive key exists, with the most recently added casing preserved.

func (*CaseInsensitiveMap[V]) AddAll

func (s *CaseInsensitiveMap[V]) AddAll(keyValueMap map[string]V)

AddAll adds multiple key-value pairs to the map. This is a convenience method that calls Add for each entry in the provided map.

func (*CaseInsensitiveMap[V]) Clear

func (s *CaseInsensitiveMap[V]) Clear()

Clear removes all key-value pairs from the map. After calling Clear, the map is empty but still usable.

func (*CaseInsensitiveMap[V]) Clone

func (s *CaseInsensitiveMap[V]) Clone() *CaseInsensitiveMap[V]

Clone creates a deep copy of the map. Returns nil if the receiver is nil.

func (*CaseInsensitiveMap[V]) ContainsKey

func (s *CaseInsensitiveMap[V]) ContainsKey(key string, caseSensitive bool) (bool, string)

ContainsKey checks if a key exists in the map. The caseSensitive parameter determines whether the lookup is case-sensitive. Returns whether the key exists and the original casing of the stored key (if found).

func (*CaseInsensitiveMap[V]) Filter

func (s *CaseInsensitiveMap[V]) Filter(predicate func(string, V) bool) *CaseInsensitiveMap[V]

Filter returns a new map containing only the key-value pairs that satisfy the predicate. The predicate receives the original key (with preserved casing) and value.

func (*CaseInsensitiveMap[V]) Get

func (s *CaseInsensitiveMap[V]) Get(key string, caseSensitive bool) (string, V, bool)

Get retrieves a value from the map by key. The caseSensitive parameter determines whether the lookup is case-sensitive. Returns the original key (with preserved casing), value, and whether the key was found. When caseSensitive is false, returns the original casing of the stored key.

Example:

m.Add("Content-Type", "application/json")
key, val, ok := m.Get("content-type", false) // returns "Content-Type", "application/json", true
key, val, ok := m.Get("content-type", true)  // returns "content-type", zero, false

nolint:ireturn

func (*CaseInsensitiveMap[V]) GetAll

func (s *CaseInsensitiveMap[V]) GetAll() map[string]V

GetAll returns all key-value pairs in the map with original key casing preserved. Returns nil if the map is empty.

func (*CaseInsensitiveMap[V]) IsEmpty

func (s *CaseInsensitiveMap[V]) IsEmpty() bool

IsEmpty returns true if the map contains no key-value pairs.

func (*CaseInsensitiveMap[V]) Keys

func (s *CaseInsensitiveMap[V]) Keys() []string

Keys returns all keys in the map with original casing preserved. The order of keys is non-deterministic.

func (*CaseInsensitiveMap[V]) Merge

func (s *CaseInsensitiveMap[V]) Merge(other *CaseInsensitiveMap[V])

Merge merges another map into this map. Existing keys (case-insensitive match) are replaced with values from the other map.

func (*CaseInsensitiveMap[V]) MergeAll

func (s *CaseInsensitiveMap[V]) MergeAll(others ...*CaseInsensitiveMap[V])

MergeAll merges multiple maps into this map. Maps are merged in order, with later maps overwriting earlier ones for duplicate keys.

func (*CaseInsensitiveMap[V]) Remove

func (s *CaseInsensitiveMap[V]) Remove(key string)

Remove removes a key-value pair from the map using case-insensitive lookup. If the key doesn't exist, this is a no-op.

func (*CaseInsensitiveMap[V]) RemoveAll

func (s *CaseInsensitiveMap[V]) RemoveAll(keys ...string)

RemoveAll removes multiple key-value pairs from the map. This is a convenience method that calls Remove for each provided key.

func (*CaseInsensitiveMap[V]) Size

func (s *CaseInsensitiveMap[V]) Size() int

Size returns the number of key-value pairs in the map.

func (*CaseInsensitiveMap[V]) Values

func (s *CaseInsensitiveMap[V]) Values() []V

Values returns all values in the map. The order of values is non-deterministic.

type Key

type Key[T comparable] struct {
	Key T
}

Key is a generic wrapper type that adapts any comparable type to be used as a map key. It implements the collectable.Collectable interface, making comparable types compatible with the Map interface that requires hashable and comparable keys.

This type bridges the gap between Go's built-in comparable constraint and the amp-common collectable.Collectable interface, allowing standard Go types (int, string, etc.) to be used with hash-based maps.

Example:

// Wrapping a string
key := Key[string]{Key: "my-key"}

// Using with a hash map
m := NewHashMap[Key[string], int](hashing.Sha256)
m.Add(Key[string]{Key: "count"}, 42)

func (Key[T]) Equals

func (m Key[T]) Equals(other Key[T]) bool

Equals compares this Key with another Key for equality. Two Keys are equal if their wrapped values are equal according to Go's == operator.

func (Key[T]) UpdateHash

func (m Key[T]) UpdateHash(h hash.Hash) error

UpdateHash writes the key's hash representation to the provided hash.Hash. It converts the comparable key to a collectable.Collectable and delegates hashing to it. This allows any comparable type to participate in the hashing process.

type KeyValuePair

type KeyValuePair[K any, V any] struct {
	Key   K
	Value V
}

KeyValuePair is a generic key-value pair struct used to represent entries in maps. It's particularly used by the OrderedMap.Seq() method to provide both the key and value in a single return value, along with an index to indicate insertion order.

The Key must implement the collectable.Collectable interface (hashable and comparable), while the Value can be any type.

Example:

// Returned by OrderedMap iteration
for i, entry := range orderedMap.Seq() {
    fmt.Printf("Index: %d, Key: %v, Value: %v\n", i, entry.Key, entry.Value)
}

type Map

type Map[K any, V any] interface {
	// Get retrieves the value for the given key from the hash map.
	// If the key exists, returns the value with found=true. If the key doesn't exist, returns
	// a zero value with found=false.
	// Returns ErrHashCollision if a different key with the same hash exists in the map.
	Get(key K) (value V, found bool, err error)

	// GetOrElse retrieves the value for the given key, or returns defaultValue if the key doesn't exist.
	// Returns ErrHashCollision if a different key with the same hash exists in the map.
	GetOrElse(key K, defaultValue V) (value V, err error)

	// Add inserts or updates a key-value pair in the map.
	// If the key already exists, its value is replaced.
	// Returns ErrHashCollision if the hash function produces a collision with a different key.
	Add(key K, value V) error

	// Remove deletes the key-value pair from the map.
	// If the key doesn't exist, this is a no-op and returns nil.
	// Returns ErrHashCollision if the hash function produces a collision with a different key.
	Remove(key K) error

	// Clear removes all key-value pairs from the map, leaving it empty.
	Clear()

	// Contains checks if the given key exists in the map.
	// Returns true if the key exists, false otherwise.
	// Returns ErrHashCollision if the hash function produces a collision with a different key.
	Contains(key K) (bool, error)

	// Size returns the number of key-value pairs currently stored in the map.
	Size() int

	// Seq returns an iterator for ranging over all key-value pairs in the map.
	// The iteration order is non-deterministic. This method is compatible with
	// Go 1.23+ range-over-func syntax: for key, value := range map.Seq() { ... }
	Seq() iter.Seq2[K, V]

	// Union creates a new map containing all key-value pairs from both this map and other.
	// If a key exists in both maps, the value from other takes precedence.
	// Returns ErrHashCollision if any hash collision occurs during the operation.
	Union(other Map[K, V]) (Map[K, V], error)

	// Intersection creates a new map containing only key-value pairs whose keys exist in both maps.
	// The values are taken from this map, not from other.
	// Returns ErrHashCollision if any hash collision occurs during the operation.
	Intersection(other Map[K, V]) (Map[K, V], error)

	// Clone creates a shallow copy of the map, duplicating its structure and entries.
	// The keys and values themselves are not deep-copied; they are referenced as-is.
	// Returns a new Map instance with the same entries.
	Clone() Map[K, V]

	// HashFunction returns the hash function used by this map.
	// This allows callers to inspect the hash function or create compatible maps
	// that use the same hashing strategy, ensuring consistent key hashing across
	// different map instances.
	//
	// Example use cases:
	//   - Creating a new map with the same hash function
	//   - Verifying two maps use compatible hash functions before merging
	//   - Debugging hash collision issues
	HashFunction() hashing.HashFunc

	// Keys returns a set containing all keys from the map.
	// The returned set is a new instance and modifications to it do not affect the original map.
	Keys() set.Set[K]

	// ForEach applies the given function to each key-value pair in the map.
	// The iteration order is non-deterministic. This method is used for side effects only
	// and does not return a value.
	ForEach(f func(key K, value V))

	// ForAll tests whether a predicate holds for all key-value pairs in the map.
	// Returns true if the predicate returns true for all entries, false otherwise.
	// The iteration stops early if the predicate returns false for any entry.
	ForAll(predicate func(key K, value V) bool) bool

	// Filter creates a new map containing only key-value pairs for which the predicate returns true.
	// The predicate function is applied to each entry, and only matching entries are included
	// in the result map.
	Filter(predicate func(key K, value V) bool) Map[K, V]

	// FilterNot creates a new map containing only key-value pairs for which the predicate returns false.
	// This is the inverse of Filter - it excludes entries where the predicate returns true.
	FilterNot(predicate func(key K, value V) bool) Map[K, V]

	// Map transforms all key-value pairs in the map by applying the given function to each entry.
	// The function receives each key-value pair and returns a new key-value pair.
	// Returns a new map containing the transformed entries.
	// Note: If the transformation produces duplicate keys, the behavior depends on insertion order.
	Map(f func(key K, value V) (K, V)) Map[K, V]

	// FlatMap applies the given function to each key-value pair and flattens the results into a single map.
	// Each function call returns a map, and all returned maps are merged together.
	// Returns a new map containing all entries from the flattened results.
	// If duplicate keys exist across multiple results, later values take precedence.
	FlatMap(f func(key K, value V) Map[K, V]) Map[K, V]

	// Exists tests whether at least one key-value pair in the map satisfies the given predicate.
	// Returns true if the predicate returns true for any entry, false otherwise.
	// The iteration stops early as soon as a matching entry is found.
	Exists(predicate func(key K, value V) bool) bool

	// FindFirst searches for the first key-value pair that satisfies the given predicate.
	// Returns Some(KeyValuePair) if a matching entry is found, None otherwise.
	// The iteration order is non-deterministic, so "first" is not guaranteed to be consistent.
	FindFirst(predicate func(key K, value V) bool) optional.Value[KeyValuePair[K, V]]
}

Map is a generic hash map interface for storing key-value pairs where keys must be both hashable and comparable. It provides set-like operations (Union, Intersection) in addition to standard map operations. All methods that modify the map or query for keys may return ErrHashCollision if the hash function produces collisions.

Keys must implement the collectable.Collectable interface, which ensures they can be hashed for efficient lookup and compared for equality to resolve hash collisions.

Thread-safety: Implementations are not guaranteed to be thread-safe unless explicitly documented. Concurrent access must be synchronized by the caller.

func FromGoMap

func FromGoMap[K comparable, V any](m map[K]V, hash hashing.HashFunc) Map[Key[K], V]

FromGoMap converts a standard Go map to an amp-common Map implementation. It creates a new HashMap and populates it with all key-value pairs from the input map.

The hash parameter specifies the hash function to use for the map (e.g., hashing.Sha256). Returns nil if the input map is nil.

Panics if adding a key-value pair fails due to a hash collision. This should be rare with a good hash function like SHA-256.

Example:

goMap := map[string]int{"a": 1, "b": 2}
ampMap := FromGoMap(goMap, hashing.Sha256)
// ampMap can now use Map interface methods

func FromSet

func FromSet[K collectable.Collectable[K], V any](s set.Set[K], getValue func(key K) V) Map[K, V]

FromSet converts a Set to a Map by applying a value function to each key. The getValue function is called for each key in the set to produce the corresponding value. The resulting map uses the same hash function as the input set and is pre-allocated to the set's size.

Returns nil if the input set is nil.

The iteration order is non-deterministic as it depends on the set's internal iteration order.

Example:

// Create a map from a set of strings to their lengths
stringSet := set.NewSet[String](hashFunc)
stringSet.Add("hello")
stringSet.Add("world")
m := FromSet(stringSet, func(s String) int { return len(s.Value) })
// m contains: {"hello": 5, "world": 5}

func NewDefaultMap

func NewDefaultMap[K any, V any](
	storageMap Map[K, V],
	getDefaultValue func(K) (V, error),
) Map[K, V]

NewDefaultMap creates a Map that automatically generates default values for missing keys. When Get or Contains is called with a key that doesn't exist, the getDefaultValue function is invoked to generate a value, which is then added to the map and returned.

The getDefaultValue function should return ErrNoDefaultValue when it cannot or chooses not to provide a default value. In that case, the map behaves as if the key doesn't exist.

If storageMap is already a defaultMap, this function clones it and replaces the default value function with the new one provided.

Parameters:

  • storageMap: The underlying Map implementation to use for storage
  • getDefaultValue: Function that generates default values for missing keys

Example:

// Create a map that defaults to empty strings for missing keys
m := maps.NewDefaultMap(
    maps.NewHashMap[MyKey, string](hashFunc),
    func(k MyKey) (string, error) {
        return "", nil
    },
)
value, found, _ := m.Get(missingKey) // Returns ("", true, nil) and adds to map

// Create a map that refuses to provide defaults
m2 := maps.NewDefaultMap(
    maps.NewHashMap[MyKey, string](hashFunc),
    func(k MyKey) (string, error) {
        return "", maps.ErrNoDefaultValue
    },
)
value, found, _ := m2.Get(missingKey) // Returns ("", false, nil) without adding

func NewDefaultZeroMap

func NewDefaultZeroMap[K any, V any](
	storageMap Map[K, V],
) Map[K, V]

NewDefaultZeroMap creates a Map that automatically returns zero values for missing keys. This is a convenience wrapper around NewDefaultMap that uses the zero value of type V as the default for all missing keys.

When Get or Contains is called with a key that doesn't exist in the map, the zero value for type V is generated, added to the map, and returned. The key is then considered to exist in the map going forward.

This is particularly useful for:

  • Counter maps: map[string]int where missing keys should start at 0
  • Collection maps: map[string][]T where missing keys should start as empty slices
  • Boolean flags: map[string]bool where missing keys should default to false
  • Optional value maps: map[string]*T where missing keys should be nil

Unlike NewDefaultMap which requires a custom function, NewDefaultZeroMap always succeeds in providing a default value - it never returns ErrNoDefaultValue.

Parameters:

  • storageMap: The underlying Map implementation to use for storage. This can be any Map implementation (HashMap, SortedMap, etc.) and determines the storage semantics.

Returns:

  • A Map that automatically generates zero values for missing keys and adds them to the map.

Example usage:

// Create a counter map where missing keys default to 0
counters := maps.NewDefaultZeroMap[StringKey, int](
    maps.NewHashMap[StringKey, int](hashFunc),
)
count, _, _ := counters.Get(key) // Returns (0, true, nil) and adds key->0 to map

// Create a map of slices where missing keys default to empty slices
lists := maps.NewDefaultZeroMap[StringKey, []string](
    maps.NewHashMap[StringKey, []string](hashFunc),
)
items, _, _ := lists.Get(key) // Returns ([]string{}, true, nil) and adds key->[] to map

// Create a boolean flag map where missing keys default to false
flags := maps.NewDefaultZeroMap[StringKey, bool](
    maps.NewHashMap[StringKey, bool](hashFunc),
)
enabled, _, _ := flags.Get(key) // Returns (false, true, nil) and adds key->false to map

func NewHashMap

func NewHashMap[K collectable.Collectable[K], V any](hash hashing.HashFunc) Map[K, V]

NewHashMap creates a new hash-based Map implementation using the provided hash function. The hash function must produce consistent hash values for equal keys and should minimize collisions to avoid ErrHashCollision errors during operations.

The returned map is not thread-safe. Concurrent access must be synchronized by the caller.

Example:

// Using a custom hash function
m := maps.NewMap[MyKey, string](func(k hashing.Hashable) (string, error) {
    return k.Hash(), nil
})
m.Add(key, "value")

func NewHashMapWithSize

func NewHashMapWithSize[K collectable.Collectable[K], V any](hash hashing.HashFunc, size int) Map[K, V]

NewHashMapWithSize creates a new hash-based Map implementation with pre-allocated capacity. This function is similar to NewHashMap but allows specifying an initial capacity hint to optimize memory allocation when the expected map size is known in advance.

The size parameter pre-allocates space for approximately 'size' entries, reducing the need for memory reallocation during initial insertions. This can improve performance when building large maps. The map will still grow dynamically if more entries are added beyond the initial size.

The hash function must produce consistent hash values for equal keys and should minimize collisions to avoid ErrHashCollision errors during operations.

The returned map is not thread-safe. Concurrent access must be synchronized by the caller.

Use this function when:

  • You know the approximate number of entries in advance
  • You're building a large map and want to avoid multiple reallocations
  • Performance during initial population is critical

Example:

// Creating a map for 1000 expected entries
m := maps.NewHashMapWithSize[MyKey, string](hashFunc, 1000)
for i := 0; i < 1000; i++ {
    m.Add(keys[i], values[i])
}

func NewRedBlackTreeMap

func NewRedBlackTreeMap[K sortable.Sortable[K], V any]() Map[K, V]

NewRedBlackTreeMap creates a new empty red-black tree map. The map maintains O(log n) performance for all operations by keeping the tree balanced.

func NewThreadSafeMap

func NewThreadSafeMap[K any, V any](m Map[K, V]) Map[K, V]

NewThreadSafeMap wraps an existing Map implementation with thread-safe access using sync.RWMutex. It provides concurrent read/write access to the underlying map while preserving the Map interface.

The wrapper uses read-write locks to allow multiple concurrent readers or exclusive writer access. Write operations (Add, Remove, Clear) acquire exclusive locks, while read operations (Contains, Size, Seq, Union, Intersection, Clone) use shared read locks for better concurrency.

Example usage:

unsafeMap := maps.New[string, int]()
safeMap := maps.NewThreadSafeMap(unsafeMap)
safeMap.Add("key", 42) // thread-safe

type OrderedMap

type OrderedMap[K any, V any] interface {
	// Get retrieves the value for the given key from the hash map.
	// If the key exists, returns the value with found=true. If the key doesn't exist, returns
	// a zero value with found=false.
	// Returns ErrHashCollision if a different key with the same hash exists in the map.
	Get(key K) (value V, found bool, err error)

	// GetOrElse retrieves the value for the given key, or returns defaultValue if the key doesn't exist.
	// Returns ErrHashCollision if a different key with the same hash exists in the map.
	GetOrElse(key K, defaultValue V) (value V, err error)

	// Add inserts or updates a key-value pair in the map.
	// If the key already exists, its value is replaced without changing the insertion order.
	// If the key is new, it's appended to the end of the insertion order.
	// Returns ErrHashCollision if the hash function produces a collision with a different key.
	Add(key K, value V) error

	// Remove deletes the key-value pair from the map.
	// If the key doesn't exist, this is a no-op and returns nil.
	// Returns ErrHashCollision if the hash function produces a collision with a different key.
	Remove(key K) error

	// Clear removes all key-value pairs from the map, leaving it empty.
	Clear()

	// Contains checks if the given key exists in the map.
	// Returns true if the key exists, false otherwise.
	// Returns ErrHashCollision if the hash function produces a collision with a different key.
	Contains(key K) (bool, error)

	// Size returns the number of key-value pairs currently stored in the map.
	Size() int

	// Seq returns an iterator for ranging over all key-value pairs in insertion order.
	// The iterator yields (index, KeyValuePair) tuples where index represents the insertion order.
	// This method is compatible with Go 1.23+ range-over-func syntax:
	// for i, entry := range map.Seq() { ... }
	Seq() iter.Seq2[int, KeyValuePair[K, V]]

	// Union creates a new map containing all key-value pairs from both this map and other.
	// Entries from this map are added first (preserving their order), followed by entries from other.
	// If a key exists in both maps, the value from other takes precedence, but the key maintains
	// its original position from this map.
	// Returns ErrHashCollision if any hash collision occurs during the operation.
	Union(other OrderedMap[K, V]) (OrderedMap[K, V], error)

	// Intersection creates a new map containing only key-value pairs whose keys exist in both maps.
	// The values are taken from this map, not from other, and the insertion order is preserved
	// from this map.
	// Returns ErrHashCollision if any hash collision occurs during the operation.
	Intersection(other OrderedMap[K, V]) (OrderedMap[K, V], error)

	// Clone creates a shallow copy of the map, duplicating its structure, entries, and insertion order.
	// The keys and values themselves are not deep-copied; they are referenced as-is.
	// Returns a new OrderedMap instance with the same entries in the same order.
	Clone() OrderedMap[K, V]

	// HashFunction returns the hash function used by this ordered map.
	// This allows callers to inspect the hash function or create compatible ordered maps
	// that use the same hashing strategy, ensuring consistent key hashing across
	// different map instances.
	//
	// Example use cases:
	//   - Creating a new ordered map with the same hash function
	//   - Verifying two ordered maps use compatible hash functions before merging
	//   - Debugging hash collision issues
	HashFunction() hashing.HashFunc

	// Keys returns a set containing all keys from the map, in insertion order.
	// The returned set is a new instance and modifications to it do not affect the original map.
	Keys() set.OrderedSet[K]

	// ForEach applies the given function to each key-value pair in the map.
	// The iteration order is non-deterministic. This method is used for side effects only
	// and does not return a value.
	ForEach(f func(key K, value V))

	// ForAll tests whether a predicate holds for all key-value pairs in the map.
	// Returns true if the predicate returns true for all entries, false otherwise.
	// The iteration stops early if the predicate returns false for any entry.
	ForAll(predicate func(key K, value V) bool) bool

	// Filter creates a new map containing only key-value pairs for which the predicate returns true.
	// The predicate function is applied to each entry, and only matching entries are included
	// in the result map.
	Filter(predicate func(key K, value V) bool) OrderedMap[K, V]

	// FilterNot creates a new map containing only key-value pairs for which the predicate returns false.
	// This is the inverse of Filter - it excludes entries where the predicate returns true.
	FilterNot(predicate func(key K, value V) bool) OrderedMap[K, V]

	// Map transforms all key-value pairs in the map by applying the given function to each entry.
	// The function receives each key-value pair and returns a new key-value pair.
	// Returns a new map containing the transformed entries.
	// Note: If the transformation produces duplicate keys, the behavior depends on insertion order.
	Map(f func(key K, value V) (K, V)) OrderedMap[K, V]

	// FlatMap applies the given function to each key-value pair and flattens the results into a single map.
	// Each function call returns a map, and all returned maps are merged together.
	// Returns a new map containing all entries from the flattened results.
	// If duplicate keys exist across multiple results, later values take precedence.
	FlatMap(f func(key K, value V) OrderedMap[K, V]) OrderedMap[K, V]

	// Exists tests whether at least one key-value pair in the map satisfies the given predicate.
	// Returns true if the predicate returns true for any entry, false otherwise.
	// The iteration stops early as soon as a matching entry is found.
	Exists(predicate func(key K, value V) bool) bool

	// FindFirst searches for the first key-value pair that satisfies the given predicate.
	// Returns Some(KeyValuePair) if a matching entry is found, None otherwise.
	// The iteration order is non-deterministic, so "first" is not guaranteed to be consistent.
	FindFirst(predicate func(key K, value V) bool) optional.Value[KeyValuePair[K, V]]
}

OrderedMap is a generic ordered hash map interface for storing key-value pairs where keys must be both hashable and comparable. Unlike the standard Map interface, OrderedMap preserves insertion order when iterating. It provides set-like operations (Union, Intersection) in addition to standard map operations. All methods that modify the map or query for keys may return ErrHashCollision if the hash function produces collisions.

Keys must implement the collectable.Collectable interface, which ensures they can be hashed for efficient lookup and compared for equality to resolve hash collisions.

Thread-safety: Implementations are not guaranteed to be thread-safe unless explicitly documented. Concurrent access must be synchronized by the caller.

func FromOrderedSet

func FromOrderedSet[K collectable.Collectable[K], V any](s set.OrderedSet[K], getValue func(key K) V) OrderedMap[K, V]

FromOrderedSet converts an OrderedSet to an OrderedMap by applying a value function to each key. The getValue function is called for each key in the ordered set to produce the corresponding value. The resulting ordered map uses the same hash function as the input set and preserves the insertion order.

Returns nil if the input set is nil.

The iteration follows the insertion order of the set, and the resulting map maintains this same order.

Example:

// Create an ordered map from an ordered set of strings to their lengths
stringSet := set.NewOrderedSet[String](hashFunc)
stringSet.Add("hello")
stringSet.Add("world")
m := FromOrderedSet(stringSet, func(s String) int { return len(s.Value) })
// m contains: {"hello": 5, "world": 5} in insertion order

func NewDefaultOrderedMap

func NewDefaultOrderedMap[K any, V any](
	storageMap OrderedMap[K, V],
	getDefaultValue func(K) (V, error),
) OrderedMap[K, V]

NewDefaultOrderedMap creates an OrderedMap that automatically generates default values for missing keys. When Get or Contains is called with a key that doesn't exist, the getDefaultValue function is invoked to generate a value, which is then added to the map (at the end of the insertion order) and returned.

The getDefaultValue function should return ErrNoDefaultValue when it cannot or chooses not to provide a default value. In that case, the map behaves as if the key doesn't exist.

If storageMap is already a defaultOrderedMap, this function clones it and replaces the default value function with the new one provided.

Unlike the standard Map, OrderedMap preserves the insertion order of keys. When a default value is generated and added, it's appended to the end of the current insertion order.

Parameters:

  • storageMap: The underlying OrderedMap implementation to use for storage
  • getDefaultValue: Function that generates default values for missing keys

Example:

// Create an ordered map that defaults to empty strings for missing keys
m := maps.NewDefaultOrderedMap(
    maps.NewOrderedHashMap[MyKey, string](hashFunc),
    func(k MyKey) (string, error) {
        return "", nil
    },
)
value, found, _ := m.Get(missingKey) // Returns ("", true, nil) and adds to end

// Create a map that refuses to provide defaults
m2 := maps.NewDefaultOrderedMap(
    maps.NewOrderedHashMap[MyKey, string](hashFunc),
    func(k MyKey) (string, error) {
        return "", maps.ErrNoDefaultValue
    },
)
value, found, _ := m2.Get(missingKey) // Returns ("", false, nil) without adding

func NewDefaultZeroOrderedMap

func NewDefaultZeroOrderedMap[K any, V any](
	storageMap OrderedMap[K, V],
) OrderedMap[K, V]

NewDefaultZeroOrderedMap creates an OrderedMap that automatically provides zero values for missing keys. This is a convenience wrapper around NewDefaultOrderedMap that uses the zero value of type V as the default value for any key that doesn't exist in the map.

When Get or Contains is called with a key that doesn't exist, the zero value for type V is automatically generated and added to the map (at the end of the insertion order), then returned. This eliminates the need to manually check if a key exists before accessing it.

Unlike NewDefaultOrderedMap, there's no way for this map to refuse providing a default value - it will always succeed in generating a zero value for missing keys. This makes it ideal for use cases where you want default initialization without custom logic.

The map preserves insertion order of keys. When a zero value is auto-generated for a missing key, that key is appended to the end of the current insertion order.

Common zero values by type:

  • Numeric types (int, float64, etc.): 0
  • Strings: ""
  • Booleans: false
  • Pointers: nil
  • Slices, maps, channels: nil
  • Structs: struct with all fields set to their zero values

Parameters:

  • storageMap: The underlying OrderedMap implementation to use for storage

Example usage:

// Create an ordered map that defaults to 0 for missing integer keys
m := maps.NewDefaultZeroOrderedMap[string, int](
    maps.NewOrderedHashMap[string, int](hashing.NewGoHasher[string]()),
)
value, found, _ := m.Get("missing") // Returns (0, true, nil) and adds key with value 0

// Create an ordered map that defaults to empty strings
m2 := maps.NewDefaultZeroOrderedMap[int, string](
    maps.NewOrderedHashMap[int, string](hashing.NewGoHasher[int]()),
)
value, found, _ := m2.Get(42) // Returns ("", true, nil) and adds key 42 with value ""

// Works with structs too - all fields initialized to their zero values
type Config struct {
    Enabled bool
    Retries int
}
m3 := maps.NewDefaultZeroOrderedMap[string, Config](
    maps.NewOrderedHashMap[string, Config](hashing.NewGoHasher[string]()),
)
cfg, found, _ := m3.Get("app") // Returns (Config{Enabled: false, Retries: 0}, true, nil)

func NewOrderedHashMap

func NewOrderedHashMap[K collectable.Collectable[K], V any](hash hashing.HashFunc) OrderedMap[K, V]

NewOrderedHashMap creates a new ordered hash-based OrderedMap implementation using the provided hash function. The hash function must produce consistent hash values for equal keys and should minimize collisions to avoid ErrHashCollision errors during operations.

Unlike the standard Map interface, the returned OrderedMap preserves insertion order when iterating through entries. The iteration order is deterministic and reflects the order in which keys were first added to the map.

The returned map is not thread-safe. Concurrent access must be synchronized by the caller.

Example:

// Using a custom hash function
m := maps.NewOrderedHashMap[MyKey, string](func(k hashing.Hashable) (string, error) {
    return k.Hash(), nil
})
m.Add(key1, "first")
m.Add(key2, "second")
// Iteration will always be in order: key1, key2

func NewThreadSafeOrderedMap

func NewThreadSafeOrderedMap[K any, V any](m OrderedMap[K, V]) OrderedMap[K, V]

NewThreadSafeOrderedMap wraps an existing OrderedMap implementation with thread-safe access using sync.RWMutex. It provides concurrent read/write access to the underlying ordered map while preserving the OrderedMap interface.

The wrapper uses read-write locks to allow multiple concurrent readers or exclusive writer access. Write operations (Add, Remove, Clear) acquire exclusive locks, while read operations (Contains, Size, Seq, Union, Intersection, Clone) use shared read locks for better concurrency.

Example usage:

unsafeMap := maps.NewOrderedHashMap[string, int](hashing.Sha256)
safeMap := maps.NewThreadSafeOrderedMap(unsafeMap)
safeMap.Add("key", 42) // thread-safe

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL