@oasys/oecs 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +553 -0
- package/README.md +207 -267
- package/dist/core/ecs/access_check.d.cts +77 -0
- package/dist/core/ecs/access_check.d.ts +77 -0
- package/dist/core/ecs/access_check.d.ts.map +1 -0
- package/dist/core/ecs/archetype.d.cts +486 -0
- package/dist/core/ecs/archetype.d.ts +486 -0
- package/dist/core/ecs/archetype.d.ts.map +1 -0
- package/dist/core/ecs/archetype_graph.d.cts +96 -0
- package/dist/core/ecs/archetype_graph.d.ts +96 -0
- package/dist/core/ecs/archetype_graph.d.ts.map +1 -0
- package/dist/core/ecs/builtin_relations.d.cts +43 -0
- package/dist/core/ecs/builtin_relations.d.ts +43 -0
- package/dist/core/ecs/builtin_relations.d.ts.map +1 -0
- package/dist/core/ecs/command_log.d.cts +116 -0
- package/dist/core/ecs/command_log.d.ts +116 -0
- package/dist/core/ecs/command_log.d.ts.map +1 -0
- package/dist/core/ecs/component.d.cts +176 -0
- package/dist/core/ecs/component.d.ts +176 -0
- package/dist/core/ecs/component.d.ts.map +1 -0
- package/dist/core/ecs/compute_backend.d.cts +37 -0
- package/dist/core/ecs/compute_backend.d.ts +37 -0
- package/dist/core/ecs/compute_backend.d.ts.map +1 -0
- package/dist/core/ecs/debug_names.d.cts +7 -0
- package/dist/core/ecs/debug_names.d.ts +7 -0
- package/dist/core/ecs/debug_names.d.ts.map +1 -0
- package/dist/core/ecs/deferred_commands.d.cts +55 -0
- package/dist/core/ecs/deferred_commands.d.ts +55 -0
- package/dist/core/ecs/deferred_commands.d.ts.map +1 -0
- package/dist/core/ecs/dispatch_trace.d.cts +93 -0
- package/dist/core/ecs/dispatch_trace.d.ts +93 -0
- package/dist/core/ecs/dispatch_trace.d.ts.map +1 -0
- package/dist/core/ecs/ecs.d.cts +562 -0
- package/dist/core/ecs/ecs.d.ts +562 -0
- package/dist/core/ecs/ecs.d.ts.map +1 -0
- package/dist/core/ecs/ecs_memory.d.cts +179 -0
- package/dist/core/ecs/ecs_memory.d.ts +179 -0
- package/dist/core/ecs/ecs_memory.d.ts.map +1 -0
- package/dist/core/ecs/entity.d.cts +34 -0
- package/dist/core/ecs/entity.d.ts +34 -0
- package/dist/core/ecs/entity.d.ts.map +1 -0
- package/dist/core/ecs/entity_allocator.d.cts +59 -0
- package/dist/core/ecs/entity_allocator.d.ts +59 -0
- package/dist/core/ecs/entity_allocator.d.ts.map +1 -0
- package/dist/core/ecs/event.d.cts +79 -0
- package/dist/core/ecs/event.d.ts +79 -0
- package/dist/core/ecs/event.d.ts.map +1 -0
- package/dist/core/ecs/event_registry.d.cts +22 -0
- package/dist/core/ecs/event_registry.d.ts +22 -0
- package/dist/core/ecs/event_registry.d.ts.map +1 -0
- package/dist/core/ecs/facades.d.cts +158 -0
- package/dist/core/ecs/facades.d.ts +158 -0
- package/dist/core/ecs/facades.d.ts.map +1 -0
- package/dist/core/ecs/frame_stepper.d.cts +58 -0
- package/dist/core/ecs/frame_stepper.d.ts +58 -0
- package/dist/core/ecs/frame_stepper.d.ts.map +1 -0
- package/dist/core/ecs/frame_trace.d.cts +133 -0
- package/dist/core/ecs/frame_trace.d.ts +133 -0
- package/dist/core/ecs/frame_trace.d.ts.map +1 -0
- package/dist/core/ecs/host_commands.d.cts +274 -0
- package/dist/core/ecs/host_commands.d.ts +274 -0
- package/dist/core/ecs/host_commands.d.ts.map +1 -0
- package/dist/core/ecs/index.d.cts +46 -0
- package/dist/core/ecs/index.d.ts +46 -0
- package/dist/core/ecs/index.d.ts.map +1 -0
- package/dist/core/ecs/observer.d.cts +173 -0
- package/dist/core/ecs/observer.d.ts +173 -0
- package/dist/core/ecs/observer.d.ts.map +1 -0
- package/dist/core/ecs/query.d.cts +718 -0
- package/dist/core/ecs/query.d.ts +718 -0
- package/dist/core/ecs/query.d.ts.map +1 -0
- package/dist/core/ecs/ref.d.cts +31 -0
- package/dist/core/ecs/ref.d.ts +31 -0
- package/dist/core/ecs/ref.d.ts.map +1 -0
- package/dist/core/ecs/relation.d.cts +243 -0
- package/dist/core/ecs/relation.d.ts +243 -0
- package/dist/core/ecs/relation.d.ts.map +1 -0
- package/dist/core/ecs/relation_service.d.cts +235 -0
- package/dist/core/ecs/relation_service.d.ts +235 -0
- package/dist/core/ecs/relation_service.d.ts.map +1 -0
- package/dist/core/ecs/resource.d.cts +53 -0
- package/dist/core/ecs/resource.d.ts +53 -0
- package/dist/core/ecs/resource.d.ts.map +1 -0
- package/dist/core/ecs/resource_registry.d.cts +20 -0
- package/dist/core/ecs/resource_registry.d.ts +20 -0
- package/dist/core/ecs/resource_registry.d.ts.map +1 -0
- package/dist/core/ecs/resume.d.cts +85 -0
- package/dist/core/ecs/resume.d.ts +85 -0
- package/dist/core/ecs/resume.d.ts.map +1 -0
- package/dist/core/ecs/run_condition.d.cts +81 -0
- package/dist/core/ecs/run_condition.d.ts +81 -0
- package/dist/core/ecs/run_condition.d.ts.map +1 -0
- package/dist/core/ecs/schedule.d.cts +142 -0
- package/dist/core/ecs/schedule.d.ts +142 -0
- package/dist/core/ecs/schedule.d.ts.map +1 -0
- package/dist/core/ecs/snapshot_service.d.cts +94 -0
- package/dist/core/ecs/snapshot_service.d.ts +94 -0
- package/dist/core/ecs/snapshot_service.d.ts.map +1 -0
- package/dist/core/ecs/sparse_store.d.cts +110 -0
- package/dist/core/ecs/sparse_store.d.ts +110 -0
- package/dist/core/ecs/sparse_store.d.ts.map +1 -0
- package/dist/core/ecs/store.d.cts +950 -0
- package/dist/core/ecs/store.d.ts +950 -0
- package/dist/core/ecs/store.d.ts.map +1 -0
- package/dist/core/ecs/store_layout_listener.d.cts +23 -0
- package/dist/core/ecs/store_layout_listener.d.ts +23 -0
- package/dist/core/ecs/store_layout_listener.d.ts.map +1 -0
- package/dist/core/ecs/system.d.cts +250 -0
- package/dist/core/ecs/system.d.ts +250 -0
- package/dist/core/ecs/system.d.ts.map +1 -0
- package/dist/core/ecs/utils/arrays.d.cts +7 -0
- package/dist/{utils → core/ecs/utils}/arrays.d.ts +2 -1
- package/dist/core/ecs/utils/arrays.d.ts.map +1 -0
- package/dist/core/ecs/utils/constants.d.ts +12 -0
- package/dist/core/ecs/utils/constants.d.ts.map +1 -0
- package/dist/core/ecs/utils/error.d.cts +61 -0
- package/dist/core/ecs/utils/error.d.ts +61 -0
- package/dist/core/ecs/utils/error.d.ts.map +1 -0
- package/dist/core/store/action_ring.d.cts +136 -0
- package/dist/core/store/action_ring.d.ts +136 -0
- package/dist/core/store/action_ring.d.ts.map +1 -0
- package/dist/core/store/allocator.d.cts +238 -0
- package/dist/core/store/allocator.d.ts +238 -0
- package/dist/core/store/allocator.d.ts.map +1 -0
- package/dist/core/store/buffer_backed_column.d.cts +69 -0
- package/dist/core/store/buffer_backed_column.d.ts +69 -0
- package/dist/core/store/buffer_backed_column.d.ts.map +1 -0
- package/dist/core/store/column_store.d.cts +273 -0
- package/dist/core/store/column_store.d.ts +273 -0
- package/dist/core/store/column_store.d.ts.map +1 -0
- package/dist/core/store/command_dispatch.d.cts +52 -0
- package/dist/core/store/command_dispatch.d.ts +52 -0
- package/dist/core/store/command_dispatch.d.ts.map +1 -0
- package/dist/core/store/command_ring.d.cts +107 -0
- package/dist/core/store/command_ring.d.ts +107 -0
- package/dist/core/store/command_ring.d.ts.map +1 -0
- package/dist/core/store/descriptor.d.cts +80 -0
- package/dist/core/store/descriptor.d.ts +80 -0
- package/dist/core/store/descriptor.d.ts.map +1 -0
- package/dist/core/store/entity_index.d.cts +108 -0
- package/dist/core/store/entity_index.d.ts +108 -0
- package/dist/core/store/entity_index.d.ts.map +1 -0
- package/dist/core/store/event_ring.d.cts +95 -0
- package/dist/core/store/event_ring.d.ts +95 -0
- package/dist/core/store/event_ring.d.ts.map +1 -0
- package/dist/core/store/extend.d.cts +39 -0
- package/dist/core/store/extend.d.ts +39 -0
- package/dist/core/store/extend.d.ts.map +1 -0
- package/dist/core/store/grow.d.cts +34 -0
- package/dist/core/store/grow.d.ts +34 -0
- package/dist/core/store/grow.d.ts.map +1 -0
- package/dist/core/store/header.d.cts +64 -0
- package/dist/core/store/header.d.ts +64 -0
- package/dist/core/store/header.d.ts.map +1 -0
- package/dist/core/store/index.d.cts +17 -0
- package/dist/core/store/index.d.ts +17 -0
- package/dist/core/store/index.d.ts.map +1 -0
- package/dist/core/store/layout_ops.d.cts +152 -0
- package/dist/core/store/layout_ops.d.ts +152 -0
- package/dist/core/store/layout_ops.d.ts.map +1 -0
- package/dist/core/store/region_table.d.cts +74 -0
- package/dist/core/store/region_table.d.ts +74 -0
- package/dist/core/store/region_table.d.ts.map +1 -0
- package/dist/core/store/snapshot.d.cts +43 -0
- package/dist/core/store/snapshot.d.ts +43 -0
- package/dist/core/store/snapshot.d.ts.map +1 -0
- package/dist/core/store/state_hash.d.cts +38 -0
- package/dist/core/store/state_hash.d.ts +38 -0
- package/dist/core/store/state_hash.d.ts.map +1 -0
- package/dist/core/store/store_regions.d.cts +38 -0
- package/dist/core/store/store_regions.d.ts +38 -0
- package/dist/core/store/store_regions.d.ts.map +1 -0
- package/dist/core/store/vendored_abi/abi.d.cts +43 -0
- package/dist/core/store/vendored_abi/abi.d.ts +43 -0
- package/dist/core/store/vendored_abi/abi.d.ts.map +1 -0
- package/dist/dev_flag.d.cts +17 -0
- package/dist/dev_flag.d.ts +17 -0
- package/dist/dev_flag.d.ts.map +1 -0
- package/dist/extensions/editor/editor.d.cts +170 -0
- package/dist/extensions/editor/editor.d.ts +170 -0
- package/dist/extensions/editor/editor.d.ts.map +1 -0
- package/dist/extensions/editor/field_handle.d.cts +40 -0
- package/dist/extensions/editor/field_handle.d.ts +40 -0
- package/dist/extensions/editor/field_handle.d.ts.map +1 -0
- package/dist/extensions/editor/index.cjs +1 -0
- package/dist/extensions/editor/index.d.cts +21 -0
- package/dist/extensions/editor/index.d.ts +21 -0
- package/dist/extensions/editor/index.d.ts.map +1 -0
- package/dist/extensions/editor/index.js +237 -0
- package/dist/extensions/reactive/ecs_sync.d.cts +214 -0
- package/dist/extensions/reactive/ecs_sync.d.ts +214 -0
- package/dist/extensions/reactive/ecs_sync.d.ts.map +1 -0
- package/dist/extensions/reactive/index.cjs +1 -0
- package/dist/extensions/reactive/index.d.cts +23 -0
- package/dist/extensions/reactive/index.d.ts +23 -0
- package/dist/extensions/reactive/index.d.ts.map +1 -0
- package/dist/extensions/reactive/index.js +215 -0
- package/dist/extensions/solid/index.cjs +1 -0
- package/dist/extensions/solid/index.d.cts +6 -0
- package/dist/extensions/solid/index.d.ts +6 -0
- package/dist/extensions/solid/index.d.ts.map +1 -0
- package/dist/extensions/solid/index.js +36 -0
- package/dist/extensions/solid/kernel_solid.d.cts +45 -0
- package/dist/extensions/solid/kernel_solid.d.ts +45 -0
- package/dist/extensions/solid/kernel_solid.d.ts.map +1 -0
- package/dist/host_commands-BF8QMi3c.cjs +1 -0
- package/dist/host_commands-i4cAeyL5.js +2318 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +66 -0
- package/dist/index.d.ts +65 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7080 -1289
- package/dist/internal.cjs +2 -0
- package/dist/internal.d.cts +20 -0
- package/dist/internal.d.ts +20 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +141 -0
- package/dist/interop-CT-REx0W.cjs +1 -0
- package/dist/interop-CcY6ASQc.js +18 -0
- package/dist/kernel-DgyrLFjW.js +227 -0
- package/dist/kernel-yWV3XnAb.cjs +1 -0
- package/dist/primitives.cjs +1 -0
- package/dist/primitives.d.cts +18 -0
- package/dist/primitives.d.ts +18 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +45 -0
- package/dist/reactive/array.d.cts +24 -0
- package/dist/reactive/array.d.ts +24 -0
- package/dist/reactive/array.d.ts.map +1 -0
- package/dist/reactive/index.cjs +1 -0
- package/dist/reactive/index.d.cts +11 -0
- package/dist/reactive/index.d.ts +11 -0
- package/dist/reactive/index.d.ts.map +1 -0
- package/dist/reactive/index.js +18 -0
- package/dist/reactive/interop.d.cts +19 -0
- package/dist/reactive/interop.d.ts +19 -0
- package/dist/reactive/interop.d.ts.map +1 -0
- package/dist/reactive/kernel.d.cts +73 -0
- package/dist/reactive/kernel.d.ts +73 -0
- package/dist/reactive/kernel.d.ts.map +1 -0
- package/dist/reactive/map.d.cts +16 -0
- package/dist/reactive/map.d.ts +16 -0
- package/dist/reactive/map.d.ts.map +1 -0
- package/dist/reactive/shallow.d.cts +11 -0
- package/dist/reactive/shallow.d.ts +11 -0
- package/dist/reactive/shallow.d.ts.map +1 -0
- package/dist/reactive/struct.d.cts +10 -0
- package/dist/reactive/struct.d.ts +10 -0
- package/dist/reactive/struct.d.ts.map +1 -0
- package/dist/shallow-DQ8aG51_.cjs +1 -0
- package/dist/shallow-DfnAm9vG.js +150 -0
- package/dist/shared-BU1Cd40h.js +103 -0
- package/dist/shared-BymrGTyR.cjs +1 -0
- package/dist/shared.cjs +1 -0
- package/dist/shared.d.cts +22 -0
- package/dist/shared.d.ts +22 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +7 -0
- package/dist/topological_sort-BDvEyb9W.cjs +1 -0
- package/dist/topological_sort-DK6EjpWa.js +135 -0
- package/dist/type_primitives/assertions.d.cts +32 -0
- package/dist/type_primitives/assertions.d.ts +25 -9
- package/dist/type_primitives/assertions.d.ts.map +1 -1
- package/dist/type_primitives/binary_heap/binary_heap.d.cts +37 -0
- package/dist/type_primitives/binary_heap/binary_heap.d.ts +6 -2
- package/dist/type_primitives/binary_heap/binary_heap.d.ts.map +1 -1
- package/dist/type_primitives/bitset/bitset.d.cts +54 -0
- package/dist/type_primitives/bitset/bitset.d.ts +16 -4
- package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
- package/dist/type_primitives/brand.d.cts +23 -0
- package/dist/type_primitives/brand.d.ts +6 -1
- package/dist/type_primitives/brand.d.ts.map +1 -1
- package/dist/type_primitives/error.d.cts +16 -0
- package/dist/type_primitives/error.d.ts +8 -3
- package/dist/type_primitives/error.d.ts.map +1 -1
- package/dist/type_primitives/index.d.cts +13 -0
- package/dist/type_primitives/index.d.ts +12 -9
- package/dist/type_primitives/index.d.ts.map +1 -1
- package/dist/type_primitives/sparse_map/sparse_map.d.cts +30 -0
- package/dist/type_primitives/sparse_map/sparse_map.d.ts +7 -3
- package/dist/type_primitives/sparse_map/sparse_map.d.ts.map +1 -1
- package/dist/type_primitives/sparse_set/sparse_set.d.cts +28 -0
- package/dist/type_primitives/sparse_set/sparse_set.d.ts +4 -0
- package/dist/type_primitives/sparse_set/sparse_set.d.ts.map +1 -1
- package/dist/type_primitives/topological_sort/topological_sort.d.cts +29 -0
- package/dist/type_primitives/topological_sort/topological_sort.d.ts +7 -3
- package/dist/type_primitives/topological_sort/topological_sort.d.ts.map +1 -1
- package/dist/type_primitives/typed_arrays/typed_arrays.d.cts +127 -0
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +53 -16
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
- package/dist/typed_arrays-BcXcnzB4.js +258 -0
- package/dist/typed_arrays-D3NmwtCG.cjs +1 -0
- package/dist/utils/error.d.cts +6 -0
- package/dist/utils/error.d.ts +2 -20
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/version.d.cts +10 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +115 -5
- package/dist/archetype.d.ts +0 -108
- package/dist/archetype.d.ts.map +0 -1
- package/dist/component.d.ts +0 -45
- package/dist/component.d.ts.map +0 -1
- package/dist/ecs.d.ts +0 -104
- package/dist/ecs.d.ts.map +0 -1
- package/dist/entity.d.ts +0 -11
- package/dist/entity.d.ts.map +0 -1
- package/dist/event.d.ts +0 -30
- package/dist/event.d.ts.map +0 -1
- package/dist/query.d.ts +0 -94
- package/dist/query.d.ts.map +0 -1
- package/dist/ref.d.ts +0 -23
- package/dist/ref.d.ts.map +0 -1
- package/dist/resource.d.ts +0 -23
- package/dist/resource.d.ts.map +0 -1
- package/dist/schedule.d.ts +0 -45
- package/dist/schedule.d.ts.map +0 -1
- package/dist/store.d.ts +0 -118
- package/dist/store.d.ts.map +0 -1
- package/dist/system.d.ts +0 -16
- package/dist/system.d.ts.map +0 -1
- package/dist/utils/arrays.d.ts.map +0 -1
- package/dist/utils/constants.d.ts.map +0 -1
- /package/dist/{utils/constants.d.ts → core/ecs/utils/constants.d.cts} +0 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BufferAllocator — pluggable buffer source for the SAB layer (#234 / PR 3D).
|
|
3
|
+
*
|
|
4
|
+
* The engine has historically allocated its SAB as a fresh
|
|
5
|
+
* `new SharedArrayBuffer(totalBytes)` inside `createColumnStore`.
|
|
6
|
+
* Phase 3D requires the SAB to optionally be backed by a
|
|
7
|
+
* `WebAssembly.Memory.buffer` so the WASM sim can read/write the live
|
|
8
|
+
* ECS columns through its own memory handle. This module abstracts the
|
|
9
|
+
* "where does the buffer come from" decision behind a single function
|
|
10
|
+
* type.
|
|
11
|
+
*
|
|
12
|
+
* Contract for every `BufferAllocator`:
|
|
13
|
+
* - Returns a `SharedArrayBuffer` of byteLength >= `bytes`.
|
|
14
|
+
* - MAY detach any prior buffer the implementation has handed out
|
|
15
|
+
* (e.g., `WebAssembly.Memory.grow` detaches existing typed-array
|
|
16
|
+
* views into the previous buffer). Callers MUST snapshot any data
|
|
17
|
+
* they need to preserve BEFORE invoking the allocator.
|
|
18
|
+
* - Returned buffers MAY be larger than `bytes` (e.g., wasm-memory
|
|
19
|
+
* rounds up to 64 KiB page boundaries). Callers must rely on the
|
|
20
|
+
* SAB header / descriptor for the canonical layout, not on
|
|
21
|
+
* `buffer.byteLength`.
|
|
22
|
+
*
|
|
23
|
+
* The default `DEFAULT_SAB_ALLOCATOR` does `new SharedArrayBuffer(bytes)`
|
|
24
|
+
* — fast, allocation-per-call, prior buffers untouched. Production code
|
|
25
|
+
* paths that don't care about wasm interop stay on this.
|
|
26
|
+
*
|
|
27
|
+
* `wasmMemoryAllocator(memory)` returns an allocator that grows the
|
|
28
|
+
* given `WebAssembly.Memory` (in 64 KiB page increments) as needed and
|
|
29
|
+
* returns its current buffer. Used by a host so the
|
|
30
|
+
* engine's SAB IS the sim's memory.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Source of `SharedArrayBuffer`s for the SAB layer. See the file header
|
|
34
|
+
* for the contract — in particular, the detachment caveat for in-place
|
|
35
|
+
* implementations.
|
|
36
|
+
*
|
|
37
|
+
* The optional `isInPlace` marker tells the SAB layer that
|
|
38
|
+
* **TypedArray and DataView views built over a returned buffer remain
|
|
39
|
+
* valid after a subsequent allocator call** — reads and writes through
|
|
40
|
+
* the old views land on the same underlying memory the new buffer
|
|
41
|
+
* exposes. The `extendColumnStore` fast path uses this hint to skip the
|
|
42
|
+
* snapshot+restore + view-rebuild work that's only necessary when the
|
|
43
|
+
* memory actually moves.
|
|
44
|
+
*
|
|
45
|
+
* Note: `isInPlace` does NOT promise the SAB *reference* stays
|
|
46
|
+
* identical. `growableSabAllocator` happens to return the same SAB
|
|
47
|
+
* instance every time (`SharedArrayBuffer.prototype.grow` resizes in
|
|
48
|
+
* place); `wasmMemoryAllocator` on shared `WebAssembly.Memory`
|
|
49
|
+
* returns a *new* SAB ref after `memory.grow()`, but old views built
|
|
50
|
+
* over the previous ref keep working — V8 keeps the underlying linear
|
|
51
|
+
* memory mapped at the same address. Verified empirically (this branch,
|
|
52
|
+
* Bun + V8): writes via an old `Int32Array(old_ref, off, len)` after
|
|
53
|
+
* `memory.grow()` are visible through a fresh view over the new ref,
|
|
54
|
+
* and vice versa. Default allocator omits the marker;
|
|
55
|
+
* `growableSabAllocator` and `wasmMemoryAllocator` set it.
|
|
56
|
+
*/
|
|
57
|
+
export interface BufferAllocator {
|
|
58
|
+
/** Returns a buffer of byteLength >= `bytes`. The historical name is
|
|
59
|
+
* "SAB", but the return is `ArrayBufferLike`: `growableSabAllocator` /
|
|
60
|
+
* `wasmMemoryAllocator` produce a `SharedArrayBuffer` (the SAB profile),
|
|
61
|
+
* while `heapArraybufferAllocator` produces a plain resizable
|
|
62
|
+
* `ArrayBuffer` (the pure-TS heap profile — no cross-origin isolation
|
|
63
|
+
* required). The store layer treats the backing uniformly; only the
|
|
64
|
+
* WASM/worker boundary narrows back to `SharedArrayBuffer`. */
|
|
65
|
+
(bytes: number): ArrayBufferLike;
|
|
66
|
+
readonly isInPlace?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The only allocator shape a **live `Store`** accepts (#682). ADR-0008 makes
|
|
70
|
+
* "a live Store is backed by an in-place allocator" a correctness invariant —
|
|
71
|
+
* the flush loops hoist entity-index views across grows. This brand moves
|
|
72
|
+
* that invariant from runtime convention to the type/construction boundary:
|
|
73
|
+
* `growableSabAllocator` / `wasmMemoryAllocator` / `heapArraybufferAllocator`
|
|
74
|
+
* return it; `DEFAULT_SAB_ALLOCATOR` keeps the wide `BufferAllocator` type and
|
|
75
|
+
* therefore cannot typecheck where a live-Store backing is required. Non-in-place
|
|
76
|
+
* allocators remain valid for snapshot/test sizing only. The brand says nothing
|
|
77
|
+
* about *shared* vs *heap* backing — `heapArraybufferAllocator`'s resizable
|
|
78
|
+
* `ArrayBuffer` is just as in-place as a growable SAB (`.resize()` preserves
|
|
79
|
+
* existing views exactly like `SharedArrayBuffer.prototype.grow`).
|
|
80
|
+
*/
|
|
81
|
+
export type InPlaceBufferAllocator = BufferAllocator & {
|
|
82
|
+
readonly isInPlace: true;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Thrown when an allocator cannot satisfy a request because its by-design
|
|
86
|
+
* byte ceiling is reached (#380: the cap is a runaway-growth signal, not a
|
|
87
|
+
* limit to paper over — there is deliberately no grow-beyond-cap fallback).
|
|
88
|
+
* Typed so `Store`'s grow handler can recognise the cap case and re-throw
|
|
89
|
+
* with the caller's declared sizing intent attached (#682) without ever
|
|
90
|
+
* catching-to-recover.
|
|
91
|
+
*/
|
|
92
|
+
export declare class StoreCapExceededError extends Error {
|
|
93
|
+
readonly requestedBytes: number;
|
|
94
|
+
/** `null` when the ceiling isn't knowable from JS (a shared
|
|
95
|
+
* `WebAssembly.Memory` doesn't expose its `maximum`). */
|
|
96
|
+
readonly capBytes: number | null;
|
|
97
|
+
constructor(message: string, requestedBytes: number,
|
|
98
|
+
/** `null` when the ceiling isn't knowable from JS (a shared
|
|
99
|
+
* `WebAssembly.Memory` doesn't expose its `maximum`). */
|
|
100
|
+
capBytes: number | null, options?: ErrorOptions);
|
|
101
|
+
}
|
|
102
|
+
/** Thrown when a **SAB-producing** allocator runs in an environment that
|
|
103
|
+
* doesn't expose `SharedArrayBuffer`. The fix is environment-level (the host
|
|
104
|
+
* must serve the page cross-origin isolated, or be a runtime like Bun that
|
|
105
|
+
* exposes SAB unconditionally) — OR choose the pure-TS heap profile
|
|
106
|
+
* (`memory: { heap: {} }` / `heapArraybufferAllocator`), which needs no SAB
|
|
107
|
+
* and no cross-origin isolation. Lives on the allocator (not the store)
|
|
108
|
+
* because the allocator is the only thing that constructs a SAB. */
|
|
109
|
+
export declare class SabUnavailableError extends Error {
|
|
110
|
+
constructor();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Allocate a fresh `SharedArrayBuffer` per call. Prior buffers are
|
|
114
|
+
* untouched and remain valid for as long as the caller holds references.
|
|
115
|
+
* This is the default used by `createColumnStore` when no allocator is
|
|
116
|
+
* provided. Throws `SabUnavailableError` in a runtime without SAB — the
|
|
117
|
+
* availability check lives here (the SAB-producing seam), not in
|
|
118
|
+
* `createColumnStore`, so a heap allocator never trips it.
|
|
119
|
+
*/
|
|
120
|
+
export declare const DEFAULT_SAB_ALLOCATOR: BufferAllocator;
|
|
121
|
+
/**
|
|
122
|
+
* Allocator that backs the SAB by a single growable `SharedArrayBuffer`
|
|
123
|
+
* (created with `{ maxByteLength: maxBytes }`). First call allocates;
|
|
124
|
+
* subsequent calls `.grow(bytes)` the existing buffer and return it.
|
|
125
|
+
*
|
|
126
|
+
* The `isInPlace` marker is set so `extendColumnStore` knows it can
|
|
127
|
+
* reuse the buffer rather than allocating fresh and copying data —
|
|
128
|
+
* existing typed-array views built with explicit `(byteOffset, length)`
|
|
129
|
+
* stay valid after `.grow()` in Bun + V8 (the underlying mapping extends
|
|
130
|
+
* in place rather than relocating).
|
|
131
|
+
*
|
|
132
|
+
* Sizing: `maxBytes` is committed *virtual* memory, not resident RAM —
|
|
133
|
+
* physical pages fault in lazily as the SAB actually grows. Larger caps
|
|
134
|
+
* cost more per allocation than smaller ones — Bun benchmark
|
|
135
|
+
* `alloc(64,max=1GB)+grow(65568)` measures ~32 µs vs ~21 µs at 256 MB
|
|
136
|
+
* and ~12 µs at 1 MB (V8 per-byte bookkeeping at construction).
|
|
137
|
+
* Production callers with bigger worlds can pass a larger cap; the bench
|
|
138
|
+
* gains are ~10 µs/Store-construction by staying under 256 MB.
|
|
139
|
+
*
|
|
140
|
+
* THE 256 MiB DEFAULT IS A HARD DESIGN CEILING, NOT A SOFT TARGET — and
|
|
141
|
+
* exceeding it is INTENDED to be fatal. There is deliberately no
|
|
142
|
+
* grow-beyond-cap fallback or compaction pass (see #380, and the loud
|
|
143
|
+
* note at the `bytes > maxBytes` throw below). If you are here because
|
|
144
|
+
* a workload died at the cap and you are tempted to add a fresh-allocator
|
|
145
|
+
* realloc fallback: don't, unless the numbers below have changed. They
|
|
146
|
+
* say the cap is structurally unreachable for a real workload.
|
|
147
|
+
*
|
|
148
|
+
* Measured footprint of a real 2-party workload (instrumented, 2026-05;
|
|
149
|
+
* do NOT trust the old "~500 archetypes × 64-capacity ≈ 2 MiB" figure
|
|
150
|
+
* that used to live here — it was wrong on every term):
|
|
151
|
+
* - Total SAB capacity ≈ 16.2 MiB — ~6% of the cap.
|
|
152
|
+
* - ~12 MiB of that is the entity-index region's *virtual* reservation
|
|
153
|
+
* (`ENTITY_INDEX_DEFAULT_CAPACITY = 1<<20` slots × 12 B); only ~12 KiB
|
|
154
|
+
* of it is physically resident for a 1000-entity workload.
|
|
155
|
+
* - Only ~5 archetypes are prewarmed (no lazy archetypes), each at
|
|
156
|
+
* `DEFAULT_COLUMN_CAPACITY = 1024` rows — NOT 64. Live column data is
|
|
157
|
+
* ~0.1 MiB; a fully-populated entity row is ~49 B.
|
|
158
|
+
* - Columns never trigger a grow: 1024 initial capacity already covers the
|
|
159
|
+
* ~1000-row budget, so the doubling + in-place hole tax never fires on
|
|
160
|
+
* the hot path.
|
|
161
|
+
* The entity-ID space itself caps total live entities at `1<<20` ≈ 1M
|
|
162
|
+
* (20-bit index in `EntityID`). Even at that absolute ceiling — ~1M rows
|
|
163
|
+
* × 49 B × ~3 (post-double capacity + abandoned holes) ≈ ~150 MiB columns
|
|
164
|
+
* + 12 MiB index — the workload still lands under 256 MiB. You cannot reach
|
|
165
|
+
* the cap without first exhausting the entity-ID space. Hitting it
|
|
166
|
+
* therefore signals a real defect upstream (runaway entity creation), not
|
|
167
|
+
* a sizing shortfall to paper over.
|
|
168
|
+
*
|
|
169
|
+
* Cited verification (#237 audit, this branch): Bun runtime check
|
|
170
|
+
* confirms `new Int32Array(buffer, off, len)` retains identical byteOffset,
|
|
171
|
+
* length, and stored values after `.grow()`; DataView byteLength
|
|
172
|
+
* auto-tracks the grown buffer.
|
|
173
|
+
*
|
|
174
|
+
* Used by the `extendColumnStore` fast path during lazy archetype
|
|
175
|
+
* registration (#237 Option A) — keeps existing column views valid so
|
|
176
|
+
* `refreshViews` is a no-op for old archetypes.
|
|
177
|
+
*/
|
|
178
|
+
export declare function growableSabAllocator(maxBytes?: number): InPlaceBufferAllocator;
|
|
179
|
+
/**
|
|
180
|
+
* Allocator that backs the store by a single growable **plain `ArrayBuffer`**
|
|
181
|
+
* (created with `{ maxByteLength: maxBytes }`, grown via `.resize()`). This is
|
|
182
|
+
* the pure-TS **heap profile** — the oecs default and the answer to ADR-0018's
|
|
183
|
+
* deferred §1B: no `SharedArrayBuffer`, hence no cross-origin isolation
|
|
184
|
+
* (COOP/COEP) requirement, and no worker/WASM transfer (single-process worlds
|
|
185
|
+
* only). Otherwise identical to `growableSabAllocator`:
|
|
186
|
+
*
|
|
187
|
+
* - `isInPlace: true`. A resizable `ArrayBuffer`'s `.resize()` keeps the
|
|
188
|
+
* same buffer object and preserves existing TypedArray/DataView views, so
|
|
189
|
+
* the store's `extend`/`grow` fast path carries column views forward
|
|
190
|
+
* unchanged — exactly as `SharedArrayBuffer.prototype.grow` does. ADR-0008's
|
|
191
|
+
* entity-index-hoist-across-grow invariant holds identically.
|
|
192
|
+
* - same 256 MiB default cap with hard-ceiling semantics (#380): reaching it
|
|
193
|
+
* signals runaway growth upstream, not a limit to route around.
|
|
194
|
+
*
|
|
195
|
+
* Why a non-shared buffer suffices: `Atomics` live only on the cross-thread
|
|
196
|
+
* command/event/action rings, never on the core store path, so a single-process
|
|
197
|
+
* world needs no sharing. `stateHash` determinism works here too — FNV1a over
|
|
198
|
+
* column bytes is backing-agnostic.
|
|
199
|
+
*/
|
|
200
|
+
export declare function heapArraybufferAllocator(maxBytes?: number): InPlaceBufferAllocator;
|
|
201
|
+
/**
|
|
202
|
+
* Allocator that backs the SAB by `memory.buffer` — i.e. makes the engine's
|
|
203
|
+
* live SAB *be* a WASM module's `WebAssembly.Memory`. Grows the memory in
|
|
204
|
+
* 64 KiB page increments when `bytes` exceeds the current buffer.
|
|
205
|
+
*
|
|
206
|
+
* This is the **opt-in storage backing for the WASM path** (#625). A consumer
|
|
207
|
+
* that attaches a WASM `ComputeBackend` passes
|
|
208
|
+
* `bufferAllocator: wasmMemoryAllocator(memory)` so the Zig systems read/write
|
|
209
|
+
* the same bytes the host's columns live in — zero-copy across the FFI boundary.
|
|
210
|
+
* It is NOT a match-context assumption: a pure-TS game omits `bufferAllocator` and
|
|
211
|
+
* gets the default (`DEFAULT_SAB_ALLOCATOR` — a fresh `SharedArrayBuffer` per
|
|
212
|
+
* alloc) or opts into `growableSabAllocator` for the in-place fast path
|
|
213
|
+
* without any WASM module. "The SAB is the WebAssembly.Memory" is thus a
|
|
214
|
+
* property the WASM backend opts into, paid for only when WASM is in use.
|
|
215
|
+
*
|
|
216
|
+
* After `memory.grow()` on a *shared* memory, `memory.buffer` returns a
|
|
217
|
+
* new `SharedArrayBuffer` reference, but **TypedArrays and DataViews
|
|
218
|
+
* built over the previous reference remain valid** — V8 keeps the
|
|
219
|
+
* underlying linear memory mapped at the same address, so reads and
|
|
220
|
+
* writes through old views land on the same bytes the new buffer
|
|
221
|
+
* exposes. This is why `isInPlace: true` is safe here (verified
|
|
222
|
+
* empirically against Bun + V8): the SAB layer's fast path can carry
|
|
223
|
+
* forward existing column views across an `extend` without paying for
|
|
224
|
+
* snapshot+restore. Old DataViews' `byteLength` is frozen at the
|
|
225
|
+
* pre-grow size, so callers needing to write past that boundary must
|
|
226
|
+
* construct a fresh DataView over the post-grow buffer (the SAB-layer
|
|
227
|
+
* extend path does this).
|
|
228
|
+
*
|
|
229
|
+
* Throws if `memory` was not constructed with `shared: true` — the SAB
|
|
230
|
+
* contract requires `SharedArrayBuffer`-backed memory. Throws a contextual
|
|
231
|
+
* error if a needed grow fails (cap reached or host refusal): the JS API's
|
|
232
|
+
* `memory.grow` throws a RangeError on cap overrun rather than returning the
|
|
233
|
+
* core wasm instruction's `-1`, and both are normalised into that error. The
|
|
234
|
+
* caller should construct memory with a `maximum` large enough for the
|
|
235
|
+
* workload's worst-case capacity.
|
|
236
|
+
*/
|
|
237
|
+
export declare function wasmMemoryAllocator(memory: WebAssembly.Memory): InPlaceBufferAllocator;
|
|
238
|
+
//# sourceMappingURL=allocator.d.ts.map
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BufferAllocator — pluggable buffer source for the SAB layer (#234 / PR 3D).
|
|
3
|
+
*
|
|
4
|
+
* The engine has historically allocated its SAB as a fresh
|
|
5
|
+
* `new SharedArrayBuffer(totalBytes)` inside `createColumnStore`.
|
|
6
|
+
* Phase 3D requires the SAB to optionally be backed by a
|
|
7
|
+
* `WebAssembly.Memory.buffer` so the WASM sim can read/write the live
|
|
8
|
+
* ECS columns through its own memory handle. This module abstracts the
|
|
9
|
+
* "where does the buffer come from" decision behind a single function
|
|
10
|
+
* type.
|
|
11
|
+
*
|
|
12
|
+
* Contract for every `BufferAllocator`:
|
|
13
|
+
* - Returns a `SharedArrayBuffer` of byteLength >= `bytes`.
|
|
14
|
+
* - MAY detach any prior buffer the implementation has handed out
|
|
15
|
+
* (e.g., `WebAssembly.Memory.grow` detaches existing typed-array
|
|
16
|
+
* views into the previous buffer). Callers MUST snapshot any data
|
|
17
|
+
* they need to preserve BEFORE invoking the allocator.
|
|
18
|
+
* - Returned buffers MAY be larger than `bytes` (e.g., wasm-memory
|
|
19
|
+
* rounds up to 64 KiB page boundaries). Callers must rely on the
|
|
20
|
+
* SAB header / descriptor for the canonical layout, not on
|
|
21
|
+
* `buffer.byteLength`.
|
|
22
|
+
*
|
|
23
|
+
* The default `DEFAULT_SAB_ALLOCATOR` does `new SharedArrayBuffer(bytes)`
|
|
24
|
+
* — fast, allocation-per-call, prior buffers untouched. Production code
|
|
25
|
+
* paths that don't care about wasm interop stay on this.
|
|
26
|
+
*
|
|
27
|
+
* `wasmMemoryAllocator(memory)` returns an allocator that grows the
|
|
28
|
+
* given `WebAssembly.Memory` (in 64 KiB page increments) as needed and
|
|
29
|
+
* returns its current buffer. Used by a host so the
|
|
30
|
+
* engine's SAB IS the sim's memory.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Source of `SharedArrayBuffer`s for the SAB layer. See the file header
|
|
34
|
+
* for the contract — in particular, the detachment caveat for in-place
|
|
35
|
+
* implementations.
|
|
36
|
+
*
|
|
37
|
+
* The optional `isInPlace` marker tells the SAB layer that
|
|
38
|
+
* **TypedArray and DataView views built over a returned buffer remain
|
|
39
|
+
* valid after a subsequent allocator call** — reads and writes through
|
|
40
|
+
* the old views land on the same underlying memory the new buffer
|
|
41
|
+
* exposes. The `extendColumnStore` fast path uses this hint to skip the
|
|
42
|
+
* snapshot+restore + view-rebuild work that's only necessary when the
|
|
43
|
+
* memory actually moves.
|
|
44
|
+
*
|
|
45
|
+
* Note: `isInPlace` does NOT promise the SAB *reference* stays
|
|
46
|
+
* identical. `growableSabAllocator` happens to return the same SAB
|
|
47
|
+
* instance every time (`SharedArrayBuffer.prototype.grow` resizes in
|
|
48
|
+
* place); `wasmMemoryAllocator` on shared `WebAssembly.Memory`
|
|
49
|
+
* returns a *new* SAB ref after `memory.grow()`, but old views built
|
|
50
|
+
* over the previous ref keep working — V8 keeps the underlying linear
|
|
51
|
+
* memory mapped at the same address. Verified empirically (this branch,
|
|
52
|
+
* Bun + V8): writes via an old `Int32Array(old_ref, off, len)` after
|
|
53
|
+
* `memory.grow()` are visible through a fresh view over the new ref,
|
|
54
|
+
* and vice versa. Default allocator omits the marker;
|
|
55
|
+
* `growableSabAllocator` and `wasmMemoryAllocator` set it.
|
|
56
|
+
*/
|
|
57
|
+
export interface BufferAllocator {
|
|
58
|
+
/** Returns a buffer of byteLength >= `bytes`. The historical name is
|
|
59
|
+
* "SAB", but the return is `ArrayBufferLike`: `growableSabAllocator` /
|
|
60
|
+
* `wasmMemoryAllocator` produce a `SharedArrayBuffer` (the SAB profile),
|
|
61
|
+
* while `heapArraybufferAllocator` produces a plain resizable
|
|
62
|
+
* `ArrayBuffer` (the pure-TS heap profile — no cross-origin isolation
|
|
63
|
+
* required). The store layer treats the backing uniformly; only the
|
|
64
|
+
* WASM/worker boundary narrows back to `SharedArrayBuffer`. */
|
|
65
|
+
(bytes: number): ArrayBufferLike;
|
|
66
|
+
readonly isInPlace?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The only allocator shape a **live `Store`** accepts (#682). ADR-0008 makes
|
|
70
|
+
* "a live Store is backed by an in-place allocator" a correctness invariant —
|
|
71
|
+
* the flush loops hoist entity-index views across grows. This brand moves
|
|
72
|
+
* that invariant from runtime convention to the type/construction boundary:
|
|
73
|
+
* `growableSabAllocator` / `wasmMemoryAllocator` / `heapArraybufferAllocator`
|
|
74
|
+
* return it; `DEFAULT_SAB_ALLOCATOR` keeps the wide `BufferAllocator` type and
|
|
75
|
+
* therefore cannot typecheck where a live-Store backing is required. Non-in-place
|
|
76
|
+
* allocators remain valid for snapshot/test sizing only. The brand says nothing
|
|
77
|
+
* about *shared* vs *heap* backing — `heapArraybufferAllocator`'s resizable
|
|
78
|
+
* `ArrayBuffer` is just as in-place as a growable SAB (`.resize()` preserves
|
|
79
|
+
* existing views exactly like `SharedArrayBuffer.prototype.grow`).
|
|
80
|
+
*/
|
|
81
|
+
export type InPlaceBufferAllocator = BufferAllocator & {
|
|
82
|
+
readonly isInPlace: true;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Thrown when an allocator cannot satisfy a request because its by-design
|
|
86
|
+
* byte ceiling is reached (#380: the cap is a runaway-growth signal, not a
|
|
87
|
+
* limit to paper over — there is deliberately no grow-beyond-cap fallback).
|
|
88
|
+
* Typed so `Store`'s grow handler can recognise the cap case and re-throw
|
|
89
|
+
* with the caller's declared sizing intent attached (#682) without ever
|
|
90
|
+
* catching-to-recover.
|
|
91
|
+
*/
|
|
92
|
+
export declare class StoreCapExceededError extends Error {
|
|
93
|
+
readonly requestedBytes: number;
|
|
94
|
+
/** `null` when the ceiling isn't knowable from JS (a shared
|
|
95
|
+
* `WebAssembly.Memory` doesn't expose its `maximum`). */
|
|
96
|
+
readonly capBytes: number | null;
|
|
97
|
+
constructor(message: string, requestedBytes: number,
|
|
98
|
+
/** `null` when the ceiling isn't knowable from JS (a shared
|
|
99
|
+
* `WebAssembly.Memory` doesn't expose its `maximum`). */
|
|
100
|
+
capBytes: number | null, options?: ErrorOptions);
|
|
101
|
+
}
|
|
102
|
+
/** Thrown when a **SAB-producing** allocator runs in an environment that
|
|
103
|
+
* doesn't expose `SharedArrayBuffer`. The fix is environment-level (the host
|
|
104
|
+
* must serve the page cross-origin isolated, or be a runtime like Bun that
|
|
105
|
+
* exposes SAB unconditionally) — OR choose the pure-TS heap profile
|
|
106
|
+
* (`memory: { heap: {} }` / `heapArraybufferAllocator`), which needs no SAB
|
|
107
|
+
* and no cross-origin isolation. Lives on the allocator (not the store)
|
|
108
|
+
* because the allocator is the only thing that constructs a SAB. */
|
|
109
|
+
export declare class SabUnavailableError extends Error {
|
|
110
|
+
constructor();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Allocate a fresh `SharedArrayBuffer` per call. Prior buffers are
|
|
114
|
+
* untouched and remain valid for as long as the caller holds references.
|
|
115
|
+
* This is the default used by `createColumnStore` when no allocator is
|
|
116
|
+
* provided. Throws `SabUnavailableError` in a runtime without SAB — the
|
|
117
|
+
* availability check lives here (the SAB-producing seam), not in
|
|
118
|
+
* `createColumnStore`, so a heap allocator never trips it.
|
|
119
|
+
*/
|
|
120
|
+
export declare const DEFAULT_SAB_ALLOCATOR: BufferAllocator;
|
|
121
|
+
/**
|
|
122
|
+
* Allocator that backs the SAB by a single growable `SharedArrayBuffer`
|
|
123
|
+
* (created with `{ maxByteLength: maxBytes }`). First call allocates;
|
|
124
|
+
* subsequent calls `.grow(bytes)` the existing buffer and return it.
|
|
125
|
+
*
|
|
126
|
+
* The `isInPlace` marker is set so `extendColumnStore` knows it can
|
|
127
|
+
* reuse the buffer rather than allocating fresh and copying data —
|
|
128
|
+
* existing typed-array views built with explicit `(byteOffset, length)`
|
|
129
|
+
* stay valid after `.grow()` in Bun + V8 (the underlying mapping extends
|
|
130
|
+
* in place rather than relocating).
|
|
131
|
+
*
|
|
132
|
+
* Sizing: `maxBytes` is committed *virtual* memory, not resident RAM —
|
|
133
|
+
* physical pages fault in lazily as the SAB actually grows. Larger caps
|
|
134
|
+
* cost more per allocation than smaller ones — Bun benchmark
|
|
135
|
+
* `alloc(64,max=1GB)+grow(65568)` measures ~32 µs vs ~21 µs at 256 MB
|
|
136
|
+
* and ~12 µs at 1 MB (V8 per-byte bookkeeping at construction).
|
|
137
|
+
* Production callers with bigger worlds can pass a larger cap; the bench
|
|
138
|
+
* gains are ~10 µs/Store-construction by staying under 256 MB.
|
|
139
|
+
*
|
|
140
|
+
* THE 256 MiB DEFAULT IS A HARD DESIGN CEILING, NOT A SOFT TARGET — and
|
|
141
|
+
* exceeding it is INTENDED to be fatal. There is deliberately no
|
|
142
|
+
* grow-beyond-cap fallback or compaction pass (see #380, and the loud
|
|
143
|
+
* note at the `bytes > maxBytes` throw below). If you are here because
|
|
144
|
+
* a workload died at the cap and you are tempted to add a fresh-allocator
|
|
145
|
+
* realloc fallback: don't, unless the numbers below have changed. They
|
|
146
|
+
* say the cap is structurally unreachable for a real workload.
|
|
147
|
+
*
|
|
148
|
+
* Measured footprint of a real 2-party workload (instrumented, 2026-05;
|
|
149
|
+
* do NOT trust the old "~500 archetypes × 64-capacity ≈ 2 MiB" figure
|
|
150
|
+
* that used to live here — it was wrong on every term):
|
|
151
|
+
* - Total SAB capacity ≈ 16.2 MiB — ~6% of the cap.
|
|
152
|
+
* - ~12 MiB of that is the entity-index region's *virtual* reservation
|
|
153
|
+
* (`ENTITY_INDEX_DEFAULT_CAPACITY = 1<<20` slots × 12 B); only ~12 KiB
|
|
154
|
+
* of it is physically resident for a 1000-entity workload.
|
|
155
|
+
* - Only ~5 archetypes are prewarmed (no lazy archetypes), each at
|
|
156
|
+
* `DEFAULT_COLUMN_CAPACITY = 1024` rows — NOT 64. Live column data is
|
|
157
|
+
* ~0.1 MiB; a fully-populated entity row is ~49 B.
|
|
158
|
+
* - Columns never trigger a grow: 1024 initial capacity already covers the
|
|
159
|
+
* ~1000-row budget, so the doubling + in-place hole tax never fires on
|
|
160
|
+
* the hot path.
|
|
161
|
+
* The entity-ID space itself caps total live entities at `1<<20` ≈ 1M
|
|
162
|
+
* (20-bit index in `EntityID`). Even at that absolute ceiling — ~1M rows
|
|
163
|
+
* × 49 B × ~3 (post-double capacity + abandoned holes) ≈ ~150 MiB columns
|
|
164
|
+
* + 12 MiB index — the workload still lands under 256 MiB. You cannot reach
|
|
165
|
+
* the cap without first exhausting the entity-ID space. Hitting it
|
|
166
|
+
* therefore signals a real defect upstream (runaway entity creation), not
|
|
167
|
+
* a sizing shortfall to paper over.
|
|
168
|
+
*
|
|
169
|
+
* Cited verification (#237 audit, this branch): Bun runtime check
|
|
170
|
+
* confirms `new Int32Array(buffer, off, len)` retains identical byteOffset,
|
|
171
|
+
* length, and stored values after `.grow()`; DataView byteLength
|
|
172
|
+
* auto-tracks the grown buffer.
|
|
173
|
+
*
|
|
174
|
+
* Used by the `extendColumnStore` fast path during lazy archetype
|
|
175
|
+
* registration (#237 Option A) — keeps existing column views valid so
|
|
176
|
+
* `refreshViews` is a no-op for old archetypes.
|
|
177
|
+
*/
|
|
178
|
+
export declare function growableSabAllocator(maxBytes?: number): InPlaceBufferAllocator;
|
|
179
|
+
/**
|
|
180
|
+
* Allocator that backs the store by a single growable **plain `ArrayBuffer`**
|
|
181
|
+
* (created with `{ maxByteLength: maxBytes }`, grown via `.resize()`). This is
|
|
182
|
+
* the pure-TS **heap profile** — the oecs default and the answer to ADR-0018's
|
|
183
|
+
* deferred §1B: no `SharedArrayBuffer`, hence no cross-origin isolation
|
|
184
|
+
* (COOP/COEP) requirement, and no worker/WASM transfer (single-process worlds
|
|
185
|
+
* only). Otherwise identical to `growableSabAllocator`:
|
|
186
|
+
*
|
|
187
|
+
* - `isInPlace: true`. A resizable `ArrayBuffer`'s `.resize()` keeps the
|
|
188
|
+
* same buffer object and preserves existing TypedArray/DataView views, so
|
|
189
|
+
* the store's `extend`/`grow` fast path carries column views forward
|
|
190
|
+
* unchanged — exactly as `SharedArrayBuffer.prototype.grow` does. ADR-0008's
|
|
191
|
+
* entity-index-hoist-across-grow invariant holds identically.
|
|
192
|
+
* - same 256 MiB default cap with hard-ceiling semantics (#380): reaching it
|
|
193
|
+
* signals runaway growth upstream, not a limit to route around.
|
|
194
|
+
*
|
|
195
|
+
* Why a non-shared buffer suffices: `Atomics` live only on the cross-thread
|
|
196
|
+
* command/event/action rings, never on the core store path, so a single-process
|
|
197
|
+
* world needs no sharing. `stateHash` determinism works here too — FNV1a over
|
|
198
|
+
* column bytes is backing-agnostic.
|
|
199
|
+
*/
|
|
200
|
+
export declare function heapArraybufferAllocator(maxBytes?: number): InPlaceBufferAllocator;
|
|
201
|
+
/**
|
|
202
|
+
* Allocator that backs the SAB by `memory.buffer` — i.e. makes the engine's
|
|
203
|
+
* live SAB *be* a WASM module's `WebAssembly.Memory`. Grows the memory in
|
|
204
|
+
* 64 KiB page increments when `bytes` exceeds the current buffer.
|
|
205
|
+
*
|
|
206
|
+
* This is the **opt-in storage backing for the WASM path** (#625). A consumer
|
|
207
|
+
* that attaches a WASM `ComputeBackend` passes
|
|
208
|
+
* `bufferAllocator: wasmMemoryAllocator(memory)` so the Zig systems read/write
|
|
209
|
+
* the same bytes the host's columns live in — zero-copy across the FFI boundary.
|
|
210
|
+
* It is NOT a match-context assumption: a pure-TS game omits `bufferAllocator` and
|
|
211
|
+
* gets the default (`DEFAULT_SAB_ALLOCATOR` — a fresh `SharedArrayBuffer` per
|
|
212
|
+
* alloc) or opts into `growableSabAllocator` for the in-place fast path
|
|
213
|
+
* without any WASM module. "The SAB is the WebAssembly.Memory" is thus a
|
|
214
|
+
* property the WASM backend opts into, paid for only when WASM is in use.
|
|
215
|
+
*
|
|
216
|
+
* After `memory.grow()` on a *shared* memory, `memory.buffer` returns a
|
|
217
|
+
* new `SharedArrayBuffer` reference, but **TypedArrays and DataViews
|
|
218
|
+
* built over the previous reference remain valid** — V8 keeps the
|
|
219
|
+
* underlying linear memory mapped at the same address, so reads and
|
|
220
|
+
* writes through old views land on the same bytes the new buffer
|
|
221
|
+
* exposes. This is why `isInPlace: true` is safe here (verified
|
|
222
|
+
* empirically against Bun + V8): the SAB layer's fast path can carry
|
|
223
|
+
* forward existing column views across an `extend` without paying for
|
|
224
|
+
* snapshot+restore. Old DataViews' `byteLength` is frozen at the
|
|
225
|
+
* pre-grow size, so callers needing to write past that boundary must
|
|
226
|
+
* construct a fresh DataView over the post-grow buffer (the SAB-layer
|
|
227
|
+
* extend path does this).
|
|
228
|
+
*
|
|
229
|
+
* Throws if `memory` was not constructed with `shared: true` — the SAB
|
|
230
|
+
* contract requires `SharedArrayBuffer`-backed memory. Throws a contextual
|
|
231
|
+
* error if a needed grow fails (cap reached or host refusal): the JS API's
|
|
232
|
+
* `memory.grow` throws a RangeError on cap overrun rather than returning the
|
|
233
|
+
* core wasm instruction's `-1`, and both are normalised into that error. The
|
|
234
|
+
* caller should construct memory with a `maximum` large enough for the
|
|
235
|
+
* workload's worst-case capacity.
|
|
236
|
+
*/
|
|
237
|
+
export declare function wasmMemoryAllocator(memory: WebAssembly.Memory): InPlaceBufferAllocator;
|
|
238
|
+
//# sourceMappingURL=allocator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allocator.d.ts","sourceRoot":"","sources":["../../../src/core/store/allocator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,eAAe;IAC/B;;;;;;mEAM+D;IAC/D,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAAC;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,sBAAsB,GAAG,eAAe,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAA;CAAE,CAAC;AAEpF;;;;;;;GAOG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;aAG9B,cAAc,EAAE,MAAM;IACtC;6DACyD;aACzC,QAAQ,EAAE,MAAM,GAAG,IAAI;gBAJvC,OAAO,EAAE,MAAM,EACC,cAAc,EAAE,MAAM;IACtC;6DACyD;IACzC,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvC,OAAO,CAAC,EAAE,YAAY;CAKvB;AAED;;;;;;oEAMoE;AACpE,qBAAa,mBAAoB,SAAQ,KAAK;;CAe7C;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAE,eAGnC,CAAC;AA+DF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,GAAE,MAA0B,GAAG,sBAAsB,CA6BjG;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,wBAAwB,CACvC,QAAQ,GAAE,MAA0B,GAClC,sBAAsB,CAuBxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,GAAG,sBAAsB,CA6DtF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ColumnBacking } from '../../type_primitives/index.cjs';
|
|
2
|
+
import { AnyTypedArray } from './column_store.cjs';
|
|
3
|
+
/** Thrown when an operation would grow a fixed-capacity SAB column. The
|
|
4
|
+
* grow path (re-allocate the SAB, bump `view_stamp`, rebuild views) is a
|
|
5
|
+
* separate sub-task; until it lands, hitting capacity is a hard error so
|
|
6
|
+
* the symptom surfaces immediately rather than silently corrupting state. */
|
|
7
|
+
export declare class StoreColumnOverflowError extends Error {
|
|
8
|
+
readonly capacity: number;
|
|
9
|
+
readonly requested: number;
|
|
10
|
+
constructor(capacity: number, requested: number);
|
|
11
|
+
}
|
|
12
|
+
export declare class BufferBackedColumn<T extends AnyTypedArray> implements ColumnBacking<T> {
|
|
13
|
+
private _buf;
|
|
14
|
+
private _capacity;
|
|
15
|
+
private _len;
|
|
16
|
+
/** `view` MUST be a TypedArray constructed over a SAB at the correct
|
|
17
|
+
* stride alignment (see `createColumnStore`). The column treats
|
|
18
|
+
* `view.length` as the immutable capacity for the lifetime of this view —
|
|
19
|
+
* call `refreshView` after a SAB realloc to point at the new view. */
|
|
20
|
+
constructor(view: T);
|
|
21
|
+
/** Swap the backing view to one over a freshly-grown SAB. The caller is
|
|
22
|
+
* responsible for having copied the first `length` elements into
|
|
23
|
+
* `newView` already (`growColumnStore` does this). The logical length is
|
|
24
|
+
* preserved across the swap; capacity becomes `newView.length`.
|
|
25
|
+
*
|
|
26
|
+
* Used to honour the `view_stamp` invariant after a host-side SAB realloc
|
|
27
|
+
* (#171 §6.1.4 / §8.1): every cached column view must be rebuilt before
|
|
28
|
+
* the next read/write. */
|
|
29
|
+
refreshView(newView: T): void;
|
|
30
|
+
get length(): number;
|
|
31
|
+
get capacity(): number;
|
|
32
|
+
push(value: number): void;
|
|
33
|
+
pop(): number;
|
|
34
|
+
get(i: number): number;
|
|
35
|
+
setAt(i: number, value: number): void;
|
|
36
|
+
/** Move the last element into slot `i`, decrement length. Returns the
|
|
37
|
+
* value previously at slot `i`. Matches `GrowableTypedArray.swapRemove`. */
|
|
38
|
+
swapRemove(i: number): number;
|
|
39
|
+
clear(): void;
|
|
40
|
+
/** Set the logical length directly, declaring that `[0, len)` of the backing
|
|
41
|
+
* SAB view already holds valid data. The snapshot-mount path
|
|
42
|
+
* (`Archetype.restoreHostRows`, #789) uses this to re-sync the column's
|
|
43
|
+
* logical length with the restored `Archetype.length` — the bytes come from
|
|
44
|
+
* the restored SAB, but `_len` is host state. Throws on overrun (cannot grow
|
|
45
|
+
* a fixed SAB view here — the mount already adopted the restored capacity). */
|
|
46
|
+
setLength(len: number): void;
|
|
47
|
+
/** Raw backing view. Stable for the lifetime of the SAB; views over a
|
|
48
|
+
* SAB do not invalidate the way a `GrowableTypedArray`'s `buf` does
|
|
49
|
+
* after a grow. (`view_stamp` will signal "underlying SAB swapped"
|
|
50
|
+
* once #171 §6.1.4 lands.) */
|
|
51
|
+
get buf(): T;
|
|
52
|
+
/** Zero-copy subarray of valid data (`0..length-1`). */
|
|
53
|
+
view(): T;
|
|
54
|
+
[Symbol.iterator](): Iterator<number>;
|
|
55
|
+
/** Throw if the backing view cannot hold `capacity` elements. Mirrors
|
|
56
|
+
* `GrowableTypedArray.ensureCapacity` but cannot allocate — a SAB
|
|
57
|
+
* grow requires republishing the underlying buffer and rebuilding views
|
|
58
|
+
* across every archetype, which is the §6.1.4 invariant. */
|
|
59
|
+
ensureCapacity(capacity: number): void;
|
|
60
|
+
/** Append `count` elements from `src[srcOffset..srcOffset+count]`.
|
|
61
|
+
* Throws on overrun. */
|
|
62
|
+
bulkAppend(src: T, srcOffset: number, count: number): void;
|
|
63
|
+
/** Append `count` zeroes. Throws on overrun. */
|
|
64
|
+
bulkAppendZeroes(count: number): void;
|
|
65
|
+
/** Append `count` copies of `value`. Throws on overrun. Single-pass
|
|
66
|
+
* analogue of `bulkAppendZeroes` for a non-zero default. */
|
|
67
|
+
bulkAppendValue(value: number, count: number): void;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=buffer_backed_column.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ColumnBacking } from '../../type_primitives/index.js';
|
|
2
|
+
import { AnyTypedArray } from './column_store.js';
|
|
3
|
+
/** Thrown when an operation would grow a fixed-capacity SAB column. The
|
|
4
|
+
* grow path (re-allocate the SAB, bump `view_stamp`, rebuild views) is a
|
|
5
|
+
* separate sub-task; until it lands, hitting capacity is a hard error so
|
|
6
|
+
* the symptom surfaces immediately rather than silently corrupting state. */
|
|
7
|
+
export declare class StoreColumnOverflowError extends Error {
|
|
8
|
+
readonly capacity: number;
|
|
9
|
+
readonly requested: number;
|
|
10
|
+
constructor(capacity: number, requested: number);
|
|
11
|
+
}
|
|
12
|
+
export declare class BufferBackedColumn<T extends AnyTypedArray> implements ColumnBacking<T> {
|
|
13
|
+
private _buf;
|
|
14
|
+
private _capacity;
|
|
15
|
+
private _len;
|
|
16
|
+
/** `view` MUST be a TypedArray constructed over a SAB at the correct
|
|
17
|
+
* stride alignment (see `createColumnStore`). The column treats
|
|
18
|
+
* `view.length` as the immutable capacity for the lifetime of this view —
|
|
19
|
+
* call `refreshView` after a SAB realloc to point at the new view. */
|
|
20
|
+
constructor(view: T);
|
|
21
|
+
/** Swap the backing view to one over a freshly-grown SAB. The caller is
|
|
22
|
+
* responsible for having copied the first `length` elements into
|
|
23
|
+
* `newView` already (`growColumnStore` does this). The logical length is
|
|
24
|
+
* preserved across the swap; capacity becomes `newView.length`.
|
|
25
|
+
*
|
|
26
|
+
* Used to honour the `view_stamp` invariant after a host-side SAB realloc
|
|
27
|
+
* (#171 §6.1.4 / §8.1): every cached column view must be rebuilt before
|
|
28
|
+
* the next read/write. */
|
|
29
|
+
refreshView(newView: T): void;
|
|
30
|
+
get length(): number;
|
|
31
|
+
get capacity(): number;
|
|
32
|
+
push(value: number): void;
|
|
33
|
+
pop(): number;
|
|
34
|
+
get(i: number): number;
|
|
35
|
+
setAt(i: number, value: number): void;
|
|
36
|
+
/** Move the last element into slot `i`, decrement length. Returns the
|
|
37
|
+
* value previously at slot `i`. Matches `GrowableTypedArray.swapRemove`. */
|
|
38
|
+
swapRemove(i: number): number;
|
|
39
|
+
clear(): void;
|
|
40
|
+
/** Set the logical length directly, declaring that `[0, len)` of the backing
|
|
41
|
+
* SAB view already holds valid data. The snapshot-mount path
|
|
42
|
+
* (`Archetype.restoreHostRows`, #789) uses this to re-sync the column's
|
|
43
|
+
* logical length with the restored `Archetype.length` — the bytes come from
|
|
44
|
+
* the restored SAB, but `_len` is host state. Throws on overrun (cannot grow
|
|
45
|
+
* a fixed SAB view here — the mount already adopted the restored capacity). */
|
|
46
|
+
setLength(len: number): void;
|
|
47
|
+
/** Raw backing view. Stable for the lifetime of the SAB; views over a
|
|
48
|
+
* SAB do not invalidate the way a `GrowableTypedArray`'s `buf` does
|
|
49
|
+
* after a grow. (`view_stamp` will signal "underlying SAB swapped"
|
|
50
|
+
* once #171 §6.1.4 lands.) */
|
|
51
|
+
get buf(): T;
|
|
52
|
+
/** Zero-copy subarray of valid data (`0..length-1`). */
|
|
53
|
+
view(): T;
|
|
54
|
+
[Symbol.iterator](): Iterator<number>;
|
|
55
|
+
/** Throw if the backing view cannot hold `capacity` elements. Mirrors
|
|
56
|
+
* `GrowableTypedArray.ensureCapacity` but cannot allocate — a SAB
|
|
57
|
+
* grow requires republishing the underlying buffer and rebuilding views
|
|
58
|
+
* across every archetype, which is the §6.1.4 invariant. */
|
|
59
|
+
ensureCapacity(capacity: number): void;
|
|
60
|
+
/** Append `count` elements from `src[srcOffset..srcOffset+count]`.
|
|
61
|
+
* Throws on overrun. */
|
|
62
|
+
bulkAppend(src: T, srcOffset: number, count: number): void;
|
|
63
|
+
/** Append `count` zeroes. Throws on overrun. */
|
|
64
|
+
bulkAppendZeroes(count: number): void;
|
|
65
|
+
/** Append `count` copies of `value`. Throws on overrun. Single-pass
|
|
66
|
+
* analogue of `bulkAppendZeroes` for a non-zero default. */
|
|
67
|
+
bulkAppendValue(value: number, count: number): void;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=buffer_backed_column.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer_backed_column.d.ts","sourceRoot":"","sources":["../../../src/core/store/buffer_backed_column.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD;;;6EAG6E;AAC7E,qBAAa,wBAAyB,SAAQ,KAAK;IAClD,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,SAAS,EAAE,MAAM,CAAC;gBAEtB,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAM/C;AAED,qBAAa,kBAAkB,CAAC,CAAC,SAAS,aAAa,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IACnF,OAAO,CAAC,IAAI,CAAI;IAChB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,IAAI,CAAK;IAEjB;;;0EAGsE;gBAC1D,IAAI,EAAE,CAAC;IAKnB;;;;;;;8BAO0B;IACnB,WAAW,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI;IAQpC,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAEM,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOzB,GAAG,IAAI,MAAM;IAIb,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAItB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI5C;gFAC4E;IACrE,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAM7B,KAAK,IAAI,IAAI;IAIpB;;;;;mFAK+E;IACxE,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAOnC;;;kCAG8B;IAC9B,IAAW,GAAG,IAAI,CAAC,CAElB;IAED,wDAAwD;IACjD,IAAI,IAAI,CAAC;IAQhB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC;IAYrC;;;gEAG4D;IACrD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAM7C;4BACwB;IACjB,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAQjE,gDAAgD;IACzC,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAM5C;gEAC4D;IACrD,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CAK1D"}
|