@daneren2005/shared-memory-objects 1.6.0 → 1.6.2
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/README.md +3 -2
- package/dist/allocated-memory.js.map +1 -1
- package/dist/cached-item-list.js.map +1 -1
- package/dist/constant-string.js.map +1 -1
- package/dist/local-pool.js.map +1 -1
- package/dist/lock/read-write-lock.js.map +1 -1
- package/dist/lock/simple-lock.js.map +1 -1
- package/dist/memory-buffer.js.map +1 -1
- package/dist/memory-heap.js.map +1 -1
- package/dist/serialize-object.js.map +1 -1
- package/dist/shared-list.js.map +1 -1
- package/dist/shared-map.d.ts +3 -0
- package/dist/shared-map.js +42 -24
- package/dist/shared-map.js.map +1 -1
- package/dist/shared-pointer-list.js.map +1 -1
- package/dist/shared-pool.js.map +1 -1
- package/dist/shared-stack.js.map +1 -1
- package/dist/shared-string.js.map +1 -1
- package/dist/shared-vector.js.map +1 -1
- package/dist/spatial/shared-quadtree.js.map +1 -1
- package/dist/spatial/shared-spatial-grid.js.map +1 -1
- package/dist/spatial/shared-spatial-map.d.ts +2 -0
- package/dist/spatial/shared-spatial-map.js +23 -19
- package/dist/spatial/shared-spatial-map.js.map +1 -1
- package/dist/spatial/spatial-entity.js.map +1 -1
- package/dist/spatial/spatial-neighbors.js.map +1 -1
- package/dist/utils/16-from-32-float.js.map +1 -1
- package/dist/utils/16-from-32-int.js.map +1 -1
- package/dist/utils/16-from-32-uint.js.map +1 -1
- package/dist/utils/16-from-64-float.js.map +1 -1
- package/dist/utils/16-from-64-int.js.map +1 -1
- package/dist/utils/16-from-64-uint.js.map +1 -1
- package/dist/utils/32-from-64-float.js.map +1 -1
- package/dist/utils/32-from-64-int.js.map +1 -1
- package/dist/utils/32-from-64-uint.js.map +1 -1
- package/dist/utils/array-type.js.map +1 -1
- package/dist/utils/atomic-math.js.map +1 -1
- package/dist/utils/float32-atomics.js.map +1 -1
- package/dist/utils/float64-atomics.js.map +1 -1
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/pointer.js.map +1 -1
- package/dist/utils/typedarray.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-spatial-map.js","names":[],"sources":["../../src/spatial/shared-spatial-map.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from '../allocated-memory';\nimport AllocatedMemory from '../allocated-memory';\nimport type MemoryHeap from '../memory-heap';\nimport SharedPool, { type SharedPoolConfig } from '../shared-pool';\nimport SharedMap from '../shared-map';\nimport SharedStack from '../shared-stack';\nimport { lock, unlock } from '../lock/simple-lock';\nimport { readLock, readUnlock, writeLock, writeUnlock } from '../lock/read-write-lock';\nimport { getPointer, loadRawPointer, storeRawPointer } from '../utils/pointer';\nimport { ARRAY_TYPE, getArrayTypeCode, getByteMultipler, makeArrayView } from '../utils/array-type';\nimport {\n\taddCandidate, candidateLimit, distanceSquaredToRect, type NeighborCandidate, type NearestNeighbor,\n} from './spatial-neighbors';\nimport { getSpatialMapCapacity, getSpatialPoolChunkSize, type SpatialEntity } from './spatial-entity';\n\n// Unbounded spatial hash (\"spatial multimap\") built for concurrent updates from many threads. It indexes the same way\n// SharedSpatialGrid does - every entity occupies each virtual cell (of side gridSize) its rect overlaps - but it drops\n// the grid's fixed cols x rows extent so the world is unbounded: cells may sit at any (col, row), positive or negative.\n//\n// A cell (col, row) is not stored at a fixed array index (there is no finite grid to index); instead it is hashed into a\n// growable hash table of buckets and every cell that lands on a bucket shares that bucket's intrusive singly-linked list.\n// Normal operations share a table read lock. When the average slot load grows past 0.5, one writer doubles the bucket\n// count and rebuilds the chains under the exclusive side of that lock. Bucket pages and their pointer stack only grow.\n//\n// Because distinct cells collide onto one bucket, a slot must carry its own cell (col, row): a bucket walk considers only\n// slots whose cell matches the cell being queried. Each (entity, cell) membership is a \"slot\" record in a SharedPool; the\n// entity's occupied cell rectangle is stored once in a separate entity pool, keyed by an id->entityIndex SharedMap, so\n// remove(id) (which only gets an id) knows which cells to unlink from.\n//\n// search returns each entity at most once even though it spans multiple cells: every slot carries the entity's anchor\n// (top-left) cell, and a slot only emits its id when its cell is the top-left cell of the entity that intersects the query\n// (col == max(anchorCol, qMinCol) && row == max(anchorRow, qMinRow)). That cell is always one of the entity's cells and\n// inside the query, so exactly one slot emits - no Set and no per-query mutation, so concurrent queries stay safe.\n//\n// Records are stored at the configured precision. Float32 (the default) keeps everything exact as long as entity ids and\n// both pools' index spaces stay under 2^24 (~16.7M) - every id, pool index, and the NULL sentinel is Float32 exact there\n// - and cell (col, row) stay within [-2^24, 2^24]. Need more (or ids >= 2^24)? Pass type: Float64Array.\n\n// Header (firstBlock) u32 layout\nconst BUCKET_STACK_POINTER_INDEX = 0;\nconst ENTITY_POOL_POINTER_INDEX = 1;\nconst SLOT_POOL_POINTER_INDEX = 2;\nconst MAP_POINTER_INDEX = 3;\nconst BUCKET_COUNT_INDEX = 4;\nconst TYPE_INDEX = 5;\n// config view starts at slot 6 (offset 24 bytes is 8-byte aligned, so a Float64 view is valid): [gridSize]\nconst CONFIG_INDEX = 6;\nconst TABLE_LOCK_INDEX = 8;\nconst MAX_BUCKET_COUNT_INDEX = 10;\n\n// Per-bucket record: [lock, head]\nconst BUCKET_LOCK_OFFSET = 0;\nconst BUCKET_HEAD_OFFSET = 1;\nconst BUCKET_SIZE = 2;\nconst BUCKET_SEGMENT_SHIFT = 8;\nconst BUCKETS_PER_SEGMENT = 1 << BUCKET_SEGMENT_SHIFT;\nconst BUCKET_SEGMENT_MASK = BUCKETS_PER_SEGMENT - 1;\n\n// Slot record fields (one per entity-cell membership). The cell (col, row) is stored explicitly because a bucket mixes\n// slots from every cell that hashes to it, so a walk must filter to the cell it is looking at.\nconst SLOT_ID = 0;\nconst SLOT_COL = 1;\nconst SLOT_ROW = 2;\nconst SLOT_ANCHOR_COL = 3;\nconst SLOT_ANCHOR_ROW = 4;\nconst SLOT_NEXT = 5;\nconst SLOT_ENTITY_INDEX = 6;\nconst SLOT_FIELDS = 7;\n\n// Entity record fields: the occupied cell rectangle\nconst ENTITY_MIN_COL = 0;\nconst ENTITY_MIN_ROW = 1;\nconst ENTITY_MAX_COL = 2;\nconst ENTITY_MAX_ROW = 3;\nconst ENTITY_X = 4;\nconst ENTITY_Y = 5;\nconst ENTITY_WIDTH = 6;\nconst ENTITY_HEIGHT = 7;\nconst ENTITY_FIELDS = 8;\n\n// Largest exact integer range for Float32 coordinates: [0, 2^24). Ids and pool indices must stay under this to survive a\n// Float32 round-trip, so it doubles as the Float32 entity cap and the value just past every valid index.\nconst FLOAT32_LIMIT = 0x1000000;\n// End-of-list / empty-bucket sentinel, chosen per element type so it is exact in the pool's view and above every valid\n// index: 2^24 for Float32 (its first non-representable index), 0xffffffff for Float64 (well within its exact range).\nconst FLOAT32_NULL_INDEX = FLOAT32_LIMIT;\nconst FLOAT64_NULL_INDEX = 0xffffffff;\n\n// Odd primes for the spatial hash (Teschner et al.): mixing col and row through Math.imul then xor scatters neighbouring\n// cells across buckets so a query's cells rarely collide on one bucket.\nconst HASH_PRIME_COL = 73856093;\nconst HASH_PRIME_ROW = 19349663;\n\nconst DEFAULT_GRID_SIZE = 50;\nconst DEFAULT_BUCKET_COUNT = 256;\nconst BUCKET_LOAD_NUMERATOR = 1;\nconst BUCKET_LOAD_DENOMINATOR = 2;\nconst DEFAULT_MAX_ENTITIES = 1_000_000;\n// A spatial-map entity can span several cells, so the slot pool needs headroom over the entity count\nconst DEFAULT_SLOTS_PER_ENTITY = 4;\nconst DEFAULT_COORD_TYPE = Float32Array;\n\ntype CoordArray = Float32Array | Float64Array;\ntype CoordArrayConstructor = Float32ArrayConstructor | Float64ArrayConstructor;\n\nexport default class SharedSpatialMap {\n\tstatic readonly ALLOCATE_COUNT = 11;\n\n\tprivate memory: MemoryHeap;\n\tprivate firstBlock: AllocatedMemory;\n\tprivate entityPool: SharedPool<CoordArray>;\n\tprivate slotPool: SharedPool<CoordArray>;\n\tprivate idMap: SharedMap<number>;\n\tprivate bucketPointers: SharedStack;\n\n\t// Reused to hand a full record to pool.push without allocating a fresh array per operation (single writer per id)\n\tprivate entityScratch: Array<number> = [0, 0, 0, 0, 0, 0, 0, 0];\n\tprivate slotScratch: Array<number> = [0, 0, 0, 0, 0, 0, 0];\n\n\t// Each cached page is viewed as Int32 for locks and Uint32 for head indexes. Both views cover the same bytes.\n\tprivate bucketSegments: Array<Int32Array | undefined> = [];\n\tprivate bucketHeadSegments: Array<Uint32Array | undefined> = [];\n\tprivate tableLock: Int32Array;\n\n\tprivate readonly coordType: number;\n\t// Empty-bucket / end-of-list sentinel for this instance's element type (see FLOAT32_NULL_INDEX)\n\tprivate readonly nullIndex: number;\n\tprivate bucketCount: number;\n\tprivate readonly maxBucketCount: number;\n\t// bucketCount-1 when bucketCount is a power of two, else -1. Lets bucketOf mask (hash & mask) instead of taking a\n\t// variable integer modulo (hash % bucketCount) on the hot path - every insert/update/remove/query cell hashes a bucket.\n\tprivate bucketMask: number;\n\t// Virtual cell size, read once (stored at the configured precision, math done in float64)\n\tprivate readonly cellSize: number;\n\n\t// Number of entities currently tracked\n\tget size(): number {\n\t\treturn this.idMap.length;\n\t}\n\n\tget gridSize(): number {\n\t\treturn this.cellSize;\n\t}\n\tget buckets(): number {\n\t\treturn Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t}\n\tget maxBuckets(): number {\n\t\treturn this.maxBucketCount;\n\t}\n\n\t// Element type the records are stored in (an ARRAY_TYPE code: float32 or float64)\n\tget type(): number {\n\t\treturn this.coordType;\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedSpatialMapConfig | SharedSpatialMapMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\tthis.firstBlock = new AllocatedMemory(memory, config.firstBlock);\n\t\t\tthis.coordType = this.firstBlock.data[TYPE_INDEX];\n\t\t\tthis.bucketPointers = new SharedStack(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, BUCKET_STACK_POINTER_INDEX), memory.positionBits),\n\t\t\t});\n\t\t\tthis.entityPool = new SharedPool<CoordArray>(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, ENTITY_POOL_POINTER_INDEX), memory.positionBits),\n\t\t\t});\n\t\t\tthis.slotPool = new SharedPool<CoordArray>(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, SLOT_POOL_POINTER_INDEX), memory.positionBits),\n\t\t\t});\n\t\t\tthis.idMap = new SharedMap<number>(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, MAP_POINTER_INDEX), memory.positionBits),\n\t\t\t});\n\t\t\tthis.bucketCount = Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t\t\tthis.maxBucketCount = this.firstBlock.data[MAX_BUCKET_COUNT_INDEX];\n\t\t\tthis.nullIndex = nullIndexFor(this.coordType);\n\t\t} else {\n\t\t\tlet gridSize = config?.gridSize ?? DEFAULT_GRID_SIZE;\n\t\t\tthis.bucketCount = Math.min(0x40000000, Math.max(1, Math.floor(config?.buckets ?? DEFAULT_BUCKET_COUNT)));\n\t\t\tlet maxEntities = config?.maxEntities ?? DEFAULT_MAX_ENTITIES;\n\t\t\tlet maxSlots = config?.maxSlots ?? maxEntities * DEFAULT_SLOTS_PER_ENTITY;\n\t\t\tthis.maxBucketCount = Math.min(\n\t\t\t\t0x40000000,\n\t\t\t\tMath.max(this.bucketCount, Math.floor(config?.maxBuckets ?? nextPowerOfTwo(maxSlots * 2))),\n\t\t\t);\n\t\t\tthis.coordType = getCoordTypeCode(config?.type);\n\t\t\tthis.nullIndex = nullIndexFor(this.coordType);\n\n\t\t\tif(this.coordType === ARRAY_TYPE.float32 && (maxEntities > FLOAT32_LIMIT || maxSlots > FLOAT32_LIMIT)) {\n\t\t\t\tthrow new Error(`Float32 SharedSpatialMap supports at most ${FLOAT32_LIMIT} entities and slots; pass type: Float64Array for more`);\n\t\t\t}\n\n\t\t\t// Inline the bucket page pointers, pools, and id-map so the stable spine is one contiguous allocation.\n\t\t\tlet entityPoolConfig: SharedPoolConfig<CoordArray> = {\n\t\t\t\ttype: getCoordTypeConstructor(this.coordType),\n\t\t\t\tdataLength: ENTITY_FIELDS,\n\t\t\t\tmaxLength: maxEntities,\n\t\t\t\tmaxChunkSize: getSpatialPoolChunkSize(maxEntities, ENTITY_FIELDS, getByteMultipler(this.coordType), memory.maxAllocationLength),\n\t\t\t};\n\t\t\tlet slotPoolConfig: SharedPoolConfig<CoordArray> = {\n\t\t\t\ttype: getCoordTypeConstructor(this.coordType),\n\t\t\t\tdataLength: SLOT_FIELDS,\n\t\t\t\tmaxLength: maxSlots,\n\t\t\t\tmaxChunkSize: getSpatialPoolChunkSize(maxSlots, SLOT_FIELDS, getByteMultipler(this.coordType), memory.maxAllocationLength),\n\t\t\t};\n\t\t\tlet entityPoolAllocateCount = SharedPool.getAllocateCount(memory, entityPoolConfig);\n\t\t\tlet slotPoolAllocateCount = SharedPool.getAllocateCount(memory, slotPoolConfig);\n\t\t\tlet mapAllocateCount = SharedMap.ALLOCATE_COUNT;\n\t\t\tlet allocateCount = SharedSpatialMap.ALLOCATE_COUNT;\n\t\t\tthis.firstBlock = memory.allocUI32(allocateCount + entityPoolAllocateCount + slotPoolAllocateCount + mapAllocateCount);\n\t\t\tthis.firstBlock.data[BUCKET_COUNT_INDEX] = this.bucketCount;\n\t\t\tthis.firstBlock.data[TYPE_INDEX] = this.coordType;\n\t\t\tthis.firstBlock.data[MAX_BUCKET_COUNT_INDEX] = this.maxBucketCount;\n\n\t\t\tlet configView = this.getConfigView();\n\t\t\tconfigView[0] = gridSize;\n\n\t\t\tthis.bucketPointers = new SharedStack(memory);\n\t\t\tstoreRawPointer(this.firstBlock.data, BUCKET_STACK_POINTER_INDEX, this.bucketPointers.pointer);\n\t\t\tthis.appendBucketSegments(this.bucketCount);\n\n\t\t\tlet entityPoolBlock = this.firstBlock.getSubAllocation(allocateCount, entityPoolAllocateCount);\n\t\t\tthis.entityPool = new SharedPool<CoordArray>(memory, { firstBlock: entityPoolBlock, ...entityPoolConfig });\n\t\t\tstoreRawPointer(this.firstBlock.data, ENTITY_POOL_POINTER_INDEX, entityPoolBlock.pointer);\n\n\t\t\tlet slotPoolBlock = this.firstBlock.getSubAllocation(allocateCount + entityPoolAllocateCount, slotPoolAllocateCount);\n\t\t\tthis.slotPool = new SharedPool<CoordArray>(memory, { firstBlock: slotPoolBlock, ...slotPoolConfig });\n\t\t\tstoreRawPointer(this.firstBlock.data, SLOT_POOL_POINTER_INDEX, slotPoolBlock.pointer);\n\n\t\t\tlet mapBlock = this.firstBlock.getSubAllocation(allocateCount + entityPoolAllocateCount + slotPoolAllocateCount, mapAllocateCount);\n\t\t\tthis.idMap = new SharedMap<number>(memory, { firstBlock: mapBlock, capacity: getSpatialMapCapacity(maxEntities, memory.maxAllocationLength) });\n\t\t\tstoreRawPointer(this.firstBlock.data, MAP_POINTER_INDEX, mapBlock.pointer);\n\t\t}\n\n\t\tthis.bucketMask = maskFor(this.bucketCount);\n\t\tthis.tableLock = new Int32Array(\n\t\t\tthis.firstBlock.data.buffer,\n\t\t\tthis.firstBlock.bufferByteOffset + TABLE_LOCK_INDEX * Uint32Array.BYTES_PER_ELEMENT,\n\t\t\t2,\n\t\t);\n\n\t\tlet configView = this.getConfigView();\n\t\tthis.cellSize = configView[0];\n\n\t}\n\n\tget pointer(): number {\n\t\treturn this.firstBlock.pointer;\n\t}\n\n\tget usedMemory(): number {\n\t\tlet total = this.firstBlock.usedMemory + this.bucketPointers.usedMemory\n\t\t\t+ this.entityPool.usedMemory + this.slotPool.usedMemory + this.idMap.usedMemory;\n\t\tfor(let pointer of this.bucketPointers) {\n\t\t\ttotal += new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits)).usedMemory;\n\t\t}\n\t\treturn total;\n\t}\n\n\tinsert(id: number, x: number, y: number, width = 0, height = 0) {\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tthis.insertLocked(id, x, y, width, height);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t\tthis.growBucketsIfNeeded();\n\t}\n\n\tbulkInsert(entities: Iterable<SpatialEntity>) {\n\t\tlet byId = new Map<number, SpatialEntity>();\n\t\tfor(let entity of entities) {\n\t\t\tbyId.set(entity.id, entity);\n\t\t}\n\t\tlet unique = Array.from(byId.values());\n\t\tlet existing = this.idMap.getAll(unique.map(entity => entity.id));\n\t\tlet mappings: Array<readonly [number, number]> = [];\n\t\tlet additionalSlots = 0;\n\t\tlet newCount = 0;\n\t\tfor(let i = 0; i < unique.length; i++) {\n\t\t\tif(existing[i] === undefined) {\n\t\t\t\tlet entity = unique[i];\n\t\t\t\tnewCount++;\n\t\t\t\tadditionalSlots += (this.colOf(entity.x + (entity.width ?? 0)) - this.colOf(entity.x) + 1)\n\t\t\t\t\t* (this.rowOf(entity.y + (entity.height ?? 0)) - this.rowOf(entity.y) + 1);\n\t\t\t}\n\t\t}\n\t\tthis.ensureBucketCapacity(this.slotPool.length + additionalSlots);\n\t\tlet nextEntityIndex = this.entityPool.reserveContiguous(newCount);\n\t\tlet nextSlotIndex = this.slotPool.reserveContiguous(additionalSlots);\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tfor(let i = 0; i < unique.length; i++) {\n\t\t\t\tlet entity = unique[i];\n\t\t\t\tlet width = entity.width ?? 0;\n\t\t\t\tlet height = entity.height ?? 0;\n\t\t\t\tif(existing[i] !== undefined) {\n\t\t\t\t\tthis.updateLocked(entity.id, entity.x, entity.y, width, height);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlet minCol = this.colOf(entity.x);\n\t\t\t\tlet minRow = this.rowOf(entity.y);\n\t\t\t\tlet maxCol = this.colOf(entity.x + width);\n\t\t\t\tlet maxRow = this.rowOf(entity.y + height);\n\t\t\t\tlet entityIndex = nextEntityIndex++;\n\t\t\t\tlet block = this.entityPool.blockFor(entityIndex);\n\t\t\t\tlet offset = this.entityPool.blockOffset(entityIndex);\n\t\t\t\tblock[offset + ENTITY_MIN_COL] = minCol;\n\t\t\t\tblock[offset + ENTITY_MIN_ROW] = minRow;\n\t\t\t\tblock[offset + ENTITY_MAX_COL] = maxCol;\n\t\t\t\tblock[offset + ENTITY_MAX_ROW] = maxRow;\n\t\t\t\tblock[offset + ENTITY_X] = entity.x;\n\t\t\t\tblock[offset + ENTITY_Y] = entity.y;\n\t\t\t\tblock[offset + ENTITY_WIDTH] = width;\n\t\t\t\tblock[offset + ENTITY_HEIGHT] = height;\n\t\t\t\tmappings.push([entity.id, entityIndex]);\n\t\t\t\tfor(let row = minRow; row <= maxRow; row++) {\n\t\t\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\t\t\tthis.linkReservedBucket(col, row, nextSlotIndex++, entity.id, entityIndex, minCol, minRow);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.idMap.setAll(mappings);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t\tthis.growBucketsForBulk();\n\t}\n\n\tprivate insertLocked(id: number, x: number, y: number, width: number, height: number) {\n\t\tif(this.idMap.get(id) !== undefined) {\n\t\t\tthis.updateLocked(id, x, y, width, height);\n\t\t\treturn;\n\t\t}\n\n\t\tlet minCol = this.colOf(x);\n\t\tlet minRow = this.rowOf(y);\n\t\tlet maxCol = this.colOf(x + width);\n\t\tlet maxRow = this.rowOf(y + height);\n\n\t\tlet entity = this.entityScratch;\n\t\tentity[ENTITY_MIN_COL] = minCol;\n\t\tentity[ENTITY_MIN_ROW] = minRow;\n\t\tentity[ENTITY_MAX_COL] = maxCol;\n\t\tentity[ENTITY_MAX_ROW] = maxRow;\n\t\tentity[ENTITY_X] = x;\n\t\tentity[ENTITY_Y] = y;\n\t\tentity[ENTITY_WIDTH] = width;\n\t\tentity[ENTITY_HEIGHT] = height;\n\t\tlet entityIndex = this.entityPool.push(entity);\n\t\tthis.idMap.set(id, entityIndex);\n\n\t\tthis.linkRange(id, entityIndex, minCol, minRow, maxCol, maxRow);\n\t}\n\n\t// Move an entity to a new position. Assumes a single writer per entity id (the standard shared-memory pattern - each\n\t// worker owns a disjoint set of entities), so this entity's record is stable until we lock its bucket(s).\n\tupdate(id: number, x: number, y: number, width = 0, height = 0) {\n\t\tlet entityIndex = this.idMap.get(id);\n\t\tif(entityIndex !== undefined) {\n\t\t\tlet block = this.entityPool.blockFor(entityIndex);\n\t\t\tlet off = this.entityPool.blockOffset(entityIndex);\n\t\t\tlet minCol = this.colOf(x);\n\t\t\tlet minRow = this.rowOf(y);\n\t\t\tlet maxCol = this.colOf(x + width);\n\t\t\tlet maxRow = this.rowOf(y + height);\n\t\t\tif(minCol === block[off + ENTITY_MIN_COL] && minRow === block[off + ENTITY_MIN_ROW]\n\t\t\t\t&& maxCol === block[off + ENTITY_MAX_COL] && maxRow === block[off + ENTITY_MAX_ROW]) {\n\t\t\t\tblock[off + ENTITY_X] = x;\n\t\t\t\tblock[off + ENTITY_Y] = y;\n\t\t\t\tblock[off + ENTITY_WIDTH] = width;\n\t\t\t\tblock[off + ENTITY_HEIGHT] = height;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tthis.updateLocked(id, x, y, width, height);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t\tthis.growBucketsIfNeeded();\n\t}\n\n\tprivate updateLocked(id: number, x: number, y: number, width: number, height: number) {\n\t\tlet entityIndex = this.idMap.get(id);\n\t\tif(entityIndex === undefined) {\n\t\t\tthis.insertLocked(id, x, y, width, height);\n\t\t\treturn;\n\t\t}\n\n\t\tlet block = this.entityPool.blockFor(entityIndex);\n\t\tlet off = this.entityPool.blockOffset(entityIndex);\n\t\tlet oldMinCol = block[off + ENTITY_MIN_COL];\n\t\tlet oldMinRow = block[off + ENTITY_MIN_ROW];\n\t\tlet oldMaxCol = block[off + ENTITY_MAX_COL];\n\t\tlet oldMaxRow = block[off + ENTITY_MAX_ROW];\n\n\t\tlet minCol = this.colOf(x);\n\t\tlet minRow = this.rowOf(y);\n\t\tlet maxCol = this.colOf(x + width);\n\t\tlet maxRow = this.rowOf(y + height);\n\n\t\t// Same cell rectangle: membership is unchanged, but neighbors still needs the new exact rectangle.\n\t\tif(minCol === oldMinCol && minRow === oldMinRow && maxCol === oldMaxCol && maxRow === oldMaxRow) {\n\t\t\tblock[off + ENTITY_X] = x;\n\t\t\tblock[off + ENTITY_Y] = y;\n\t\t\tblock[off + ENTITY_WIDTH] = width;\n\t\t\tblock[off + ENTITY_HEIGHT] = height;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.relinkRange(id, entityIndex, minCol, minRow, maxCol, maxRow, oldMinCol, oldMinRow, oldMaxCol, oldMaxRow);\n\n\t\tblock[off + ENTITY_MIN_COL] = minCol;\n\t\tblock[off + ENTITY_MIN_ROW] = minRow;\n\t\tblock[off + ENTITY_MAX_COL] = maxCol;\n\t\tblock[off + ENTITY_MAX_ROW] = maxRow;\n\t\tblock[off + ENTITY_X] = x;\n\t\tblock[off + ENTITY_Y] = y;\n\t\tblock[off + ENTITY_WIDTH] = width;\n\t\tblock[off + ENTITY_HEIGHT] = height;\n\t}\n\n\tremove(id: number): boolean {\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\treturn this.removeLocked(id);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate removeLocked(id: number): boolean {\n\t\tlet entityIndex = this.idMap.get(id);\n\t\tif(entityIndex === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet block = this.entityPool.blockFor(entityIndex);\n\t\tlet off = this.entityPool.blockOffset(entityIndex);\n\t\tthis.unlinkRange(id, block[off + ENTITY_MIN_COL], block[off + ENTITY_MIN_ROW], block[off + ENTITY_MAX_COL], block[off + ENTITY_MAX_ROW]);\n\n\t\tthis.entityPool.deleteIndex(entityIndex);\n\t\tthis.idMap.delete(id);\n\t\treturn true;\n\t}\n\n\thas(id: number): boolean {\n\t\treturn this.idMap.get(id) !== undefined;\n\t}\n\n\t// Broad-phase query: ids of every entity occupying a cell that overlaps the query rect. Each entity is returned at most\n\t// once (see the anchor-cell dedup in collectBucket); the caller does the narrow-phase overlap check.\n\tsearch(x: number, y: number, width: number, height: number, filter?: (id: number) => boolean): Array<number> {\n\t\tlet out: Array<number> = [];\n\t\tthis.searchInto(out, x, y, width, height, filter);\n\t\treturn out;\n\t}\n\t// Same as search but appends into a caller-owned array so hot loops can reuse it. Returns the array.\n\tsearchInto(out: Array<number>, x: number, y: number, width: number, height: number, filter?: (id: number) => boolean): Array<number> {\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\treturn this.searchIntoLocked(out, x, y, width, height, filter);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate searchIntoLocked(out: Array<number>, x: number, y: number, width: number, height: number, filter?: (id: number) => boolean): Array<number> {\n\t\tlet start = out.length;\n\t\tlet qMinCol = this.colOf(x);\n\t\tlet qMinRow = this.rowOf(y);\n\t\tlet qMaxCol = this.colOf(x + width);\n\t\tlet qMaxRow = this.rowOf(y + height);\n\n\t\tlet nullIndex = this.nullIndex;\n\t\tfor(let row = qMinRow; row <= qMaxRow; row++) {\n\t\t\tfor(let col = qMinCol; col <= qMaxCol; col++) {\n\t\t\t\tlet bucket = this.bucketOf(col, row);\n\t\t\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\t\t\t// Inline the empty-bucket peek (the common case) so an empty bucket never pays for a method call - most cells in\n\t\t\t\t// a typical query hash to empty buckets, so this skip dominates query cost.\n\t\t\t\tlet offset = this.bucketOffset(bucket);\n\t\t\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\t\t\tif(bucketHeads[offset + BUCKET_HEAD_OFFSET] === nullIndex) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.collectBucket(out, bucketInts, bucketHeads, offset, col, row, qMinCol, qMinRow);\n\t\t\t}\n\t\t}\n\t\tif(filter !== undefined) {\n\t\t\tlet write = start;\n\t\t\tfor(let read = start; read < out.length; read++) {\n\t\t\t\tlet id = out[read];\n\t\t\t\tif(filter(id)) {\n\t\t\t\t\tout[write++] = id;\n\t\t\t\t}\n\t\t\t}\n\t\t\tout.length = write;\n\t\t}\n\t\treturn out;\n\t}\n\n\tneighbors(x: number, y: number, maxResults: number, maxDistance: number, filter?: (id: number) => boolean): Array<number> {\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\treturn this.neighborsLocked(x, y, maxResults, maxDistance, filter);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate neighborsLocked(x: number, y: number, maxResults: number, maxDistance: number, filter?: (id: number) => boolean): Array<number> {\n\t\tif(maxResults <= 0 || maxDistance < 0 || Number.isNaN(maxResults) || Number.isNaN(maxDistance)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tmaxResults = Math.floor(maxResults);\n\t\tif(maxResults === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tlet maxDistanceSquared = maxDistance * maxDistance;\n\t\tlet candidates: Array<NeighborCandidate> = [];\n\t\tif(!Number.isFinite(maxDistance)) {\n\t\t\tfor(let [id, entityIndex] of this.idMap) {\n\t\t\t\tif(filter === undefined || filter(id)) {\n\t\t\t\t\tthis.addEntityCandidate(candidates, id, entityIndex, x, y, maxResults, maxDistanceSquared);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn candidates.map(candidate => candidate.id);\n\t\t}\n\n\t\tlet cellIds: Array<number> = [];\n\t\tlet seenEntities = filter !== undefined && maxResults > 1 ? new Set<number>() : undefined;\n\t\tlet startCol = this.colOf(x);\n\t\tlet startRow = this.rowOf(y);\n\t\tlet nearest: NearestNeighbor = { id: undefined, distance: maxDistanceSquared };\n\t\tlet visit = (col: number, row: number) => {\n\t\t\tif(filter === undefined) {\n\t\t\t\tif(maxResults === 1) {\n\t\t\t\t\tthis.collectNearestBucket(nearest, col, row, x, y);\n\t\t\t\t} else {\n\t\t\t\t\tthis.collectNeighborCandidates(\n\t\t\t\t\t\tcandidates, col, row, startCol, startRow, x, y, maxResults, maxDistanceSquared,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcellIds.length = 0;\n\t\t\tthis.collectNeighborBucket(cellIds, col, row);\n\t\t\tfor(let id of cellIds) {\n\t\t\t\tif(seenEntities?.has(id)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tseenEntities?.add(id);\n\t\t\t\tlet entityIndex = this.idMap.get(id);\n\t\t\t\tif(entityIndex !== undefined && (filter === undefined || filter(id))) {\n\t\t\t\t\tif(maxResults === 1) {\n\t\t\t\t\t\tlet distance = this.entityDistanceSquared(entityIndex, x, y);\n\t\t\t\t\t\tif(distance < nearest.distance\n\t\t\t\t\t\t\t|| (distance === nearest.distance && (nearest.id === undefined || id < nearest.id))) {\n\t\t\t\t\t\t\tnearest.id = id;\n\t\t\t\t\t\t\tnearest.distance = distance;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.addEntityCandidate(candidates, id, entityIndex, x, y, maxResults, maxDistanceSquared);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tfor(let radius = 0; ; radius++) {\n\t\t\tlet limit = maxResults === 1 ? nearest.distance : candidateLimit(candidates, maxResults, maxDistanceSquared);\n\t\t\tif(this.mapRingDistanceSquared(x, y, startCol, startRow, radius) > limit) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(radius === 0) {\n\t\t\t\tvisit(startCol, startRow);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet minCol = startCol - radius;\n\t\t\tlet maxCol = startCol + radius;\n\t\t\tlet top = startRow - radius;\n\t\t\tlet bottom = startRow + radius;\n\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\tvisit(col, top);\n\t\t\t\tvisit(col, bottom);\n\t\t\t}\n\t\t\tfor(let row = top + 1; row < bottom; row++) {\n\t\t\t\tvisit(minCol, row);\n\t\t\t\tvisit(maxCol, row);\n\t\t\t}\n\t\t}\n\n\t\treturn maxResults === 1 ? nearest.id === undefined ? [] : [nearest.id] : candidates.map(candidate => candidate.id);\n\t}\n\n\tclear() {\n\t\twriteLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tfor(let segmentIndex = 0; segmentIndex < this.bucketPointers.length; segmentIndex++) {\n\t\t\t\tthis.getBucketSegment(segmentIndex << BUCKET_SEGMENT_SHIFT);\n\t\t\t\tlet heads = this.bucketHeadSegments[segmentIndex]!;\n\t\t\t\tfor(let i = BUCKET_HEAD_OFFSET; i < heads.length; i += BUCKET_SIZE) {\n\t\t\t\t\theads[i] = this.nullIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.entityPool.clear();\n\t\t\tthis.slotPool.clear();\n\t\t\tlet keys: Array<number> = [];\n\t\t\tfor(let [key] of this.idMap) {\n\t\t\t\tkeys.push(key);\n\t\t\t}\n\t\t\tfor(let key of keys) {\n\t\t\t\tthis.idMap.delete(key);\n\t\t\t}\n\t\t} finally {\n\t\t\twriteUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tfree() {\n\t\tfor(let pointer of this.bucketPointers) {\n\t\t\tnew AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits)).free();\n\t\t}\n\t\tthis.bucketPointers.free();\n\t\tthis.entityPool.free();\n\t\tthis.slotPool.free();\n\t\tthis.idMap.free();\n\t\tthis.firstBlock.free();\n\t}\n\n\tgetSharedMemory(): SharedSpatialMapMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n\n\tprivate getConfigView(): CoordArray {\n\t\treturn makeArrayView(\n\t\t\tthis.coordType,\n\t\t\tthis.firstBlock.data.buffer,\n\t\t\tthis.firstBlock.bufferByteOffset + CONFIG_INDEX * Uint32Array.BYTES_PER_ELEMENT,\n\t\t\t1,\n\t\t) as CoordArray;\n\t}\n\n\tprivate colOf(x: number): number {\n\t\treturn Math.floor(x / this.cellSize);\n\t}\n\tprivate rowOf(y: number): number {\n\t\treturn Math.floor(y / this.cellSize);\n\t}\n\tprivate mapRingDistanceSquared(x: number, y: number, centerCol: number, centerRow: number, radius: number): number {\n\t\tif(radius === 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tlet cellSize = this.cellSize;\n\t\tlet left = x - (centerCol - radius + 1) * cellSize;\n\t\tlet right = (centerCol + radius) * cellSize - x;\n\t\tlet top = y - (centerRow - radius + 1) * cellSize;\n\t\tlet bottom = (centerRow + radius) * cellSize - y;\n\t\tlet distance = Math.min(left, right, top, bottom);\n\t\treturn distance * distance;\n\t}\n\t// Hash a virtual cell to the current bucket count. The table read lock keeps this count stable for the operation.\n\tprivate bucketOf(col: number, row: number): number {\n\t\tlet hash = (Math.imul(col, HASH_PRIME_COL) ^ Math.imul(row, HASH_PRIME_ROW)) >>> 0;\n\t\tlet mask = this.bucketMask;\n\t\treturn mask >= 0 ? hash & mask : hash % this.bucketCount;\n\t}\n\n\tprivate bucketOffset(bucket: number): number {\n\t\treturn (bucket & BUCKET_SEGMENT_MASK) * BUCKET_SIZE;\n\t}\n\n\tprivate getBucketSegment(bucket: number): Int32Array {\n\t\tlet segmentIndex = bucket >>> BUCKET_SEGMENT_SHIFT;\n\t\tlet cached = this.bucketSegments[segmentIndex];\n\t\tif(cached !== undefined) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tlet pointer = this.bucketPointers.at(segmentIndex);\n\t\tlet block = new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits));\n\t\t// A segment is exactly BUCKETS_PER_SEGMENT * BUCKET_SIZE u32s. Never size the view by block.data.length: a production\n\t\t// build leaves that view unbounded (it runs to the end of the buffer), so the head-clearing loops below would write\n\t\t// across every allocation that follows this block and stomp their headers.\n\t\tlet ints = new Int32Array(block.data.buffer, block.bufferByteOffset, BUCKETS_PER_SEGMENT * BUCKET_SIZE);\n\t\tthis.bucketHeadSegments[segmentIndex] = new Uint32Array(block.data.buffer, block.bufferByteOffset, BUCKETS_PER_SEGMENT * BUCKET_SIZE);\n\t\tthis.bucketSegments[segmentIndex] = ints;\n\t\treturn ints;\n\t}\n\n\tprivate appendBucketSegments(bucketCount: number) {\n\t\tlet needed = Math.ceil(bucketCount / BUCKETS_PER_SEGMENT);\n\t\twhile(this.bucketPointers.length < needed) {\n\t\t\tlet block = this.memory.allocUI32(BUCKETS_PER_SEGMENT * BUCKET_SIZE);\n\t\t\tlet heads = new Uint32Array(block.data.buffer, block.bufferByteOffset, BUCKETS_PER_SEGMENT * BUCKET_SIZE);\n\t\t\tfor(let i = BUCKET_HEAD_OFFSET; i < heads.length; i += BUCKET_SIZE) {\n\t\t\t\theads[i] = this.nullIndex;\n\t\t\t}\n\t\t\tthis.bucketPointers.push(block.pointer);\n\t\t}\n\t}\n\n\tprivate syncBucketCount() {\n\t\tlet bucketCount = Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t\tif(bucketCount !== this.bucketCount) {\n\t\t\tthis.bucketCount = bucketCount;\n\t\t\tthis.bucketMask = maskFor(bucketCount);\n\t\t}\n\t}\n\n\tprivate growBucketsIfNeeded() {\n\t\tlet bucketCount = Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t\tif(bucketCount >= this.maxBucketCount\n\t\t\t|| this.slotPool.length * BUCKET_LOAD_DENOMINATOR <= bucketCount * BUCKET_LOAD_NUMERATOR) {\n\t\t\treturn;\n\t\t}\n\n\t\twriteLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tif(this.slotPool.length * BUCKET_LOAD_DENOMINATOR <= this.bucketCount * BUCKET_LOAD_NUMERATOR) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet newBucketCount = Math.min(this.bucketCount * 2, this.maxBucketCount);\n\t\t\tif(newBucketCount === this.bucketCount) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.resizeBuckets(newBucketCount);\n\t\t} finally {\n\t\t\twriteUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate ensureBucketCapacity(slotCount: number) {\n\t\tlet needed = Math.ceil(slotCount * BUCKET_LOAD_DENOMINATOR / BUCKET_LOAD_NUMERATOR);\n\t\tlet target = Math.min(nextPowerOfTwo(needed), this.maxBucketCount);\n\t\tif(target <= Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX)) {\n\t\t\treturn;\n\t\t}\n\t\twriteLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tif(target > this.bucketCount) {\n\t\t\t\tthis.resizeBuckets(target);\n\t\t\t}\n\t\t} finally {\n\t\t\twriteUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate resizeBuckets(newBucketCount: number) {\n\t\tthis.appendBucketSegments(newBucketCount);\n\t\tfor(let segmentIndex = 0; segmentIndex < this.bucketPointers.length; segmentIndex++) {\n\t\t\tthis.getBucketSegment(segmentIndex << BUCKET_SEGMENT_SHIFT);\n\t\t\tlet heads = this.bucketHeadSegments[segmentIndex]!;\n\t\t\tfor(let i = BUCKET_HEAD_OFFSET; i < heads.length; i += BUCKET_SIZE) {\n\t\t\t\theads[i] = this.nullIndex;\n\t\t\t}\n\t\t}\n\n\t\tthis.bucketCount = newBucketCount;\n\t\tthis.bucketMask = maskFor(newBucketCount);\n\t\tfor(let [slotIndex, slot] of this.slotPool.entries()) {\n\t\t\tlet bucket = this.bucketOf(slot[SLOT_COL], slot[SLOT_ROW]);\n\t\t\tlet heads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\t\tlet headIndex = this.bucketOffset(bucket) + BUCKET_HEAD_OFFSET;\n\t\t\tslot[SLOT_NEXT] = heads[headIndex];\n\t\t\theads[headIndex] = slotIndex;\n\t\t}\n\t\tAtomics.store(this.firstBlock.data, BUCKET_COUNT_INDEX, newBucketCount);\n\t}\n\n\tprivate growBucketsForBulk() {\n\t\twhile(true) {\n\t\t\tlet before = Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t\t\tthis.growBucketsIfNeeded();\n\t\t\tif(Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX) === before) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Push one slot into each cell of the rectangle, carrying the cell's own (col, row) and the entity's top-left cell as\n\t// the dedup anchor. Every slot shares the id and anchor, so those are filled once before the loop.\n\tprivate linkRange(id: number, entityIndex: number, minCol: number, minRow: number, maxCol: number, maxRow: number) {\n\t\tlet slot = this.slotScratch;\n\t\tslot[SLOT_ID] = id;\n\t\tslot[SLOT_ANCHOR_COL] = minCol;\n\t\tslot[SLOT_ANCHOR_ROW] = minRow;\n\t\tslot[SLOT_NEXT] = this.nullIndex;\n\t\tslot[SLOT_ENTITY_INDEX] = entityIndex;\n\n\t\tfor(let row = minRow; row <= maxRow; row++) {\n\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\tthis.linkIntoBucket(col, row, slot);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Push a fresh slot for cell (col, row) - carrying the shared record in slot plus that cell's own coords - onto the\n\t// head of its bucket.\n\tprivate linkIntoBucket(col: number, row: number, slot: Array<number>) {\n\t\tslot[SLOT_COL] = col;\n\t\tslot[SLOT_ROW] = row;\n\t\tlet pool = this.slotPool;\n\t\tlet slotIndex = pool.push(slot);\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tpool.set(slotIndex, SLOT_NEXT, bucketHeads[headIndex]);\n\t\tbucketHeads[headIndex] = slotIndex;\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate linkReservedBucket(\n\t\tcol: number, row: number, slotIndex: number, id: number, entityIndex: number, anchorCol: number, anchorRow: number,\n\t) {\n\t\tlet pool = this.slotPool;\n\t\tlet block = pool.blockFor(slotIndex);\n\t\tlet slotOffset = pool.blockOffset(slotIndex);\n\t\tblock[slotOffset + SLOT_ID] = id;\n\t\tblock[slotOffset + SLOT_COL] = col;\n\t\tblock[slotOffset + SLOT_ROW] = row;\n\t\tblock[slotOffset + SLOT_ANCHOR_COL] = anchorCol;\n\t\tblock[slotOffset + SLOT_ANCHOR_ROW] = anchorRow;\n\t\tblock[slotOffset + SLOT_ENTITY_INDEX] = entityIndex;\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tblock[slotOffset + SLOT_NEXT] = bucketHeads[headIndex];\n\t\tbucketHeads[headIndex] = slotIndex;\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\t// Move an entity's slots from its old cell rectangle to a new one, touching only the cells that actually change. A cell\n\t// in both rectangles keeps its slot and just gets its anchor refreshed; new-only cells are linked before old-only cells\n\t// are unlinked, so a query racing the move never sees the entity in neither rectangle. Doing it this way (rather than\n\t// linkRange(new) + unlinkRange(old)) is what keeps overlap cells correct: unlinkFromBucket matches by id + cell and\n\t// would splice out the freshly linked slot in an overlap cell, leaving the stale one behind and corrupting the anchor.\n\tprivate relinkRange(id: number, entityIndex: number, minCol: number, minRow: number, maxCol: number, maxRow: number, oldMinCol: number, oldMinRow: number, oldMaxCol: number, oldMaxRow: number) {\n\t\tlet ovMinCol = minCol > oldMinCol ? minCol : oldMinCol;\n\t\tlet ovMaxCol = maxCol < oldMaxCol ? maxCol : oldMaxCol;\n\t\tlet ovMinRow = minRow > oldMinRow ? minRow : oldMinRow;\n\t\tlet ovMaxRow = maxRow < oldMaxRow ? maxRow : oldMaxRow;\n\t\tlet hasOverlap = ovMinCol <= ovMaxCol && ovMinRow <= ovMaxRow;\n\n\t\tlet slot = this.slotScratch;\n\t\tslot[SLOT_ID] = id;\n\t\tslot[SLOT_ANCHOR_COL] = minCol;\n\t\tslot[SLOT_ANCHOR_ROW] = minRow;\n\t\tslot[SLOT_NEXT] = this.nullIndex;\n\t\tslot[SLOT_ENTITY_INDEX] = entityIndex;\n\n\t\tfor(let row = minRow; row <= maxRow; row++) {\n\t\t\tlet inOverlapRow = hasOverlap && row >= ovMinRow && row <= ovMaxRow;\n\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\tif(inOverlapRow && col >= ovMinCol && col <= ovMaxCol) {\n\t\t\t\t\tthis.refreshAnchorInBucket(this.bucketOf(col, row), id, col, row, minCol, minRow);\n\t\t\t\t} else {\n\t\t\t\t\tthis.linkIntoBucket(col, row, slot);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet pool = this.slotPool;\n\t\tfor(let row = oldMinRow; row <= oldMaxRow; row++) {\n\t\t\tlet inOverlapRow = hasOverlap && row >= ovMinRow && row <= ovMaxRow;\n\t\t\tfor(let col = oldMinCol; col <= oldMaxCol; col++) {\n\t\t\t\tif(inOverlapRow && col >= ovMinCol && col <= ovMaxCol) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlet slotIndex = this.unlinkFromBucket(this.bucketOf(col, row), id, col, row);\n\t\t\t\tif(slotIndex !== nullIndex) {\n\t\t\t\t\tpool.deleteIndex(slotIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Refresh the anchor on this entity's slot already linked for cell (col, row) (single writer per id, so it is present).\n\tprivate refreshAnchorInBucket(bucket: number, id: number, col: number, row: number, anchorCol: number, anchorRow: number) {\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet pool = this.slotPool;\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet index = bucketHeads[offset + BUCKET_HEAD_OFFSET];\n\t\twhile(index !== nullIndex) {\n\t\t\tlet block = pool.blockFor(index);\n\t\t\tlet off = pool.blockOffset(index);\n\t\t\tif(block[off + SLOT_ID] === id && block[off + SLOT_COL] === col && block[off + SLOT_ROW] === row) {\n\t\t\t\tblock[off + SLOT_ANCHOR_COL] = anchorCol;\n\t\t\t\tblock[off + SLOT_ANCHOR_ROW] = anchorRow;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tindex = block[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\t// Remove and recycle this entity's slot from each cell of the rectangle.\n\tprivate unlinkRange(id: number, minCol: number, minRow: number, maxCol: number, maxRow: number) {\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet pool = this.slotPool;\n\t\tfor(let row = minRow; row <= maxRow; row++) {\n\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\tlet slotIndex = this.unlinkFromBucket(this.bucketOf(col, row), id, col, row);\n\t\t\t\tif(slotIndex !== nullIndex) {\n\t\t\t\t\tpool.deleteIndex(slotIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Caller has already peeked the head unlocked and skipped empty buckets (an empty bucket has nothing to read, so the\n\t// lock and its atomics would be pure overhead). Taking the lock only to walk a non-empty bucket preserves the snapshot\n\t// guarantee - a concurrent insert we race is simply not in this snapshot.\n\tprivate collectBucket(\n\t\tout: Array<number>, bucketInts: Int32Array, bucketHeads: Uint32Array, offset: number,\n\t\tcol: number, row: number, qMinCol: number, qMinRow: number,\n\t) {\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet index = bucketHeads[headIndex];\n\t\tlet pool = this.slotPool;\n\t\twhile(index !== nullIndex) {\n\t\t\t// One chunk resolve per slot covers every field it reads\n\t\t\tlet block = pool.blockFor(index);\n\t\t\tlet off = pool.blockOffset(index);\n\t\t\t// Other cells hash to this bucket too; only slots living in the cell being queried count.\n\t\t\tif(block[off + SLOT_COL] === col && block[off + SLOT_ROW] === row) {\n\t\t\t\t// Emit only from the entity's top-left cell that intersects this query, so a multi-cell entity is returned once.\n\t\t\t\tlet anchorCol = block[off + SLOT_ANCHOR_COL];\n\t\t\t\tlet anchorRow = block[off + SLOT_ANCHOR_ROW];\n\t\t\t\tlet tlCol = anchorCol > qMinCol ? anchorCol : qMinCol;\n\t\t\t\tlet tlRow = anchorRow > qMinRow ? anchorRow : qMinRow;\n\t\t\t\tif(col === tlCol && row === tlRow) {\n\t\t\t\t\tout.push(block[off + SLOT_ID]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tindex = block[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate collectNeighborBucket(out: Array<number>, col: number, row: number) {\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tif(bucketHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet index = bucketHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet block = this.slotPool.blockFor(index);\n\t\t\tlet off = this.slotPool.blockOffset(index);\n\t\t\tif(block[off + SLOT_COL] === col && block[off + SLOT_ROW] === row) {\n\t\t\t\tout.push(block[off + SLOT_ID]);\n\t\t\t}\n\t\t\tindex = block[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate collectNearestBucket(\n\t\tnearest: NearestNeighbor, col: number, row: number, x: number, y: number,\n\t) {\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tif(bucketHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet index = bucketHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet slot = this.slotPool.blockFor(index);\n\t\t\tlet off = this.slotPool.blockOffset(index);\n\t\t\tif(slot[off + SLOT_COL] === col && slot[off + SLOT_ROW] === row) {\n\t\t\t\tlet entityIndex = slot[off + SLOT_ENTITY_INDEX];\n\t\t\t\tlet entity = this.entityPool.blockFor(entityIndex);\n\t\t\t\tlet entityOffset = this.entityPool.blockOffset(entityIndex);\n\t\t\t\tlet id = slot[off + SLOT_ID];\n\t\t\t\tlet distance = this.entityBlockDistanceSquared(entity, entityOffset, x, y);\n\t\t\t\tif(distance < nearest.distance\n\t\t\t\t\t|| (distance === nearest.distance && (nearest.id === undefined || id < nearest.id))) {\n\t\t\t\t\tnearest.id = id;\n\t\t\t\t\tnearest.distance = distance;\n\t\t\t\t}\n\t\t\t}\n\t\t\tindex = slot[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate collectNeighborCandidates(\n\t\tcandidates: Array<NeighborCandidate>, col: number, row: number, queryCol: number, queryRow: number,\n\t\tx: number, y: number, maxResults: number, maxDistanceSquared: number,\n\t) {\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tif(bucketHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet index = bucketHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet slot = this.slotPool.blockFor(index);\n\t\t\tlet off = this.slotPool.blockOffset(index);\n\t\t\tif(slot[off + SLOT_COL] === col && slot[off + SLOT_ROW] === row) {\n\t\t\t\tlet entityIndex = slot[off + SLOT_ENTITY_INDEX];\n\t\t\t\tlet entity = this.entityPool.blockFor(entityIndex);\n\t\t\t\tlet entityOffset = this.entityPool.blockOffset(entityIndex);\n\t\t\t\tlet minCol = entity[entityOffset + ENTITY_MIN_COL];\n\t\t\t\tlet maxCol = entity[entityOffset + ENTITY_MAX_COL];\n\t\t\t\tlet minRow = entity[entityOffset + ENTITY_MIN_ROW];\n\t\t\t\tlet maxRow = entity[entityOffset + ENTITY_MAX_ROW];\n\t\t\t\tlet nearestCol = queryCol < minCol ? minCol : queryCol > maxCol ? maxCol : queryCol;\n\t\t\t\tlet nearestRow = queryRow < minRow ? minRow : queryRow > maxRow ? maxRow : queryRow;\n\t\t\t\tif(col === nearestCol && row === nearestRow) {\n\t\t\t\t\tlet distance = this.entityBlockDistanceSquared(entity, entityOffset, x, y);\n\t\t\t\t\tif(distance <= maxDistanceSquared) {\n\t\t\t\t\t\taddCandidate(candidates, slot[off + SLOT_ID], distance, maxResults);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tindex = slot[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate addEntityCandidate(candidates: Array<NeighborCandidate>, id: number, entityIndex: number, x: number, y: number, maxResults: number, maxDistanceSquared: number) {\n\t\tlet distance = this.entityDistanceSquared(entityIndex, x, y);\n\t\tif(distance <= maxDistanceSquared) {\n\t\t\taddCandidate(candidates, id, distance, maxResults);\n\t\t}\n\t}\n\n\tprivate entityDistanceSquared(entityIndex: number, x: number, y: number): number {\n\t\tlet entity = this.entityPool.blockFor(entityIndex);\n\t\tlet off = this.entityPool.blockOffset(entityIndex);\n\t\treturn this.entityBlockDistanceSquared(entity, off, x, y);\n\t}\n\n\tprivate entityBlockDistanceSquared(entity: CoordArray, off: number, x: number, y: number): number {\n\t\tlet minX = entity[off + ENTITY_X];\n\t\tlet minY = entity[off + ENTITY_Y];\n\t\treturn distanceSquaredToRect(\n\t\t\tx, y, minX, minY, minX + entity[off + ENTITY_WIDTH], minY + entity[off + ENTITY_HEIGHT],\n\t\t);\n\t}\n\n\t// Splice this entity's slot for exactly cell (col, row) out of the bucket and return its index (nullIndex if absent).\n\t// Matching on id and cell is required: two of an entity's own cells can hash to the same bucket, so id alone is ambiguous.\n\tprivate unlinkFromBucket(bucket: number, id: number, col: number, row: number): number {\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tlet pool = this.slotPool;\n\n\t\tlet prev = nullIndex;\n\t\tlet index = bucketHeads[headIndex];\n\t\twhile(index !== nullIndex) {\n\t\t\t// One chunk resolve per slot covers every field it reads\n\t\t\tlet block = pool.blockFor(index);\n\t\t\tlet off = pool.blockOffset(index);\n\t\t\tlet next = block[off + SLOT_NEXT];\n\t\t\tif(block[off + SLOT_ID] === id && block[off + SLOT_COL] === col && block[off + SLOT_ROW] === row) {\n\t\t\t\tif(prev === nullIndex) {\n\t\t\t\t\tbucketHeads[headIndex] = next;\n\t\t\t\t} else {\n\t\t\t\t\tpool.set(prev, SLOT_NEXT, next);\n\t\t\t\t}\n\t\t\t\tunlock(bucketInts, lockIndex);\n\t\t\t\treturn index;\n\t\t\t}\n\t\t\tprev = index;\n\t\t\tindex = next;\n\t\t}\n\n\t\tunlock(bucketInts, lockIndex);\n\t\treturn nullIndex;\n\t}\n}\n\nfunction getCoordTypeCode(type: CoordArrayConstructor | undefined): number {\n\tlet code = getArrayTypeCode(type ?? DEFAULT_COORD_TYPE);\n\tif(code !== ARRAY_TYPE.float32 && code !== ARRAY_TYPE.float64) {\n\t\tthrow new Error('SharedSpatialMap must be Float32Array or Float64Array');\n\t}\n\treturn code;\n}\nfunction getCoordTypeConstructor(typeCode: number): CoordArrayConstructor {\n\treturn getByteMultipler(typeCode) === 2 ? Float64Array : Float32Array;\n}\nfunction nullIndexFor(typeCode: number): number {\n\treturn typeCode === ARRAY_TYPE.float32 ? FLOAT32_NULL_INDEX : FLOAT64_NULL_INDEX;\n}\nfunction maskFor(bucketCount: number): number {\n\treturn (bucketCount & (bucketCount - 1)) === 0 ? bucketCount - 1 : -1;\n}\nfunction nextPowerOfTwo(value: number): number {\n\treturn Math.pow(2, Math.ceil(Math.log2(Math.max(1, value))));\n}\n\ninterface SharedSpatialMapConfig {\n\tgridSize?: number\n\tbuckets?: number\n\tmaxBuckets?: number\n\tmaxEntities?: number\n\tmaxSlots?: number\n\ttype?: CoordArrayConstructor\n}\ninterface SharedSpatialMapMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedSpatialMapConfig, SharedSpatialMapMemory, SpatialEntity };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-spatial-map.js","names":["AllocatedMemory","SharedMap","SharedStack","SharedPool","BUCKET_STACK_POINTER_INDEX","ENTITY_POOL_POINTER_INDEX","SLOT_POOL_POINTER_INDEX","MAP_POINTER_INDEX","BUCKET_COUNT_INDEX","TYPE_INDEX","CONFIG_INDEX","TABLE_LOCK_INDEX","MAX_BUCKET_COUNT_INDEX","BUCKET_LOCK_OFFSET","BUCKET_HEAD_OFFSET","BUCKET_SIZE","BUCKET_SEGMENT_SHIFT","BUCKETS_PER_SEGMENT","BUCKET_SEGMENT_MASK","SLOT_ID","SLOT_COL","SLOT_ROW","SLOT_ANCHOR_COL","SLOT_ANCHOR_ROW","SLOT_NEXT","SLOT_ENTITY_INDEX","SLOT_FIELDS","ENTITY_MIN_COL","ENTITY_MIN_ROW","ENTITY_MAX_COL","ENTITY_MAX_ROW","ENTITY_X","ENTITY_Y","ENTITY_WIDTH","ENTITY_HEIGHT","ENTITY_FIELDS","FLOAT32_LIMIT","FLOAT32_NULL_INDEX","FLOAT64_NULL_INDEX","UINT32_LIMIT","HASH_PRIME_COL","HASH_PRIME_ROW","DEFAULT_GRID_SIZE","DEFAULT_BUCKET_COUNT","BUCKET_LOAD_NUMERATOR","BUCKET_LOAD_DENOMINATOR","DEFAULT_MAX_ENTITIES","DEFAULT_SLOTS_PER_ENTITY","DEFAULT_COORD_TYPE","SharedSpatialMap","memory","config","getPointer","loadRawPointer","nullIndexFor","gridSize","maxEntities","maxSlots","nextPowerOfTwo","getCoordTypeCode","ARRAY_TYPE","entityPoolConfig","getCoordTypeConstructor","getSpatialPoolChunkSize","getByteMultipler","slotPoolConfig","entityPoolAllocateCount","slotPoolAllocateCount","mapAllocateCount","allocateCount","configView","storeRawPointer","entityPoolBlock","slotPoolBlock","mapBlock","getSpatialMapCapacity","maskFor","total","pointer","id","x","y","width","height","byId","entity","entities","unique","existing","mappings","additionalSlots","newCount","i","nextEntityIndex","nextSlotIndex","minCol","minRow","maxCol","maxRow","entityIndex","block","offset","row","col","off","oldMinCol","oldMinRow","oldMaxCol","oldMaxRow","out","filter","start","qMinCol","qMinRow","qMaxCol","qMaxRow","nullIndex","bucket","bucketInts","bucketHeads","write","read","maxResults","maxDistance","maxDistanceSquared","candidates","candidate","cellIds","seenEntities","startCol","startRow","nearest","visit","distance","radius","limit","candidateLimit","top","bottom","segmentIndex","heads","keys","key","makeArrayView","cellSize","left","centerCol","right","centerRow","hash","mask","cached","ints","needed","bucketCount","newBucketCount","slotCount","target","slotIndex","slot","headIndex","before","pool","lockIndex","unlock","slotOffset","anchorCol","anchorRow","ovMinCol","ovMaxCol","ovMinRow","ovMaxRow","hasOverlap","inOverlapRow","index","entityOffset","queryCol","queryRow","addCandidate","minX","minY","distanceSquaredToRect","prev","next","code","getArrayTypeCode","type","typeCode","value"],"sources":["../../src/spatial/shared-spatial-map.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from '../allocated-memory';\nimport AllocatedMemory from '../allocated-memory';\nimport type MemoryHeap from '../memory-heap';\nimport SharedPool, { type SharedPoolConfig } from '../shared-pool';\nimport SharedMap from '../shared-map';\nimport SharedStack from '../shared-stack';\nimport { lock, unlock } from '../lock/simple-lock';\nimport { readLock, readUnlock, writeLock, writeUnlock } from '../lock/read-write-lock';\nimport { getPointer, loadRawPointer, storeRawPointer } from '../utils/pointer';\nimport { ARRAY_TYPE, getArrayTypeCode, getByteMultipler, makeArrayView } from '../utils/array-type';\nimport {\n\taddCandidate, candidateLimit, distanceSquaredToRect, type NeighborCandidate, type NearestNeighbor,\n} from './spatial-neighbors';\nimport { getSpatialMapCapacity, getSpatialPoolChunkSize, type SpatialEntity } from './spatial-entity';\n\n// Unbounded spatial hash (\"spatial multimap\") built for concurrent updates from many threads. It indexes the same way\n// SharedSpatialGrid does - every entity occupies each virtual cell (of side gridSize) its rect overlaps - but it drops\n// the grid's fixed cols x rows extent so the world is unbounded: cells may sit at any (col, row), positive or negative.\n//\n// A cell (col, row) is not stored at a fixed array index (there is no finite grid to index); instead it is hashed into a\n// growable hash table of buckets and every cell that lands on a bucket shares that bucket's intrusive singly-linked list.\n// Normal operations share a table read lock. When the average slot load grows past 0.5, one writer doubles the bucket\n// count and rebuilds the chains under the exclusive side of that lock. Bucket pages and their pointer stack only grow.\n//\n// Because distinct cells collide onto one bucket, a slot must carry its own cell (col, row): a bucket walk considers only\n// slots whose cell matches the cell being queried. Each (entity, cell) membership is a \"slot\" record in a SharedPool; the\n// entity's occupied cell rectangle is stored once in a separate entity pool, keyed by an id->entityIndex SharedMap, so\n// remove(id) (which only gets an id) knows which cells to unlink from.\n//\n// search returns each entity at most once even though it spans multiple cells: every slot carries the entity's anchor\n// (top-left) cell, and a slot only emits its id when its cell is the top-left cell of the entity that intersects the query\n// (col == max(anchorCol, qMinCol) && row == max(anchorRow, qMinRow)). That cell is always one of the entity's cells and\n// inside the query, so exactly one slot emits - no Set and no per-query mutation, so concurrent queries stay safe.\n//\n// Records are stored at the configured precision. Float32 (the default) keeps everything exact as long as entity ids and\n// both pools' index spaces stay under 2^24 (~16.7M) - every id, pool index, and the NULL sentinel is Float32 exact there\n// - and cell (col, row) stay within [-2^24, 2^24]. Need more (or ids >= 2^24)? Pass type: Float64Array, which accepts\n// ids up to 2^32 - 1: the id->entityIndex SharedMap keys are uint32 at either precision.\n\n// Header (firstBlock) u32 layout\nconst BUCKET_STACK_POINTER_INDEX = 0;\nconst ENTITY_POOL_POINTER_INDEX = 1;\nconst SLOT_POOL_POINTER_INDEX = 2;\nconst MAP_POINTER_INDEX = 3;\nconst BUCKET_COUNT_INDEX = 4;\nconst TYPE_INDEX = 5;\n// config view starts at slot 6 (offset 24 bytes is 8-byte aligned, so a Float64 view is valid): [gridSize]\nconst CONFIG_INDEX = 6;\nconst TABLE_LOCK_INDEX = 8;\nconst MAX_BUCKET_COUNT_INDEX = 10;\n\n// Per-bucket record: [lock, head]\nconst BUCKET_LOCK_OFFSET = 0;\nconst BUCKET_HEAD_OFFSET = 1;\nconst BUCKET_SIZE = 2;\nconst BUCKET_SEGMENT_SHIFT = 8;\nconst BUCKETS_PER_SEGMENT = 1 << BUCKET_SEGMENT_SHIFT;\nconst BUCKET_SEGMENT_MASK = BUCKETS_PER_SEGMENT - 1;\n\n// Slot record fields (one per entity-cell membership). The cell (col, row) is stored explicitly because a bucket mixes\n// slots from every cell that hashes to it, so a walk must filter to the cell it is looking at.\nconst SLOT_ID = 0;\nconst SLOT_COL = 1;\nconst SLOT_ROW = 2;\nconst SLOT_ANCHOR_COL = 3;\nconst SLOT_ANCHOR_ROW = 4;\nconst SLOT_NEXT = 5;\nconst SLOT_ENTITY_INDEX = 6;\nconst SLOT_FIELDS = 7;\n\n// Entity record fields: the occupied cell rectangle\nconst ENTITY_MIN_COL = 0;\nconst ENTITY_MIN_ROW = 1;\nconst ENTITY_MAX_COL = 2;\nconst ENTITY_MAX_ROW = 3;\nconst ENTITY_X = 4;\nconst ENTITY_Y = 5;\nconst ENTITY_WIDTH = 6;\nconst ENTITY_HEIGHT = 7;\nconst ENTITY_FIELDS = 8;\n\n// Largest exact integer range for Float32 coordinates: [0, 2^24). Ids and pool indices must stay under this to survive a\n// Float32 round-trip, so it doubles as the Float32 entity cap and the value just past every valid index.\nconst FLOAT32_LIMIT = 0x1000000;\n// End-of-list / empty-bucket sentinel, chosen per element type so it is exact in the pool's view and above every valid\n// index: 2^24 for Float32 (its first non-representable index), 0xffffffff for Float64 (well within its exact range).\nconst FLOAT32_NULL_INDEX = FLOAT32_LIMIT;\nconst FLOAT64_NULL_INDEX = 0xffffffff;\nconst UINT32_LIMIT = 0x100000000;\n\n// Odd primes for the spatial hash (Teschner et al.): mixing col and row through Math.imul then xor scatters neighbouring\n// cells across buckets so a query's cells rarely collide on one bucket.\nconst HASH_PRIME_COL = 73856093;\nconst HASH_PRIME_ROW = 19349663;\n\nconst DEFAULT_GRID_SIZE = 50;\nconst DEFAULT_BUCKET_COUNT = 256;\nconst BUCKET_LOAD_NUMERATOR = 1;\nconst BUCKET_LOAD_DENOMINATOR = 2;\nconst DEFAULT_MAX_ENTITIES = 1_000_000;\n// A spatial-map entity can span several cells, so the slot pool needs headroom over the entity count\nconst DEFAULT_SLOTS_PER_ENTITY = 4;\nconst DEFAULT_COORD_TYPE = Float32Array;\n\ntype CoordArray = Float32Array | Float64Array;\ntype CoordArrayConstructor = Float32ArrayConstructor | Float64ArrayConstructor;\n\nexport default class SharedSpatialMap {\n\tstatic readonly ALLOCATE_COUNT = 11;\n\n\tprivate memory: MemoryHeap;\n\tprivate firstBlock: AllocatedMemory;\n\tprivate entityPool: SharedPool<CoordArray>;\n\tprivate slotPool: SharedPool<CoordArray>;\n\tprivate idMap: SharedMap<number>;\n\tprivate bucketPointers: SharedStack;\n\n\t// Reused to hand a full record to pool.push without allocating a fresh array per operation (single writer per id)\n\tprivate entityScratch: Array<number> = [0, 0, 0, 0, 0, 0, 0, 0];\n\tprivate slotScratch: Array<number> = [0, 0, 0, 0, 0, 0, 0];\n\n\t// Each cached page is viewed as Int32 for locks and Uint32 for head indexes. Both views cover the same bytes.\n\tprivate bucketSegments: Array<Int32Array | undefined> = [];\n\tprivate bucketHeadSegments: Array<Uint32Array | undefined> = [];\n\tprivate tableLock: Int32Array;\n\n\tprivate readonly coordType: number;\n\t// Empty-bucket / end-of-list sentinel for this instance's element type (see FLOAT32_NULL_INDEX)\n\tprivate readonly nullIndex: number;\n\t// Exclusive upper bound on ids: exact in the slot records and representable as a SharedMap key\n\tprivate readonly idLimit: number;\n\tprivate bucketCount: number;\n\tprivate readonly maxBucketCount: number;\n\t// bucketCount-1 when bucketCount is a power of two, else -1. Lets bucketOf mask (hash & mask) instead of taking a\n\t// variable integer modulo (hash % bucketCount) on the hot path - every insert/update/remove/query cell hashes a bucket.\n\tprivate bucketMask: number;\n\t// Virtual cell size, read once (stored at the configured precision, math done in float64)\n\tprivate readonly cellSize: number;\n\n\t// Number of entities currently tracked\n\tget size(): number {\n\t\treturn this.idMap.length;\n\t}\n\n\tget gridSize(): number {\n\t\treturn this.cellSize;\n\t}\n\tget buckets(): number {\n\t\treturn Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t}\n\tget maxBuckets(): number {\n\t\treturn this.maxBucketCount;\n\t}\n\n\t// Element type the records are stored in (an ARRAY_TYPE code: float32 or float64)\n\tget type(): number {\n\t\treturn this.coordType;\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedSpatialMapConfig | SharedSpatialMapMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\tthis.firstBlock = new AllocatedMemory(memory, config.firstBlock);\n\t\t\tthis.coordType = this.firstBlock.data[TYPE_INDEX];\n\t\t\tthis.bucketPointers = new SharedStack(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, BUCKET_STACK_POINTER_INDEX), memory.positionBits),\n\t\t\t});\n\t\t\tthis.entityPool = new SharedPool<CoordArray>(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, ENTITY_POOL_POINTER_INDEX), memory.positionBits),\n\t\t\t});\n\t\t\tthis.slotPool = new SharedPool<CoordArray>(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, SLOT_POOL_POINTER_INDEX), memory.positionBits),\n\t\t\t});\n\t\t\tthis.idMap = new SharedMap<number>(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, MAP_POINTER_INDEX), memory.positionBits),\n\t\t\t});\n\t\t\tthis.bucketCount = Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t\t\tthis.maxBucketCount = this.firstBlock.data[MAX_BUCKET_COUNT_INDEX];\n\t\t\tthis.nullIndex = nullIndexFor(this.coordType);\n\t\t} else {\n\t\t\tlet gridSize = config?.gridSize ?? DEFAULT_GRID_SIZE;\n\t\t\tthis.bucketCount = Math.min(0x40000000, Math.max(1, Math.floor(config?.buckets ?? DEFAULT_BUCKET_COUNT)));\n\t\t\tlet maxEntities = config?.maxEntities ?? DEFAULT_MAX_ENTITIES;\n\t\t\tlet maxSlots = config?.maxSlots ?? maxEntities * DEFAULT_SLOTS_PER_ENTITY;\n\t\t\tthis.maxBucketCount = Math.min(\n\t\t\t\t0x40000000,\n\t\t\t\tMath.max(this.bucketCount, Math.floor(config?.maxBuckets ?? nextPowerOfTwo(maxSlots * 2))),\n\t\t\t);\n\t\t\tthis.coordType = getCoordTypeCode(config?.type);\n\t\t\tthis.nullIndex = nullIndexFor(this.coordType);\n\n\t\t\tif(this.coordType === ARRAY_TYPE.float32 && (maxEntities > FLOAT32_LIMIT || maxSlots > FLOAT32_LIMIT)) {\n\t\t\t\tthrow new Error(`Float32 SharedSpatialMap supports at most ${FLOAT32_LIMIT} entities and slots; pass type: Float64Array for more`);\n\t\t\t}\n\n\t\t\t// Inline the bucket page pointers, pools, and id-map so the stable spine is one contiguous allocation.\n\t\t\tlet entityPoolConfig: SharedPoolConfig<CoordArray> = {\n\t\t\t\ttype: getCoordTypeConstructor(this.coordType),\n\t\t\t\tdataLength: ENTITY_FIELDS,\n\t\t\t\tmaxLength: maxEntities,\n\t\t\t\tmaxChunkSize: getSpatialPoolChunkSize(maxEntities, ENTITY_FIELDS, getByteMultipler(this.coordType), memory.maxAllocationLength),\n\t\t\t};\n\t\t\tlet slotPoolConfig: SharedPoolConfig<CoordArray> = {\n\t\t\t\ttype: getCoordTypeConstructor(this.coordType),\n\t\t\t\tdataLength: SLOT_FIELDS,\n\t\t\t\tmaxLength: maxSlots,\n\t\t\t\tmaxChunkSize: getSpatialPoolChunkSize(maxSlots, SLOT_FIELDS, getByteMultipler(this.coordType), memory.maxAllocationLength),\n\t\t\t};\n\t\t\tlet entityPoolAllocateCount = SharedPool.getAllocateCount(memory, entityPoolConfig);\n\t\t\tlet slotPoolAllocateCount = SharedPool.getAllocateCount(memory, slotPoolConfig);\n\t\t\tlet mapAllocateCount = SharedMap.ALLOCATE_COUNT;\n\t\t\tlet allocateCount = SharedSpatialMap.ALLOCATE_COUNT;\n\t\t\tthis.firstBlock = memory.allocUI32(allocateCount + entityPoolAllocateCount + slotPoolAllocateCount + mapAllocateCount);\n\t\t\tthis.firstBlock.data[BUCKET_COUNT_INDEX] = this.bucketCount;\n\t\t\tthis.firstBlock.data[TYPE_INDEX] = this.coordType;\n\t\t\tthis.firstBlock.data[MAX_BUCKET_COUNT_INDEX] = this.maxBucketCount;\n\n\t\t\tlet configView = this.getConfigView();\n\t\t\tconfigView[0] = gridSize;\n\n\t\t\tthis.bucketPointers = new SharedStack(memory);\n\t\t\tstoreRawPointer(this.firstBlock.data, BUCKET_STACK_POINTER_INDEX, this.bucketPointers.pointer);\n\t\t\tthis.appendBucketSegments(this.bucketCount);\n\n\t\t\tlet entityPoolBlock = this.firstBlock.getSubAllocation(allocateCount, entityPoolAllocateCount);\n\t\t\tthis.entityPool = new SharedPool<CoordArray>(memory, { firstBlock: entityPoolBlock, ...entityPoolConfig });\n\t\t\tstoreRawPointer(this.firstBlock.data, ENTITY_POOL_POINTER_INDEX, entityPoolBlock.pointer);\n\n\t\t\tlet slotPoolBlock = this.firstBlock.getSubAllocation(allocateCount + entityPoolAllocateCount, slotPoolAllocateCount);\n\t\t\tthis.slotPool = new SharedPool<CoordArray>(memory, { firstBlock: slotPoolBlock, ...slotPoolConfig });\n\t\t\tstoreRawPointer(this.firstBlock.data, SLOT_POOL_POINTER_INDEX, slotPoolBlock.pointer);\n\n\t\t\tlet mapBlock = this.firstBlock.getSubAllocation(allocateCount + entityPoolAllocateCount + slotPoolAllocateCount, mapAllocateCount);\n\t\t\tthis.idMap = new SharedMap<number>(memory, { firstBlock: mapBlock, capacity: getSpatialMapCapacity(maxEntities, memory.maxAllocationLength) });\n\t\t\tstoreRawPointer(this.firstBlock.data, MAP_POINTER_INDEX, mapBlock.pointer);\n\t\t}\n\n\t\tthis.idLimit = this.coordType === ARRAY_TYPE.float32 ? FLOAT32_LIMIT : UINT32_LIMIT;\n\t\tthis.bucketMask = maskFor(this.bucketCount);\n\t\tthis.tableLock = new Int32Array(\n\t\t\tthis.firstBlock.data.buffer,\n\t\t\tthis.firstBlock.bufferByteOffset + TABLE_LOCK_INDEX * Uint32Array.BYTES_PER_ELEMENT,\n\t\t\t2,\n\t\t);\n\n\t\tlet configView = this.getConfigView();\n\t\tthis.cellSize = configView[0];\n\n\t}\n\n\tget pointer(): number {\n\t\treturn this.firstBlock.pointer;\n\t}\n\n\tget usedMemory(): number {\n\t\tlet total = this.firstBlock.usedMemory + this.bucketPointers.usedMemory\n\t\t\t+ this.entityPool.usedMemory + this.slotPool.usedMemory + this.idMap.usedMemory;\n\t\tfor(let pointer of this.bucketPointers) {\n\t\t\ttotal += new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits)).usedMemory;\n\t\t}\n\t\treturn total;\n\t}\n\n\tinsert(id: number, x: number, y: number, width = 0, height = 0) {\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tthis.insertLocked(id, x, y, width, height);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t\tthis.growBucketsIfNeeded();\n\t}\n\n\tbulkInsert(entities: Iterable<SpatialEntity>) {\n\t\tlet byId = new Map<number, SpatialEntity>();\n\t\tfor(let entity of entities) {\n\t\t\tthis.assertValidId(entity.id);\n\t\t\tbyId.set(entity.id, entity);\n\t\t}\n\t\tlet unique = Array.from(byId.values());\n\t\tlet existing = this.idMap.getAll(unique.map(entity => entity.id));\n\t\tlet mappings: Array<readonly [number, number]> = [];\n\t\tlet additionalSlots = 0;\n\t\tlet newCount = 0;\n\t\tfor(let i = 0; i < unique.length; i++) {\n\t\t\tif(existing[i] === undefined) {\n\t\t\t\tlet entity = unique[i];\n\t\t\t\tnewCount++;\n\t\t\t\tadditionalSlots += (this.colOf(entity.x + (entity.width ?? 0)) - this.colOf(entity.x) + 1)\n\t\t\t\t\t* (this.rowOf(entity.y + (entity.height ?? 0)) - this.rowOf(entity.y) + 1);\n\t\t\t}\n\t\t}\n\t\tthis.ensureBucketCapacity(this.slotPool.length + additionalSlots);\n\t\tlet nextEntityIndex = this.entityPool.reserveContiguous(newCount);\n\t\tlet nextSlotIndex = this.slotPool.reserveContiguous(additionalSlots);\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tfor(let i = 0; i < unique.length; i++) {\n\t\t\t\tlet entity = unique[i];\n\t\t\t\tlet width = entity.width ?? 0;\n\t\t\t\tlet height = entity.height ?? 0;\n\t\t\t\tif(existing[i] !== undefined) {\n\t\t\t\t\tthis.updateLocked(entity.id, entity.x, entity.y, width, height);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlet minCol = this.colOf(entity.x);\n\t\t\t\tlet minRow = this.rowOf(entity.y);\n\t\t\t\tlet maxCol = this.colOf(entity.x + width);\n\t\t\t\tlet maxRow = this.rowOf(entity.y + height);\n\t\t\t\tlet entityIndex = nextEntityIndex++;\n\t\t\t\tlet block = this.entityPool.blockFor(entityIndex);\n\t\t\t\tlet offset = this.entityPool.blockOffset(entityIndex);\n\t\t\t\tblock[offset + ENTITY_MIN_COL] = minCol;\n\t\t\t\tblock[offset + ENTITY_MIN_ROW] = minRow;\n\t\t\t\tblock[offset + ENTITY_MAX_COL] = maxCol;\n\t\t\t\tblock[offset + ENTITY_MAX_ROW] = maxRow;\n\t\t\t\tblock[offset + ENTITY_X] = entity.x;\n\t\t\t\tblock[offset + ENTITY_Y] = entity.y;\n\t\t\t\tblock[offset + ENTITY_WIDTH] = width;\n\t\t\t\tblock[offset + ENTITY_HEIGHT] = height;\n\t\t\t\tmappings.push([entity.id, entityIndex]);\n\t\t\t\tfor(let row = minRow; row <= maxRow; row++) {\n\t\t\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\t\t\tthis.linkReservedBucket(col, row, nextSlotIndex++, entity.id, entityIndex, minCol, minRow);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.idMap.setAll(mappings);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t\tthis.growBucketsForBulk();\n\t}\n\n\t// An out-of-range id would be stored but never found again, leaving its slots unremovable\n\tprivate assertValidId(id: number) {\n\t\tif(!Number.isInteger(id) || id < 0 || id >= this.idLimit) {\n\t\t\tthrow new Error(`SharedSpatialMap id ${id} must be an integer in [0, ${this.idLimit})`\n\t\t\t\t+ (this.coordType === ARRAY_TYPE.float32 ? '; pass type: Float64Array for ids up to 2^32 - 1' : ''));\n\t\t}\n\t}\n\n\tprivate insertLocked(id: number, x: number, y: number, width: number, height: number) {\n\t\tthis.assertValidId(id);\n\t\tif(this.idMap.get(id) !== undefined) {\n\t\t\tthis.updateLocked(id, x, y, width, height);\n\t\t\treturn;\n\t\t}\n\n\t\tlet minCol = this.colOf(x);\n\t\tlet minRow = this.rowOf(y);\n\t\tlet maxCol = this.colOf(x + width);\n\t\tlet maxRow = this.rowOf(y + height);\n\n\t\tlet entity = this.entityScratch;\n\t\tentity[ENTITY_MIN_COL] = minCol;\n\t\tentity[ENTITY_MIN_ROW] = minRow;\n\t\tentity[ENTITY_MAX_COL] = maxCol;\n\t\tentity[ENTITY_MAX_ROW] = maxRow;\n\t\tentity[ENTITY_X] = x;\n\t\tentity[ENTITY_Y] = y;\n\t\tentity[ENTITY_WIDTH] = width;\n\t\tentity[ENTITY_HEIGHT] = height;\n\t\tlet entityIndex = this.entityPool.push(entity);\n\t\tthis.idMap.set(id, entityIndex);\n\n\t\tthis.linkRange(id, entityIndex, minCol, minRow, maxCol, maxRow);\n\t}\n\n\t// Move an entity to a new position. Assumes a single writer per entity id (the standard shared-memory pattern - each\n\t// worker owns a disjoint set of entities), so this entity's record is stable until we lock its bucket(s).\n\tupdate(id: number, x: number, y: number, width = 0, height = 0) {\n\t\tlet entityIndex = this.idMap.get(id);\n\t\tif(entityIndex !== undefined) {\n\t\t\tlet block = this.entityPool.blockFor(entityIndex);\n\t\t\tlet off = this.entityPool.blockOffset(entityIndex);\n\t\t\tlet minCol = this.colOf(x);\n\t\t\tlet minRow = this.rowOf(y);\n\t\t\tlet maxCol = this.colOf(x + width);\n\t\t\tlet maxRow = this.rowOf(y + height);\n\t\t\tif(minCol === block[off + ENTITY_MIN_COL] && minRow === block[off + ENTITY_MIN_ROW]\n\t\t\t\t&& maxCol === block[off + ENTITY_MAX_COL] && maxRow === block[off + ENTITY_MAX_ROW]) {\n\t\t\t\tblock[off + ENTITY_X] = x;\n\t\t\t\tblock[off + ENTITY_Y] = y;\n\t\t\t\tblock[off + ENTITY_WIDTH] = width;\n\t\t\t\tblock[off + ENTITY_HEIGHT] = height;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tthis.updateLocked(id, x, y, width, height);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t\tthis.growBucketsIfNeeded();\n\t}\n\n\tprivate updateLocked(id: number, x: number, y: number, width: number, height: number) {\n\t\tlet entityIndex = this.idMap.get(id);\n\t\tif(entityIndex === undefined) {\n\t\t\tthis.insertLocked(id, x, y, width, height);\n\t\t\treturn;\n\t\t}\n\n\t\tlet block = this.entityPool.blockFor(entityIndex);\n\t\tlet off = this.entityPool.blockOffset(entityIndex);\n\t\tlet oldMinCol = block[off + ENTITY_MIN_COL];\n\t\tlet oldMinRow = block[off + ENTITY_MIN_ROW];\n\t\tlet oldMaxCol = block[off + ENTITY_MAX_COL];\n\t\tlet oldMaxRow = block[off + ENTITY_MAX_ROW];\n\n\t\tlet minCol = this.colOf(x);\n\t\tlet minRow = this.rowOf(y);\n\t\tlet maxCol = this.colOf(x + width);\n\t\tlet maxRow = this.rowOf(y + height);\n\n\t\t// Same cell rectangle: membership is unchanged, but neighbors still needs the new exact rectangle.\n\t\tif(minCol === oldMinCol && minRow === oldMinRow && maxCol === oldMaxCol && maxRow === oldMaxRow) {\n\t\t\tblock[off + ENTITY_X] = x;\n\t\t\tblock[off + ENTITY_Y] = y;\n\t\t\tblock[off + ENTITY_WIDTH] = width;\n\t\t\tblock[off + ENTITY_HEIGHT] = height;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.relinkRange(id, entityIndex, minCol, minRow, maxCol, maxRow, oldMinCol, oldMinRow, oldMaxCol, oldMaxRow);\n\n\t\tblock[off + ENTITY_MIN_COL] = minCol;\n\t\tblock[off + ENTITY_MIN_ROW] = minRow;\n\t\tblock[off + ENTITY_MAX_COL] = maxCol;\n\t\tblock[off + ENTITY_MAX_ROW] = maxRow;\n\t\tblock[off + ENTITY_X] = x;\n\t\tblock[off + ENTITY_Y] = y;\n\t\tblock[off + ENTITY_WIDTH] = width;\n\t\tblock[off + ENTITY_HEIGHT] = height;\n\t}\n\n\tremove(id: number): boolean {\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\treturn this.removeLocked(id);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate removeLocked(id: number): boolean {\n\t\tlet entityIndex = this.idMap.get(id);\n\t\tif(entityIndex === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet block = this.entityPool.blockFor(entityIndex);\n\t\tlet off = this.entityPool.blockOffset(entityIndex);\n\t\tthis.unlinkRange(id, block[off + ENTITY_MIN_COL], block[off + ENTITY_MIN_ROW], block[off + ENTITY_MAX_COL], block[off + ENTITY_MAX_ROW]);\n\n\t\tthis.entityPool.deleteIndex(entityIndex);\n\t\tthis.idMap.delete(id);\n\t\treturn true;\n\t}\n\n\thas(id: number): boolean {\n\t\treturn this.idMap.get(id) !== undefined;\n\t}\n\n\t// Broad-phase query: ids of every entity occupying a cell that overlaps the query rect. Each entity is returned at most\n\t// once (see the anchor-cell dedup in collectBucket); the caller does the narrow-phase overlap check.\n\tsearch(x: number, y: number, width: number, height: number, filter?: (id: number) => boolean): Array<number> {\n\t\tlet out: Array<number> = [];\n\t\tthis.searchInto(out, x, y, width, height, filter);\n\t\treturn out;\n\t}\n\t// Same as search but appends into a caller-owned array so hot loops can reuse it. Returns the array.\n\tsearchInto(out: Array<number>, x: number, y: number, width: number, height: number, filter?: (id: number) => boolean): Array<number> {\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\treturn this.searchIntoLocked(out, x, y, width, height, filter);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate searchIntoLocked(out: Array<number>, x: number, y: number, width: number, height: number, filter?: (id: number) => boolean): Array<number> {\n\t\tlet start = out.length;\n\t\tlet qMinCol = this.colOf(x);\n\t\tlet qMinRow = this.rowOf(y);\n\t\tlet qMaxCol = this.colOf(x + width);\n\t\tlet qMaxRow = this.rowOf(y + height);\n\n\t\tlet nullIndex = this.nullIndex;\n\t\tfor(let row = qMinRow; row <= qMaxRow; row++) {\n\t\t\tfor(let col = qMinCol; col <= qMaxCol; col++) {\n\t\t\t\tlet bucket = this.bucketOf(col, row);\n\t\t\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\t\t\t// Inline the empty-bucket peek (the common case) so an empty bucket never pays for a method call - most cells in\n\t\t\t\t// a typical query hash to empty buckets, so this skip dominates query cost.\n\t\t\t\tlet offset = this.bucketOffset(bucket);\n\t\t\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\t\t\tif(bucketHeads[offset + BUCKET_HEAD_OFFSET] === nullIndex) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.collectBucket(out, bucketInts, bucketHeads, offset, col, row, qMinCol, qMinRow);\n\t\t\t}\n\t\t}\n\t\tif(filter !== undefined) {\n\t\t\tlet write = start;\n\t\t\tfor(let read = start; read < out.length; read++) {\n\t\t\t\tlet id = out[read];\n\t\t\t\tif(filter(id)) {\n\t\t\t\t\tout[write++] = id;\n\t\t\t\t}\n\t\t\t}\n\t\t\tout.length = write;\n\t\t}\n\t\treturn out;\n\t}\n\n\tneighbors(x: number, y: number, maxResults: number, maxDistance: number, filter?: (id: number) => boolean): Array<number> {\n\t\treadLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\treturn this.neighborsLocked(x, y, maxResults, maxDistance, filter);\n\t\t} finally {\n\t\t\treadUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate neighborsLocked(x: number, y: number, maxResults: number, maxDistance: number, filter?: (id: number) => boolean): Array<number> {\n\t\tif(maxResults <= 0 || maxDistance < 0 || Number.isNaN(maxResults) || Number.isNaN(maxDistance)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tmaxResults = Math.floor(maxResults);\n\t\tif(maxResults === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tlet maxDistanceSquared = maxDistance * maxDistance;\n\t\tlet candidates: Array<NeighborCandidate> = [];\n\t\tif(!Number.isFinite(maxDistance)) {\n\t\t\tfor(let [id, entityIndex] of this.idMap) {\n\t\t\t\tif(filter === undefined || filter(id)) {\n\t\t\t\t\tthis.addEntityCandidate(candidates, id, entityIndex, x, y, maxResults, maxDistanceSquared);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn candidates.map(candidate => candidate.id);\n\t\t}\n\n\t\tlet cellIds: Array<number> = [];\n\t\tlet seenEntities = filter !== undefined && maxResults > 1 ? new Set<number>() : undefined;\n\t\tlet startCol = this.colOf(x);\n\t\tlet startRow = this.rowOf(y);\n\t\tlet nearest: NearestNeighbor = { id: undefined, distance: maxDistanceSquared };\n\t\tlet visit = (col: number, row: number) => {\n\t\t\tif(filter === undefined) {\n\t\t\t\tif(maxResults === 1) {\n\t\t\t\t\tthis.collectNearestBucket(nearest, col, row, x, y);\n\t\t\t\t} else {\n\t\t\t\t\tthis.collectNeighborCandidates(\n\t\t\t\t\t\tcandidates, col, row, startCol, startRow, x, y, maxResults, maxDistanceSquared,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcellIds.length = 0;\n\t\t\tthis.collectNeighborBucket(cellIds, col, row);\n\t\t\tfor(let id of cellIds) {\n\t\t\t\tif(seenEntities?.has(id)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tseenEntities?.add(id);\n\t\t\t\tlet entityIndex = this.idMap.get(id);\n\t\t\t\tif(entityIndex !== undefined && (filter === undefined || filter(id))) {\n\t\t\t\t\tif(maxResults === 1) {\n\t\t\t\t\t\tlet distance = this.entityDistanceSquared(entityIndex, x, y);\n\t\t\t\t\t\tif(distance < nearest.distance\n\t\t\t\t\t\t\t|| (distance === nearest.distance && (nearest.id === undefined || id < nearest.id))) {\n\t\t\t\t\t\t\tnearest.id = id;\n\t\t\t\t\t\t\tnearest.distance = distance;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.addEntityCandidate(candidates, id, entityIndex, x, y, maxResults, maxDistanceSquared);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tfor(let radius = 0; ; radius++) {\n\t\t\tlet limit = maxResults === 1 ? nearest.distance : candidateLimit(candidates, maxResults, maxDistanceSquared);\n\t\t\tif(this.mapRingDistanceSquared(x, y, startCol, startRow, radius) > limit) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(radius === 0) {\n\t\t\t\tvisit(startCol, startRow);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet minCol = startCol - radius;\n\t\t\tlet maxCol = startCol + radius;\n\t\t\tlet top = startRow - radius;\n\t\t\tlet bottom = startRow + radius;\n\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\tvisit(col, top);\n\t\t\t\tvisit(col, bottom);\n\t\t\t}\n\t\t\tfor(let row = top + 1; row < bottom; row++) {\n\t\t\t\tvisit(minCol, row);\n\t\t\t\tvisit(maxCol, row);\n\t\t\t}\n\t\t}\n\n\t\treturn maxResults === 1 ? nearest.id === undefined ? [] : [nearest.id] : candidates.map(candidate => candidate.id);\n\t}\n\n\tclear() {\n\t\twriteLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tfor(let segmentIndex = 0; segmentIndex < this.bucketPointers.length; segmentIndex++) {\n\t\t\t\tthis.getBucketSegment(segmentIndex << BUCKET_SEGMENT_SHIFT);\n\t\t\t\tlet heads = this.bucketHeadSegments[segmentIndex]!;\n\t\t\t\tfor(let i = BUCKET_HEAD_OFFSET; i < heads.length; i += BUCKET_SIZE) {\n\t\t\t\t\theads[i] = this.nullIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.entityPool.clear();\n\t\t\tthis.slotPool.clear();\n\t\t\tlet keys: Array<number> = [];\n\t\t\tfor(let [key] of this.idMap) {\n\t\t\t\tkeys.push(key);\n\t\t\t}\n\t\t\tfor(let key of keys) {\n\t\t\t\tthis.idMap.delete(key);\n\t\t\t}\n\t\t} finally {\n\t\t\twriteUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tfree() {\n\t\tfor(let pointer of this.bucketPointers) {\n\t\t\tnew AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits)).free();\n\t\t}\n\t\tthis.bucketPointers.free();\n\t\tthis.entityPool.free();\n\t\tthis.slotPool.free();\n\t\tthis.idMap.free();\n\t\tthis.firstBlock.free();\n\t}\n\n\tgetSharedMemory(): SharedSpatialMapMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n\n\tprivate getConfigView(): CoordArray {\n\t\treturn makeArrayView(\n\t\t\tthis.coordType,\n\t\t\tthis.firstBlock.data.buffer,\n\t\t\tthis.firstBlock.bufferByteOffset + CONFIG_INDEX * Uint32Array.BYTES_PER_ELEMENT,\n\t\t\t1,\n\t\t) as CoordArray;\n\t}\n\n\tprivate colOf(x: number): number {\n\t\treturn Math.floor(x / this.cellSize);\n\t}\n\tprivate rowOf(y: number): number {\n\t\treturn Math.floor(y / this.cellSize);\n\t}\n\tprivate mapRingDistanceSquared(x: number, y: number, centerCol: number, centerRow: number, radius: number): number {\n\t\tif(radius === 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tlet cellSize = this.cellSize;\n\t\tlet left = x - (centerCol - radius + 1) * cellSize;\n\t\tlet right = (centerCol + radius) * cellSize - x;\n\t\tlet top = y - (centerRow - radius + 1) * cellSize;\n\t\tlet bottom = (centerRow + radius) * cellSize - y;\n\t\tlet distance = Math.min(left, right, top, bottom);\n\t\treturn distance * distance;\n\t}\n\t// Hash a virtual cell to the current bucket count. The table read lock keeps this count stable for the operation.\n\tprivate bucketOf(col: number, row: number): number {\n\t\tlet hash = (Math.imul(col, HASH_PRIME_COL) ^ Math.imul(row, HASH_PRIME_ROW)) >>> 0;\n\t\tlet mask = this.bucketMask;\n\t\treturn mask >= 0 ? hash & mask : hash % this.bucketCount;\n\t}\n\n\tprivate bucketOffset(bucket: number): number {\n\t\treturn (bucket & BUCKET_SEGMENT_MASK) * BUCKET_SIZE;\n\t}\n\n\tprivate getBucketSegment(bucket: number): Int32Array {\n\t\tlet segmentIndex = bucket >>> BUCKET_SEGMENT_SHIFT;\n\t\tlet cached = this.bucketSegments[segmentIndex];\n\t\tif(cached !== undefined) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tlet pointer = this.bucketPointers.at(segmentIndex);\n\t\tlet block = new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits));\n\t\t// A segment is exactly BUCKETS_PER_SEGMENT * BUCKET_SIZE u32s. Never size the view by block.data.length: a production\n\t\t// build leaves that view unbounded (it runs to the end of the buffer), so the head-clearing loops below would write\n\t\t// across every allocation that follows this block and stomp their headers.\n\t\tlet ints = new Int32Array(block.data.buffer, block.bufferByteOffset, BUCKETS_PER_SEGMENT * BUCKET_SIZE);\n\t\tthis.bucketHeadSegments[segmentIndex] = new Uint32Array(block.data.buffer, block.bufferByteOffset, BUCKETS_PER_SEGMENT * BUCKET_SIZE);\n\t\tthis.bucketSegments[segmentIndex] = ints;\n\t\treturn ints;\n\t}\n\n\tprivate appendBucketSegments(bucketCount: number) {\n\t\tlet needed = Math.ceil(bucketCount / BUCKETS_PER_SEGMENT);\n\t\twhile(this.bucketPointers.length < needed) {\n\t\t\tlet block = this.memory.allocUI32(BUCKETS_PER_SEGMENT * BUCKET_SIZE);\n\t\t\tlet heads = new Uint32Array(block.data.buffer, block.bufferByteOffset, BUCKETS_PER_SEGMENT * BUCKET_SIZE);\n\t\t\tfor(let i = BUCKET_HEAD_OFFSET; i < heads.length; i += BUCKET_SIZE) {\n\t\t\t\theads[i] = this.nullIndex;\n\t\t\t}\n\t\t\tthis.bucketPointers.push(block.pointer);\n\t\t}\n\t}\n\n\tprivate syncBucketCount() {\n\t\tlet bucketCount = Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t\tif(bucketCount !== this.bucketCount) {\n\t\t\tthis.bucketCount = bucketCount;\n\t\t\tthis.bucketMask = maskFor(bucketCount);\n\t\t}\n\t}\n\n\tprivate growBucketsIfNeeded() {\n\t\tlet bucketCount = Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t\tif(bucketCount >= this.maxBucketCount\n\t\t\t|| this.slotPool.length * BUCKET_LOAD_DENOMINATOR <= bucketCount * BUCKET_LOAD_NUMERATOR) {\n\t\t\treturn;\n\t\t}\n\n\t\twriteLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tif(this.slotPool.length * BUCKET_LOAD_DENOMINATOR <= this.bucketCount * BUCKET_LOAD_NUMERATOR) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet newBucketCount = Math.min(this.bucketCount * 2, this.maxBucketCount);\n\t\t\tif(newBucketCount === this.bucketCount) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.resizeBuckets(newBucketCount);\n\t\t} finally {\n\t\t\twriteUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate ensureBucketCapacity(slotCount: number) {\n\t\tlet needed = Math.ceil(slotCount * BUCKET_LOAD_DENOMINATOR / BUCKET_LOAD_NUMERATOR);\n\t\tlet target = Math.min(nextPowerOfTwo(needed), this.maxBucketCount);\n\t\tif(target <= Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX)) {\n\t\t\treturn;\n\t\t}\n\t\twriteLock(this.tableLock);\n\t\ttry {\n\t\t\tthis.syncBucketCount();\n\t\t\tif(target > this.bucketCount) {\n\t\t\t\tthis.resizeBuckets(target);\n\t\t\t}\n\t\t} finally {\n\t\t\twriteUnlock(this.tableLock);\n\t\t}\n\t}\n\n\tprivate resizeBuckets(newBucketCount: number) {\n\t\tthis.appendBucketSegments(newBucketCount);\n\t\tfor(let segmentIndex = 0; segmentIndex < this.bucketPointers.length; segmentIndex++) {\n\t\t\tthis.getBucketSegment(segmentIndex << BUCKET_SEGMENT_SHIFT);\n\t\t\tlet heads = this.bucketHeadSegments[segmentIndex]!;\n\t\t\tfor(let i = BUCKET_HEAD_OFFSET; i < heads.length; i += BUCKET_SIZE) {\n\t\t\t\theads[i] = this.nullIndex;\n\t\t\t}\n\t\t}\n\n\t\tthis.bucketCount = newBucketCount;\n\t\tthis.bucketMask = maskFor(newBucketCount);\n\t\tfor(let [slotIndex, slot] of this.slotPool.entries()) {\n\t\t\tlet bucket = this.bucketOf(slot[SLOT_COL], slot[SLOT_ROW]);\n\t\t\tlet heads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\t\tlet headIndex = this.bucketOffset(bucket) + BUCKET_HEAD_OFFSET;\n\t\t\tslot[SLOT_NEXT] = heads[headIndex];\n\t\t\theads[headIndex] = slotIndex;\n\t\t}\n\t\tAtomics.store(this.firstBlock.data, BUCKET_COUNT_INDEX, newBucketCount);\n\t}\n\n\tprivate growBucketsForBulk() {\n\t\twhile(true) {\n\t\t\tlet before = Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX);\n\t\t\tthis.growBucketsIfNeeded();\n\t\t\tif(Atomics.load(this.firstBlock.data, BUCKET_COUNT_INDEX) === before) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Push one slot into each cell of the rectangle, carrying the cell's own (col, row) and the entity's top-left cell as\n\t// the dedup anchor. Every slot shares the id and anchor, so those are filled once before the loop.\n\tprivate linkRange(id: number, entityIndex: number, minCol: number, minRow: number, maxCol: number, maxRow: number) {\n\t\tlet slot = this.slotScratch;\n\t\tslot[SLOT_ID] = id;\n\t\tslot[SLOT_ANCHOR_COL] = minCol;\n\t\tslot[SLOT_ANCHOR_ROW] = minRow;\n\t\tslot[SLOT_NEXT] = this.nullIndex;\n\t\tslot[SLOT_ENTITY_INDEX] = entityIndex;\n\n\t\tfor(let row = minRow; row <= maxRow; row++) {\n\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\tthis.linkIntoBucket(col, row, slot);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Push a fresh slot for cell (col, row) - carrying the shared record in slot plus that cell's own coords - onto the\n\t// head of its bucket.\n\tprivate linkIntoBucket(col: number, row: number, slot: Array<number>) {\n\t\tslot[SLOT_COL] = col;\n\t\tslot[SLOT_ROW] = row;\n\t\tlet pool = this.slotPool;\n\t\tlet slotIndex = pool.push(slot);\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tpool.set(slotIndex, SLOT_NEXT, bucketHeads[headIndex]);\n\t\tbucketHeads[headIndex] = slotIndex;\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate linkReservedBucket(\n\t\tcol: number, row: number, slotIndex: number, id: number, entityIndex: number, anchorCol: number, anchorRow: number,\n\t) {\n\t\tlet pool = this.slotPool;\n\t\tlet block = pool.blockFor(slotIndex);\n\t\tlet slotOffset = pool.blockOffset(slotIndex);\n\t\tblock[slotOffset + SLOT_ID] = id;\n\t\tblock[slotOffset + SLOT_COL] = col;\n\t\tblock[slotOffset + SLOT_ROW] = row;\n\t\tblock[slotOffset + SLOT_ANCHOR_COL] = anchorCol;\n\t\tblock[slotOffset + SLOT_ANCHOR_ROW] = anchorRow;\n\t\tblock[slotOffset + SLOT_ENTITY_INDEX] = entityIndex;\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tblock[slotOffset + SLOT_NEXT] = bucketHeads[headIndex];\n\t\tbucketHeads[headIndex] = slotIndex;\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\t// Move an entity's slots from its old cell rectangle to a new one, touching only the cells that actually change. A cell\n\t// in both rectangles keeps its slot and just gets its anchor refreshed; new-only cells are linked before old-only cells\n\t// are unlinked, so a query racing the move never sees the entity in neither rectangle. Doing it this way (rather than\n\t// linkRange(new) + unlinkRange(old)) is what keeps overlap cells correct: unlinkFromBucket matches by id + cell and\n\t// would splice out the freshly linked slot in an overlap cell, leaving the stale one behind and corrupting the anchor.\n\tprivate relinkRange(id: number, entityIndex: number, minCol: number, minRow: number, maxCol: number, maxRow: number, oldMinCol: number, oldMinRow: number, oldMaxCol: number, oldMaxRow: number) {\n\t\tlet ovMinCol = minCol > oldMinCol ? minCol : oldMinCol;\n\t\tlet ovMaxCol = maxCol < oldMaxCol ? maxCol : oldMaxCol;\n\t\tlet ovMinRow = minRow > oldMinRow ? minRow : oldMinRow;\n\t\tlet ovMaxRow = maxRow < oldMaxRow ? maxRow : oldMaxRow;\n\t\tlet hasOverlap = ovMinCol <= ovMaxCol && ovMinRow <= ovMaxRow;\n\n\t\tlet slot = this.slotScratch;\n\t\tslot[SLOT_ID] = id;\n\t\tslot[SLOT_ANCHOR_COL] = minCol;\n\t\tslot[SLOT_ANCHOR_ROW] = minRow;\n\t\tslot[SLOT_NEXT] = this.nullIndex;\n\t\tslot[SLOT_ENTITY_INDEX] = entityIndex;\n\n\t\tfor(let row = minRow; row <= maxRow; row++) {\n\t\t\tlet inOverlapRow = hasOverlap && row >= ovMinRow && row <= ovMaxRow;\n\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\tif(inOverlapRow && col >= ovMinCol && col <= ovMaxCol) {\n\t\t\t\t\tthis.refreshAnchorInBucket(this.bucketOf(col, row), id, col, row, minCol, minRow);\n\t\t\t\t} else {\n\t\t\t\t\tthis.linkIntoBucket(col, row, slot);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet pool = this.slotPool;\n\t\tfor(let row = oldMinRow; row <= oldMaxRow; row++) {\n\t\t\tlet inOverlapRow = hasOverlap && row >= ovMinRow && row <= ovMaxRow;\n\t\t\tfor(let col = oldMinCol; col <= oldMaxCol; col++) {\n\t\t\t\tif(inOverlapRow && col >= ovMinCol && col <= ovMaxCol) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlet slotIndex = this.unlinkFromBucket(this.bucketOf(col, row), id, col, row);\n\t\t\t\tif(slotIndex !== nullIndex) {\n\t\t\t\t\tpool.deleteIndex(slotIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Refresh the anchor on this entity's slot already linked for cell (col, row) (single writer per id, so it is present).\n\tprivate refreshAnchorInBucket(bucket: number, id: number, col: number, row: number, anchorCol: number, anchorRow: number) {\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet pool = this.slotPool;\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet index = bucketHeads[offset + BUCKET_HEAD_OFFSET];\n\t\twhile(index !== nullIndex) {\n\t\t\tlet block = pool.blockFor(index);\n\t\t\tlet off = pool.blockOffset(index);\n\t\t\tif(block[off + SLOT_ID] === id && block[off + SLOT_COL] === col && block[off + SLOT_ROW] === row) {\n\t\t\t\tblock[off + SLOT_ANCHOR_COL] = anchorCol;\n\t\t\t\tblock[off + SLOT_ANCHOR_ROW] = anchorRow;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tindex = block[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\t// Remove and recycle this entity's slot from each cell of the rectangle.\n\tprivate unlinkRange(id: number, minCol: number, minRow: number, maxCol: number, maxRow: number) {\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet pool = this.slotPool;\n\t\tfor(let row = minRow; row <= maxRow; row++) {\n\t\t\tfor(let col = minCol; col <= maxCol; col++) {\n\t\t\t\tlet slotIndex = this.unlinkFromBucket(this.bucketOf(col, row), id, col, row);\n\t\t\t\tif(slotIndex !== nullIndex) {\n\t\t\t\t\tpool.deleteIndex(slotIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Caller has already peeked the head unlocked and skipped empty buckets (an empty bucket has nothing to read, so the\n\t// lock and its atomics would be pure overhead). Taking the lock only to walk a non-empty bucket preserves the snapshot\n\t// guarantee - a concurrent insert we race is simply not in this snapshot.\n\tprivate collectBucket(\n\t\tout: Array<number>, bucketInts: Int32Array, bucketHeads: Uint32Array, offset: number,\n\t\tcol: number, row: number, qMinCol: number, qMinRow: number,\n\t) {\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet index = bucketHeads[headIndex];\n\t\tlet pool = this.slotPool;\n\t\twhile(index !== nullIndex) {\n\t\t\t// One chunk resolve per slot covers every field it reads\n\t\t\tlet block = pool.blockFor(index);\n\t\t\tlet off = pool.blockOffset(index);\n\t\t\t// Other cells hash to this bucket too; only slots living in the cell being queried count.\n\t\t\tif(block[off + SLOT_COL] === col && block[off + SLOT_ROW] === row) {\n\t\t\t\t// Emit only from the entity's top-left cell that intersects this query, so a multi-cell entity is returned once.\n\t\t\t\tlet anchorCol = block[off + SLOT_ANCHOR_COL];\n\t\t\t\tlet anchorRow = block[off + SLOT_ANCHOR_ROW];\n\t\t\t\tlet tlCol = anchorCol > qMinCol ? anchorCol : qMinCol;\n\t\t\t\tlet tlRow = anchorRow > qMinRow ? anchorRow : qMinRow;\n\t\t\t\tif(col === tlCol && row === tlRow) {\n\t\t\t\t\tout.push(block[off + SLOT_ID]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tindex = block[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate collectNeighborBucket(out: Array<number>, col: number, row: number) {\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tif(bucketHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet index = bucketHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet block = this.slotPool.blockFor(index);\n\t\t\tlet off = this.slotPool.blockOffset(index);\n\t\t\tif(block[off + SLOT_COL] === col && block[off + SLOT_ROW] === row) {\n\t\t\t\tout.push(block[off + SLOT_ID]);\n\t\t\t}\n\t\t\tindex = block[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate collectNearestBucket(\n\t\tnearest: NearestNeighbor, col: number, row: number, x: number, y: number,\n\t) {\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tif(bucketHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet index = bucketHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet slot = this.slotPool.blockFor(index);\n\t\t\tlet off = this.slotPool.blockOffset(index);\n\t\t\tif(slot[off + SLOT_COL] === col && slot[off + SLOT_ROW] === row) {\n\t\t\t\tlet entityIndex = slot[off + SLOT_ENTITY_INDEX];\n\t\t\t\tlet entity = this.entityPool.blockFor(entityIndex);\n\t\t\t\tlet entityOffset = this.entityPool.blockOffset(entityIndex);\n\t\t\t\tlet id = slot[off + SLOT_ID];\n\t\t\t\tlet distance = this.entityBlockDistanceSquared(entity, entityOffset, x, y);\n\t\t\t\tif(distance < nearest.distance\n\t\t\t\t\t|| (distance === nearest.distance && (nearest.id === undefined || id < nearest.id))) {\n\t\t\t\t\tnearest.id = id;\n\t\t\t\t\tnearest.distance = distance;\n\t\t\t\t}\n\t\t\t}\n\t\t\tindex = slot[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate collectNeighborCandidates(\n\t\tcandidates: Array<NeighborCandidate>, col: number, row: number, queryCol: number, queryRow: number,\n\t\tx: number, y: number, maxResults: number, maxDistanceSquared: number,\n\t) {\n\t\tlet bucket = this.bucketOf(col, row);\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tif(bucketHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet index = bucketHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet slot = this.slotPool.blockFor(index);\n\t\t\tlet off = this.slotPool.blockOffset(index);\n\t\t\tif(slot[off + SLOT_COL] === col && slot[off + SLOT_ROW] === row) {\n\t\t\t\tlet entityIndex = slot[off + SLOT_ENTITY_INDEX];\n\t\t\t\tlet entity = this.entityPool.blockFor(entityIndex);\n\t\t\t\tlet entityOffset = this.entityPool.blockOffset(entityIndex);\n\t\t\t\tlet minCol = entity[entityOffset + ENTITY_MIN_COL];\n\t\t\t\tlet maxCol = entity[entityOffset + ENTITY_MAX_COL];\n\t\t\t\tlet minRow = entity[entityOffset + ENTITY_MIN_ROW];\n\t\t\t\tlet maxRow = entity[entityOffset + ENTITY_MAX_ROW];\n\t\t\t\tlet nearestCol = queryCol < minCol ? minCol : queryCol > maxCol ? maxCol : queryCol;\n\t\t\t\tlet nearestRow = queryRow < minRow ? minRow : queryRow > maxRow ? maxRow : queryRow;\n\t\t\t\tif(col === nearestCol && row === nearestRow) {\n\t\t\t\t\tlet distance = this.entityBlockDistanceSquared(entity, entityOffset, x, y);\n\t\t\t\t\tif(distance <= maxDistanceSquared) {\n\t\t\t\t\t\taddCandidate(candidates, slot[off + SLOT_ID], distance, maxResults);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tindex = slot[off + SLOT_NEXT];\n\t\t}\n\t\tunlock(bucketInts, lockIndex);\n\t}\n\n\tprivate addEntityCandidate(candidates: Array<NeighborCandidate>, id: number, entityIndex: number, x: number, y: number, maxResults: number, maxDistanceSquared: number) {\n\t\tlet distance = this.entityDistanceSquared(entityIndex, x, y);\n\t\tif(distance <= maxDistanceSquared) {\n\t\t\taddCandidate(candidates, id, distance, maxResults);\n\t\t}\n\t}\n\n\tprivate entityDistanceSquared(entityIndex: number, x: number, y: number): number {\n\t\tlet entity = this.entityPool.blockFor(entityIndex);\n\t\tlet off = this.entityPool.blockOffset(entityIndex);\n\t\treturn this.entityBlockDistanceSquared(entity, off, x, y);\n\t}\n\n\tprivate entityBlockDistanceSquared(entity: CoordArray, off: number, x: number, y: number): number {\n\t\tlet minX = entity[off + ENTITY_X];\n\t\tlet minY = entity[off + ENTITY_Y];\n\t\treturn distanceSquaredToRect(\n\t\t\tx, y, minX, minY, minX + entity[off + ENTITY_WIDTH], minY + entity[off + ENTITY_HEIGHT],\n\t\t);\n\t}\n\n\t// Splice this entity's slot for exactly cell (col, row) out of the bucket and return its index (nullIndex if absent).\n\t// Matching on id and cell is required: two of an entity's own cells can hash to the same bucket, so id alone is ambiguous.\n\tprivate unlinkFromBucket(bucket: number, id: number, col: number, row: number): number {\n\t\tlet nullIndex = this.nullIndex;\n\t\tlet bucketInts = this.getBucketSegment(bucket);\n\t\tlet bucketHeads = this.bucketHeadSegments[bucket >>> BUCKET_SEGMENT_SHIFT]!;\n\t\tlet offset = this.bucketOffset(bucket);\n\t\tlet lockIndex = offset + BUCKET_LOCK_OFFSET;\n\t\tlock(bucketInts, lockIndex);\n\t\tlet headIndex = offset + BUCKET_HEAD_OFFSET;\n\t\tlet pool = this.slotPool;\n\n\t\tlet prev = nullIndex;\n\t\tlet index = bucketHeads[headIndex];\n\t\twhile(index !== nullIndex) {\n\t\t\t// One chunk resolve per slot covers every field it reads\n\t\t\tlet block = pool.blockFor(index);\n\t\t\tlet off = pool.blockOffset(index);\n\t\t\tlet next = block[off + SLOT_NEXT];\n\t\t\tif(block[off + SLOT_ID] === id && block[off + SLOT_COL] === col && block[off + SLOT_ROW] === row) {\n\t\t\t\tif(prev === nullIndex) {\n\t\t\t\t\tbucketHeads[headIndex] = next;\n\t\t\t\t} else {\n\t\t\t\t\tpool.set(prev, SLOT_NEXT, next);\n\t\t\t\t}\n\t\t\t\tunlock(bucketInts, lockIndex);\n\t\t\t\treturn index;\n\t\t\t}\n\t\t\tprev = index;\n\t\t\tindex = next;\n\t\t}\n\n\t\tunlock(bucketInts, lockIndex);\n\t\treturn nullIndex;\n\t}\n}\n\nfunction getCoordTypeCode(type: CoordArrayConstructor | undefined): number {\n\tlet code = getArrayTypeCode(type ?? DEFAULT_COORD_TYPE);\n\tif(code !== ARRAY_TYPE.float32 && code !== ARRAY_TYPE.float64) {\n\t\tthrow new Error('SharedSpatialMap must be Float32Array or Float64Array');\n\t}\n\treturn code;\n}\nfunction getCoordTypeConstructor(typeCode: number): CoordArrayConstructor {\n\treturn getByteMultipler(typeCode) === 2 ? Float64Array : Float32Array;\n}\nfunction nullIndexFor(typeCode: number): number {\n\treturn typeCode === ARRAY_TYPE.float32 ? FLOAT32_NULL_INDEX : FLOAT64_NULL_INDEX;\n}\nfunction maskFor(bucketCount: number): number {\n\treturn (bucketCount & (bucketCount - 1)) === 0 ? bucketCount - 1 : -1;\n}\nfunction nextPowerOfTwo(value: number): number {\n\treturn Math.pow(2, Math.ceil(Math.log2(Math.max(1, value))));\n}\n\ninterface SharedSpatialMapConfig {\n\tgridSize?: number\n\tbuckets?: number\n\tmaxBuckets?: number\n\tmaxEntities?: number\n\tmaxSlots?: number\n\ttype?: CoordArrayConstructor\n}\ninterface SharedSpatialMapMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedSpatialMapConfig, SharedSpatialMapMemory, SpatialEntity };\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-entity.js","names":[],"sources":["../../src/spatial/spatial-entity.ts"],"sourcesContent":["interface SpatialEntity {\n\tid: number\n\tx: number\n\ty: number\n\twidth?: number\n\theight?: number\n}\n\nconst DEFAULT_POOL_CHUNK_SIZE = 100;\nconst MAX_PACKED_POOL_LENGTH = 16_384;\n\nfunction getSpatialPoolChunkSize(maxLength: number, fields: number, byteMultiplier: number, maxAllocationLength: number): number {\n\tif(maxLength < DEFAULT_POOL_CHUNK_SIZE || maxLength > MAX_PACKED_POOL_LENGTH) {\n\t\treturn DEFAULT_POOL_CHUNK_SIZE;\n\t}\n\tlet allocationLimit = Math.floor(maxAllocationLength / (fields * byteMultiplier));\n\treturn Math.max(1, Math.min(maxLength, allocationLimit));\n}\n\nfunction getSpatialMapCapacity(maxEntities: number, maxAllocationLength: number): number {\n\tif(maxEntities > MAX_PACKED_POOL_LENGTH) {\n\t\treturn 16;\n\t}\n\tlet needed = Math.ceil(maxEntities * 4 / 3);\n\tlet capacity = 16;\n\twhile(capacity < needed) {\n\t\tcapacity *= 2;\n\t}\n\tlet allocationLimit = 16;\n\twhile(allocationLimit * 2 * 3 <= maxAllocationLength) {\n\t\tallocationLimit *= 2;\n\t}\n\treturn Math.min(capacity, allocationLimit);\n}\n\nexport { getSpatialMapCapacity, getSpatialPoolChunkSize };\nexport type { SpatialEntity };\n"],"mappings":";AAQA,
|
|
1
|
+
{"version":3,"file":"spatial-entity.js","names":["MAX_PACKED_POOL_LENGTH","getSpatialPoolChunkSize","maxLength","allocationLimit","maxAllocationLength","fields","byteMultiplier","getSpatialMapCapacity","maxEntities","needed","capacity"],"sources":["../../src/spatial/spatial-entity.ts"],"sourcesContent":["interface SpatialEntity {\n\tid: number\n\tx: number\n\ty: number\n\twidth?: number\n\theight?: number\n}\n\nconst DEFAULT_POOL_CHUNK_SIZE = 100;\nconst MAX_PACKED_POOL_LENGTH = 16_384;\n\nfunction getSpatialPoolChunkSize(maxLength: number, fields: number, byteMultiplier: number, maxAllocationLength: number): number {\n\tif(maxLength < DEFAULT_POOL_CHUNK_SIZE || maxLength > MAX_PACKED_POOL_LENGTH) {\n\t\treturn DEFAULT_POOL_CHUNK_SIZE;\n\t}\n\tlet allocationLimit = Math.floor(maxAllocationLength / (fields * byteMultiplier));\n\treturn Math.max(1, Math.min(maxLength, allocationLimit));\n}\n\nfunction getSpatialMapCapacity(maxEntities: number, maxAllocationLength: number): number {\n\tif(maxEntities > MAX_PACKED_POOL_LENGTH) {\n\t\treturn 16;\n\t}\n\tlet needed = Math.ceil(maxEntities * 4 / 3);\n\tlet capacity = 16;\n\twhile(capacity < needed) {\n\t\tcapacity *= 2;\n\t}\n\tlet allocationLimit = 16;\n\twhile(allocationLimit * 2 * 3 <= maxAllocationLength) {\n\t\tallocationLimit *= 2;\n\t}\n\treturn Math.min(capacity, allocationLimit);\n}\n\nexport { getSpatialMapCapacity, getSpatialPoolChunkSize };\nexport type { SpatialEntity };\n"],"mappings":";AAQA,IACMA,IAAyB;AAE/B,SAASC,EAAwB,GAAmB,GAAgB,GAAwB,GAAqC;CAChI,IAAGC,IAAY,OAA2BA,IAAYF,GACrD,OAAO;CAER,IAAIG,IAAkB,KAAK,MAAMC,KAAuBC,IAASC,EAAe;CAChF,OAAO,KAAK,IAAI,GAAG,KAAK,IAAIJ,GAAWC,CAAe,CAAC;AACxD;AAEA,SAASI,EAAsB,GAAqB,GAAqC;CACxF,IAAGC,IAAcR,GAChB,OAAO;CAER,IAAIS,IAAS,KAAK,KAAKD,IAAc,IAAI,CAAC,GACtCE,IAAW;CACf,OAAMA,IAAWD,IAChB,KAAY;CAEb,IAAIN,IAAkB;CACtB,OAAMA,IAAkB,IAAI,KAAKC,IAChC,KAAmB;CAEpB,OAAO,KAAK,IAAIM,GAAUP,CAAe;AAC1C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-neighbors.js","names":[],"sources":["../../src/spatial/spatial-neighbors.ts"],"sourcesContent":["interface NeighborCandidate {\n\tid: number\n\tdistance: number\n}\n\ninterface NearestNeighbor {\n\tid: number | undefined\n\tdistance: number\n}\n\nclass MinPriorityQueue<T> {\n\tprivate values: Array<T> = [];\n\tprivate priorities: Array<number> = [];\n\n\tget length(): number {\n\t\treturn this.values.length;\n\t}\n\n\tget priority(): number {\n\t\treturn this.priorities[0] ?? Infinity;\n\t}\n\n\tpush(value: T, priority: number) {\n\t\tlet index = this.values.length;\n\t\tthis.values.push(value);\n\t\tthis.priorities.push(priority);\n\t\twhile(index > 0) {\n\t\t\tlet parent = (index - 1) >> 1;\n\t\t\tif(this.priorities[parent] <= priority) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.values[index] = this.values[parent];\n\t\t\tthis.priorities[index] = this.priorities[parent];\n\t\t\tindex = parent;\n\t\t}\n\t\tthis.values[index] = value;\n\t\tthis.priorities[index] = priority;\n\t}\n\n\tpop(): T | undefined {\n\t\tlet root = this.values[0];\n\t\tlet lastValue = this.values.pop();\n\t\tlet lastPriority = this.priorities.pop();\n\t\tif(this.values.length === 0 || lastValue === undefined || lastPriority === undefined) {\n\t\t\treturn root;\n\t\t}\n\n\t\tlet index = 0;\n\t\twhile(true) {\n\t\t\tlet left = index * 2 + 1;\n\t\t\tif(left >= this.values.length) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlet right = left + 1;\n\t\t\tlet child = right < this.values.length && this.priorities[right] < this.priorities[left] ? right : left;\n\t\t\tif(this.priorities[child] >= lastPriority) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.values[index] = this.values[child];\n\t\t\tthis.priorities[index] = this.priorities[child];\n\t\t\tindex = child;\n\t\t}\n\t\tthis.values[index] = lastValue;\n\t\tthis.priorities[index] = lastPriority;\n\t\treturn root;\n\t}\n}\n\nfunction distanceSquaredToRect(x: number, y: number, minX: number, minY: number, maxX: number, maxY: number): number {\n\tlet dx = Math.max(minX - x, x - maxX, 0);\n\tlet dy = Math.max(minY - y, y - maxY, 0);\n\treturn dx * dx + dy * dy;\n}\n\nfunction addCandidate(candidates: Array<NeighborCandidate>, id: number, distance: number, maxResults: number) {\n\tlet low = 0;\n\tlet high = candidates.length;\n\twhile(low < high) {\n\t\tlet mid = (low + high) >> 1;\n\t\tlet candidate = candidates[mid];\n\t\tif(candidate.distance < distance || (candidate.distance === distance && candidate.id < id)) {\n\t\t\tlow = mid + 1;\n\t\t} else {\n\t\t\thigh = mid;\n\t\t}\n\t}\n\tif(low < maxResults) {\n\t\tcandidates.splice(low, 0, { id, distance });\n\t\tif(candidates.length > maxResults) {\n\t\t\tcandidates.pop();\n\t\t}\n\t}\n}\n\nfunction candidateLimit(candidates: Array<NeighborCandidate>, maxResults: number, maxDistanceSquared: number): number {\n\treturn candidates.length === maxResults ? Math.min(maxDistanceSquared, candidates[candidates.length - 1].distance) : maxDistanceSquared;\n}\n\nexport { MinPriorityQueue, addCandidate, candidateLimit, distanceSquaredToRect };\nexport type { NeighborCandidate, NearestNeighbor };\n"],"mappings":";AAUA,
|
|
1
|
+
{"version":3,"file":"spatial-neighbors.js","names":["MinPriorityQueue","index","value","priority","parent","root","lastValue","lastPriority","left","right","child","distanceSquaredToRect","dx","minX","x","maxX","dy","minY","y","maxY","addCandidate","low","high","candidates","mid","candidate","distance","id","maxResults","candidateLimit","maxDistanceSquared"],"sources":["../../src/spatial/spatial-neighbors.ts"],"sourcesContent":["interface NeighborCandidate {\n\tid: number\n\tdistance: number\n}\n\ninterface NearestNeighbor {\n\tid: number | undefined\n\tdistance: number\n}\n\nclass MinPriorityQueue<T> {\n\tprivate values: Array<T> = [];\n\tprivate priorities: Array<number> = [];\n\n\tget length(): number {\n\t\treturn this.values.length;\n\t}\n\n\tget priority(): number {\n\t\treturn this.priorities[0] ?? Infinity;\n\t}\n\n\tpush(value: T, priority: number) {\n\t\tlet index = this.values.length;\n\t\tthis.values.push(value);\n\t\tthis.priorities.push(priority);\n\t\twhile(index > 0) {\n\t\t\tlet parent = (index - 1) >> 1;\n\t\t\tif(this.priorities[parent] <= priority) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.values[index] = this.values[parent];\n\t\t\tthis.priorities[index] = this.priorities[parent];\n\t\t\tindex = parent;\n\t\t}\n\t\tthis.values[index] = value;\n\t\tthis.priorities[index] = priority;\n\t}\n\n\tpop(): T | undefined {\n\t\tlet root = this.values[0];\n\t\tlet lastValue = this.values.pop();\n\t\tlet lastPriority = this.priorities.pop();\n\t\tif(this.values.length === 0 || lastValue === undefined || lastPriority === undefined) {\n\t\t\treturn root;\n\t\t}\n\n\t\tlet index = 0;\n\t\twhile(true) {\n\t\t\tlet left = index * 2 + 1;\n\t\t\tif(left >= this.values.length) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlet right = left + 1;\n\t\t\tlet child = right < this.values.length && this.priorities[right] < this.priorities[left] ? right : left;\n\t\t\tif(this.priorities[child] >= lastPriority) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.values[index] = this.values[child];\n\t\t\tthis.priorities[index] = this.priorities[child];\n\t\t\tindex = child;\n\t\t}\n\t\tthis.values[index] = lastValue;\n\t\tthis.priorities[index] = lastPriority;\n\t\treturn root;\n\t}\n}\n\nfunction distanceSquaredToRect(x: number, y: number, minX: number, minY: number, maxX: number, maxY: number): number {\n\tlet dx = Math.max(minX - x, x - maxX, 0);\n\tlet dy = Math.max(minY - y, y - maxY, 0);\n\treturn dx * dx + dy * dy;\n}\n\nfunction addCandidate(candidates: Array<NeighborCandidate>, id: number, distance: number, maxResults: number) {\n\tlet low = 0;\n\tlet high = candidates.length;\n\twhile(low < high) {\n\t\tlet mid = (low + high) >> 1;\n\t\tlet candidate = candidates[mid];\n\t\tif(candidate.distance < distance || (candidate.distance === distance && candidate.id < id)) {\n\t\t\tlow = mid + 1;\n\t\t} else {\n\t\t\thigh = mid;\n\t\t}\n\t}\n\tif(low < maxResults) {\n\t\tcandidates.splice(low, 0, { id, distance });\n\t\tif(candidates.length > maxResults) {\n\t\t\tcandidates.pop();\n\t\t}\n\t}\n}\n\nfunction candidateLimit(candidates: Array<NeighborCandidate>, maxResults: number, maxDistanceSquared: number): number {\n\treturn candidates.length === maxResults ? Math.min(maxDistanceSquared, candidates[candidates.length - 1].distance) : maxDistanceSquared;\n}\n\nexport { MinPriorityQueue, addCandidate, candidateLimit, distanceSquaredToRect };\nexport type { NeighborCandidate, NearestNeighbor };\n"],"mappings":";AAUA,IAAMA,IAAN,MAA0B;CACzB,SAA2B,CAAC;CAC5B,aAAoC,CAAC;CAErC,IAAI,SAAiB;EACpB,OAAO,KAAK,OAAO;CACpB;CAEA,IAAI,WAAmB;EACtB,OAAO,KAAK,WAAW,MAAM;CAC9B;CAEA,KAAK,GAAU,GAAkB;EAChC,IAAIC,IAAQ,KAAK,OAAO;EAGxB,KAFA,KAAK,OAAO,KAAKC,CAAK,GACtB,KAAK,WAAW,KAAKC,CAAQ,GACvBF,IAAQ,IAAG;GAChB,IAAIG,IAAUH,IAAQ,KAAM;GAC5B,IAAG,KAAK,WAAWG,MAAWD,GAC7B;GAID,AAFA,KAAK,OAAOF,KAAS,KAAK,OAAOG,IACjC,KAAK,WAAWH,KAAS,KAAK,WAAWG,IACzC,IAAQA;EACT;EAEA,AADA,KAAK,OAAOH,KAASC,GACrB,KAAK,WAAWD,KAASE;CAC1B;CAEA,MAAqB;EACpB,IAAIE,IAAO,KAAK,OAAO,IACnBC,IAAY,KAAK,OAAO,IAAI,GAC5BC,IAAe,KAAK,WAAW,IAAI;EACvC,IAAG,KAAK,OAAO,WAAW,KAAKD,MAAc,KAAA,KAAaC,MAAiB,KAAA,GAC1E,OAAOF;EAGR,IAAIJ,IAAQ;EACZ,SAAY;GACX,IAAIO,IAAOP,IAAQ,IAAI;GACvB,IAAGO,KAAQ,KAAK,OAAO,QACtB;GAED,IAAIC,IAAQD,IAAO,GACfE,IAAQD,IAAQ,KAAK,OAAO,UAAU,KAAK,WAAWA,KAAS,KAAK,WAAWD,KAAQC,IAAQD;GACnG,IAAG,KAAK,WAAWE,MAAUH,GAC5B;GAID,AAFA,KAAK,OAAON,KAAS,KAAK,OAAOS,IACjC,KAAK,WAAWT,KAAS,KAAK,WAAWS,IACzC,IAAQA;EACT;EAGA,OAFA,KAAK,OAAOT,KAASK,GACrB,KAAK,WAAWL,KAASM,GAClBF;CACR;AACD;AAEA,SAASM,EAAsB,GAAW,GAAW,GAAc,GAAc,GAAc,GAAsB;CACpH,IAAIC,IAAK,KAAK,IAAIC,IAAOC,GAAGA,IAAIC,GAAM,CAAC,GACnCC,IAAK,KAAK,IAAIC,IAAOC,GAAGA,IAAIC,GAAM,CAAC;CACvC,OAAOP,IAAKA,IAAKI,IAAKA;AACvB;AAEA,SAASI,EAAa,GAAsC,GAAY,GAAkB,GAAoB;CAC7G,IAAIC,IAAM,GACNC,IAAOC,EAAW;CACtB,OAAMF,IAAMC,IAAM;EACjB,IAAIE,IAAOH,IAAMC,KAAS,GACtBG,IAAYF,EAAWC;EAC3B,AAAGC,EAAU,WAAWC,KAAaD,EAAU,aAAaC,KAAYD,EAAU,KAAKE,IACtF,IAAMH,IAAM,IAEZ,IAAOA;CAET;CACA,AAAGH,IAAMO,MACRL,EAAW,OAAOF,GAAK,GAAG;EAAE;EAAI;CAAS,CAAC,GACvCE,EAAW,SAASK,KACtBL,EAAW,IAAI;AAGlB;AAEA,SAASM,EAAe,GAAsC,GAAoB,GAAoC;CACrH,OAAON,EAAW,WAAWK,IAAa,KAAK,IAAIE,GAAoBP,EAAWA,EAAW,SAAS,EAAE,CAAC,QAAQ,IAAIO;AACtH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"16-from-32-float.js","names":[],"sources":["../../src/utils/16-from-32-float.ts"],"sourcesContent":["const buffer = new ArrayBuffer(4);\nconst float32Array = new Float32Array(buffer);\nconst int32Array = new Int32Array(buffer);\nconst float16Array = new Float16Array(buffer);\n\nexport function load16From32Float(data: Float32Array, index: number): [number, number] {\n\tconst atomicData = new Int32Array(data.buffer, data.byteOffset, data.length);\n\tint32Array[0] = Atomics.load(atomicData, index);\n\treturn [float16Array[0], float16Array[1]];\n}\n\nexport function store16In32Float(data: Float32Array, index: number, value1: number, value2: number) {\n\tconst atomicData = new Int32Array(data.buffer, data.byteOffset, data.length);\n\tfloat16Array[0] = value1;\n\tfloat16Array[1] = value2;\n\tAtomics.store(atomicData, index, int32Array[0]);\n}\n\nexport function convert32To16Float(value: number): [number, number] {\n\tfloat32Array[0] = value;\n\treturn [float16Array[0], float16Array[1]];\n}\n\nexport function convert16To32Float(value1: number, value2: number): number {\n\tfloat16Array[0] = value1;\n\tfloat16Array[1] = value2;\n\treturn float32Array[0];\n}\n"],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"16-from-32-float.js","names":["buffer","float32Array","int32Array","float16Array","load16From32Float","atomicData","data","index","store16In32Float","value1","value2","convert32To16Float","value","convert16To32Float"],"sources":["../../src/utils/16-from-32-float.ts"],"sourcesContent":["const buffer = new ArrayBuffer(4);\nconst float32Array = new Float32Array(buffer);\nconst int32Array = new Int32Array(buffer);\nconst float16Array = new Float16Array(buffer);\n\nexport function load16From32Float(data: Float32Array, index: number): [number, number] {\n\tconst atomicData = new Int32Array(data.buffer, data.byteOffset, data.length);\n\tint32Array[0] = Atomics.load(atomicData, index);\n\treturn [float16Array[0], float16Array[1]];\n}\n\nexport function store16In32Float(data: Float32Array, index: number, value1: number, value2: number) {\n\tconst atomicData = new Int32Array(data.buffer, data.byteOffset, data.length);\n\tfloat16Array[0] = value1;\n\tfloat16Array[1] = value2;\n\tAtomics.store(atomicData, index, int32Array[0]);\n}\n\nexport function convert32To16Float(value: number): [number, number] {\n\tfloat32Array[0] = value;\n\treturn [float16Array[0], float16Array[1]];\n}\n\nexport function convert16To32Float(value1: number, value2: number): number {\n\tfloat16Array[0] = value1;\n\tfloat16Array[1] = value2;\n\treturn float32Array[0];\n}\n"],"mappings":";AAAA,IAAMA,oBAAS,IAAI,YAAY,CAAC,GAC1BC,IAAe,IAAI,aAAaD,CAAM,GACtCE,IAAa,IAAI,WAAWF,CAAM,GAClCG,IAAe,IAAI,aAAaH,CAAM;AAE5C,SAAgBI,EAAkB,GAAoB,GAAiC;CACtF,IAAMC,IAAa,IAAI,WAAWC,EAAK,QAAQA,EAAK,YAAYA,EAAK,MAAM;CAE3E,OADA,EAAW,KAAK,QAAQ,KAAKD,GAAYE,CAAK,GACvC,CAACJ,EAAa,IAAIA,EAAa,EAAE;AACzC;AAEA,SAAgBK,EAAiB,GAAoB,GAAe,GAAgB,GAAgB;CACnG,IAAMH,IAAa,IAAI,WAAWC,EAAK,QAAQA,EAAK,YAAYA,EAAK,MAAM;CAG3E,AAFA,EAAa,KAAKG,GAClB,EAAa,KAAKC,GAClB,QAAQ,MAAML,GAAYE,GAAOL,EAAW,EAAE;AAC/C;AAEA,SAAgBS,EAAmB,GAAiC;CAEnE,OADA,EAAa,KAAKC,GACX,CAACT,EAAa,IAAIA,EAAa,EAAE;AACzC;AAEA,SAAgBU,EAAmB,GAAgB,GAAwB;CAG1E,OAFA,EAAa,KAAKJ,GAClB,EAAa,KAAKC,GACXT,EAAa;AACrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"16-from-32-int.js","names":[],"sources":["../../src/utils/16-from-32-int.ts"],"sourcesContent":["const buffer = new ArrayBuffer(4);\nconst int32Array = new Int32Array(buffer);\nconst int16Array = new Int16Array(buffer);\n\nexport function load16From32Int(data: Int32Array, index: number): [number, number] {\n\treturn convert32To16Int(Atomics.load(data, index));\n}\n\nexport function store16In32Int(data: Int32Array, index: number, value1: number, value2: number) {\n\tAtomics.store(data, index, convert16To32Int(value1, value2));\n}\n\nexport function convert32To16Int(value: number): [number, number] {\n\tint32Array[0] = value;\n\n\treturn [int16Array[0], int16Array[1]];\n}\n\nexport function convert16To32Int(value1: number, value2: number): number {\n\tint16Array[0] = value1;\n\tint16Array[1] = value2;\n\n\treturn int32Array[0];\n}\n"],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"16-from-32-int.js","names":["buffer","int32Array","int16Array","load16From32Int","convert32To16Int","data","index","store16In32Int","convert16To32Int","value1","value2","value"],"sources":["../../src/utils/16-from-32-int.ts"],"sourcesContent":["const buffer = new ArrayBuffer(4);\nconst int32Array = new Int32Array(buffer);\nconst int16Array = new Int16Array(buffer);\n\nexport function load16From32Int(data: Int32Array, index: number): [number, number] {\n\treturn convert32To16Int(Atomics.load(data, index));\n}\n\nexport function store16In32Int(data: Int32Array, index: number, value1: number, value2: number) {\n\tAtomics.store(data, index, convert16To32Int(value1, value2));\n}\n\nexport function convert32To16Int(value: number): [number, number] {\n\tint32Array[0] = value;\n\n\treturn [int16Array[0], int16Array[1]];\n}\n\nexport function convert16To32Int(value1: number, value2: number): number {\n\tint16Array[0] = value1;\n\tint16Array[1] = value2;\n\n\treturn int32Array[0];\n}\n"],"mappings":";AAAA,IAAMA,oBAAS,IAAI,YAAY,CAAC,GAC1BC,IAAa,IAAI,WAAWD,CAAM,GAClCE,IAAa,IAAI,WAAWF,CAAM;AAExC,SAAgBG,EAAgB,GAAkB,GAAiC;CAClF,OAAOC,EAAiB,QAAQ,KAAKC,GAAMC,CAAK,CAAC;AAClD;AAEA,SAAgBC,EAAe,GAAkB,GAAe,GAAgB,GAAgB;CAC/F,QAAQ,MAAMF,GAAMC,GAAOE,EAAiBC,GAAQC,CAAM,CAAC;AAC5D;AAEA,SAAgBN,EAAiB,GAAiC;CAGjE,OAFA,EAAW,KAAKO,GAET,CAACT,EAAW,IAAIA,EAAW,EAAE;AACrC;AAEA,SAAgBM,EAAiB,GAAgB,GAAwB;CAIxE,OAHA,EAAW,KAAKC,GAChB,EAAW,KAAKC,GAETT,EAAW;AACnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"16-from-32-uint.js","names":[],"sources":["../../src/utils/16-from-32-uint.ts"],"sourcesContent":["const buffer = new ArrayBuffer(4);\nconst uint32Array = new Uint32Array(buffer);\nconst uint16Array = new Uint16Array(buffer);\n\nexport function load16From32Uint(data: Uint32Array, index: number): [number, number] {\n\treturn convert32To16Uint(Atomics.load(data, index));\n}\n\nexport function store16In32Uint(data: Uint32Array, index: number, value1: number, value2: number) {\n\tAtomics.store(data, index, convert16To32Uint(value1, value2));\n}\n\nexport function convert32To16Uint(value: number): [number, number] {\n\tuint32Array[0] = value;\n\n\treturn [uint16Array[0], uint16Array[1]];\n}\n\nexport function convert16To32Uint(value1: number, value2: number): number {\n\tuint16Array[0] = value1;\n\tuint16Array[1] = value2;\n\n\treturn uint32Array[0];\n}\n"],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"16-from-32-uint.js","names":["buffer","uint32Array","uint16Array","load16From32Uint","convert32To16Uint","data","index","store16In32Uint","convert16To32Uint","value1","value2","value"],"sources":["../../src/utils/16-from-32-uint.ts"],"sourcesContent":["const buffer = new ArrayBuffer(4);\nconst uint32Array = new Uint32Array(buffer);\nconst uint16Array = new Uint16Array(buffer);\n\nexport function load16From32Uint(data: Uint32Array, index: number): [number, number] {\n\treturn convert32To16Uint(Atomics.load(data, index));\n}\n\nexport function store16In32Uint(data: Uint32Array, index: number, value1: number, value2: number) {\n\tAtomics.store(data, index, convert16To32Uint(value1, value2));\n}\n\nexport function convert32To16Uint(value: number): [number, number] {\n\tuint32Array[0] = value;\n\n\treturn [uint16Array[0], uint16Array[1]];\n}\n\nexport function convert16To32Uint(value1: number, value2: number): number {\n\tuint16Array[0] = value1;\n\tuint16Array[1] = value2;\n\n\treturn uint32Array[0];\n}\n"],"mappings":";AAAA,IAAMA,oBAAS,IAAI,YAAY,CAAC,GAC1BC,IAAc,IAAI,YAAYD,CAAM,GACpCE,IAAc,IAAI,YAAYF,CAAM;AAE1C,SAAgBG,EAAiB,GAAmB,GAAiC;CACpF,OAAOC,EAAkB,QAAQ,KAAKC,GAAMC,CAAK,CAAC;AACnD;AAEA,SAAgBC,EAAgB,GAAmB,GAAe,GAAgB,GAAgB;CACjG,QAAQ,MAAMF,GAAMC,GAAOE,EAAkBC,GAAQC,CAAM,CAAC;AAC7D;AAEA,SAAgBN,EAAkB,GAAiC;CAGlE,OAFA,EAAY,KAAKO,GAEV,CAACT,EAAY,IAAIA,EAAY,EAAE;AACvC;AAEA,SAAgBM,EAAkB,GAAgB,GAAwB;CAIzE,OAHA,EAAY,KAAKC,GACjB,EAAY,KAAKC,GAEVT,EAAY;AACpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"16-from-64-float.js","names":[],"sources":["../../src/utils/16-from-64-float.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst float64Array = new Float64Array(buffer);\nconst int64Array = new BigInt64Array(buffer);\nconst float16Array = new Float16Array(buffer);\n\nexport function load16From64Float(data: Float64Array, index: number): [number, number, number, number] {\n\tconst atomicData = new BigInt64Array(data.buffer, data.byteOffset, data.length);\n\tint64Array[0] = Atomics.load(atomicData, index);\n\treturn [float16Array[0], float16Array[1], float16Array[2], float16Array[3]];\n}\n\nexport function store16In64Float(data: Float64Array, index: number, value1: number, value2: number, value3: number, value4: number = 0) {\n\tconst atomicData = new BigInt64Array(data.buffer, data.byteOffset, data.length);\n\tfloat16Array[0] = value1;\n\tfloat16Array[1] = value2;\n\tfloat16Array[2] = value3;\n\tfloat16Array[3] = value4;\n\tAtomics.store(atomicData, index, int64Array[0]);\n}\n\nexport function convert64To16Float(value: number): [number, number, number, number] {\n\tfloat64Array[0] = value;\n\treturn [float16Array[0], float16Array[1], float16Array[2], float16Array[3]];\n}\n\nexport function convert16To64Float(value1: number, value2: number, value3: number, value4: number = 0): number {\n\tfloat16Array[0] = value1;\n\tfloat16Array[1] = value2;\n\tfloat16Array[2] = value3;\n\tfloat16Array[3] = value4;\n\treturn float64Array[0];\n}\n"],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"16-from-64-float.js","names":["buffer","float64Array","int64Array","float16Array","load16From64Float","atomicData","data","index","store16In64Float","value1","value2","value3","value4","convert64To16Float","value","convert16To64Float"],"sources":["../../src/utils/16-from-64-float.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst float64Array = new Float64Array(buffer);\nconst int64Array = new BigInt64Array(buffer);\nconst float16Array = new Float16Array(buffer);\n\nexport function load16From64Float(data: Float64Array, index: number): [number, number, number, number] {\n\tconst atomicData = new BigInt64Array(data.buffer, data.byteOffset, data.length);\n\tint64Array[0] = Atomics.load(atomicData, index);\n\treturn [float16Array[0], float16Array[1], float16Array[2], float16Array[3]];\n}\n\nexport function store16In64Float(data: Float64Array, index: number, value1: number, value2: number, value3: number, value4: number = 0) {\n\tconst atomicData = new BigInt64Array(data.buffer, data.byteOffset, data.length);\n\tfloat16Array[0] = value1;\n\tfloat16Array[1] = value2;\n\tfloat16Array[2] = value3;\n\tfloat16Array[3] = value4;\n\tAtomics.store(atomicData, index, int64Array[0]);\n}\n\nexport function convert64To16Float(value: number): [number, number, number, number] {\n\tfloat64Array[0] = value;\n\treturn [float16Array[0], float16Array[1], float16Array[2], float16Array[3]];\n}\n\nexport function convert16To64Float(value1: number, value2: number, value3: number, value4: number = 0): number {\n\tfloat16Array[0] = value1;\n\tfloat16Array[1] = value2;\n\tfloat16Array[2] = value3;\n\tfloat16Array[3] = value4;\n\treturn float64Array[0];\n}\n"],"mappings":";AAAA,IAAMA,oBAAS,IAAI,YAAY,CAAC,GAC1BC,IAAe,IAAI,aAAaD,CAAM,GACtCE,IAAa,IAAI,cAAcF,CAAM,GACrCG,IAAe,IAAI,aAAaH,CAAM;AAE5C,SAAgBI,EAAkB,GAAoB,GAAiD;CACtG,IAAMC,IAAa,IAAI,cAAcC,EAAK,QAAQA,EAAK,YAAYA,EAAK,MAAM;CAE9E,OADA,EAAW,KAAK,QAAQ,KAAKD,GAAYE,CAAK,GACvC;EAACJ,EAAa;EAAIA,EAAa;EAAIA,EAAa;EAAIA,EAAa;CAAE;AAC3E;AAEA,SAAgBK,EAAiB,GAAoB,GAAe,GAAgB,GAAgB,GAAgB,IAAiB,GAAG;CACvI,IAAMH,IAAa,IAAI,cAAcC,EAAK,QAAQA,EAAK,YAAYA,EAAK,MAAM;CAK9E,AAJA,EAAa,KAAKG,GAClB,EAAa,KAAKC,GAClB,EAAa,KAAKC,GAClB,EAAa,KAAKC,GAClB,QAAQ,MAAMP,GAAYE,GAAOL,EAAW,EAAE;AAC/C;AAEA,SAAgBW,EAAmB,GAAiD;CAEnF,OADA,EAAa,KAAKC,GACX;EAACX,EAAa;EAAIA,EAAa;EAAIA,EAAa;EAAIA,EAAa;CAAE;AAC3E;AAEA,SAAgBY,EAAmB,GAAgB,GAAgB,GAAgB,IAAiB,GAAW;CAK9G,OAJA,EAAa,KAAKN,GAClB,EAAa,KAAKC,GAClB,EAAa,KAAKC,GAClB,EAAa,KAAKC,GACXX,EAAa;AACrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"16-from-64-int.js","names":[],"sources":["../../src/utils/16-from-64-int.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst int64Array = new BigInt64Array(buffer);\nconst int16Array = new Int16Array(buffer);\n\nexport function load16From64Int(data: BigInt64Array, index: number): [number, number, number, number] {\n\treturn convert64To16Int(Atomics.load(data, index));\n}\n\nexport function store16In64Int(data: BigInt64Array, index: number, value1: number, value2: number, value3: number, value4: number = 0) {\n\tAtomics.store(data, index, convert16To64Int(value1, value2, value3, value4));\n}\n\nexport function convert64To16Int(value: bigint): [number, number, number, number] {\n\tint64Array[0] = value;\n\n\treturn [int16Array[0], int16Array[1], int16Array[2], int16Array[3]];\n}\n\nexport function convert16To64Int(value1: number, value2: number, value3: number, value4: number = 0): bigint {\n\tint16Array[0] = value1;\n\tint16Array[1] = value2;\n\tint16Array[2] = value3;\n\tint16Array[3] = value4;\n\n\treturn int64Array[0];\n}\n"],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"16-from-64-int.js","names":["buffer","int64Array","int16Array","load16From64Int","convert64To16Int","data","index","store16In64Int","convert16To64Int","value1","value2","value3","value4","value"],"sources":["../../src/utils/16-from-64-int.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst int64Array = new BigInt64Array(buffer);\nconst int16Array = new Int16Array(buffer);\n\nexport function load16From64Int(data: BigInt64Array, index: number): [number, number, number, number] {\n\treturn convert64To16Int(Atomics.load(data, index));\n}\n\nexport function store16In64Int(data: BigInt64Array, index: number, value1: number, value2: number, value3: number, value4: number = 0) {\n\tAtomics.store(data, index, convert16To64Int(value1, value2, value3, value4));\n}\n\nexport function convert64To16Int(value: bigint): [number, number, number, number] {\n\tint64Array[0] = value;\n\n\treturn [int16Array[0], int16Array[1], int16Array[2], int16Array[3]];\n}\n\nexport function convert16To64Int(value1: number, value2: number, value3: number, value4: number = 0): bigint {\n\tint16Array[0] = value1;\n\tint16Array[1] = value2;\n\tint16Array[2] = value3;\n\tint16Array[3] = value4;\n\n\treturn int64Array[0];\n}\n"],"mappings":";AAAA,IAAMA,oBAAS,IAAI,YAAY,CAAC,GAC1BC,IAAa,IAAI,cAAcD,CAAM,GACrCE,IAAa,IAAI,WAAWF,CAAM;AAExC,SAAgBG,EAAgB,GAAqB,GAAiD;CACrG,OAAOC,EAAiB,QAAQ,KAAKC,GAAMC,CAAK,CAAC;AAClD;AAEA,SAAgBC,EAAe,GAAqB,GAAe,GAAgB,GAAgB,GAAgB,IAAiB,GAAG;CACtI,QAAQ,MAAMF,GAAMC,GAAOE,EAAiBC,GAAQC,GAAQC,GAAQC,CAAM,CAAC;AAC5E;AAEA,SAAgBR,EAAiB,GAAiD;CAGjF,OAFA,EAAW,KAAKS,GAET;EAACX,EAAW;EAAIA,EAAW;EAAIA,EAAW;EAAIA,EAAW;CAAE;AACnE;AAEA,SAAgBM,EAAiB,GAAgB,GAAgB,GAAgB,IAAiB,GAAW;CAM5G,OALA,EAAW,KAAKC,GAChB,EAAW,KAAKC,GAChB,EAAW,KAAKC,GAChB,EAAW,KAAKC,GAETX,EAAW;AACnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"16-from-64-uint.js","names":[],"sources":["../../src/utils/16-from-64-uint.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst uint64Array = new BigUint64Array(buffer);\nconst uint16Array = new Uint16Array(buffer);\n\nexport function load16From64Uint(data: BigUint64Array, index: number): [number, number, number, number] {\n\treturn convert64To16Uint(Atomics.load(data, index));\n}\n\nexport function store16In64Uint(data: BigUint64Array, index: number, value1: number, value2: number, value3: number, value4: number = 0) {\n\tAtomics.store(data, index, convert16To64Uint(value1, value2, value3, value4));\n}\n\nexport function convert64To16Uint(value: bigint): [number, number, number, number] {\n\tuint64Array[0] = value;\n\n\treturn [uint16Array[0], uint16Array[1], uint16Array[2], uint16Array[3]];\n}\n\nexport function convert16To64Uint(value1: number, value2: number, value3: number, value4: number = 0): bigint {\n\tuint16Array[0] = value1;\n\tuint16Array[1] = value2;\n\tuint16Array[2] = value3;\n\tuint16Array[3] = value4;\n\n\treturn uint64Array[0];\n}\n"],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"16-from-64-uint.js","names":["buffer","uint64Array","uint16Array","load16From64Uint","convert64To16Uint","data","index","store16In64Uint","convert16To64Uint","value1","value2","value3","value4","value"],"sources":["../../src/utils/16-from-64-uint.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst uint64Array = new BigUint64Array(buffer);\nconst uint16Array = new Uint16Array(buffer);\n\nexport function load16From64Uint(data: BigUint64Array, index: number): [number, number, number, number] {\n\treturn convert64To16Uint(Atomics.load(data, index));\n}\n\nexport function store16In64Uint(data: BigUint64Array, index: number, value1: number, value2: number, value3: number, value4: number = 0) {\n\tAtomics.store(data, index, convert16To64Uint(value1, value2, value3, value4));\n}\n\nexport function convert64To16Uint(value: bigint): [number, number, number, number] {\n\tuint64Array[0] = value;\n\n\treturn [uint16Array[0], uint16Array[1], uint16Array[2], uint16Array[3]];\n}\n\nexport function convert16To64Uint(value1: number, value2: number, value3: number, value4: number = 0): bigint {\n\tuint16Array[0] = value1;\n\tuint16Array[1] = value2;\n\tuint16Array[2] = value3;\n\tuint16Array[3] = value4;\n\n\treturn uint64Array[0];\n}\n"],"mappings":";AAAA,IAAMA,oBAAS,IAAI,YAAY,CAAC,GAC1BC,IAAc,IAAI,eAAeD,CAAM,GACvCE,IAAc,IAAI,YAAYF,CAAM;AAE1C,SAAgBG,EAAiB,GAAsB,GAAiD;CACvG,OAAOC,EAAkB,QAAQ,KAAKC,GAAMC,CAAK,CAAC;AACnD;AAEA,SAAgBC,EAAgB,GAAsB,GAAe,GAAgB,GAAgB,GAAgB,IAAiB,GAAG;CACxI,QAAQ,MAAMF,GAAMC,GAAOE,EAAkBC,GAAQC,GAAQC,GAAQC,CAAM,CAAC;AAC7E;AAEA,SAAgBR,EAAkB,GAAiD;CAGlF,OAFA,EAAY,KAAKS,GAEV;EAACX,EAAY;EAAIA,EAAY;EAAIA,EAAY;EAAIA,EAAY;CAAE;AACvE;AAEA,SAAgBM,EAAkB,GAAgB,GAAgB,GAAgB,IAAiB,GAAW;CAM7G,OALA,EAAY,KAAKC,GACjB,EAAY,KAAKC,GACjB,EAAY,KAAKC,GACjB,EAAY,KAAKC,GAEVX,EAAY;AACpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"32-from-64-float.js","names":[],"sources":["../../src/utils/32-from-64-float.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst float64Array = new Float64Array(buffer);\nconst float32Array = new Float32Array(buffer);\nconst int64Array = new BigInt64Array(buffer);\n\nexport function load32From64Float(data: Float64Array, index: number): [number, number] {\n\tconst atomicData = new BigInt64Array(data.buffer, data.byteOffset, data.length);\n\tint64Array[0] = Atomics.load(atomicData, index);\n\treturn [float32Array[0], float32Array[1]];\n}\n\nexport function store32In64Float(data: Float64Array, index: number, value1: number, value2: number) {\n\tconst atomicData = new BigInt64Array(data.buffer, data.byteOffset, data.length);\n\tfloat32Array[0] = value1;\n\tfloat32Array[1] = value2;\n\tAtomics.store(atomicData, index, int64Array[0]);\n}\n\nexport function convert64To32Float(value: number): [number, number] {\n\tfloat64Array[0] = value;\n\treturn [float32Array[0], float32Array[1]];\n}\n\nexport function convert32To64Float(value1: number, value2: number): number {\n\tfloat32Array[0] = value1;\n\tfloat32Array[1] = value2;\n\treturn float64Array[0];\n}\n"],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"32-from-64-float.js","names":["buffer","float64Array","float32Array","int64Array","load32From64Float","atomicData","data","index","store32In64Float","value1","value2","convert64To32Float","value","convert32To64Float"],"sources":["../../src/utils/32-from-64-float.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst float64Array = new Float64Array(buffer);\nconst float32Array = new Float32Array(buffer);\nconst int64Array = new BigInt64Array(buffer);\n\nexport function load32From64Float(data: Float64Array, index: number): [number, number] {\n\tconst atomicData = new BigInt64Array(data.buffer, data.byteOffset, data.length);\n\tint64Array[0] = Atomics.load(atomicData, index);\n\treturn [float32Array[0], float32Array[1]];\n}\n\nexport function store32In64Float(data: Float64Array, index: number, value1: number, value2: number) {\n\tconst atomicData = new BigInt64Array(data.buffer, data.byteOffset, data.length);\n\tfloat32Array[0] = value1;\n\tfloat32Array[1] = value2;\n\tAtomics.store(atomicData, index, int64Array[0]);\n}\n\nexport function convert64To32Float(value: number): [number, number] {\n\tfloat64Array[0] = value;\n\treturn [float32Array[0], float32Array[1]];\n}\n\nexport function convert32To64Float(value1: number, value2: number): number {\n\tfloat32Array[0] = value1;\n\tfloat32Array[1] = value2;\n\treturn float64Array[0];\n}\n"],"mappings":";AAAA,IAAMA,oBAAS,IAAI,YAAY,CAAC,GAC1BC,IAAe,IAAI,aAAaD,CAAM,GACtCE,IAAe,IAAI,aAAaF,CAAM,GACtCG,IAAa,IAAI,cAAcH,CAAM;AAE3C,SAAgBI,EAAkB,GAAoB,GAAiC;CACtF,IAAMC,IAAa,IAAI,cAAcC,EAAK,QAAQA,EAAK,YAAYA,EAAK,MAAM;CAE9E,OADA,EAAW,KAAK,QAAQ,KAAKD,GAAYE,CAAK,GACvC,CAACL,EAAa,IAAIA,EAAa,EAAE;AACzC;AAEA,SAAgBM,EAAiB,GAAoB,GAAe,GAAgB,GAAgB;CACnG,IAAMH,IAAa,IAAI,cAAcC,EAAK,QAAQA,EAAK,YAAYA,EAAK,MAAM;CAG9E,AAFA,EAAa,KAAKG,GAClB,EAAa,KAAKC,GAClB,QAAQ,MAAML,GAAYE,GAAOJ,EAAW,EAAE;AAC/C;AAEA,SAAgBQ,EAAmB,GAAiC;CAEnE,OADA,EAAa,KAAKC,GACX,CAACV,EAAa,IAAIA,EAAa,EAAE;AACzC;AAEA,SAAgBW,EAAmB,GAAgB,GAAwB;CAG1E,OAFA,EAAa,KAAKJ,GAClB,EAAa,KAAKC,GACXT,EAAa;AACrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"32-from-64-int.js","names":[],"sources":["../../src/utils/32-from-64-int.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst int64Array = new BigInt64Array(buffer);\nconst int32Array = new Int32Array(buffer);\n\nexport function load32From64Int(data: BigInt64Array, index: number): [number, number] {\n\treturn convert64To32Int(Atomics.load(data, index));\n}\n\nexport function store32In64Int(data: BigInt64Array, index: number, value1: number, value2: number) {\n\tAtomics.store(data, index, convert32To64Int(value1, value2));\n}\n\nexport function convert64To32Int(value: bigint): [number, number] {\n\tint64Array[0] = value;\n\n\treturn [int32Array[0], int32Array[1]];\n}\n\nexport function convert32To64Int(value1: number, value2: number): bigint {\n\tint32Array[0] = value1;\n\tint32Array[1] = value2;\n\n\treturn int64Array[0];\n}\n"],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"32-from-64-int.js","names":["buffer","int64Array","int32Array","load32From64Int","convert64To32Int","data","index","store32In64Int","convert32To64Int","value1","value2","value"],"sources":["../../src/utils/32-from-64-int.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst int64Array = new BigInt64Array(buffer);\nconst int32Array = new Int32Array(buffer);\n\nexport function load32From64Int(data: BigInt64Array, index: number): [number, number] {\n\treturn convert64To32Int(Atomics.load(data, index));\n}\n\nexport function store32In64Int(data: BigInt64Array, index: number, value1: number, value2: number) {\n\tAtomics.store(data, index, convert32To64Int(value1, value2));\n}\n\nexport function convert64To32Int(value: bigint): [number, number] {\n\tint64Array[0] = value;\n\n\treturn [int32Array[0], int32Array[1]];\n}\n\nexport function convert32To64Int(value1: number, value2: number): bigint {\n\tint32Array[0] = value1;\n\tint32Array[1] = value2;\n\n\treturn int64Array[0];\n}\n"],"mappings":";AAAA,IAAMA,oBAAS,IAAI,YAAY,CAAC,GAC1BC,IAAa,IAAI,cAAcD,CAAM,GACrCE,IAAa,IAAI,WAAWF,CAAM;AAExC,SAAgBG,EAAgB,GAAqB,GAAiC;CACrF,OAAOC,EAAiB,QAAQ,KAAKC,GAAMC,CAAK,CAAC;AAClD;AAEA,SAAgBC,EAAe,GAAqB,GAAe,GAAgB,GAAgB;CAClG,QAAQ,MAAMF,GAAMC,GAAOE,EAAiBC,GAAQC,CAAM,CAAC;AAC5D;AAEA,SAAgBN,EAAiB,GAAiC;CAGjE,OAFA,EAAW,KAAKO,GAET,CAACT,EAAW,IAAIA,EAAW,EAAE;AACrC;AAEA,SAAgBM,EAAiB,GAAgB,GAAwB;CAIxE,OAHA,EAAW,KAAKC,GAChB,EAAW,KAAKC,GAETT,EAAW;AACnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"32-from-64-uint.js","names":[],"sources":["../../src/utils/32-from-64-uint.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst uint64Array = new BigUint64Array(buffer);\nconst uint32Array = new Uint32Array(buffer);\n\nexport function load32From64Uint(data: BigUint64Array, index: number): [number, number] {\n\treturn convert64To32Uint(Atomics.load(data, index));\n}\n\nexport function store32In64Uint(data: BigUint64Array, index: number, value1: number, value2: number) {\n\tAtomics.store(data, index, convert32To64Uint(value1, value2));\n}\n\nexport function convert64To32Uint(value: bigint): [number, number] {\n\tuint64Array[0] = value;\n\n\treturn [uint32Array[0], uint32Array[1]];\n}\n\nexport function convert32To64Uint(value1: number, value2: number): bigint {\n\tuint32Array[0] = value1;\n\tuint32Array[1] = value2;\n\n\treturn uint64Array[0];\n}\n"],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"32-from-64-uint.js","names":["buffer","uint64Array","uint32Array","load32From64Uint","convert64To32Uint","data","index","store32In64Uint","convert32To64Uint","value1","value2","value"],"sources":["../../src/utils/32-from-64-uint.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst uint64Array = new BigUint64Array(buffer);\nconst uint32Array = new Uint32Array(buffer);\n\nexport function load32From64Uint(data: BigUint64Array, index: number): [number, number] {\n\treturn convert64To32Uint(Atomics.load(data, index));\n}\n\nexport function store32In64Uint(data: BigUint64Array, index: number, value1: number, value2: number) {\n\tAtomics.store(data, index, convert32To64Uint(value1, value2));\n}\n\nexport function convert64To32Uint(value: bigint): [number, number] {\n\tuint64Array[0] = value;\n\n\treturn [uint32Array[0], uint32Array[1]];\n}\n\nexport function convert32To64Uint(value1: number, value2: number): bigint {\n\tuint32Array[0] = value1;\n\tuint32Array[1] = value2;\n\n\treturn uint64Array[0];\n}\n"],"mappings":";AAAA,IAAMA,oBAAS,IAAI,YAAY,CAAC,GAC1BC,IAAc,IAAI,eAAeD,CAAM,GACvCE,IAAc,IAAI,YAAYF,CAAM;AAE1C,SAAgBG,EAAiB,GAAsB,GAAiC;CACvF,OAAOC,EAAkB,QAAQ,KAAKC,GAAMC,CAAK,CAAC;AACnD;AAEA,SAAgBC,EAAgB,GAAsB,GAAe,GAAgB,GAAgB;CACpG,QAAQ,MAAMF,GAAMC,GAAOE,EAAkBC,GAAQC,CAAM,CAAC;AAC7D;AAEA,SAAgBN,EAAkB,GAAiC;CAGlE,OAFA,EAAY,KAAKO,GAEV,CAACT,EAAY,IAAIA,EAAY,EAAE;AACvC;AAEA,SAAgBM,EAAkB,GAAgB,GAAwB;CAIzE,OAHA,EAAY,KAAKC,GACjB,EAAY,KAAKC,GAEVT,EAAY;AACpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"array-type.js","names":[],"sources":["../../src/utils/array-type.ts"],"sourcesContent":["import type { TypedArrayConstructor } from '../interfaces/typed-array-constructor';\n\n// Every numeric view a data structure can store values in. The BigInt views (int64/uint64) carry bigint elements;\n// all others carry number. A view's scalar type is T[number], so public signatures derive it straight from T.\ntype NumericArray = Uint32Array | Int32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array;\n\n// Persisted in shared memory (the TYPE slot), so the order is append-only - never renumber an existing entry.\nconst ARRAY_TYPE = {\n\tuint32: 0,\n\tint32: 1,\n\tfloat32: 2,\n\tfloat64: 3,\n\tint64: 4,\n\tuint64: 5,\n} as const;\n\n// A numeric view whose element getter/setter accepts number or bigint. TypeScript can't prove `view[i] = value` on a\n// generic (possibly-bigint) view because the union's index signatures collapse to `never`; going through this alias\n// keeps the write type-safe at the boundary. Types are erased, so the emitted store is identical to a direct one.\ntype NumericArrayIO = { [index: number]: number | bigint };\n\nfunction getArrayTypeCode(type: unknown): number {\n\tif(type === Int32Array) {\n\t\treturn ARRAY_TYPE.int32;\n\t} else if(type === Float32Array) {\n\t\treturn ARRAY_TYPE.float32;\n\t} else if(type === Float64Array) {\n\t\treturn ARRAY_TYPE.float64;\n\t} else if(type === BigInt64Array) {\n\t\treturn ARRAY_TYPE.int64;\n\t} else if(type === BigUint64Array) {\n\t\treturn ARRAY_TYPE.uint64;\n\t} else {\n\t\treturn ARRAY_TYPE.uint32;\n\t}\n}\n\n// 64-bit elements occupy two u32 allocation units; everything else occupies one. Callers size blocks as count * this.\nfunction getByteMultipler(typeCode: number): number {\n\treturn typeCode >= ARRAY_TYPE.float64 ? 2 : 1;\n}\n\nfunction isBigIntType(typeCode: number): boolean {\n\treturn typeCode === ARRAY_TYPE.int64 || typeCode === ARRAY_TYPE.uint64;\n}\n\n// Float views don't support Atomics; callers that publish elements atomically must fall back to a plain store for these.\nfunction isFloatType(typeCode: number): boolean {\n\treturn typeCode === ARRAY_TYPE.float32 || typeCode === ARRAY_TYPE.float64;\n}\n\n// Builds the typed view for a resolved type code. `length` is the element count (not u32 units); for 64-bit types the\n// backing block must already reserve length * getByteMultipler(typeCode) u32s.\nfunction makeArrayView(typeCode: number, buffer: ArrayBufferLike, byteOffset: number, length: number): NumericArray {\n\tswitch(typeCode) {\n\t\tcase ARRAY_TYPE.int32:\n\t\t\treturn new Int32Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.float32:\n\t\t\treturn new Float32Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.float64:\n\t\t\treturn new Float64Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.int64:\n\t\t\treturn new BigInt64Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.uint64:\n\t\t\treturn new BigUint64Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.uint32:\n\t\t\treturn new Uint32Array(buffer, byteOffset, length);\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown data block type ${typeCode}`);\n\t}\n}\n\nexport { ARRAY_TYPE, getArrayTypeCode, getByteMultipler, isBigIntType, isFloatType, makeArrayView };\nexport type { NumericArray, NumericArrayIO, TypedArrayConstructor };\n"],"mappings":";AAOA,
|
|
1
|
+
{"version":3,"file":"array-type.js","names":["ARRAY_TYPE","getArrayTypeCode","type","getByteMultipler","typeCode","isBigIntType","isFloatType","makeArrayView","buffer","byteOffset","length"],"sources":["../../src/utils/array-type.ts"],"sourcesContent":["import type { TypedArrayConstructor } from '../interfaces/typed-array-constructor';\n\n// Every numeric view a data structure can store values in. The BigInt views (int64/uint64) carry bigint elements;\n// all others carry number. A view's scalar type is T[number], so public signatures derive it straight from T.\ntype NumericArray = Uint32Array | Int32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array;\n\n// Persisted in shared memory (the TYPE slot), so the order is append-only - never renumber an existing entry.\nconst ARRAY_TYPE = {\n\tuint32: 0,\n\tint32: 1,\n\tfloat32: 2,\n\tfloat64: 3,\n\tint64: 4,\n\tuint64: 5,\n} as const;\n\n// A numeric view whose element getter/setter accepts number or bigint. TypeScript can't prove `view[i] = value` on a\n// generic (possibly-bigint) view because the union's index signatures collapse to `never`; going through this alias\n// keeps the write type-safe at the boundary. Types are erased, so the emitted store is identical to a direct one.\ntype NumericArrayIO = { [index: number]: number | bigint };\n\nfunction getArrayTypeCode(type: unknown): number {\n\tif(type === Int32Array) {\n\t\treturn ARRAY_TYPE.int32;\n\t} else if(type === Float32Array) {\n\t\treturn ARRAY_TYPE.float32;\n\t} else if(type === Float64Array) {\n\t\treturn ARRAY_TYPE.float64;\n\t} else if(type === BigInt64Array) {\n\t\treturn ARRAY_TYPE.int64;\n\t} else if(type === BigUint64Array) {\n\t\treturn ARRAY_TYPE.uint64;\n\t} else {\n\t\treturn ARRAY_TYPE.uint32;\n\t}\n}\n\n// 64-bit elements occupy two u32 allocation units; everything else occupies one. Callers size blocks as count * this.\nfunction getByteMultipler(typeCode: number): number {\n\treturn typeCode >= ARRAY_TYPE.float64 ? 2 : 1;\n}\n\nfunction isBigIntType(typeCode: number): boolean {\n\treturn typeCode === ARRAY_TYPE.int64 || typeCode === ARRAY_TYPE.uint64;\n}\n\n// Float views don't support Atomics; callers that publish elements atomically must fall back to a plain store for these.\nfunction isFloatType(typeCode: number): boolean {\n\treturn typeCode === ARRAY_TYPE.float32 || typeCode === ARRAY_TYPE.float64;\n}\n\n// Builds the typed view for a resolved type code. `length` is the element count (not u32 units); for 64-bit types the\n// backing block must already reserve length * getByteMultipler(typeCode) u32s.\nfunction makeArrayView(typeCode: number, buffer: ArrayBufferLike, byteOffset: number, length: number): NumericArray {\n\tswitch(typeCode) {\n\t\tcase ARRAY_TYPE.int32:\n\t\t\treturn new Int32Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.float32:\n\t\t\treturn new Float32Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.float64:\n\t\t\treturn new Float64Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.int64:\n\t\t\treturn new BigInt64Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.uint64:\n\t\t\treturn new BigUint64Array(buffer, byteOffset, length);\n\t\tcase ARRAY_TYPE.uint32:\n\t\t\treturn new Uint32Array(buffer, byteOffset, length);\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown data block type ${typeCode}`);\n\t}\n}\n\nexport { ARRAY_TYPE, getArrayTypeCode, getByteMultipler, isBigIntType, isFloatType, makeArrayView };\nexport type { NumericArray, NumericArrayIO, TypedArrayConstructor };\n"],"mappings":";AAOA,IAAMA,IAAa;CAClB,QAAQ;CACR,OAAO;CACP,SAAS;CACT,SAAS;CACT,OAAO;CACP,QAAQ;AACT;AAOA,SAASC,EAAiB,GAAuB;CAY/C,OAXEC,MAAS,aACJF,EAAW,QACTE,MAAS,eACXF,EAAW,UACTE,MAAS,eACXF,EAAW,UACTE,MAAS,gBACXF,EAAW,QACTE,MAAS,iBACXF,EAAW,SAEXA,EAAW;AAEpB;AAGA,SAASG,EAAiB,GAA0B;CACnD,OAAOC,KAAYJ,EAAW,UAAU,IAAI;AAC7C;AAEA,SAASK,EAAa,GAA2B;CAChD,OAAOD,MAAaJ,EAAW,SAASI,MAAaJ,EAAW;AACjE;AAGA,SAASM,EAAY,GAA2B;CAC/C,OAAOF,MAAaJ,EAAW,WAAWI,MAAaJ,EAAW;AACnE;AAIA,SAASO,EAAc,GAAkB,GAAyB,GAAoB,GAA8B;CACnH,QAAOH,GAAP;EACC,KAAKJ,EAAW,OACf,OAAO,IAAI,WAAWQ,GAAQC,GAAYC,CAAM;EACjD,KAAKV,EAAW,SACf,OAAO,IAAI,aAAaQ,GAAQC,GAAYC,CAAM;EACnD,KAAKV,EAAW,SACf,OAAO,IAAI,aAAaQ,GAAQC,GAAYC,CAAM;EACnD,KAAKV,EAAW,OACf,OAAO,IAAI,cAAcQ,GAAQC,GAAYC,CAAM;EACpD,KAAKV,EAAW,QACf,OAAO,IAAI,eAAeQ,GAAQC,GAAYC,CAAM;EACrD,KAAKV,EAAW,QACf,OAAO,IAAI,YAAYQ,GAAQC,GAAYC,CAAM;EAClD,SACC,MAAU,MAAM,2BAA2BN,GAAU;CACvD;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atomic-math.js","names":[],"sources":["../../src/utils/atomic-math.ts"],"sourcesContent":["import { compareExchangeFloat32, loadFloat32 } from './float32-atomics';\n\nexport function addAtomicInt(array: Uint32Array | Int32Array, index: number, amount: number, max: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = Atomics.load(array, index);\n\t\tnewValue = Math.min(oldValue + amount, max);\n\t} while(Atomics.compareExchange(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}\n\nexport function subtractAtomicInt(array: Uint32Array | Int32Array, index: number, amount: number, min: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = Atomics.load(array, index);\n\t\tnewValue = Math.max(oldValue - amount, min);\n\t} while(Atomics.compareExchange(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}\n\nexport function addAtomicFloat32(array: Float32Array, index: number, amount: number, max: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = loadFloat32(array, index);\n\t\tnewValue = Math.min(oldValue + amount, max);\n\t} while(compareExchangeFloat32(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}\n\nexport function subtractAtomicFloat(array: Float32Array, index: number, amount: number, min: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = loadFloat32(array, index);\n\t\tnewValue = Math.max(oldValue - amount, min);\n\t} while(compareExchangeFloat32(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}"],"mappings":";;AAEA,
|
|
1
|
+
{"version":3,"file":"atomic-math.js","names":["addAtomicInt","oldValue","newValue","array","index","amount","max","subtractAtomicInt","min","addAtomicFloat32","loadFloat32","compareExchangeFloat32","subtractAtomicFloat"],"sources":["../../src/utils/atomic-math.ts"],"sourcesContent":["import { compareExchangeFloat32, loadFloat32 } from './float32-atomics';\n\nexport function addAtomicInt(array: Uint32Array | Int32Array, index: number, amount: number, max: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = Atomics.load(array, index);\n\t\tnewValue = Math.min(oldValue + amount, max);\n\t} while(Atomics.compareExchange(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}\n\nexport function subtractAtomicInt(array: Uint32Array | Int32Array, index: number, amount: number, min: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = Atomics.load(array, index);\n\t\tnewValue = Math.max(oldValue - amount, min);\n\t} while(Atomics.compareExchange(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}\n\nexport function addAtomicFloat32(array: Float32Array, index: number, amount: number, max: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = loadFloat32(array, index);\n\t\tnewValue = Math.min(oldValue + amount, max);\n\t} while(compareExchangeFloat32(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}\n\nexport function subtractAtomicFloat(array: Float32Array, index: number, amount: number, min: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = loadFloat32(array, index);\n\t\tnewValue = Math.max(oldValue - amount, min);\n\t} while(compareExchangeFloat32(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}"],"mappings":";;AAEA,SAAgBA,EAAa,GAAiC,GAAe,GAAgB,GAAa;CACzG,IAAIC,GACAC;CACJ;EAEC,AADA,IAAW,QAAQ,KAAKC,GAAOC,CAAK,GACpC,IAAW,KAAK,IAAIH,IAAWI,GAAQC,CAAG;QACnC,QAAQ,gBAAgBH,GAAOC,GAAOH,GAAUC,CAAQ,MAAMD;CAEtE,OAAOC;AACR;AAEA,SAAgBK,EAAkB,GAAiC,GAAe,GAAgB,GAAa;CAC9G,IAAIN,GACAC;CACJ;EAEC,AADA,IAAW,QAAQ,KAAKC,GAAOC,CAAK,GACpC,IAAW,KAAK,IAAIH,IAAWI,GAAQG,CAAG;QACnC,QAAQ,gBAAgBL,GAAOC,GAAOH,GAAUC,CAAQ,MAAMD;CAEtE,OAAOC;AACR;AAEA,SAAgBO,EAAiB,GAAqB,GAAe,GAAgB,GAAa;CACjG,IAAIR,GACAC;CACJ;EAEC,AADA,IAAWQ,EAAYP,GAAOC,CAAK,GACnC,IAAW,KAAK,IAAIH,IAAWI,GAAQC,CAAG;QACnCK,EAAuBR,GAAOC,GAAOH,GAAUC,CAAQ,MAAMD;CAErE,OAAOC;AACR;AAEA,SAAgBU,EAAoB,GAAqB,GAAe,GAAgB,GAAa;CACpG,IAAIX,GACAC;CACJ;EAEC,AADA,IAAWQ,EAAYP,GAAOC,CAAK,GACnC,IAAW,KAAK,IAAIH,IAAWI,GAAQG,CAAG;QACnCG,EAAuBR,GAAOC,GAAOH,GAAUC,CAAQ,MAAMD;CAErE,OAAOC;AACR"}
|