3.5 KiB
3.5 KiB
BitSet
(no submodules)
Purpose
BitSet is the foundational mask primitive used by archetypes, queries, and the component registry inside @suaveplan/ecs. Storing component membership as bits packed into Uint32Array words gives the engine cache-friendly storage and O(words) algebra for subset, superset, and intersection tests — the hot paths driving every archetype-graph transition.
The class is intentionally narrow: it offers only the operators needed by the engine itself (set, unset, has, containsAll, intersects, equals, count, clone, clear, toKey, iterator). It is universal — no node:*, browser, or React dependency — so it runs identically in Bun, Node, and the browser.
Features
Uint32Array-backed storage; one word per 32 bits.- O(words)
containsAllandintersects, safe across mismatched sizes. - Population count (
count) via the SWAR Hamming-weight trick. - Sorted-ascending iteration through
Symbol.iterator. - Stable serialised key from
toKey()used as the archetype-graph map key. - Defensive
set/unsetguards: out-of-range bit indices throwRangeError; the constructor rejects non-positive sizes.
Usage: Basic Example
import { BitSet } from "@suaveplan/ecs";
const mask = new BitSet(64);
mask.set(0);
mask.set(5);
mask.set(32);
console.log(mask.has(5)); // true
console.log([...mask]); // [0, 5, 32]
console.log(mask.toKey()); // "0,5,32"
Usage: Advanced Example
import { BitSet } from "@suaveplan/ecs";
const include = new BitSet(128);
const archetype = new BitSet(128);
include.set(3);
include.set(7);
for (const cid of [3, 7, 11, 18]) archetype.set(cid);
if (archetype.containsAll(include)) {
// Archetype has every required component — yield its entities.
}
const exclude = new BitSet(128);
exclude.set(11);
if (archetype.intersects(exclude)) {
// Skip — archetype contains a banned component.
}
API Reference
| Member | Description |
|---|---|
new BitSet(size) |
Allocate a bitset of size bits. Throws RangeError for non-positive integer sizes. |
size |
Read-only declared bit-width. |
set(bit) / unset(bit) |
Flip a single bit. RangeError on out-of-range index. |
has(bit) |
Test a bit. Returns false for out-of-range indices. |
containsAll(other) |
true when every bit set in other is also set here. Safe across mismatched word counts. |
intersects(other) |
true when at least one bit is set in both bitsets. |
equals(other) |
Structural word-by-word equality. |
count() |
Population count via SWAR. |
clone() |
Deep copy with the same size. |
clear() |
Reset every bit to zero. |
toKey() |
Comma-separated string of set indices, ascending. |
[Symbol.iterator]() |
Yield set indices in ascending order. |
Implementation Notes
- Words are accessed with
>>> 5(divide by 32) and& 31(mod 32). Using bitwise math keeps everything in the 32-bit-integer fast path. containsAllwalks each word in lock-step and treats trailing words ofotheras zero whenthisis shorter — this lets the world build mask-only diffs between archetypes without forcing both sides to the same allocation size.countis the classic 5-step parallel bit-population trick, fast and branch-free.toKeyproduces a stable, comparable string used as the archetype-graph map key. It is O(size) but only paid once per archetype-create event.- The iterator is a generator;
for (const bit of set)consumes it lazily.