Skip to main content

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 holes. InfArray:Length reports the highest assigned index (holes included), while InfArray:Count reports the number of present elements. A hole reads back as nil through InfArray:Get and is skipped by iteration, but the backing slot holds the InfArray.EMPTY tombstone, so raw chunks are dense tables rather than holey ones.

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 Onlystatic
InfArray.LIMIT: number

Maximum number of elements a single chunk can hold (2^26 = 67108864).

EMPTY​

This item is read only and cannot be modified. Read Onlystatic
InfArray.EMPTY: any

Marks a hole in a raw chunk.

Use EMPTY only when you index a chunk table yourself. Everywhere else use nil. The three functions that hand back a raw chunk are InfArray:GetChunk, InfArray:GetChunkAndPosition and InfArray:IterateChunks.

Doing Use
Set(i, nil), PushBack(nil), Transform returning nil nil
A table with gaps passed to InfArray:SetChunk nil, rewritten for you
Reading InfArray:Get nil
InfArray:Transform callback's value argument nil
InfArray:Iterate or for..in value neither, holes are skipped
chunk[j] from a raw chunk EMPTY

Inside a chunk's tracked length a slot is a value or EMPTY, never nil.

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.

Writing past the chunk's current length extends it and tombstones the skipped slots, which costs O(gap).

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. Cleared slots hold InfArray.EMPTY, not nil, and the table is padded past its logical length; 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.

Takes ownership of value: any nil below the chunk's length is rewritten in place as an InfArray.EMPTY tombstone.

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). Appending nil extends InfArray:Length with a hole and leaves InfArray:Count unchanged.

RemoveIndex​

InfArray:RemoveIndex(
index: number--

1-based global index to clear.

) → ()

Clears the value at index, decrementing InfArray:Count. This leaves a 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 skip slots equal to InfArray.EMPTY itself, since chunks tombstone their 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. Holes never cut the search short, and searching for nil always returns nil. Pass InfArray.EMPTY to locate the first hole.

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. updateFunc sees nil for a hole and may return nil to clear a slot; 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).

