Skip to content

TomTonic/multimap

Repository files navigation

multimap for Go

Go Report Card Go Reference Linter Tests coverage

multimap provides a compact, thread-safe multimap implementation for Go. A multimap is a data structure that allows multiple values to be associated with a single key, unlike a regular map where each key has exactly one value.

Key Characteristics

  • One-to-many mapping: Each key can have zero, one, or multiple values
  • Duplicate values: The same value can only be stored once per key but it can be stored multiple times for different keys
  • Key uniqueness: Keys themselves are still unique - there's only one entry per key

Common Use Cases

  • Indexing: Group items by category (e.g., products by brand)
  • Graph representations: Store adjacency lists where each node maps to multiple connected nodes
  • HTTP headers: Multiple values for the same header name
  • Database indexes: Multiple records sharing the same indexed value

Indexing

The multimap uses Key objects for indexing, which are internally represented as []byte arrays. This allows for efficient storage and comparison regardless of the original data type used to create the key.

Key behavior

  • Mixed types: A single multimap can contain keys created from different data types (strings, integers, custom byte arrays) without any issues.
  • Lexicographic ordering: All keys are compared using byte-wise lexicographic ordering of their internal []byte representation.
  • Custom keys: You can create keys from any []byte array using the generic constructor for your own implementations.

Important: When mixing different key types in range queries, the lexicographic ordering may be counter-intuitive. For example:

// These keys will NOT be ordered numerically when mixed with strings:
key1 := FromString("100")     // UTF-8 bytes: [0x31, 0x30, 0x30]
key2 := FromInt64(50)         // Encoded as: [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32]
key3 := FromString("25")      // UTF-8 bytes: [0x32, 0x35]

// Lexicographic order: key1 ("100") < key3 ("25") < key2 (50)
// This differs from intuitive numeric/alphabetic ordering!

For predictable range query behavior, use consistent key types within logical ranges. See the type-specific encoding details below.

String keys

  • Use FromString(s) to convert a string to a Key. FromString normalizes the input string using Unicode NFC so canonically equivalent strings map to the same key.
  • Key ordering (LessThan) is a byte-wise lexicographic comparison of the UTF-8 bytes — it is neither locale-aware nor rune-aware.

Numeric keys

  • Use FromInt* / FromUint* helpers to build integer keys.
  • All integer keys are encoded as fixed-width 8-byte big-endian sequences (MSB first).
  • To ensure consistent ordering across signed/unsigned types and across widths, all integer constructors add an offset of 1<<63 before encoding. Signed values are converted to int64 first; unsigned values are treated as uint64 and the same offset is added. This maps signed and unsigned values into a single uint64 namespace so that lexicographic comparison matches numeric ordering.

Examples / consequences:

  • FromInt64(0) equals FromUint64(0) because both are encoded as 0 + (1<<63).
  • The smallest int64 (-2^63) maps to [00,00,00,00,00,00,00,00] after encoding; negative signed values compare before zero/positive values as expected for numeric order.
  • Values encoded from different widths are comparable — for example FromInt32(x) is identical to FromInt64(x) for the same numeric x.

Behavior and semantics

  • PutValue(key, v) clones key before inserting; mutating the caller's Key after calling PutValue will not affect the stored key.
  • GetValuesFor(key) and other retrieval mehods return clones of stored Set3 instances; modifying the returned set does not affect the MultiMap's contents.
  • Range queries: Keys are ordered in lexicographic order, allowing efficient range queries between two key boundaries. Range operations return a set of all values of all keys where the key falls within the specified range (inclusive or exclusive based on the method). The ordering follows the byte-wise comparison rules described above for string and numeric keys.

Examples

See the example_test.go in this package for runnable examples that also appear in generated GoDoc.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages