zena:collections
import {…} from 'zena:collections';
Collection data structures: maps, sets, and array types.
Provides mutable and ordered hash maps (HashMap, OrderedHashMap),
hash sets (HashSet, OrderedHashSet), array abstractions
(FixedArray, GrowableArray, ImmutableArray), and zip, which
iterates two iterables in step.
Examples ​
import { HashMap, HashSet } from 'zena:collections';
let counts = new HashMap<String, i32>();
counts['apples'] = 3;
counts['oranges'] = 5;
let seen = new HashSet<String>();
seen.add('first');
let hasFirst = seen.has('first');
Classes
FixedArray
final extension class FixedArray<T> with IterableUtils<T> implements MutableArray<T>, Iterable<T>
new(length: i32, value: T)
length: i32
static from<A>(seq: Array<A>): FixedArray<A>
map<U>(f: (item: T, index: i32, seq: FixedArray<T>) => U): FixedArray<U>
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
reverse(): FixedArray<T>
slice(start: i32, end: i32): FixedArray<T>
Returns a shallow copy of a portion of the array. The start index is inclusive, the end index is exclusive. Negative indices are not supported.
contentEquals(other: Array<T>): boolean
Whether other has the same length and == elements in the same
order, whatever array class it is. == on two arrays compares
identity; this compares contents, as two byte strings are compared.
7 inherited members
Array
Iterable
contains(value: T): boolean
Returns true if the collection contains the specified value.
all(predicate: (item: T) => boolean): boolean
Returns true if all elements match the given predicate. Returns true if the collection is empty.
some(predicate: (item: T) => boolean): boolean
Returns true if at least one element matches the given predicate. Returns false if the collection is empty.
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.
filter(predicate: (item: T) => boolean): Iterable<T>
Returns a new iterable containing only the elements that match the predicate.
GrowableArray
final class GrowableArray<T> implements MutableArray<T>, Iterable<T>
new(capacity: i32 = 8, adopting: FixedArray<T> | null = null)
adopting, when given, becomes the backing storage, full: length
starts at its length, no copy is made, and capacity is ignored.
The caller must hand the buffer over — writes through either alias
would be visible through the other. from copies; this adopts.
(A constructor parameter rather than a static so it works from
generic bodies — see the issue linked from growable below.)
length: i32 { get; }
static from<A>(seq: Array<A>): GrowableArray<A>
push(value: T): void
pop(): T
clear(): void
Empties the array in place, keeping its buffer for reuse. The cleared slots are not overwritten, so references they held stay reachable until a later push replaces them.
slice(start: i32, end: i32): GrowableArray<T>
A copy of the elements from start up to but not including end.
Bounds outside the array are clamped to it.
map<U>(f: (item: T, index: i32, seq: GrowableArray<T>) => U): GrowableArray<U>
contains(value: T): boolean
all(predicate: (item: T) => boolean): boolean
some(predicate: (item: T) => boolean): boolean
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
filter(predicate: (item: T) => boolean): Iterable<T>
contentEquals(other: Array<T>): boolean
Whether other has the same length and == elements in the same
order, whatever array class it is. == on two arrays compares
identity; this compares contents.
ImmutableArray
final extension class ImmutableArray<T> with IterableUtils<T> implements Array<T>
length: i32
slice(start: i32, end: i32): FixedArray<T>
A copy of the elements from start up to but not including end.
Bounds outside the array are clamped to it.
map<U>(f: (item: T, index: i32, seq: ImmutableArray<T>) => U): FixedArray<U>
contentEquals(other: Array<T>): boolean
Whether other has the same length and == elements in the same
order, whatever array class it is. == on two arrays compares
identity; this compares contents.
9 inherited members
Array
new(capacity: i32 = 8): GrowableArray<T>
An empty growable array, with room for capacity items before it grows.
new growable(capacity: i32 = 8): GrowableArray<T>
The same as new Array(), named for symmetry with fixed.
new fixed(length: i32, value: T): FixedArray<T>
A fixed-length array of length copies of value.
Iterable
contains(value: T): boolean
Returns true if the collection contains the specified value.
all(predicate: (item: T) => boolean): boolean
Returns true if all elements match the given predicate. Returns true if the collection is empty.
some(predicate: (item: T) => boolean): boolean
Returns true if at least one element matches the given predicate. Returns false if the collection is empty.
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
Reduces the collection to a single value by accumulating state.
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.
filter(predicate: (item: T) => boolean): Iterable<T>
Returns a new iterable containing only the elements that match the predicate.
MapEntry
class MapEntry<K, V>
A key-value pair from a Map.
HashMap
class HashMap<K extends Hashable, V> with IterableUtils<MapEntry<K, V>> implements Map<K, V>
A hash map with separate chaining, growing at a 75% load factor.
Iteration order is unspecified and changes as the map grows; use OrderedHashMap when order matters. Lookup, insertion and deletion are O(1) amortized.
A subclass adapts the table through :newEntry, :entryRemoved and
:rehash, which is how OrderedMap threads an insertion-order list through
the entries without duplicating any of the lookup paths.
new(capacity: i32 = 16)
size: i32 { get; }
get(key: K): inline (true, V) | inline (false, _)
(true, value) if the key is present, (false, _) otherwise. An inline
tuple, so this is the allocation-free way to test and read in one step.
getOr(key: K, defaultValue: V): V
The value for key, or defaultValue if the key is absent.
getOption(key: K): Option<V>
Some(value) if the key is present, None otherwise. Prefer get unless
the result has to be stored or passed on.
has(key: K): boolean
delete(key: K): boolean
Removes key. Returns whether it was present.
clear(): void
Removes every entry.
keys(): Iterator<K>
Returns an iterator over the keys.
forEach(callback: (key: K, value: V) => void): void
Calls callback once per entry.
7 inherited members
Map
new ordered<K extends Hashable, V>(capacity: i32 = 16): OrderedMap<K, V>
An empty OrderedHashMap: iteration follows insertion order.
Iterable
contains(value: T): boolean
Returns true if the collection contains the specified value.
all(predicate: (item: T) => boolean): boolean
Returns true if all elements match the given predicate. Returns true if the collection is empty.
some(predicate: (item: T) => boolean): boolean
Returns true if at least one element matches the given predicate. Returns false if the collection is empty.
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
Reduces the collection to a single value by accumulating state.
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.
filter(predicate: (item: T) => boolean): Iterable<T>
Returns a new iterable containing only the elements that match the predicate.
OrderedHashMap
final class OrderedMap<K extends Hashable, V> extends HashMap<K, V>
A hash map that iterates in insertion order — exported as OrderedHashMap.
Order is maintained by a doubly-linked list through the entries, so it costs two pointers per entry and nothing per lookup. Replacing an existing key's value keeps its position; deleting a key and inserting it again moves it to the end.
Iteration follows the same rules as JavaScript's Map:
- entries inserted during an iteration are visited by it;
- entries deleted before an iteration reaches them are not visited;
- deleting the entry an iteration is parked on does not disturb it;
- once an iterator reports exhaustion it stays exhausted.
Example: let m = new OrderedHashMap<String, i32>(); m["b"] = 2; m["a"] = 1; // Iteration order: "b", "a"
new(capacity: i32 = 16)
15 inherited members
Map
new ordered<K extends Hashable, V>(capacity: i32 = 16): OrderedMap<K, V>
An empty OrderedHashMap: iteration follows insertion order.
HashMap
size: i32 { get; }
get(key: K): inline (true, V) | inline (false, _)
(true, value) if the key is present, (false, _) otherwise. An inline
tuple, so this is the allocation-free way to test and read in one step.
getOr(key: K, defaultValue: V): V
The value for key, or defaultValue if the key is absent.
getOption(key: K): Option<V>
Some(value) if the key is present, None otherwise. Prefer get unless
the result has to be stored or passed on.
has(key: K): boolean
delete(key: K): boolean
Removes key. Returns whether it was present.
Iterable
contains(value: T): boolean
Returns true if the collection contains the specified value.
all(predicate: (item: T) => boolean): boolean
Returns true if all elements match the given predicate. Returns true if the collection is empty.
some(predicate: (item: T) => boolean): boolean
Returns true if at least one element matches the given predicate. Returns false if the collection is empty.
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
Reduces the collection to a single value by accumulating state.
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.
filter(predicate: (item: T) => boolean): Iterable<T>
Returns a new iterable containing only the elements that match the predicate.
HashSet
final class HashSet<T extends Hashable> extends MapBackedSet<T>
A set of unique values with efficient membership tests.
Iteration order is unspecified and can change as the set grows. Use OrderedHashSet from 'zena:collections' when insertion order matters.
new(capacity: i32 = 16)
OrderedHashSet
final class OrderedHashSet<T extends Hashable> extends MapBackedSet<T>
A set that iterates in insertion order.
Order costs two pointers per value and nothing per membership test.
Re-adding a value it already holds keeps its position; deleting a value and
adding it again moves it to the end. Iteration follows the same rules as
OrderedHashMap, and so as JavaScript's Set.
Example:
let s = new OrderedHashSet
new(capacity: i32 = 16)
ZippedIterable
final class ZippedIterable<A, B> with IterableUtils<(A, B)> implements Iterable<(A, B)>
Two iterables in step, as pairs of their elements. See zip.
new(a: Iterable<A>, b: Iterable<B>)
6 inherited members
Iterable
contains(value: T): boolean
Returns true if the collection contains the specified value.
all(predicate: (item: T) => boolean): boolean
Returns true if all elements match the given predicate. Returns true if the collection is empty.
some(predicate: (item: T) => boolean): boolean
Returns true if at least one element matches the given predicate. Returns false if the collection is empty.
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
Reduces the collection to a single value by accumulating state.
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.
filter(predicate: (item: T) => boolean): Iterable<T>
Returns a new iterable containing only the elements that match the predicate.
ZipIterator
final class ZipIterator<A, B> implements Iterator<(A, B)>
An Iterator over two iterators in step. Each step is a pair of their next elements; it is done as soon as either iterator is.
Interfaces
Hashable
interface Hashable extends Equatable
A type that can be used as a key in hash-based collections like HashMap and HashSet.
A hash key declares its equality, so Hashable extends Equatable, and the
two must agree: if two values are equal (per operator ==), they must
return the same hashCode. The reverse is not required — unequal values may
share a hash code, though fewer collisions means better performance.
A class whose equality is identity says so, and returns an identity hash: a value that is unique per instance and stable for its lifetime, such as a counter assigned in the constructor.
class Session implements Hashable {
#id: i32 = nextSessionId();
operator ==(other: Session): boolean { return this === other; }
hashCode(): i32 { return this.#id; }
}
Case classes automatically satisfy Hashable: the compiler derives a
structural hashCode() and operator == from their parameters, unless the
class inherits either one from its base, whose pair is then the hierarchy's
equality. Primitives (i32, boolean, enums, and distinct types over them)
also satisfy the Hashable constraint; they hash to their own value. Strings
hash with FNV-1a, cached after the first computation.
hashCode(): i32
Array
interface Array<T> extends Iterable<T>
A sequence with a length and indexed reads.
This is the read-only view; MutableArray adds indexed writes. The
constructors build the standard implementations — new Array() is a
GrowableArray and new Array.fixed(n, value) a FixedArray — and are
typed as those classes, so the result has the class's full API.
(The modules declaring those classes import this one back; classes and
interfaces may cross an import cycle.)
new(capacity: i32 = 8): GrowableArray<T>
An empty growable array, with room for capacity items before it grows.
new growable(capacity: i32 = 8): GrowableArray<T>
The same as new Array(), named for symmetry with fixed.
new fixed(length: i32, value: T): FixedArray<T>
A fixed-length array of length copies of value.
length: i32 { get; }
map<U>(f: (item: T, index: i32, seq: this) => U): Array<U>
contentEquals(other: Array<T>): boolean
Whether other has the same length and == elements in the same
order, whatever array class it is. == on two arrays compares
identity; this compares contents, as two byte strings are compared.
operator [](index: i32): T
operator [](r: Range): Array<T>
A copy of the elements whose indices are in the range: a..b (from
a up to but not including b), a.. (from a to the end), ..b
(from the start up to b) or .. (all of them). Bounds outside the
array are clamped to it, and a range with no elements gives an empty
array.
6 inherited members
Iterable
contains(value: T): boolean
Returns true if the collection contains the specified value.
all(predicate: (item: T) => boolean): boolean
Returns true if all elements match the given predicate. Returns true if the collection is empty.
some(predicate: (item: T) => boolean): boolean
Returns true if at least one element matches the given predicate. Returns false if the collection is empty.
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
Reduces the collection to a single value by accumulating state.
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.
filter(predicate: (item: T) => boolean): Iterable<T>
Returns a new iterable containing only the elements that match the predicate.
MutableArray
interface MutableArray<T> extends Array<T>
operator []=(index: i32, value: T): void
13 inherited members
Array
new(capacity: i32 = 8): GrowableArray<T>
An empty growable array, with room for capacity items before it grows.
new growable(capacity: i32 = 8): GrowableArray<T>
The same as new Array(), named for symmetry with fixed.
new fixed(length: i32, value: T): FixedArray<T>
A fixed-length array of length copies of value.
length: i32 { get; }
map<U>(f: (item: T, index: i32, seq: this) => U): Array<U>
contentEquals(other: Array<T>): boolean
Whether other has the same length and == elements in the same
order, whatever array class it is. == on two arrays compares
identity; this compares contents, as two byte strings are compared.
operator [](index: i32): T
Iterable
contains(value: T): boolean
Returns true if the collection contains the specified value.
all(predicate: (item: T) => boolean): boolean
Returns true if all elements match the given predicate. Returns true if the collection is empty.
some(predicate: (item: T) => boolean): boolean
Returns true if at least one element matches the given predicate. Returns false if the collection is empty.
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
Reduces the collection to a single value by accumulating state.
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.
filter(predicate: (item: T) => boolean): Iterable<T>
Returns a new iterable containing only the elements that match the predicate.
Map
interface Map<K, V> extends Iterable<MapEntry<K, V>>
A collection of key-value pairs with efficient lookup by key.
A key maps to at most one value; inserting over an existing key replaces the value.
Keys must not change while they are in the map. An implementation places an
entry by the key's hash code and finds it again by equality, so a key that
changes either leaves its entry unreachable — still held, still counted in
size, but no longer findable — or collides with another. Prefer keys that
cannot change: primitives, Strings, enums, and case classes over those.
size: i32 { get; }
How many entries the map holds.
get(key: K): inline (true, V) | inline (false, _)
(true, value) if the key is present, (false, _) otherwise.
The way to ask and read in one step, and the one to prefer: the result is an inline tuple, so it allocates nothing and is usually destructured straight away.
if (let (true, v) = m.get(k))
getOr(key: K, defaultValue: V): V
The value for key, or defaultValue if the key is absent.
getOption(key: K): Option<V>
Some(value) if the key is present, None otherwise.
Answers the same question as get, but as a value that can be stored,
returned or passed on. That costs an allocation, so prefer get when the
answer is used where it is asked for.
has(key: K): boolean
Whether key is present.
delete(key: K): boolean
Removes key. Returns whether it was present.
clear(): void
Removes every entry.
keys(): Iterator<K>
An iterator over the keys, in the map's iteration order.
forEach(callback: (key: K, value: V) => void): void
Calls callback once per entry, in the map's iteration order.
6 inherited members
Iterable
contains(value: T): boolean
Returns true if the collection contains the specified value.
all(predicate: (item: T) => boolean): boolean
Returns true if all elements match the given predicate. Returns true if the collection is empty.
some(predicate: (item: T) => boolean): boolean
Returns true if at least one element matches the given predicate. Returns false if the collection is empty.
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
Reduces the collection to a single value by accumulating state.
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.
filter(predicate: (item: T) => boolean): Iterable<T>
Returns a new iterable containing only the elements that match the predicate.
Set
interface Set<T> extends Iterable<T>
size: i32 { get; }
add(value: T): boolean
Adds a value to the set. Returns true if the value was newly added, false if it already existed.
has(value: T): boolean
Checks if the set contains the given value.
delete(value: T): boolean
Removes a value from the set. Returns true if the value was removed, false if it didn't exist.
clear(): void
Removes all values from the set.
operator [](value: T): boolean
Checks if the set contains the given value.
6 inherited members
Iterable
contains(value: T): boolean
Returns true if the collection contains the specified value.
all(predicate: (item: T) => boolean): boolean
Returns true if all elements match the given predicate. Returns true if the collection is empty.
some(predicate: (item: T) => boolean): boolean
Returns true if at least one element matches the given predicate. Returns false if the collection is empty.
fold<R>(initial: R, combine: (acc: R, item: T) => R): R
Reduces the collection to a single value by accumulating state.
find(predicate: (item: T) => boolean): inline (true, T) | inline (false, _)
Finds the first element that matches the predicate. Returns an inline tuple (true, item) if found, or (false, _) if not.
filter(predicate: (item: T) => boolean): Iterable<T>
Returns a new iterable containing only the elements that match the predicate.
Functions
fixed
function fixed<T>(items: FixedArray<T>): FixedArray<T>
Its argument, unchanged: fixed([1, 2, 3]).
The parameter supplies the mutable context, so a literal argument builds directly as a FixedArray — a mutable literal in expression position, where no annotation can say so. The identity body inlines away, leaving the bare allocation.
growable
function growable<T>(items: FixedArray<T>): GrowableArray<T>
A growable array from an array literal: growable([1, 2, 3]).
The parameter supplies the mutable context, so the literal builds
directly as a FixedArray and is adopted as the backing storage —
no copy, unlike GrowableArray.from over an interface-typed source.
Until literal decorators land, this is the concise spelling for a
growable array with initial contents.
zip
function zip<A, B>(a: Iterable<A>, b: Iterable<B>): ZippedIterable<A, B>
The elements of a and b in step, as pairs, until either runs out:
for (let (x, y) in zip(xs, ys)) {
dot += x * y;
}
When b runs out first, the element of a read in that step is
dropped.