Show raw api
{
    "functions": [
        {
            "name": "new",
            "desc": "Creates a new [InfArray]. When `size` is given, the array is pre-sized to `size`\nelements; if `value` is also provided, every slot is filled with it and\n[InfArray:Count] reflects the full size (otherwise the slots start as holes).",
            "params": [
                {
                    "name": "size",
                    "desc": "Optional initial length; pre-allocates chunks.",
                    "lua_type": "number?"
                },
                {
                    "name": "value",
                    "desc": "Optional fill value written to every pre-allocated slot.",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "InfArray"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 122,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "Get",
            "desc": "Reads the value at `index` in O(1). Returns `nil` for holes and for indices\nwhose chunk does not exist yet.",
            "params": [
                {
                    "name": "index",
                    "desc": "1-based global index.",
                    "lua_type": "number"
                }
            ],
            "returns": [
                {
                    "desc": "The value at `index`, or `nil` if unset or out of range.",
                    "lua_type": "any?"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 161,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "Set",
            "desc": "In-range O(1) write that keeps [InfArray:Count] and [InfArray:Length] correct.\nReturns `true` when the write lands. This is a **no-op** returning `false` if\nthe index's chunk does not exist yet — use [InfArray:PushBack],\n[InfArray.new] with a size, or [InfArray:SetChunk] to grow the array first.\n\nWriting past the chunk's current length extends it and tombstones the skipped\nslots, which costs O(gap).",
            "params": [
                {
                    "name": "index",
                    "desc": "1-based global index within an existing chunk.",
                    "lua_type": "number"
                },
                {
                    "name": "value",
                    "desc": "New value; pass `nil` to clear the slot into a hole.",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "`true` if the write happened, `false` if it was a no-op.",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 188,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "GetChunk",
            "desc": "Returns the raw chunk table by chunk index. Cleared slots hold\n[InfArray.EMPTY], not `nil`, and the table is padded past its logical length;\npair it with the chunk's tracked length (see [InfArray:IterateChunks]) when\nscanning it.",
            "params": [
                {
                    "name": "index",
                    "desc": "1-based chunk index.",
                    "lua_type": "number"
                }
            ],
            "returns": [
                {
                    "desc": "The raw backing table for that chunk, or `nil`.",
                    "lua_type": "{any}?"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 257,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "SetChunk",
            "desc": "Replaces an entire chunk in one call, recomputing [InfArray:Count] for the\nswapped range and extending [InfArray:Length] if the new chunk reaches further.\nPrefer this over per-element writes for bulk population.\n\nTakes ownership of `value`: any `nil` below the chunk's length is rewritten in\nplace as an [InfArray.EMPTY] tombstone.",
            "params": [
                {
                    "name": "chunkIndex",
                    "desc": "1-based chunk index to replace.",
                    "lua_type": "number"
                },
                {
                    "name": "value",
                    "desc": "The new backing table for the chunk.",
                    "lua_type": "{any}"
                },
                {
                    "name": "len",
                    "desc": "Logical length of `value`; defaults to `#value`.",
                    "lua_type": "number?"
                }
            ],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 276,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "GetChunkAndPosition",
            "desc": "Resolves a global index to its chunk and in-chunk position in one call, useful\nfor hot loops that want to read/write a slot without recomputing the location.",
            "params": [
                {
                    "name": "index",
                    "desc": "1-based global index.",
                    "lua_type": "number"
                }
            ],
            "returns": [
                {
                    "desc": "The chunk containing `index`, or `nil` if absent.",
                    "lua_type": "{any}?"
                },
                {
                    "desc": "The 1-based position of `index` within that chunk.",
                    "lua_type": "number"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 328,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "PushBack",
            "desc": "Appends `value` after the highest assigned index, allocating a new chunk when\nthe current one fills up. Amortised O(1). Appending `nil` extends\n[InfArray:Length] with a hole and leaves [InfArray:Count] unchanged.",
            "params": [
                {
                    "name": "value",
                    "desc": "Value to append at the end of the array.",
                    "lua_type": "any"
                }
            ],
            "returns": [
                {
                    "desc": "The global index the value was written to.",
                    "lua_type": "number"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 345,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "RemoveIndex",
            "desc": "Clears the value at `index`, decrementing [InfArray:Count]. This leaves a hole.\n[InfArray:Length] is **unchanged** and later elements are not shifted.",
            "params": [
                {
                    "name": "index",
                    "desc": "1-based global index to clear.",
                    "lua_type": "number"
                }
            ],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 382,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "__iter",
            "desc": "Generalized `for..in` iteration (`for index, value in arr do`). Holes are\nskipped. Prefer [InfArray:IterateChunks] for bulk throughput.",
            "params": [],
            "returns": [],
            "function_type": "method",
            "ignore": true,
            "source": {
                "line": 410,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "Iterate",
            "desc": "Iterates every present element in ascending index order, skipping holes. Return\n`true` from `callback` to break out early. For maximum bulk throughput, use\n[InfArray:IterateChunks] instead.",
            "params": [
                {
                    "name": "callback",
                    "desc": "Called for each present element; return `true` to stop early.",
                    "lua_type": "(index: number, value: any) -> boolean?"
                }
            ],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 453,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "IterateChunks",
            "desc": "Hands each raw chunk to `callback` along with its `base` global-index offset and\ntracked `len`. The fastest way to process the whole array in bulk. The caller\n**must** skip slots equal to [InfArray.EMPTY] itself, since chunks tombstone\ntheir holes. Return `true` to stop early.",
            "params": [
                {
                    "name": "callback",
                    "desc": "Called once per chunk; return `true` to stop early.",
                    "lua_type": "(chunk: {any}, base: number, len: number) -> boolean?"
                }
            ],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 490,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "Find",
            "desc": "Linearly scans in ascending order and returns the first global index whose value\nequals `needle`, or `nil` if not found. Holes never cut the search short, and\nsearching for `nil` always returns `nil`. Pass [InfArray.EMPTY] to locate the\nfirst hole.",
            "params": [
                {
                    "name": "needle",
                    "desc": "Value to search for.",
                    "lua_type": "any"
                }
            ],
            "returns": [
                {
                    "desc": "The first global index equal to `needle`, or `nil`.",
                    "lua_type": "number?"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 511,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "Transform",
            "desc": "Applies `updateFunc` over the range `[start, stop]` by `step`, writing back each\nreturned value. `updateFunc` sees `nil` for a hole and may return `nil` to clear\na slot; [InfArray:Count] stays correct either way. Indices whose chunk does not\nexist are skipped.",
            "params": [
                {
                    "name": "start",
                    "desc": "First global index to visit (inclusive).",
                    "lua_type": "number"
                },
                {
                    "name": "stop",
                    "desc": "Last global index to visit (inclusive).",
                    "lua_type": "number"
                },
                {
                    "name": "step",
                    "desc": "Stride between visited indices.",
                    "lua_type": "number"
                },
                {
                    "name": "updateFunc",
                    "desc": "Returns the new value for each visited slot.",
                    "lua_type": "(index: number, value: any) -> any"
                }
            ],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 539,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "Count",
            "desc": "Returns how many elements are actually present, excluding holes. O(1).",
            "params": [],
            "returns": [
                {
                    "desc": "The number of present (non-`nil`) elements.",
                    "lua_type": "number"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 608,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "Length",
            "desc": "Returns the logical length: the highest index ever assigned, counting holes.\nEquivalent to `#arr`. O(1).",
            "params": [],
            "returns": [
                {
                    "desc": "The highest assigned index (holes included).",
                    "lua_type": "number"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 621,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "__len",
            "desc": "`#arr` returns the highest assigned index. See [InfArray:Length].",
            "params": [],
            "returns": [],
            "function_type": "method",
            "ignore": true,
            "source": {
                "line": 632,
                "path": "InfArray.luau"
            }
        }
    ],
    "properties": [
        {
            "name": "LIMIT",
            "desc": "Maximum number of elements a single chunk can hold (2^26 = 67108864).",
            "lua_type": "number",
            "tags": [
                "static"
            ],
            "readonly": true,
            "source": {
                "line": 85,
                "path": "InfArray.luau"
            }
        },
        {
            "name": "EMPTY",
            "desc": "Marks a hole in a raw chunk.\n\n**Use `EMPTY` only when you index a chunk table yourself. Everywhere else use\n`nil`.** The three functions that hand back a raw chunk are\n[InfArray:GetChunk], [InfArray:GetChunkAndPosition] and\n[InfArray:IterateChunks].\n\n| Doing | Use |\n| --- | --- |\n| `Set(i, nil)`, `PushBack(nil)`, `Transform` returning nil | `nil` |\n| A table with gaps passed to [InfArray:SetChunk] | `nil`, rewritten for you |\n| Reading [InfArray:Get] | `nil` |\n| [InfArray:Transform] callback's value argument | `nil` |\n| [InfArray:Iterate] or `for..in` value | neither, holes are skipped |\n| `chunk[j]` from a raw chunk | `EMPTY` |\n\nInside a chunk's tracked length a slot is a value or `EMPTY`, never `nil`.",
            "lua_type": "any",
            "tags": [
                "static"
            ],
            "readonly": true,
            "source": {
                "line": 110,
                "path": "InfArray.luau"
            }
        }
    ],
    "types": [],
    "name": "InfArray",
    "desc": "A chunked array that bypasses Luau's internal table size limit of 2^26.\n\nValues are stored across fixed-size chunks so a single logical array can hold\nup to 2^53 elements (the largest exact integer a Luau `number` can represent).\nIndices are 1-based and resolved with integer math.\n\nRemovals leave holes. [InfArray:Length] reports the highest assigned index\n(holes included), while [InfArray:Count] reports the number of present\nelements. A hole reads back as `nil` through [InfArray:Get] and is skipped by\niteration, but the backing slot holds the [InfArray.EMPTY] tombstone, so raw\nchunks are dense tables rather than holey ones.\n\n```lua\nlocal InfArray = require(path.to.InfArray)\n\nlocal arr = InfArray.new()\narr:PushBack(\"a\")\narr:PushBack(\"b\")\nprint(arr:Get(1)) --> \"a\"\nprint(#arr)       --> 2\n```\n\nSeveral backwards-compatible aliases exist for the primary methods:\n`get`/`GetValueAtIndex` (Get), `set`/`Replace` (Set), `InsertBack` (PushBack),\n`TransformRange` (Transform), `GetTotalLen` (Count) and `GetLength` (Length).",
    "source": {
        "line": 74,
        "path": "InfArray.luau"
    }
}