Skip to main content

12  Arrays, Slices & Maps

Edva provides three built-in collection shapes backed by the active arena: - Growable arrays (T{} / T{cap}): Dynamically resized contiguous buffers ({ i64 len, ptr data, i64 cap }, 24 bytes). - Slices (T[]): Non-owning contiguous views ({ i64 len, ptr data }, 16 bytes) over arrays or homogeneous tuples (T * N). - Hash maps (K ^ V): Open-addressed associative tables with linear probing and tombstone compaction.

12.1 Container comparison table

Property Growable Array (T{}) Slice (T[]) Hash Map (K ^ V)
Declaration #type Ints Int{} / Int{100} #type View Int[] #type Dict String ^ Int
Runtime layout { i64 len, ptr data, i64 cap } (24B) { i64 len, ptr data } (16B) Arena table handle (ptr, 8B)
Construction Ints() or Int{} xs(a..b) / tuple(a..b) Dict() or ("a" ^= 1, "b" ^= 2)
Element / key read xs(i) \(\to\) < T | Error > (fallible) view(i) \(\to\) T (bounds-checked) m ^ k \(\to\) < V | Error > (fallible)
Element / key write xs(i) = v \(\to\) < | Error > (!| _) view(i) = v \(\to\) () m ^ k = v \(\to\) ()
Count ?xs (Int) ?view (Int) ?m (Int, active live entries)
Cycle binders (@) elem => or elem, i => (_, _i) elem => or elem, i => (_, _i) val => or val, key => (_, _i)

12.2 Growable arrays (T{}) and slices (T[])

Operation Syntax Result Type Semantics
Instantiate empty xs = Ints() / xs = Int{} T{} Allocates array descriptor (default initial capacity 16, or cap in T{cap})
Append element xs += val () Appends val in place, doubling capacity in the arena when len == cap
Fallible read xs(i) < T | Error > Returns <+ elem -> if 0 <= i < ?xs, else <- Error(...) +>
Unwrap / fallback read xs(i)!! / xs(i) | _ | def T Panics on out-of-bounds (!!) or substitutes def
Fallible write xs(i) = val / xs(i) = val !| _ < | Error > / () Updates slot i if in bounds; !| _ aborts on out-of-bounds write
Create slice view xs(a..b) / xs(a...b) / xs(..) T[] Non-owning window into xs’s current buffer (a.., ..b, -k.. supported)
Shallow container copy ++xs / ++view Same as operand Allocates a fresh backing buffer and copies element slots
Iteration (@) xs @ x, i => body () (or <U|> with >--) Captures initial len and data pointer at loop entry
#use io

#type Ints Int{}

sum_slice: Int[] => Int
sum_slice = s =>
   acc' = 0
   s @ x => acc' = acc' + x
   acc'

xs = Ints()
xs += 10
xs += 20
xs += 30
xs(1) = 25 !| _

io::out $ (xs(0)!!, ?xs, sum_slice(xs(0..3)))   // (10, 3, 65)

12.3 Associative hash maps (K ^ V)

12.3.1 Supported key and value types

Slot Allowed Types Hashing & Storage Mechanism
Key (K) String, Int, Addr String: 64-bit FNV-1 variant (\(O(L)\)); Int & Addr: SplitMix64 (Stafford variant 13) mixer
Value (V) Any storable Edva type Stored in 64-bit packed slots (Float, Int, Addr, or arena pointers to records/strings/containers)

12.3.2 Map operations and runtime characteristics

Operation Syntax Result Type Semantics
Empty construction m = Dict() K ^ V Initial capacity 8 slots
Literal construction m = ("k1" ^= 10, "k2" ^= 20) K ^ V Infers K ^ V from key ^= value pairs
Insert / overwrite m ^ k = val () Inserts (k, val) or overwrites existing k in place without rehashing
Fallible lookup m ^ k < V | Error > Returns <+ val -> if present, else <- Error(...) +>
Membership check m ^? k <> Returns <+> if k is present, <-> if absent
Delete entry m ^- k <> Marks slot as tombstone (2) and returns <+> if removed, <-> if absent
Active count ?m Int Number of live occupied entries (excludes tombstones)
Snapshot iteration m @ val, key => body
m @ body
() Captures snapshot of (keys, vals, states) at loop entry; concurrent m ^ k = v or m ^- k mutations never invalidate or desynchronize the active traversal. Note: binder order is value first (_), key second (_i)
Load factor & resize Automatic at 75% occupancy — When (count + tombs + 1) * 4 > cap * 3: doubles capacity if count > cap / 2, otherwise rebuilds in place at same capacity to purge tombstones
#use io

scores = ("Alice" ^= 95, "Bob" ^= 88)
scores ^ "Carol" = 92
removed = scores ^- "Bob"

io::out $ (?scores, removed, scores ^? "Alice", scores ^ "Carol" | _ | 0)