Issie logo Issie

LookupArray Module

A growable, index-addressed store: items are added in creation order, each one stamped with the index it was stored at, and read back by that index. It exists because the simulator's build phase was indexing its own components by structural keys. A `Map` - a component id and its access path - costs a boxed comparison of the id and one of the list per lookup - 200,000 lookups into a 10,000-entry map measured 77.2 ms as such a Map and 0.2 ms as an array index - and the build does millions of them. The fix is not a faster map but an index: the thing being looked up is created by the same walk that later reads it, so it can be given its position as it is made. Nothing past `Count` is ever read, which is what lets the backing array be oversized without an `option` per slot - the codebase forbids nulls, and `Array.zeroCreate` on a reference type yields them. `Count` is the whole of the contract that keeps them out of sight.

Types

Type Description

LookupArray<'T>

A store of 'T addressed by the index each item was stamped with when it was added. Mutable, deliberately, and build-scoped: see docs/mutableState.md. Nothing outside the module should write `Items` or `Count`.

Functions and values

Function or value Description

addItem item store

Full Usage: addItem item store

Parameters:
Returns: 'T

Add an item, stamping it with the index it is stored at. **Use the returned item, never the argument.** With an in-place stamp the two are the same object and with a lens they are not, so `addItem x store |> ignore` is correct in one flavour and silently wrong in the other. The compiler cannot tell them apart.

item : 'T
store : LookupArray<'T>
Returns: 'T

count store

Full Usage: count store

Parameters:
Returns: int
Modifiers: inline
Type parameters: 'T

How many items have been added.

store : LookupArray<'T>
Returns: int

create getIndex addIndexStamp capacity maxIncrement

Full Usage: create getIndex addIndexStamp capacity maxIncrement

Parameters:
    getIndex : 'T -> int
    addIndexStamp : 'T -> int -> 'T
    capacity : int
    maxIncrement : int

Returns: LookupArray<'T>
 A store of `capacity` items before it has to grow, extending by at most `maxIncrement` slots
 at a time once it does.

 The two functions are given separately rather than as a `Lens<'T,int>` so that the caller
 chooses what stamping costs. A lens setter is a record copy, and the simulator's use of this
 stores a 24-field record created hundreds of thousands of times per build - while that record
 is `[]` and already carries mutable fields, so an index written in place
 costs nothing and keeps the object identity the simulator relies on:

     // in place - no copy, the same object back. The store works in bare ints; a caller whose
     // index is a wrapped one unwraps at this boundary and nowhere else.
     LookupArray.create (fun fc -> fcToInt fc.Index) (fun fc i -> fc.Index <- FastCompIndex i; fc) n maxInc
     // through a lens, where the type is immutable
     LookupArray.create (Optic.get index_) (fun t i -> Optic.set index_ i t) n maxInc

 It also keeps Optics out of this file, which is why it can sit anywhere in compile order.
getIndex : 'T -> int
addIndexStamp : 'T -> int -> 'T
capacity : int
maxIncrement : int
Returns: LookupArray<'T>

indexOf item store

Full Usage: indexOf item store

Parameters:
Returns: int
Modifiers: inline
Type parameters: 'T

The index an item was stamped with, read back off the item itself.

item : 'T
store : LookupArray<'T>
Returns: int

item i store

Full Usage: item i store

Parameters:
Returns: 'T
Modifiers: inline
Type parameters: 'T

The item at an index. The hot operation, and the reason this module exists.

i : int
store : LookupArray<'T>
Returns: 'T

iteri f store

Full Usage: iteri f store

Parameters:

Apply a function to every stored item and its index, in creation order.

f : int -> 'T -> unit
store : LookupArray<'T>

toArray store

Full Usage: toArray store

Parameters:
Returns: 'T array

A copy of what is stored, truncated to Count - so it never exposes an unwritten slot.

store : LookupArray<'T>
Returns: 'T array

updateItem i item store

Full Usage: updateItem i item store

Parameters:

Replace the item at an index already in the store. Does not re-stamp: the index is the one the item was given when it was added.

i : int
item : 'T
store : LookupArray<'T>

Type something to start searching.