# 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) `containsAll` and `intersects`, 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` / `unset` guards: out-of-range bit indices throw `RangeError`; the constructor rejects non-positive sizes. ## Usage: Basic Example ```ts 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 ```ts 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. - `containsAll` walks each word in lock-step and treats trailing words of `other` as zero when `this` is shorter — this lets the world build mask-only diffs between archetypes without forcing both sides to the same allocation size. - `count` is the classic 5-step parallel bit-population trick, fast and branch-free. - `toKey` produces 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.