Types
BlockIter = object
BlockSpan = object
- Every slot a store had handed out at the moment the span was taken, described in raw terms so a caller can walk it without going back through the store for each one. The slots are laid out end to end, so walking is a matter of stepping a pointer
BlockStore[V] = ref BlockStoreObj[V]
- Stores a block of packed values
Entry[V] = object
- A reserved slot in a BlockStore. Liveness is tracked in a bitmap alongside the values instead of inline, which keeps the stored rows free of bookkeeping
Procs
proc `[]`[V](store: BlockStore[V]; idx: uint): var V
- Reads a field
proc del[V](store: var BlockStore[V]; idx: uint): V
- Deletes a field
func len[V](blockstore: var BlockStore[V]): Natural
- Returns the length of this blockstore
proc newBlockStore[V](size: Natural): BlockStore[V]
- Instantiates a new BlockStore
proc next[V](store: var BlockStore[V]; iter: var BlockIter): ptr V {.inline.}
- Returns the next value in an iterator
proc reserve[V](blockstore: var BlockStore[V]): Entry[V]
- Reserves a slot for a value
proc wholeSpan[V](store: var BlockStore[V]): BlockSpan
-
Returns every slot the store has handed out, filled or not. The count is fixed when the span is taken, so a walk sees the store as it stood when the walk began and values pushed part way through are left for the next one.
Liveness is deliberately not baked in, because values can be deleted midway through a span being walked. It travels with the span so each slot can be confirmed as it is reached
Iterators
iterator addresses[V](span: BlockSpan; kind: typedesc[V]): ptr V
-
Walks the filled slots in a span, yielding the address of each as a ptr V. V needs to fit in a slot, but does not have to fill it: a caller that only knows how a slot starts can walk it as that, then work out the rest of the slot from there.
Liveness is confirmed as the walk goes rather than trusted from when the span was taken, so a caller is free to delete slots this walk has not reached yet. The bitmap word is shared by sixty four slots, so it stays in cache.
This is named apart from items on purpose: items is late bound inside generic code, which would resolve it against whatever the instantiating module happens to import
iterator items[V](span: BlockSpan; kind: typedesc[V]): var V
- Walks the filled slots in a span as the type they were stored as
iterator items[V](store: var BlockStore[V]): var V
- Iterate through all values in this BlockStore
Templates
template `[]=`[V](store: BlockStore[V]; idx: uint; newValue: V)
- Sets a new value for a key
template push[V](store: var BlockStore[V]; newValue: V): uint
- Adds a value and returns an index to it