Collection.Map.Fast
Flat compound-key store for O(1) point lookups into nested data. Keys are dot-delimited paths into a single bash associative array. No insertion order, no per-level objects, no subtree pass-by-reference — just fast get/set on fully-qualified paths.
Contents
- Dependencies
- Fast vs Map
- Constructor
- Getting and Setting
- Counting and Clearing
- Enumeration
- Serialization
- Loading from JSON
- Full Example
- Design Notes
Dependencies
. boop Collection::Map::Fast
Fast vs Map
Use Fast when you need:
- Quick point lookups into config or parsed data
- A flat store keyed by paths (
"users.0.name","server.port") - Minimal overhead per node
Use Map when you need:
- Insertion-ordered iteration
- Subtrees as objects you can pass around
- Per-level
getAt/setAtwith real object dispatch
Constructor
into=doc Collection.Map.Fast # default separator "."
into=doc Collection.Map.Fast sep="/" # custom separator
The separator is stored in the sep property and used by keysUnder
and deleteUnder to identify path boundaries.
Getting and Setting
$doc.set "server.host" "localhost"
$doc.set "server.port" "8080"
$doc.set "database.host" "db.internal"
$doc.set "database.name" "myapp"
into=h $doc.get "server.host" # h="localhost"
into=p $doc.get "server.port" # p="8080"
into=x $doc.get "missing.key" # x="" — no crash, empty string
$doc.set key value
Store any string value at any string key. Keys are arbitrary strings;
the separator character has no special meaning in get/set —
it is just part of the key. Hierarchy is a naming convention,
not a structural constraint.
$doc.set "some.deep.path" "value"
$doc.set "no/separator/needed" "also works if sep='|'"
$doc.get key
Retrieve the value at key. Returns empty string for unknown keys.
$doc.has key
Exit code: 0 if the key exists, 1 if not.
$doc.has "server.port" || { echo "port not configured"; exit 1; }
$doc.delete key
Remove a single key. No-op if absent.
$doc.delete "database.password"
Counting and Clearing
into=n $doc.length # total keys stored
$doc.clear # remove all keys
Enumeration
All keys
_EOL=$'\n' into=all $doc.keys
while IFS= read -r k; do
into=v $doc.get "$k"
printf "%s = %s\n" "$k" "$v"
done <<< "$all"
Keys are returned in hash-defined order (not insertion order).
Keys under a prefix
_EOL=$'\n' into=skeys $doc.keysUnder "server"
# skeys = "server.host\nserver.port"
keysUnder prefix returns all keys that start with prefix followed
by the separator. The prefix itself is not returned.
# With sep="/"
$doc.set "a/b/c" "1"
$doc.set "a/b/d" "2"
$doc.set "a/x" "3"
_EOL=$'\n' into=ab $doc.keysUnder "a/b"
# ab = "a/b/c\na/b/d"
Delete a subtree
$doc.deleteUnder "database" # removes all keys starting with "database."
Serialization
into=s $doc.toString # "key=value\n..." one per line, order undefined
Loading from JSON
Data.JSON produces Collection.Map trees (nested objects, insertion-ordered).
If you parse JSON and want Fast’s O(1) access, flatten it:
. boop JSON Collection::Map::Fast
into=j Data.JSON
into=parsed $j.parse "$json_str" # gives Collection.Map tree
into=fast Collection.Map.Fast
# Flatten manually for the keys you care about
into=host $parsed.getAt "server" # get the "server" sub-map
into=host $host.getAt "host"
$fast.set "server.host" "$host"
Full Example
. boop Collection::Map::Fast
into=cfg Collection.Map.Fast
# Populate
$cfg.set "app.name" "myapp"
$cfg.set "app.version" "2.1.0"
$cfg.set "db.host" "localhost"
$cfg.set "db.port" "5432"
$cfg.set "db.name" "myapp_prod"
# Query
into=v $cfg.get "app.version" # v="2.1.0"
$cfg.has "db.password" || echo "no db password set"
# Enumerate a subtree
_EOL=$'\n' into=dbkeys $cfg.keysUnder "db"
printf "DB keys:\n%s\n" "$dbkeys"
# Remove a subtree
$cfg.deleteUnder "app"
into=n $cfg.length # n="3" (only db.* remain)
Design Notes
All keys are flat. There are no nested objects inside a Fast instance.
"a.b.c" is just a string key. keysUnder "a.b" is a prefix search, not
a structural traversal.
O(1) for everything except enumeration. get, set, has, delete
are all single associative-array operations. keys and keysUnder scan
all keys linearly — fine for small stores, slow for very large ones.
No insertion order. If you need keys in a predictable order, use a
Collection.Map or build your own ordered list alongside the store.