InfArray
A chunked array that bypasses Luau's internal table size limit of 2^26.
Values are stored across fixed-size chunks so a single logical array can hold
up to 2^53 elements (the largest exact integer a Luau number can represent).
Indices are 1-based and resolved with integer math.
Removals leave nil holes. Per-chunk logical lengths are tracked explicitly, so
the implementation never relies on # over a chunk (which is undefined once the
chunk contains holes). InfArray:Length reports the highest assigned index
(holes included), while InfArray:Count reports the number of present elements.
local InfArray = require(path.to.InfArray)
local arr = InfArray.new()
arr:PushBack("a")
arr:PushBack("b")
print(arr:Get(1)) --> "a"
print(#arr) --> 2
Several backwards-compatible aliases exist for the primary methods:
get/GetValueAtIndex (Get), set/Replace (Set), InsertBack (PushBack),
TransformRange (Transform), GetTotalLen (Count) and GetLength (Length).
Properties
LIMIT
This item is read only and cannot be modified. Read OnlystaticInfArray.LIMIT: numberMaximum number of elements a single chunk can hold (2^26 = 67108864).
Functions
new
InfArray.new(size: number?,--
Optional initial length; pre-allocates chunks.
value: any?--
Optional fill value written to every pre-allocated slot.
) → InfArray
Creates a new InfArray. When size is given, the array is pre-sized to size
elements; if value is also provided, every slot is filled with it and
InfArray:Count reflects the full size (otherwise the slots start as holes).
Get
InfArray:Get(index: number--
1-based global index.
) → any?--
The value at index, or nil if unset or out of range.
Reads the value at index in O(1). Returns nil for holes and for indices
whose chunk does not exist yet.
Set
InfArray:Set(index: number,--
1-based global index within an existing chunk.
value: any?--
New value; pass nil to clear the slot into a hole.
) → boolean--
true if the write happened, false if it was a no-op.
In-range O(1) write that keeps InfArray:Count and InfArray:Length correct.
Returns true when the write lands. This is a no-op returning false if
the index's chunk does not exist yet — use InfArray:PushBack,
InfArray.new with a size, or InfArray:SetChunk to grow the array first.
GetChunk
InfArray:GetChunk(index: number--
1-based chunk index.
) → {any}?--
The raw backing table for that chunk, or nil.
Returns the raw chunk table by chunk index. The returned table may contain
nil holes and is not length-safe under #; pair it with the chunk's tracked
length (see InfArray:IterateChunks) when scanning it.
SetChunk
InfArray:SetChunk(chunkIndex: number,--
1-based chunk index to replace.
value: {any},--
The new backing table for the chunk.
len: number?--
Logical length of value; defaults to #value.
) → ()Replaces an entire chunk in one call, recomputing InfArray:Count for the swapped range and extending InfArray:Length if the new chunk reaches further. Prefer this over per-element writes for bulk population.
GetChunkAndPosition
InfArray:GetChunkAndPosition(index: number--
1-based global index.
) → ({any}?,--
The chunk containing index, or nil if absent.
number--
The 1-based position of index within that chunk.
)Resolves a global index to its chunk and in-chunk position in one call, useful for hot loops that want to read/write a slot without recomputing the location.
PushBack
InfArray:PushBack(value: any--
Value to append at the end of the array.
) → number--
The global index the value was written to.
Appends value after the highest assigned index, allocating a new chunk when
the current one fills up. Amortised O(1).
RemoveIndex
InfArray:RemoveIndex(index: number--
1-based global index to clear.
) → ()
Clears the value at index, decrementing InfArray:Count. This leaves a nil
hole — InfArray:Length is unchanged and later elements are not shifted.
Iterate
InfArray:Iterate(callback: (index: number,value: any) → boolean?--
Called for each present element; return true to stop early.
) → ()
Iterates every present element in ascending index order, skipping holes. Return
true from callback to break out early. For maximum bulk throughput, use
InfArray:IterateChunks instead.
IterateChunks
InfArray:IterateChunks(callback: (chunk: {any},base: number,len: number) → boolean?--
Called once per chunk; return true to stop early.
) → ()
Hands each raw chunk to callback along with its base global-index offset and
tracked len. The fastest way to process the whole array in bulk. The caller
must nil-check chunk[j] itself, since chunks may contain holes. Return
true to stop early.
Find
InfArray:Find(needle: any--
Value to search for.
) → number?--
The first global index equal to needle, or nil.
Linearly scans in ascending order and returns the first global index whose value
equals needle, or nil if not found. Scans to each chunk's tracked length so
holes never cut the search short.
Transform
InfArray:Transform(start: number,--
First global index to visit (inclusive).
stop: number,--
Last global index to visit (inclusive).
step: number,--
Stride between visited indices.
updateFunc: (index: number,value: any) → any--
Returns the new value for each visited slot.
) → ()
Applies updateFunc over the range [start, stop] by step, writing back each
returned value. May turn holes into values (or values back into holes);
InfArray:Count stays correct either way. Indices whose chunk does not exist
are skipped.
Count
InfArray:Count() → number--
The number of present (non-nil) elements.
Returns how many elements are actually present, excluding holes. O(1).
Length
InfArray:Length() → number--
The highest assigned index (holes included).
Returns the logical length: the highest index ever assigned, counting holes.
Equivalent to #arr. O(1).