@daneren2005/shared-memory-objects 1.6.0 → 1.6.1

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.
Files changed (40) hide show
  1. package/dist/allocated-memory.js.map +1 -1
  2. package/dist/cached-item-list.js.map +1 -1
  3. package/dist/constant-string.js.map +1 -1
  4. package/dist/local-pool.js.map +1 -1
  5. package/dist/lock/read-write-lock.js.map +1 -1
  6. package/dist/lock/simple-lock.js.map +1 -1
  7. package/dist/memory-buffer.js.map +1 -1
  8. package/dist/memory-heap.js.map +1 -1
  9. package/dist/serialize-object.js.map +1 -1
  10. package/dist/shared-list.js.map +1 -1
  11. package/dist/shared-map.d.ts +3 -0
  12. package/dist/shared-map.js +42 -24
  13. package/dist/shared-map.js.map +1 -1
  14. package/dist/shared-pointer-list.js.map +1 -1
  15. package/dist/shared-pool.js.map +1 -1
  16. package/dist/shared-stack.js.map +1 -1
  17. package/dist/shared-string.js.map +1 -1
  18. package/dist/shared-vector.js.map +1 -1
  19. package/dist/spatial/shared-quadtree.js.map +1 -1
  20. package/dist/spatial/shared-spatial-grid.js.map +1 -1
  21. package/dist/spatial/shared-spatial-map.js.map +1 -1
  22. package/dist/spatial/spatial-entity.js.map +1 -1
  23. package/dist/spatial/spatial-neighbors.js.map +1 -1
  24. package/dist/utils/16-from-32-float.js.map +1 -1
  25. package/dist/utils/16-from-32-int.js.map +1 -1
  26. package/dist/utils/16-from-32-uint.js.map +1 -1
  27. package/dist/utils/16-from-64-float.js.map +1 -1
  28. package/dist/utils/16-from-64-int.js.map +1 -1
  29. package/dist/utils/16-from-64-uint.js.map +1 -1
  30. package/dist/utils/32-from-64-float.js.map +1 -1
  31. package/dist/utils/32-from-64-int.js.map +1 -1
  32. package/dist/utils/32-from-64-uint.js.map +1 -1
  33. package/dist/utils/array-type.js.map +1 -1
  34. package/dist/utils/atomic-math.js.map +1 -1
  35. package/dist/utils/float32-atomics.js.map +1 -1
  36. package/dist/utils/float64-atomics.js.map +1 -1
  37. package/dist/utils/hash.js.map +1 -1
  38. package/dist/utils/pointer.js.map +1 -1
  39. package/dist/utils/typedarray.js.map +1 -1
  40. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"shared-string.js","names":[],"sources":["../src/shared-string.ts"],"sourcesContent":["import AllocatedMemory from './allocated-memory';\nimport type { SharedAllocatedMemory } from './allocated-memory';\nimport { lock, unlock } from './lock/simple-lock';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer, loadPointer, loadRawPointer, storeRawPointer } from './utils/pointer';\n\nenum CHAR_TYPE {\n\tUNDEFINED,\n\tASCII,\n\tUTF16,\n}\nconst TYPED_ARRAY_MAP = {\n\t[CHAR_TYPE.ASCII]: Uint8Array,\n\t[CHAR_TYPE.UTF16]: Uint16Array,\n};\n\nconst POINTER_INDEX = 0;\nconst LENGTH_INDEX = 1;\nconst TYPE_INDEX = 2;\nconst LOCK_INDEX = 3;\nexport default class SharedString {\n\tstatic readonly ALLOCATE_COUNT = 4;\n\n\tprivate memory: MemoryHeap;\n\tprivate allocatedMemory: AllocatedMemory;\n\tprivate lock: Int32Array;\n\n\tprivate cachedPointer?: number;\n\tprivate cachedString?: string;\n\t\n\tconstructor(memory: MemoryHeap, value: string | SharedStringConfig | SharedStringMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(typeof value === 'string') {\n\t\t\tthis.allocatedMemory = this.memory.allocUI32(SharedString.ALLOCATE_COUNT);\n\t\t\tthis.lock = new Int32Array(this.allocatedMemory.data.buffer, this.allocatedMemory.bufferByteOffset + LOCK_INDEX * this.allocatedMemory.data.BYTES_PER_ELEMENT);\n\t\t\tthis.updateString(value);\n\t\t} else {\n\t\t\tthis.allocatedMemory = new AllocatedMemory(memory, value);\n\t\t\tthis.lock = new Int32Array(this.allocatedMemory.data.buffer, this.allocatedMemory.bufferByteOffset + LOCK_INDEX * this.allocatedMemory.data.BYTES_PER_ELEMENT);\n\n\t\t\t// We only allocated memory but didn't initialize the string yet\n\t\t\tif('value' in value) {\n\t\t\t\tthis.updateString(value.value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tprivate updateString(value: string) {\n\t\tlet stringMemory = this.createString(value);\n\n\t\tlock(this.lock);\n\t\tstoreRawPointer(this.allocatedMemory.data, POINTER_INDEX, stringMemory.pointer);\n\t\tAtomics.store(this.allocatedMemory.data, LENGTH_INDEX, value.length);\n\t\tAtomics.store(this.allocatedMemory.data, TYPE_INDEX, stringMemory.charType);\n\t\tunlock(this.lock);\n\n\t\tthis.cachedPointer = stringMemory.pointer;\n\t\tthis.cachedString = value;\n\t}\n\tprivate createString(value: string) {\n\t\tif(value === '') {\n\t\t\treturn {\n\t\t\t\tpointer: 0,\n\t\t\t\tcharType: CHAR_TYPE.ASCII,\n\t\t\t};\n\t\t}\n\n\t\t// NOTE: Scan with a loop instead of Math.max(...charCodes) which blows the stack for large strings\n\t\tlet maxCharCode = 0;\n\t\tfor(let i = 0; i < value.length; i++) {\n\t\t\tlet charCode = value.charCodeAt(i);\n\t\t\tif(charCode > maxCharCode) {\n\t\t\t\tmaxCharCode = charCode;\n\t\t\t}\n\t\t}\n\t\tlet charType = maxCharCode > 255 ? CHAR_TYPE.UTF16 : CHAR_TYPE.ASCII;\n\n\t\tlet typedArray = TYPED_ARRAY_MAP[charType];\n\t\tlet allocatedMemory = this.memory.allocUI32(Math.ceil(value.length / (4 / typedArray.BYTES_PER_ELEMENT)));\n\t\tlet data = new typedArray(allocatedMemory.data.buffer as ArrayBuffer, allocatedMemory.data.byteOffset, value.length);\n\t\tfor(let i = 0; i < value.length; i++) {\n\t\t\tdata[i] = value.charCodeAt(i);\n\t\t}\n\n\t\treturn {\n\t\t\tpointer: allocatedMemory.pointer,\n\t\t\tcharType,\n\t\t};\n\t}\n\n\tget value(): string {\n\t\tlet pointer = loadRawPointer(this.allocatedMemory.data, POINTER_INDEX);\n\t\tif(this.cachedPointer === pointer && this.cachedString !== undefined) {\n\t\t\treturn this.cachedString;\n\t\t} else if(pointer === 0) {\n\t\t\treturn '';\n\t\t}\n\t\tlet { bufferPosition, bufferByteOffset } = getPointer(pointer, this.memory.positionBits);\n\n\t\tlock(this.lock);\n\t\tlet charType = Atomics.load(this.allocatedMemory.data, TYPE_INDEX);\n\t\t// @ts-expect-error\n\t\tlet typedArray = TYPED_ARRAY_MAP[charType];\n\t\tlet bufferLength = Atomics.load(this.allocatedMemory.data, LENGTH_INDEX);\n\n\t\tlet data = new typedArray(this.memory.buffers[bufferPosition].buf, bufferByteOffset, bufferLength);\n\t\tlet string = fromCharCodes(data);\n\t\t// NOTE: Do not unlock until after transforming the data since the second this is done it can free that memory block\n\t\tunlock(this.lock);\n\n\t\tthis.cachedPointer = pointer;\n\t\tthis.cachedString = string;\n\n\t\treturn string;\n\t}\n\tset value(value: string) {\n\t\tlet { bufferPosition: oldBufferPosition, bufferByteOffset: oldBufferByteOffset } = loadPointer(this.allocatedMemory.data, POINTER_INDEX, this.memory.positionBits);\n\t\tthis.updateString(value);\n\n\t\tif(oldBufferByteOffset) {\n\t\t\tthis.memory.buffers[oldBufferPosition].free(oldBufferByteOffset);\n\t\t}\n\t}\n\n\tgetSharedMemory(): SharedStringMemory {\n\t\treturn this.allocatedMemory.getSharedMemory();\n\t}\n\n\tget pointer() {\n\t\treturn this.allocatedMemory.pointer;\n\t}\n\n\tfree() {\n\t\tlet { bufferPosition, bufferByteOffset } = loadPointer(this.allocatedMemory.data, POINTER_INDEX, this.memory.positionBits);\n\t\tif(bufferByteOffset) {\n\t\t\tthis.memory.buffers[bufferPosition].free(bufferByteOffset);\n\t\t}\n\t\tthis.allocatedMemory.free();\n\t}\n}\n\n// String.fromCharCode.apply throws a RangeError (Maximum call stack size exceeded) when handed too many\n// arguments at once, so decode large buffers in chunks to support arbitrarily long strings\nfunction fromCharCodes(data: Uint8Array | Uint16Array): string {\n\tconst CHUNK_SIZE = 8192;\n\tif(data.length <= CHUNK_SIZE) {\n\t\treturn String.fromCharCode.apply(null, data as unknown as Array<number>);\n\t}\n\n\tlet string = '';\n\tfor(let i = 0; i < data.length; i += CHUNK_SIZE) {\n\t\tstring += String.fromCharCode.apply(null, data.subarray(i, i + CHUNK_SIZE) as unknown as Array<number>);\n\t}\n\n\treturn string;\n}\n\ninterface SharedStringConfig extends SharedStringMemory {\n\tvalue: string\n}\ntype SharedStringMemory = SharedAllocatedMemory;"],"mappings":"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"}
1
+ {"version":3,"file":"shared-string.js","names":["AllocatedMemory","TYPED_ARRAY_MAP","POINTER_INDEX","LENGTH_INDEX","TYPE_INDEX","LOCK_INDEX","SharedString","memory","value","stringMemory","lock","storeRawPointer","unlock","maxCharCode","i","charCode","charType","typedArray","allocatedMemory","data","pointer","loadRawPointer","getPointer","bufferLength","string","fromCharCodes","bufferPosition","bufferByteOffset","oldBufferPosition","oldBufferByteOffset","loadPointer","CHUNK_SIZE"],"sources":["../src/shared-string.ts"],"sourcesContent":["import AllocatedMemory from './allocated-memory';\nimport type { SharedAllocatedMemory } from './allocated-memory';\nimport { lock, unlock } from './lock/simple-lock';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer, loadPointer, loadRawPointer, storeRawPointer } from './utils/pointer';\n\nenum CHAR_TYPE {\n\tUNDEFINED,\n\tASCII,\n\tUTF16,\n}\nconst TYPED_ARRAY_MAP = {\n\t[CHAR_TYPE.ASCII]: Uint8Array,\n\t[CHAR_TYPE.UTF16]: Uint16Array,\n};\n\nconst POINTER_INDEX = 0;\nconst LENGTH_INDEX = 1;\nconst TYPE_INDEX = 2;\nconst LOCK_INDEX = 3;\nexport default class SharedString {\n\tstatic readonly ALLOCATE_COUNT = 4;\n\n\tprivate memory: MemoryHeap;\n\tprivate allocatedMemory: AllocatedMemory;\n\tprivate lock: Int32Array;\n\n\tprivate cachedPointer?: number;\n\tprivate cachedString?: string;\n\t\n\tconstructor(memory: MemoryHeap, value: string | SharedStringConfig | SharedStringMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(typeof value === 'string') {\n\t\t\tthis.allocatedMemory = this.memory.allocUI32(SharedString.ALLOCATE_COUNT);\n\t\t\tthis.lock = new Int32Array(this.allocatedMemory.data.buffer, this.allocatedMemory.bufferByteOffset + LOCK_INDEX * this.allocatedMemory.data.BYTES_PER_ELEMENT);\n\t\t\tthis.updateString(value);\n\t\t} else {\n\t\t\tthis.allocatedMemory = new AllocatedMemory(memory, value);\n\t\t\tthis.lock = new Int32Array(this.allocatedMemory.data.buffer, this.allocatedMemory.bufferByteOffset + LOCK_INDEX * this.allocatedMemory.data.BYTES_PER_ELEMENT);\n\n\t\t\t// We only allocated memory but didn't initialize the string yet\n\t\t\tif('value' in value) {\n\t\t\t\tthis.updateString(value.value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tprivate updateString(value: string) {\n\t\tlet stringMemory = this.createString(value);\n\n\t\tlock(this.lock);\n\t\tstoreRawPointer(this.allocatedMemory.data, POINTER_INDEX, stringMemory.pointer);\n\t\tAtomics.store(this.allocatedMemory.data, LENGTH_INDEX, value.length);\n\t\tAtomics.store(this.allocatedMemory.data, TYPE_INDEX, stringMemory.charType);\n\t\tunlock(this.lock);\n\n\t\tthis.cachedPointer = stringMemory.pointer;\n\t\tthis.cachedString = value;\n\t}\n\tprivate createString(value: string) {\n\t\tif(value === '') {\n\t\t\treturn {\n\t\t\t\tpointer: 0,\n\t\t\t\tcharType: CHAR_TYPE.ASCII,\n\t\t\t};\n\t\t}\n\n\t\t// NOTE: Scan with a loop instead of Math.max(...charCodes) which blows the stack for large strings\n\t\tlet maxCharCode = 0;\n\t\tfor(let i = 0; i < value.length; i++) {\n\t\t\tlet charCode = value.charCodeAt(i);\n\t\t\tif(charCode > maxCharCode) {\n\t\t\t\tmaxCharCode = charCode;\n\t\t\t}\n\t\t}\n\t\tlet charType = maxCharCode > 255 ? CHAR_TYPE.UTF16 : CHAR_TYPE.ASCII;\n\n\t\tlet typedArray = TYPED_ARRAY_MAP[charType];\n\t\tlet allocatedMemory = this.memory.allocUI32(Math.ceil(value.length / (4 / typedArray.BYTES_PER_ELEMENT)));\n\t\tlet data = new typedArray(allocatedMemory.data.buffer as ArrayBuffer, allocatedMemory.data.byteOffset, value.length);\n\t\tfor(let i = 0; i < value.length; i++) {\n\t\t\tdata[i] = value.charCodeAt(i);\n\t\t}\n\n\t\treturn {\n\t\t\tpointer: allocatedMemory.pointer,\n\t\t\tcharType,\n\t\t};\n\t}\n\n\tget value(): string {\n\t\tlet pointer = loadRawPointer(this.allocatedMemory.data, POINTER_INDEX);\n\t\tif(this.cachedPointer === pointer && this.cachedString !== undefined) {\n\t\t\treturn this.cachedString;\n\t\t} else if(pointer === 0) {\n\t\t\treturn '';\n\t\t}\n\t\tlet { bufferPosition, bufferByteOffset } = getPointer(pointer, this.memory.positionBits);\n\n\t\tlock(this.lock);\n\t\tlet charType = Atomics.load(this.allocatedMemory.data, TYPE_INDEX);\n\t\t// @ts-expect-error\n\t\tlet typedArray = TYPED_ARRAY_MAP[charType];\n\t\tlet bufferLength = Atomics.load(this.allocatedMemory.data, LENGTH_INDEX);\n\n\t\tlet data = new typedArray(this.memory.buffers[bufferPosition].buf, bufferByteOffset, bufferLength);\n\t\tlet string = fromCharCodes(data);\n\t\t// NOTE: Do not unlock until after transforming the data since the second this is done it can free that memory block\n\t\tunlock(this.lock);\n\n\t\tthis.cachedPointer = pointer;\n\t\tthis.cachedString = string;\n\n\t\treturn string;\n\t}\n\tset value(value: string) {\n\t\tlet { bufferPosition: oldBufferPosition, bufferByteOffset: oldBufferByteOffset } = loadPointer(this.allocatedMemory.data, POINTER_INDEX, this.memory.positionBits);\n\t\tthis.updateString(value);\n\n\t\tif(oldBufferByteOffset) {\n\t\t\tthis.memory.buffers[oldBufferPosition].free(oldBufferByteOffset);\n\t\t}\n\t}\n\n\tgetSharedMemory(): SharedStringMemory {\n\t\treturn this.allocatedMemory.getSharedMemory();\n\t}\n\n\tget pointer() {\n\t\treturn this.allocatedMemory.pointer;\n\t}\n\n\tfree() {\n\t\tlet { bufferPosition, bufferByteOffset } = loadPointer(this.allocatedMemory.data, POINTER_INDEX, this.memory.positionBits);\n\t\tif(bufferByteOffset) {\n\t\t\tthis.memory.buffers[bufferPosition].free(bufferByteOffset);\n\t\t}\n\t\tthis.allocatedMemory.free();\n\t}\n}\n\n// String.fromCharCode.apply throws a RangeError (Maximum call stack size exceeded) when handed too many\n// arguments at once, so decode large buffers in chunks to support arbitrarily long strings\nfunction fromCharCodes(data: Uint8Array | Uint16Array): string {\n\tconst CHUNK_SIZE = 8192;\n\tif(data.length <= CHUNK_SIZE) {\n\t\treturn String.fromCharCode.apply(null, data as unknown as Array<number>);\n\t}\n\n\tlet string = '';\n\tfor(let i = 0; i < data.length; i += CHUNK_SIZE) {\n\t\tstring += String.fromCharCode.apply(null, data.subarray(i, i + CHUNK_SIZE) as unknown as Array<number>);\n\t}\n\n\treturn string;\n}\n\ninterface SharedStringConfig extends SharedStringMemory {\n\tvalue: string\n}\ntype SharedStringMemory = SharedAllocatedMemory;"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"shared-vector.js","names":[],"sources":["../src/shared-vector.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport AllocatedMemory from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer, loadPointer, storePointer, storeRawPointer } from './utils/pointer';\nimport { getArrayTypeCode, getByteMultipler, makeArrayView, type NumericArray, type NumericArrayIO, type TypedArrayConstructor } from './utils/array-type';\n\nconst VECTOR_INDEX = 0;\nconst LENGTH_INDEX = 1;\nconst BUFFER_LENGTH_INDEX = 2;\nconst TYPE_INDEX = 3;\nconst DEFAULT_SIZE = 4;\nexport default class SharedVector<T extends NumericArray = Uint32Array> implements Iterable<T> {\n\tstatic readonly ALLOCATE_COUNT = 4;\n\tprivate memory: MemoryHeap;\n\n\t// Pointer, List Length, Buffer Length, Type/DataLength\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\t// u32 units per element: 1 for 32-bit types, 2 for 64-bit (float64/int64/uint64). Every data-block allocation scales\n\t// by this; the typed view length stays in elements.\n\tprivate cachedByteMultipler = 1;\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t}\n\t\n\tget type(): number {\n\t\treturn this.uint16Array[0];\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\tget byteMultipler(): number {\n\t\treturn this.cachedByteMultipler;\n\t}\n\tget dataLength(): number {\n\t\t// Can technically be initialized by passing memory without actually every being called - need to make sure dataLength is always at least one\n\t\treturn this.uint16Array[1] || 1;\n\t}\n\tprivate set dataLength(value: number) {\n\t\tAtomics.store(this.uint16Array, 1, value);\n\t}\n\n\tget bufferLength(): number {\n\t\treturn Atomics.load(this.firstBlock.data, BUFFER_LENGTH_INDEX);\n\t}\n\tprivate set bufferLength(value: number) {\n\t\tAtomics.store(this.firstBlock.data, BUFFER_LENGTH_INDEX, value);\n\t}\n\n\tget pointer() {\n\t\treturn this.firstBlock.pointer;\n\t}\n\n\tget usedMemory(): number {\n\t\tlet dataMemory = new AllocatedMemory(this.memory, loadPointer(this.firstBlock.data, VECTOR_INDEX, this.memory.positionBits));\n\t\treturn this.firstBlock.usedMemory + dataMemory.usedMemory;\n\t}\n\n\tprivate cachedFullDataBlock?: T;\n\tprivate cachedPointer: number;\n\n\tconstructor(memory: MemoryHeap, config?: SharedVectorConfig<T> | SharedVectorMemory | SharedVectorMemory & SharedVectorConfig<T>) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\tthis.firstBlock = new AllocatedMemory(memory, {\n\t\t\t\tlength: SharedVector.ALLOCATE_COUNT,\n\t\t\t\t...config.firstBlock,\n\t\t\t});\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\t// Pre-allocating memory and setting up in specific memory location\n\t\t\tif('type' in config || 'dataLength' in config) {\n\t\t\t\tconst typeCode = getArrayTypeCode(config.type ?? Uint32Array);\n\t\t\t\tconst byteMultipler = getByteMultipler(typeCode);\n\t\t\t\tconst bufferLength = config.bufferLength ?? DEFAULT_SIZE;\n\t\t\t\tlet dataBlock = memory.allocUI32(bufferLength * (config.dataLength ?? 1) * byteMultipler);\n\t\t\t\tstorePointer(this.firstBlock.data, VECTOR_INDEX, dataBlock.bufferPosition, dataBlock.bufferByteOffset, memory.positionBits);\n\t\t\t\tthis.bufferLength = bufferLength;\n\t\t\t\tthis.dataLength = (config.dataLength ?? 1);\n\t\t\t\tthis.type = typeCode;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.firstBlock = memory.allocUI32(SharedVector.ALLOCATE_COUNT);\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\tlet dataLength = config?.dataLength ?? 1;\n\t\t\tlet bufferLength = config?.bufferLength ?? DEFAULT_SIZE;\n\t\t\tlet typeCode = getArrayTypeCode(config?.type ?? Uint32Array);\n\t\t\tlet dataBlock = memory.allocUI32(bufferLength * dataLength * getByteMultipler(typeCode));\n\t\t\tstorePointer(this.firstBlock.data, VECTOR_INDEX, dataBlock.bufferPosition, dataBlock.bufferByteOffset, memory.positionBits);\n\t\t\tthis.bufferLength = bufferLength;\n\t\t\tthis.type = typeCode;\n\t\t\tthis.dataLength = dataLength;\n\t\t}\n\n\t\tthis.cachedByteMultipler = getByteMultipler(this.type);\n\t\tthis.cachedPointer = this.firstBlock.data[0];\n\t\tthis.cachedFullDataBlock = this.getFullDataBlock();\n\t}\n\n\tat(index: number): T {\n\t\tlet length = this.length;\n\t\tif(index >= length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${length}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn this.getDataBlock(dataBlock, index);\n\t}\n\tget(index: number, dataIndex = 0): T[number] {\n\t\tif(dataIndex >= this.dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${this.dataLength}`);\n\t\t} else if(index >= this.length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${this.length}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock() as NumericArrayIO;\n\t\treturn dataBlock[index * this.dataLength + dataIndex];\n\t}\n\n\tpush(values: T[number] | Array<T[number]>): number {\n\t\tlet dataLength = this.dataLength;\n\t\tconst isSingleValue = typeof values !== 'object';\n\t\tif(!isSingleValue && values.length > dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${dataLength} dataLength`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock() as NumericArrayIO;\n\t\tlet currentLength = this.length;\n\t\tlet startIndex = dataLength * currentLength;\n\t\tif(isSingleValue) {\n\t\t\tdataBlock[startIndex] = values;\n\t\t} else {\n\t\t\tfor(let i = 0; i < values.length; i++) {\n\t\t\t\tdataBlock[startIndex + i] = values[i];\n\t\t\t}\n\t\t}\n\n\t\tlet newLength = Atomics.add(this.firstBlock.data, LENGTH_INDEX, 1) + 1;\n\t\tif(newLength >= this.bufferLength) {\n\t\t\tthis.growBuffer();\n\t\t}\n\n\t\treturn currentLength;\n\t}\n\n\tpop(): T {\n\t\tlet oldLength = Atomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn this.getDataBlock(dataBlock, oldLength - 1);\n\t}\n\n\t// Returns the first number irregardless of dataLength - faster way to pop if you don't care about the rest of the data block\n\tpopNumber(): T[number] {\n\t\tconst oldLength = Atomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\t\tconst dataBlock = this.getFullDataBlock() as NumericArrayIO;\n\t\treturn dataBlock[(oldLength - 1) * this.dataLength];\n\t}\n\n\tdeleteIndex(index: number) {\n\t\tlet length = this.length;\n\t\tif(index >= length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${length}`);\n\t\t}\n\n\t\tlet dataLength = this.dataLength;\n\t\tlet dataBlock = this.getFullDataBlock() as NumericArrayIO;\n\t\tfor(let i = index; i < length; i++) {\n\t\t\tfor(let j = 0; j < dataLength; j++) {\n\t\t\t\tdataBlock[i * dataLength + j] = dataBlock[(i + 1) * dataLength + j];\n\t\t\t}\n\t\t}\n\n\t\tAtomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\t}\n\n\tclear() {\n\t\tthis.firstBlock.data[LENGTH_INDEX] = 0;\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\tlet dataLength = this.dataLength;\n\t\tlet totalDataEntries = this.length * dataLength;\n\n\t\tfor(let i = 0; i < totalDataEntries; i += dataLength) {\n\t\t\tyield dataBlock.subarray(i, i + dataLength) as T;\n\t\t}\n\t}\n\n\t// Significantly faster but won't be thread safe if anything is removing/adding to it during iteration\n\tgetCurrentArray(): T {\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn dataBlock.subarray(0, this.length * this.dataLength) as T;\n\t}\n\n\tprivate getFullDataBlock(): T {\n\t\tlet pointerNumber = Atomics.load(this.firstBlock.data, VECTOR_INDEX);\n\t\tif(this.cachedPointer === pointerNumber && this.cachedFullDataBlock) {\n\t\t\treturn this.cachedFullDataBlock;\n\t\t}\n\n\t\tlet pointer = getPointer(pointerNumber, this.memory.positionBits);\n\t\tlet rawData = new AllocatedMemory(this.memory, pointer);\n\n\t\tlet data = makeArrayView(this.type, rawData.data.buffer, rawData.bufferByteOffset, this.dataLength * this.bufferLength) as T;\n\n\t\tthis.cachedPointer = pointerNumber;\n\t\tthis.cachedFullDataBlock = data;\n\n\t\treturn data;\n\t}\n\tprivate getDataBlock(rawData: T, index: number): T {\n\t\tconst start = index * this.dataLength;\n\t\treturn rawData.subarray(start, start + this.dataLength) as T;\n\t}\n\n\tprivate growBuffer() {\n\t\tlet oldBufferLength = this.bufferLength;\n\t\tlet newBufferLength = oldBufferLength * 2;\n\t\tlet dataLength = this.dataLength;\n\n\t\tlet oldPointer = loadPointer(this.firstBlock.data, VECTOR_INDEX, this.memory.positionBits);\n\t\tlet oldDataMemory = new AllocatedMemory(this.memory, oldPointer);\n\t\tlet oldDataBlock = this.getFullDataBlock();\n\t\tlet newDataBlock = this.memory.allocUI32(newBufferLength * dataLength * this.cachedByteMultipler);\n\n\t\tlet newData = makeArrayView(this.type, newDataBlock.data.buffer, newDataBlock.bufferByteOffset, dataLength * newBufferLength) as T;\n\n\t\t// newData and oldDataBlock are the same concrete view type, so a direct copy is valid; the cast only bridges the\n\t\t// union's mutually-incompatible set() overloads (number vs bigint element types)\n\t\t(newData as Float64Array).set(oldDataBlock as unknown as Float64Array);\n\n\t\tconst newPointer = newDataBlock.pointer;\n\t\tstoreRawPointer(this.firstBlock.data, VECTOR_INDEX, newPointer);\n\t\tthis.bufferLength = newBufferLength;\n\t\toldDataMemory.free();\n\n\t\tthis.cachedPointer = newPointer;\n\t\tthis.cachedFullDataBlock = newData;\n\t}\n\n\tfree() {\n\t\tlet pointer = loadPointer(this.firstBlock.data, VECTOR_INDEX, this.memory.positionBits);\n\t\tlet dataMemory = new AllocatedMemory(this.memory, pointer);\n\n\t\tdataMemory.free();\n\t\tthis.firstBlock.free();\n\t}\n\n\tgetSharedMemory(): SharedVectorMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedVectorConfig<T extends NumericArray> {\n\ttype?: TypedArrayConstructor<T>\n\tdataLength?: number\n\n\tbufferLength?: number\n}\ninterface SharedVectorMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedVectorConfig, SharedVectorMemory };"],"mappings":"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"}
1
+ {"version":3,"file":"shared-vector.js","names":["AllocatedMemory","VECTOR_INDEX","LENGTH_INDEX","BUFFER_LENGTH_INDEX","TYPE_INDEX","DEFAULT_SIZE","SharedVector","value","dataMemory","loadPointer","memory","config","typeCode","getArrayTypeCode","byteMultipler","getByteMultipler","bufferLength","dataBlock","storePointer","dataLength","length","index","dataIndex","isSingleValue","values","currentLength","startIndex","i","oldLength","j","totalDataEntries","pointerNumber","pointer","getPointer","rawData","data","makeArrayView","start","newBufferLength","oldPointer","oldDataMemory","oldDataBlock","newDataBlock","newData","newPointer","storeRawPointer"],"sources":["../src/shared-vector.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport AllocatedMemory from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer, loadPointer, storePointer, storeRawPointer } from './utils/pointer';\nimport { getArrayTypeCode, getByteMultipler, makeArrayView, type NumericArray, type NumericArrayIO, type TypedArrayConstructor } from './utils/array-type';\n\nconst VECTOR_INDEX = 0;\nconst LENGTH_INDEX = 1;\nconst BUFFER_LENGTH_INDEX = 2;\nconst TYPE_INDEX = 3;\nconst DEFAULT_SIZE = 4;\nexport default class SharedVector<T extends NumericArray = Uint32Array> implements Iterable<T> {\n\tstatic readonly ALLOCATE_COUNT = 4;\n\tprivate memory: MemoryHeap;\n\n\t// Pointer, List Length, Buffer Length, Type/DataLength\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\t// u32 units per element: 1 for 32-bit types, 2 for 64-bit (float64/int64/uint64). Every data-block allocation scales\n\t// by this; the typed view length stays in elements.\n\tprivate cachedByteMultipler = 1;\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t}\n\t\n\tget type(): number {\n\t\treturn this.uint16Array[0];\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\tget byteMultipler(): number {\n\t\treturn this.cachedByteMultipler;\n\t}\n\tget dataLength(): number {\n\t\t// Can technically be initialized by passing memory without actually every being called - need to make sure dataLength is always at least one\n\t\treturn this.uint16Array[1] || 1;\n\t}\n\tprivate set dataLength(value: number) {\n\t\tAtomics.store(this.uint16Array, 1, value);\n\t}\n\n\tget bufferLength(): number {\n\t\treturn Atomics.load(this.firstBlock.data, BUFFER_LENGTH_INDEX);\n\t}\n\tprivate set bufferLength(value: number) {\n\t\tAtomics.store(this.firstBlock.data, BUFFER_LENGTH_INDEX, value);\n\t}\n\n\tget pointer() {\n\t\treturn this.firstBlock.pointer;\n\t}\n\n\tget usedMemory(): number {\n\t\tlet dataMemory = new AllocatedMemory(this.memory, loadPointer(this.firstBlock.data, VECTOR_INDEX, this.memory.positionBits));\n\t\treturn this.firstBlock.usedMemory + dataMemory.usedMemory;\n\t}\n\n\tprivate cachedFullDataBlock?: T;\n\tprivate cachedPointer: number;\n\n\tconstructor(memory: MemoryHeap, config?: SharedVectorConfig<T> | SharedVectorMemory | SharedVectorMemory & SharedVectorConfig<T>) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\tthis.firstBlock = new AllocatedMemory(memory, {\n\t\t\t\tlength: SharedVector.ALLOCATE_COUNT,\n\t\t\t\t...config.firstBlock,\n\t\t\t});\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\t// Pre-allocating memory and setting up in specific memory location\n\t\t\tif('type' in config || 'dataLength' in config) {\n\t\t\t\tconst typeCode = getArrayTypeCode(config.type ?? Uint32Array);\n\t\t\t\tconst byteMultipler = getByteMultipler(typeCode);\n\t\t\t\tconst bufferLength = config.bufferLength ?? DEFAULT_SIZE;\n\t\t\t\tlet dataBlock = memory.allocUI32(bufferLength * (config.dataLength ?? 1) * byteMultipler);\n\t\t\t\tstorePointer(this.firstBlock.data, VECTOR_INDEX, dataBlock.bufferPosition, dataBlock.bufferByteOffset, memory.positionBits);\n\t\t\t\tthis.bufferLength = bufferLength;\n\t\t\t\tthis.dataLength = (config.dataLength ?? 1);\n\t\t\t\tthis.type = typeCode;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.firstBlock = memory.allocUI32(SharedVector.ALLOCATE_COUNT);\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\tlet dataLength = config?.dataLength ?? 1;\n\t\t\tlet bufferLength = config?.bufferLength ?? DEFAULT_SIZE;\n\t\t\tlet typeCode = getArrayTypeCode(config?.type ?? Uint32Array);\n\t\t\tlet dataBlock = memory.allocUI32(bufferLength * dataLength * getByteMultipler(typeCode));\n\t\t\tstorePointer(this.firstBlock.data, VECTOR_INDEX, dataBlock.bufferPosition, dataBlock.bufferByteOffset, memory.positionBits);\n\t\t\tthis.bufferLength = bufferLength;\n\t\t\tthis.type = typeCode;\n\t\t\tthis.dataLength = dataLength;\n\t\t}\n\n\t\tthis.cachedByteMultipler = getByteMultipler(this.type);\n\t\tthis.cachedPointer = this.firstBlock.data[0];\n\t\tthis.cachedFullDataBlock = this.getFullDataBlock();\n\t}\n\n\tat(index: number): T {\n\t\tlet length = this.length;\n\t\tif(index >= length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${length}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn this.getDataBlock(dataBlock, index);\n\t}\n\tget(index: number, dataIndex = 0): T[number] {\n\t\tif(dataIndex >= this.dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${this.dataLength}`);\n\t\t} else if(index >= this.length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${this.length}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock() as NumericArrayIO;\n\t\treturn dataBlock[index * this.dataLength + dataIndex];\n\t}\n\n\tpush(values: T[number] | Array<T[number]>): number {\n\t\tlet dataLength = this.dataLength;\n\t\tconst isSingleValue = typeof values !== 'object';\n\t\tif(!isSingleValue && values.length > dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${dataLength} dataLength`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock() as NumericArrayIO;\n\t\tlet currentLength = this.length;\n\t\tlet startIndex = dataLength * currentLength;\n\t\tif(isSingleValue) {\n\t\t\tdataBlock[startIndex] = values;\n\t\t} else {\n\t\t\tfor(let i = 0; i < values.length; i++) {\n\t\t\t\tdataBlock[startIndex + i] = values[i];\n\t\t\t}\n\t\t}\n\n\t\tlet newLength = Atomics.add(this.firstBlock.data, LENGTH_INDEX, 1) + 1;\n\t\tif(newLength >= this.bufferLength) {\n\t\t\tthis.growBuffer();\n\t\t}\n\n\t\treturn currentLength;\n\t}\n\n\tpop(): T {\n\t\tlet oldLength = Atomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn this.getDataBlock(dataBlock, oldLength - 1);\n\t}\n\n\t// Returns the first number irregardless of dataLength - faster way to pop if you don't care about the rest of the data block\n\tpopNumber(): T[number] {\n\t\tconst oldLength = Atomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\t\tconst dataBlock = this.getFullDataBlock() as NumericArrayIO;\n\t\treturn dataBlock[(oldLength - 1) * this.dataLength];\n\t}\n\n\tdeleteIndex(index: number) {\n\t\tlet length = this.length;\n\t\tif(index >= length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${length}`);\n\t\t}\n\n\t\tlet dataLength = this.dataLength;\n\t\tlet dataBlock = this.getFullDataBlock() as NumericArrayIO;\n\t\tfor(let i = index; i < length; i++) {\n\t\t\tfor(let j = 0; j < dataLength; j++) {\n\t\t\t\tdataBlock[i * dataLength + j] = dataBlock[(i + 1) * dataLength + j];\n\t\t\t}\n\t\t}\n\n\t\tAtomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\t}\n\n\tclear() {\n\t\tthis.firstBlock.data[LENGTH_INDEX] = 0;\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\tlet dataLength = this.dataLength;\n\t\tlet totalDataEntries = this.length * dataLength;\n\n\t\tfor(let i = 0; i < totalDataEntries; i += dataLength) {\n\t\t\tyield dataBlock.subarray(i, i + dataLength) as T;\n\t\t}\n\t}\n\n\t// Significantly faster but won't be thread safe if anything is removing/adding to it during iteration\n\tgetCurrentArray(): T {\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn dataBlock.subarray(0, this.length * this.dataLength) as T;\n\t}\n\n\tprivate getFullDataBlock(): T {\n\t\tlet pointerNumber = Atomics.load(this.firstBlock.data, VECTOR_INDEX);\n\t\tif(this.cachedPointer === pointerNumber && this.cachedFullDataBlock) {\n\t\t\treturn this.cachedFullDataBlock;\n\t\t}\n\n\t\tlet pointer = getPointer(pointerNumber, this.memory.positionBits);\n\t\tlet rawData = new AllocatedMemory(this.memory, pointer);\n\n\t\tlet data = makeArrayView(this.type, rawData.data.buffer, rawData.bufferByteOffset, this.dataLength * this.bufferLength) as T;\n\n\t\tthis.cachedPointer = pointerNumber;\n\t\tthis.cachedFullDataBlock = data;\n\n\t\treturn data;\n\t}\n\tprivate getDataBlock(rawData: T, index: number): T {\n\t\tconst start = index * this.dataLength;\n\t\treturn rawData.subarray(start, start + this.dataLength) as T;\n\t}\n\n\tprivate growBuffer() {\n\t\tlet oldBufferLength = this.bufferLength;\n\t\tlet newBufferLength = oldBufferLength * 2;\n\t\tlet dataLength = this.dataLength;\n\n\t\tlet oldPointer = loadPointer(this.firstBlock.data, VECTOR_INDEX, this.memory.positionBits);\n\t\tlet oldDataMemory = new AllocatedMemory(this.memory, oldPointer);\n\t\tlet oldDataBlock = this.getFullDataBlock();\n\t\tlet newDataBlock = this.memory.allocUI32(newBufferLength * dataLength * this.cachedByteMultipler);\n\n\t\tlet newData = makeArrayView(this.type, newDataBlock.data.buffer, newDataBlock.bufferByteOffset, dataLength * newBufferLength) as T;\n\n\t\t// newData and oldDataBlock are the same concrete view type, so a direct copy is valid; the cast only bridges the\n\t\t// union's mutually-incompatible set() overloads (number vs bigint element types)\n\t\t(newData as Float64Array).set(oldDataBlock as unknown as Float64Array);\n\n\t\tconst newPointer = newDataBlock.pointer;\n\t\tstoreRawPointer(this.firstBlock.data, VECTOR_INDEX, newPointer);\n\t\tthis.bufferLength = newBufferLength;\n\t\toldDataMemory.free();\n\n\t\tthis.cachedPointer = newPointer;\n\t\tthis.cachedFullDataBlock = newData;\n\t}\n\n\tfree() {\n\t\tlet pointer = loadPointer(this.firstBlock.data, VECTOR_INDEX, this.memory.positionBits);\n\t\tlet dataMemory = new AllocatedMemory(this.memory, pointer);\n\n\t\tdataMemory.free();\n\t\tthis.firstBlock.free();\n\t}\n\n\tgetSharedMemory(): SharedVectorMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedVectorConfig<T extends NumericArray> {\n\ttype?: TypedArrayConstructor<T>\n\tdataLength?: number\n\n\tbufferLength?: number\n}\ninterface SharedVectorMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedVectorConfig, SharedVectorMemory };"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"shared-quadtree.js","names":[],"sources":["../../src/spatial/shared-quadtree.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 { lock, unlock } from '../lock/simple-lock';\nimport { getPointer, loadRawPointer, storeRawPointer } from '../utils/pointer';\nimport { ARRAY_TYPE, getArrayTypeCode, getByteMultipler, makeArrayView } from '../utils/array-type';\nimport {\n\tMinPriorityQueue, addCandidate, candidateLimit, distanceSquaredToRect,\n\ttype NeighborCandidate, type NearestNeighbor,\n} from './spatial-neighbors';\nimport { getSpatialMapCapacity, getSpatialPoolChunkSize, type SpatialEntity } from './spatial-entity';\n\n// Fixed-depth region quadtree (\"implicit\" / hierarchical grid) built for concurrent updates from many threads. Dynamic\n// subdivision is deliberately avoided: creating/redistributing/freeing nodes at runtime races with readers mid-traversal\n// (the same hazard MemoryBuffer disables compaction for). Here the tree of nodes is allocated once and never changes\n// shape, so concurrency reduces to per-cell content updates - different cells never contend.\n//\n// Node layout is implicit: node 0 is the root, the four children of node i are 4i+1..4i+4 (NW, NE, SW, SE). Bounds are\n// derived from the root bounds during descent, never stored. Each node owns an intrusive singly-linked bucket: the node\n// record holds a lock and the head item index, and each item record carries the next index. Items live in a SharedPool\n// (stable indices, recycling) and an id->itemIndex SharedMap makes update/remove O(depth) by entity id.\n//\n// Each entity is stored in the single deepest node that fully contains its rect (an item too large or straddling a\n// midline stays at an ancestor). search walks every node whose region intersects the query and returns a broad-phase\n// superset of candidate ids - the same guarantee quadtree-js's retrieve gives, without duplicating straddlers.\n//\n// The whole item record (id, coords, node, bucket link) lives in one pool at the configured precision. Float32 (the\n// default, matching a physics engine that keeps positions in Float32) keeps everything exact as long as entity ids and\n// the pool's index space both stay under 2^24 (~16.7M) - every id, pool index, node index and the NULL sentinel is a\n// Float32-exact integer there. Need more than that many entities (or ids >= 2^24)? Pass type: Float64Array.\n\n// Header (firstBlock) u32 layout\nconst NODE_POINTER_INDEX = 0;\nconst POOL_POINTER_INDEX = 1;\nconst MAP_POINTER_INDEX = 2;\nconst MAX_LEVELS_INDEX = 3;\nconst NODE_COUNT_INDEX = 4;\nconst TYPE_INDEX = 5;\n// bounds view starts at slot 6 (offset 24 bytes is 8-byte aligned, so a Float64 bounds view is valid)\nconst BOUNDS_INDEX = 6;\n\n// Per-node record: [lock, head]\nconst NODE_LOCK_OFFSET = 0;\nconst NODE_HEAD_OFFSET = 1;\nconst NODE_SIZE = 2;\n\n// Item record fields\nconst ITEM_ID = 0;\nconst ITEM_X = 1;\nconst ITEM_Y = 2;\nconst ITEM_W = 3;\nconst ITEM_H = 4;\nconst ITEM_NODE = 5;\nconst ITEM_NEXT = 6;\nconst ITEM_FIELDS = 7;\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\nconst DEFAULT_MAX_LEVELS = 4;\nconst DEFAULT_MAX_ENTITIES = 1_000_000;\nconst DEFAULT_COORD_TYPE = Float32Array;\n\ntype CoordArray = Float32Array | Float64Array;\ntype CoordArrayConstructor = Float32ArrayConstructor | Float64ArrayConstructor;\n\nexport default class SharedQuadtree {\n\tstatic readonly ALLOCATE_COUNT = 14;\n\n\tprivate memory: MemoryHeap;\n\tprivate firstBlock: AllocatedMemory;\n\tprivate pool: SharedPool<CoordArray>;\n\tprivate idMap: SharedMap<number>;\n\n\t// Reused to hand a full item record to pool.push without allocating a fresh array per insert (single writer per id)\n\tprivate insertScratch: Array<number> = [0, 0, 0, 0, 0, 0, 0];\n\n\t// Node block views over one contiguous region: Int32 for the per-node locks, Uint32 for the head indexes.\n\tprivate nodeInts: Int32Array;\n\tprivate nodeHeads: Uint32Array;\n\n\tprivate readonly maxLevels: number;\n\tprivate readonly nodeCount: number;\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// Root bounds, read once (stored at the configured precision, math done in float64)\n\tprivate readonly rootX: number;\n\tprivate readonly rootY: number;\n\tprivate readonly rootWidth: number;\n\tprivate readonly rootHeight: number;\n\n\t// Number of entities currently tracked\n\tget size(): number {\n\t\treturn this.idMap.length;\n\t}\n\n\tget bounds(): QuadtreeBounds {\n\t\treturn { x: this.rootX, y: this.rootY, width: this.rootWidth, height: this.rootHeight };\n\t}\n\n\t// Element type the record is 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?: SharedQuadtreeConfig | SharedQuadtreeMemory) {\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.pool = new SharedPool<CoordArray>(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, 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.maxLevels = this.firstBlock.data[MAX_LEVELS_INDEX];\n\t\t\tthis.nodeCount = this.firstBlock.data[NODE_COUNT_INDEX];\n\t\t\tthis.nullIndex = nullIndexFor(this.coordType);\n\t\t} else {\n\t\t\tlet bounds = config?.bounds ?? { x: 0, y: 0, width: 0, height: 0 };\n\t\t\tlet maxEntities = config?.maxEntities ?? DEFAULT_MAX_ENTITIES;\n\t\t\tthis.maxLevels = config?.maxLevels ?? DEFAULT_MAX_LEVELS;\n\t\t\tthis.nodeCount = SharedQuadtree.getNodeCount(this.maxLevels);\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) {\n\t\t\t\tthrow new Error(`Float32 SharedQuadtree supports at most ${FLOAT32_LIMIT} entities; pass type: Float64Array for more`);\n\t\t\t}\n\n\t\t\t// Inline the pool and id-map firstBlocks right after the header so the whole spine is one contiguous allocation\n\t\t\t// (the pool's own firstBlock already inlines its two stacks). The node block stays separate: it is large and\n\t\t\t// sized independently of these headers.\n\t\t\tlet poolConfig: SharedPoolConfig<CoordArray> = {\n\t\t\t\ttype: getCoordTypeConstructor(this.coordType),\n\t\t\t\tdataLength: ITEM_FIELDS,\n\t\t\t\tmaxLength: maxEntities,\n\t\t\t\tmaxChunkSize: getSpatialPoolChunkSize(maxEntities, ITEM_FIELDS, getByteMultipler(this.coordType), memory.maxAllocationLength),\n\t\t\t};\n\t\t\tlet poolAllocateCount = SharedPool.getAllocateCount(memory, poolConfig);\n\t\t\tlet mapAllocateCount = SharedMap.ALLOCATE_COUNT;\n\t\t\tthis.firstBlock = memory.allocUI32(SharedQuadtree.ALLOCATE_COUNT + poolAllocateCount + mapAllocateCount);\n\t\t\tthis.firstBlock.data[MAX_LEVELS_INDEX] = this.maxLevels;\n\t\t\tthis.firstBlock.data[NODE_COUNT_INDEX] = this.nodeCount;\n\t\t\tthis.firstBlock.data[TYPE_INDEX] = this.coordType;\n\n\t\t\tlet boundsView = this.getBoundsView();\n\t\t\tboundsView[0] = bounds.x;\n\t\t\tboundsView[1] = bounds.y;\n\t\t\tboundsView[2] = bounds.width;\n\t\t\tboundsView[3] = bounds.height;\n\n\t\t\t// Node block must fit one allocation - it is never resized. Every head starts as NULL (calloc leaves them 0,\n\t\t\t// a valid item index, so they must be initialized explicitly).\n\t\t\tlet nodeBlock = memory.allocUI32(this.nodeCount * NODE_SIZE);\n\t\t\tlet heads = new Uint32Array(nodeBlock.data.buffer, nodeBlock.bufferByteOffset, this.nodeCount * NODE_SIZE);\n\t\t\tfor(let i = 0; i < this.nodeCount; i++) {\n\t\t\t\theads[i * NODE_SIZE + NODE_HEAD_OFFSET] = this.nullIndex;\n\t\t\t}\n\t\t\tstoreRawPointer(this.firstBlock.data, NODE_POINTER_INDEX, nodeBlock.pointer);\n\n\t\t\tlet poolBlock = this.firstBlock.getSubAllocation(SharedQuadtree.ALLOCATE_COUNT, poolAllocateCount);\n\t\t\tthis.pool = new SharedPool<CoordArray>(memory, { firstBlock: poolBlock, ...poolConfig });\n\t\t\tstoreRawPointer(this.firstBlock.data, POOL_POINTER_INDEX, poolBlock.pointer);\n\n\t\t\tlet mapBlock = this.firstBlock.getSubAllocation(SharedQuadtree.ALLOCATE_COUNT + poolAllocateCount, 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\tlet boundsView = this.getBoundsView();\n\t\tthis.rootX = boundsView[0];\n\t\tthis.rootY = boundsView[1];\n\t\tthis.rootWidth = boundsView[2];\n\t\tthis.rootHeight = boundsView[3];\n\n\t\tlet nodeBlock = new AllocatedMemory(memory, getPointer(loadRawPointer(this.firstBlock.data, NODE_POINTER_INDEX), memory.positionBits));\n\t\tthis.nodeInts = new Int32Array(nodeBlock.data.buffer, nodeBlock.bufferByteOffset, this.nodeCount * NODE_SIZE);\n\t\tthis.nodeHeads = new Uint32Array(nodeBlock.data.buffer, nodeBlock.bufferByteOffset, this.nodeCount * NODE_SIZE);\n\t}\n\n\t// Total nodes in a complete quadtree of the given depth: sum of 4^level for level 0..maxLevels.\n\tstatic getNodeCount(maxLevels: number): number {\n\t\treturn (Math.pow(4, maxLevels + 1) - 1) / 3;\n\t}\n\n\tget pointer(): number {\n\t\treturn this.firstBlock.pointer;\n\t}\n\n\tget usedMemory(): number {\n\t\tlet nodeBlock = new AllocatedMemory(this.memory, getPointer(loadRawPointer(this.firstBlock.data, NODE_POINTER_INDEX), this.memory.positionBits));\n\t\treturn this.firstBlock.usedMemory + nodeBlock.usedMemory + this.pool.usedMemory + this.idMap.usedMemory;\n\t}\n\n\tinsert(id: number, x: number, y: number, width = 0, height = 0) {\n\t\tif(this.idMap.get(id) !== undefined) {\n\t\t\tthis.update(id, x, y, width, height);\n\t\t\treturn;\n\t\t}\n\n\t\tlet node = this.locate(x, y, width, height);\n\t\tlet record = this.insertScratch;\n\t\trecord[ITEM_ID] = id;\n\t\trecord[ITEM_X] = x;\n\t\trecord[ITEM_Y] = y;\n\t\trecord[ITEM_W] = width;\n\t\trecord[ITEM_H] = height;\n\t\trecord[ITEM_NODE] = node;\n\t\trecord[ITEM_NEXT] = this.nullIndex;\n\t\tlet index = this.pool.push(record);\n\t\tthis.linkIntoNode(node, index);\n\t\tthis.idMap.set(id, index);\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 newCount = existing.reduce<number>((count, index) => count + (index === undefined ? 1 : 0), 0);\n\t\tlet nextIndex = this.pool.reserveContiguous(newCount);\n\t\tfor(let i = 0; i < unique.length; i++) {\n\t\t\tlet entity = unique[i];\n\t\t\tlet width = entity.width ?? 0;\n\t\t\tlet height = entity.height ?? 0;\n\t\t\tif(existing[i] !== undefined) {\n\t\t\t\tthis.update(entity.id, entity.x, entity.y, width, height);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet node = this.locate(entity.x, entity.y, width, height);\n\t\t\tlet index = nextIndex++;\n\t\t\tlet block = this.pool.blockFor(index);\n\t\t\tlet offset = this.pool.blockOffset(index);\n\t\t\tblock[offset + ITEM_ID] = entity.id;\n\t\t\tblock[offset + ITEM_X] = entity.x;\n\t\t\tblock[offset + ITEM_Y] = entity.y;\n\t\t\tblock[offset + ITEM_W] = width;\n\t\t\tblock[offset + ITEM_H] = height;\n\t\t\tblock[offset + ITEM_NODE] = node;\n\t\t\tblock[offset + ITEM_NEXT] = this.nullIndex;\n\t\t\tthis.linkIntoNode(node, index);\n\t\t\tmappings.push([entity.id, index]);\n\t\t}\n\t\tthis.idMap.setAll(mappings);\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 item fields are stable until we lock its node(s).\n\tupdate(id: number, x: number, y: number, width = 0, height = 0) {\n\t\tlet index = this.idMap.get(id);\n\t\tif(index === undefined) {\n\t\t\tthis.insert(id, x, y, width, height);\n\t\t\treturn;\n\t\t}\n\n\t\tlet block = this.pool.blockFor(index);\n\t\tlet off = this.pool.blockOffset(index);\n\t\tlet oldNode = block[off + ITEM_NODE];\n\t\tlet newNode = this.locate(x, y, width, height);\n\n\t\tif(oldNode === newNode) {\n\t\t\t// Same cell: only the coordinates change, no relinking. Lock so a concurrent reader sees a consistent record.\n\t\t\tlock(this.nodeInts, oldNode * NODE_SIZE + NODE_LOCK_OFFSET);\n\t\t\tblock[off + ITEM_X] = x;\n\t\t\tblock[off + ITEM_Y] = y;\n\t\t\tblock[off + ITEM_W] = width;\n\t\t\tblock[off + ITEM_H] = height;\n\t\t\tunlock(this.nodeInts, oldNode * NODE_SIZE + NODE_LOCK_OFFSET);\n\t\t\treturn;\n\t\t}\n\n\t\t// Cross-cell move: hold both node locks, ordered by index to avoid deadlock with another thread moving the reverse way.\n\t\tlet first = Math.min(oldNode, newNode);\n\t\tlet second = Math.max(oldNode, newNode);\n\t\tlock(this.nodeInts, first * NODE_SIZE + NODE_LOCK_OFFSET);\n\t\tlock(this.nodeInts, second * NODE_SIZE + NODE_LOCK_OFFSET);\n\n\t\tthis.unlinkNoLock(oldNode, index);\n\t\tblock[off + ITEM_X] = x;\n\t\tblock[off + ITEM_Y] = y;\n\t\tblock[off + ITEM_W] = width;\n\t\tblock[off + ITEM_H] = height;\n\t\tblock[off + ITEM_NODE] = newNode;\n\t\tthis.linkNoLock(newNode, index);\n\n\t\tunlock(this.nodeInts, second * NODE_SIZE + NODE_LOCK_OFFSET);\n\t\tunlock(this.nodeInts, first * NODE_SIZE + NODE_LOCK_OFFSET);\n\t}\n\n\tremove(id: number): boolean {\n\t\tlet index = this.idMap.get(id);\n\t\tif(index === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet node = this.pool.get(index, ITEM_NODE);\n\t\tthis.unlinkFromNode(node, index);\n\t\tthis.pool.deleteIndex(index);\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 in a node whose region intersects the given rect. Result is a superset of true\n\t// overlaps (the caller does the narrow-phase check), matching quadtree-js retrieve.\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\tlet start = out.length;\n\t\tthis.collect(out, 0, this.rootX, this.rootY, this.rootWidth, this.rootHeight, 0, x, y, width, height);\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\tif(maxResults <= 0 || maxDistance < 0 || Number.isNaN(maxResults) || Number.isNaN(maxDistance)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tinterface Node {\n\t\t\tindex: number\n\t\t\tx: number\n\t\t\ty: number\n\t\t\twidth: number\n\t\t\theight: number\n\t\t\tlevel: number\n\t\t}\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\tif(maxResults === 1) {\n\t\t\treturn this.nearestNeighbor(x, y, maxDistanceSquared, filter);\n\t\t}\n\t\tlet candidates: Array<NeighborCandidate> = [];\n\t\tlet nodeCandidates: Array<NeighborCandidate> = [];\n\t\tlet queue = new MinPriorityQueue<Node>();\n\t\tlet root = { index: 0, x: this.rootX, y: this.rootY, width: this.rootWidth, height: this.rootHeight, level: 0 };\n\t\tqueue.push(root, distanceSquaredToRect(x, y, this.rootX, this.rootY, this.rootX + this.rootWidth, this.rootY + this.rootHeight));\n\n\t\twhile(queue.length > 0 && queue.priority <= candidateLimit(candidates, maxResults, maxDistanceSquared)) {\n\t\t\tlet node = queue.pop();\n\t\t\tif(node === undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tnodeCandidates.length = 0;\n\t\t\tthis.collectNeighborNode(nodeCandidates, node.index, x, y, maxDistanceSquared);\n\t\t\tfor(let candidate of nodeCandidates) {\n\t\t\t\tlet duplicate = false;\n\t\t\t\tfor(let existing of candidates) {\n\t\t\t\t\tif(existing.id === candidate.id) {\n\t\t\t\t\t\tduplicate = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(duplicate) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(filter === undefined || filter(candidate.id)) {\n\t\t\t\t\taddCandidate(candidates, candidate.id, candidate.distance, maxResults);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(node.level >= this.maxLevels) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet halfWidth = node.width / 2;\n\t\t\tlet halfHeight = node.height / 2;\n\t\t\tlet childLevel = node.level + 1;\n\t\t\tlet children: Array<Node> = [\n\t\t\t\t{ index: node.index * 4 + 1, x: node.x, y: node.y, width: halfWidth, height: halfHeight, level: childLevel },\n\t\t\t\t{ index: node.index * 4 + 2, x: node.x + halfWidth, y: node.y, width: halfWidth, height: halfHeight, level: childLevel },\n\t\t\t\t{ index: node.index * 4 + 3, x: node.x, y: node.y + halfHeight, width: halfWidth, height: halfHeight, level: childLevel },\n\t\t\t\t{ index: node.index * 4 + 4, x: node.x + halfWidth, y: node.y + halfHeight, width: halfWidth, height: halfHeight, level: childLevel },\n\t\t\t];\n\t\t\tfor(let child of children) {\n\t\t\t\tlet distance = distanceSquaredToRect(x, y, child.x, child.y, child.x + child.width, child.y + child.height);\n\t\t\t\tif(distance <= candidateLimit(candidates, maxResults, maxDistanceSquared)) {\n\t\t\t\t\tqueue.push(child, distance);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn candidates.map(candidate => candidate.id);\n\t}\n\n\tprivate nearestNeighbor(\n\t\tx: number, y: number, maxDistanceSquared: number, filter: ((id: number) => boolean) | undefined,\n\t): Array<number> {\n\t\tlet nearest: NearestNeighbor = { id: undefined, distance: maxDistanceSquared };\n\t\tlet nodeCandidates: Array<NeighborCandidate> = [];\n\t\tthis.findNearest(\n\t\t\t0, this.rootX, this.rootY, this.rootWidth, this.rootHeight, 0,\n\t\t\tx, y, nearest, nodeCandidates, filter,\n\t\t);\n\t\treturn nearest.id === undefined ? [] : [nearest.id];\n\t}\n\n\tprivate findNearest(\n\t\tnode: number, nodeX: number, nodeY: number, width: number, height: number, level: number,\n\t\tx: number, y: number, nearest: NearestNeighbor,\n\t\tnodeCandidates: Array<NeighborCandidate>, filter: ((id: number) => boolean) | undefined,\n\t) {\n\t\tif(distanceSquaredToRect(x, y, nodeX, nodeY, nodeX + width, nodeY + height) > nearest.distance) {\n\t\t\treturn;\n\t\t}\n\t\tif(filter === undefined) {\n\t\t\tthis.collectNearestNode(nearest, node, x, y);\n\t\t} else {\n\t\t\tnodeCandidates.length = 0;\n\t\t\tthis.collectNeighborNode(nodeCandidates, node, x, y, nearest.distance);\n\t\t\tfor(let candidate of nodeCandidates) {\n\t\t\t\tif(filter(candidate.id)\n\t\t\t\t\t&& (candidate.distance < nearest.distance\n\t\t\t\t\t\t|| (candidate.distance === nearest.distance && (nearest.id === undefined || candidate.id < nearest.id)))) {\n\t\t\t\t\tnearest.id = candidate.id;\n\t\t\t\t\tnearest.distance = candidate.distance;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(level >= this.maxLevels) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet halfWidth = width / 2;\n\t\tlet halfHeight = height / 2;\n\t\tlet midX = nodeX + halfWidth;\n\t\tlet midY = nodeY + halfHeight;\n\t\tlet base = node * 4;\n\t\tlet nextLevel = level + 1;\n\t\tlet east = x >= midX;\n\t\tlet south = y >= midY;\n\t\tlet visit = (index: number, childX: number, childY: number) => {\n\t\t\tthis.findNearest(\n\t\t\t\tindex, childX, childY, halfWidth, halfHeight, nextLevel,\n\t\t\t\tx, y, nearest, nodeCandidates, filter,\n\t\t\t);\n\t\t};\n\t\tif(south) {\n\t\t\tif(east) {\n\t\t\t\tvisit(base + 4, midX, midY);\n\t\t\t\tvisit(base + 3, nodeX, midY);\n\t\t\t\tvisit(base + 2, midX, nodeY);\n\t\t\t\tvisit(base + 1, nodeX, nodeY);\n\t\t\t} else {\n\t\t\t\tvisit(base + 3, nodeX, midY);\n\t\t\t\tvisit(base + 4, midX, midY);\n\t\t\t\tvisit(base + 1, nodeX, nodeY);\n\t\t\t\tvisit(base + 2, midX, nodeY);\n\t\t\t}\n\t\t} else if(east) {\n\t\t\tvisit(base + 2, midX, nodeY);\n\t\t\tvisit(base + 1, nodeX, nodeY);\n\t\t\tvisit(base + 4, midX, midY);\n\t\t\tvisit(base + 3, nodeX, midY);\n\t\t} else {\n\t\t\tvisit(base + 1, nodeX, nodeY);\n\t\t\tvisit(base + 2, midX, nodeY);\n\t\t\tvisit(base + 3, nodeX, midY);\n\t\t\tvisit(base + 4, midX, midY);\n\t\t}\n\t}\n\n\tclear() {\n\t\tfor(let i = 0; i < this.nodeCount; i++) {\n\t\t\tthis.nodeHeads[i * NODE_SIZE + NODE_HEAD_OFFSET] = this.nullIndex;\n\t\t}\n\t\tthis.pool.clear();\n\t\t// SharedMap has no clear(); drop every key. Not safe to run concurrently with writers (documented on clear()).\n\t\tlet keys: Array<number> = [];\n\t\tfor(let [key] of this.idMap) {\n\t\t\tkeys.push(key);\n\t\t}\n\t\tfor(let key of keys) {\n\t\t\tthis.idMap.delete(key);\n\t\t}\n\t}\n\n\tfree() {\n\t\tlet nodeBlock = new AllocatedMemory(this.memory, getPointer(loadRawPointer(this.firstBlock.data, NODE_POINTER_INDEX), this.memory.positionBits));\n\t\tnodeBlock.free();\n\t\tthis.pool.free();\n\t\tthis.idMap.free();\n\t\tthis.firstBlock.free();\n\t}\n\n\tgetSharedMemory(): SharedQuadtreeMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n\n\tprivate getBoundsView(): CoordArray {\n\t\treturn makeArrayView(\n\t\t\tthis.coordType,\n\t\t\tthis.firstBlock.data.buffer,\n\t\t\tthis.firstBlock.bufferByteOffset + BOUNDS_INDEX * Uint32Array.BYTES_PER_ELEMENT,\n\t\t\t4,\n\t\t) as CoordArray;\n\t}\n\n\t// Deepest node index that fully contains the rect. Descends into the one child that still fully contains it; stops at a\n\t// straddle or at max depth.\n\tprivate locate(x: number, y: number, width: number, height: number): number {\n\t\tlet node = 0;\n\t\tlet nx = this.rootX;\n\t\tlet ny = this.rootY;\n\t\tlet nw = this.rootWidth;\n\t\tlet nh = this.rootHeight;\n\n\t\tfor(let level = 0; level < this.maxLevels; level++) {\n\t\t\tlet midX = nx + nw / 2;\n\t\t\tlet midY = ny + nh / 2;\n\t\t\tlet west = x >= nx && x + width <= midX && (width > 0 || x < midX);\n\t\t\tlet east = x >= midX && x + width <= nx + nw;\n\t\t\tlet north = y >= ny && y + height <= midY && (height > 0 || y < midY);\n\t\t\tlet south = y >= midY && y + height <= ny + nh;\n\n\t\t\tif(north && west) {\n\t\t\t\tnode = node * 4 + 1;\n\t\t\t\tnw /= 2;\n\t\t\t\tnh /= 2;\n\t\t\t} else if(north && east) {\n\t\t\t\tnode = node * 4 + 2;\n\t\t\t\tnx = midX;\n\t\t\t\tnw /= 2;\n\t\t\t\tnh /= 2;\n\t\t\t} else if(south && west) {\n\t\t\t\tnode = node * 4 + 3;\n\t\t\t\tny = midY;\n\t\t\t\tnw /= 2;\n\t\t\t\tnh /= 2;\n\t\t\t} else if(south && east) {\n\t\t\t\tnode = node * 4 + 4;\n\t\t\t\tnx = midX;\n\t\t\t\tny = midY;\n\t\t\t\tnw /= 2;\n\t\t\t\tnh /= 2;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tprivate collect(out: Array<number>, node: number, nx: number, ny: number, nw: number, nh: number, level: number, qx: number, qy: number, qw: number, qh: number) {\n\t\t// Peek the head unlocked: an empty bucket has nothing to read, so the lock (and its atomics) is pure overhead. Most\n\t\t// nodes in a fixed-depth tree are empty, so skipping them dominates query cost. Taking the lock only to walk a\n\t\t// non-empty bucket preserves the snapshot guarantee - a concurrent insert we race is simply not in this snapshot.\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tif(this.nodeHeads[headIndex] !== this.nullIndex) {\n\t\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\t\tlock(this.nodeInts, lockIndex);\n\t\t\tlet index = this.nodeHeads[headIndex];\n\t\t\tlet pool = this.pool;\n\t\t\twhile(index !== this.nullIndex) {\n\t\t\t\t// One chunk resolve per item covers both fields it reads\n\t\t\t\tlet block = pool.blockFor(index);\n\t\t\t\tlet off = pool.blockOffset(index);\n\t\t\t\tout.push(block[off + ITEM_ID]);\n\t\t\t\tindex = block[off + ITEM_NEXT];\n\t\t\t}\n\t\t\tunlock(this.nodeInts, lockIndex);\n\t\t}\n\n\t\tif(level >= this.maxLevels) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet midX = nx + nw / 2;\n\t\tlet midY = ny + nh / 2;\n\t\tlet hw = nw / 2;\n\t\tlet hh = nh / 2;\n\t\tlet overlapsWest = qx < midX;\n\t\tlet overlapsEast = qx + qw > midX;\n\t\tlet overlapsNorth = qy < midY;\n\t\tlet overlapsSouth = qy + qh > midY;\n\n\t\tif(overlapsNorth && overlapsWest) {\n\t\t\tthis.collect(out, node * 4 + 1, nx, ny, hw, hh, level + 1, qx, qy, qw, qh);\n\t\t}\n\t\tif(overlapsNorth && overlapsEast) {\n\t\t\tthis.collect(out, node * 4 + 2, midX, ny, hw, hh, level + 1, qx, qy, qw, qh);\n\t\t}\n\t\tif(overlapsSouth && overlapsWest) {\n\t\t\tthis.collect(out, node * 4 + 3, nx, midY, hw, hh, level + 1, qx, qy, qw, qh);\n\t\t}\n\t\tif(overlapsSouth && overlapsEast) {\n\t\t\tthis.collect(out, node * 4 + 4, midX, midY, hw, hh, level + 1, qx, qy, qw, qh);\n\t\t}\n\t}\n\n\tprivate collectNeighborNode(\n\t\tout: Array<NeighborCandidate>, node: number, x: number, y: number, maxDistanceSquared: number,\n\t) {\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tif(this.nodeHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\tlock(this.nodeInts, lockIndex);\n\t\tlet index = this.nodeHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet block = this.pool.blockFor(index);\n\t\t\tlet off = this.pool.blockOffset(index);\n\t\t\tlet id = block[off + ITEM_ID];\n\t\t\tlet distance = distanceSquaredToRect(x, y, block[off + ITEM_X], block[off + ITEM_Y], block[off + ITEM_X] + block[off + ITEM_W], block[off + ITEM_Y] + block[off + ITEM_H]);\n\t\t\tif(distance <= maxDistanceSquared) {\n\t\t\t\tout.push({ id, distance });\n\t\t\t}\n\t\t\tindex = block[off + ITEM_NEXT];\n\t\t}\n\t\tunlock(this.nodeInts, lockIndex);\n\t}\n\n\tprivate collectNearestNode(nearest: NearestNeighbor, node: number, x: number, y: number) {\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tif(this.nodeHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\tlock(this.nodeInts, lockIndex);\n\t\tlet index = this.nodeHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet block = this.pool.blockFor(index);\n\t\t\tlet off = this.pool.blockOffset(index);\n\t\t\tlet id = block[off + ITEM_ID];\n\t\t\tlet distance = distanceSquaredToRect(\n\t\t\t\tx, y, block[off + ITEM_X], block[off + ITEM_Y],\n\t\t\t\tblock[off + ITEM_X] + block[off + ITEM_W], block[off + ITEM_Y] + block[off + ITEM_H],\n\t\t\t);\n\t\t\tif(distance < nearest.distance\n\t\t\t\t|| (distance === nearest.distance && (nearest.id === undefined || id < nearest.id))) {\n\t\t\t\tnearest.id = id;\n\t\t\t\tnearest.distance = distance;\n\t\t\t}\n\t\t\tindex = block[off + ITEM_NEXT];\n\t\t}\n\t\tunlock(this.nodeInts, lockIndex);\n\t}\n\n\tprivate linkIntoNode(node: number, index: number) {\n\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\tlock(this.nodeInts, lockIndex);\n\t\tthis.linkNoLock(node, index);\n\t\tunlock(this.nodeInts, lockIndex);\n\t}\n\t// Push the item onto the node's bucket head. Caller holds the node lock.\n\tprivate linkNoLock(node: number, index: number) {\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tthis.pool.set(index, ITEM_NEXT, this.nodeHeads[headIndex]);\n\t\tthis.nodeHeads[headIndex] = index;\n\t}\n\n\tprivate unlinkFromNode(node: number, index: number) {\n\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\tlock(this.nodeInts, lockIndex);\n\t\tthis.unlinkNoLock(node, index);\n\t\tunlock(this.nodeInts, lockIndex);\n\t}\n\t// Splice the item out of the node's bucket. Caller holds the node lock.\n\tprivate unlinkNoLock(node: number, index: number) {\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tlet head = this.nodeHeads[headIndex];\n\t\tlet next = this.pool.get(index, ITEM_NEXT);\n\t\tif(head === index) {\n\t\t\tthis.nodeHeads[headIndex] = next;\n\t\t\treturn;\n\t\t}\n\n\t\tlet prev = head;\n\t\twhile(prev !== this.nullIndex) {\n\t\t\tlet prevNext = this.pool.get(prev, ITEM_NEXT);\n\t\t\tif(prevNext === index) {\n\t\t\t\tthis.pool.set(prev, ITEM_NEXT, next);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprev = prevNext;\n\t\t}\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('SharedQuadtree 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}\n\ninterface QuadtreeBounds {\n\tx: number\n\ty: number\n\twidth: number\n\theight: number\n}\ninterface SharedQuadtreeConfig {\n\tbounds: QuadtreeBounds\n\tmaxLevels?: number\n\tmaxEntities?: number\n\ttype?: CoordArrayConstructor\n}\ninterface SharedQuadtreeMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedQuadtreeConfig, SharedQuadtreeMemory, QuadtreeBounds, SpatialEntity };\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-quadtree.js","names":["AllocatedMemory","SharedMap","SharedPool","NODE_POINTER_INDEX","POOL_POINTER_INDEX","MAP_POINTER_INDEX","MAX_LEVELS_INDEX","NODE_COUNT_INDEX","TYPE_INDEX","BOUNDS_INDEX","NODE_LOCK_OFFSET","NODE_HEAD_OFFSET","NODE_SIZE","ITEM_ID","ITEM_X","ITEM_Y","ITEM_W","ITEM_H","ITEM_NODE","ITEM_NEXT","ITEM_FIELDS","FLOAT32_LIMIT","FLOAT32_NULL_INDEX","FLOAT64_NULL_INDEX","DEFAULT_MAX_LEVELS","DEFAULT_MAX_ENTITIES","DEFAULT_COORD_TYPE","SharedQuadtree","memory","config","getPointer","loadRawPointer","nullIndexFor","bounds","maxEntities","getCoordTypeCode","ARRAY_TYPE","poolConfig","getCoordTypeConstructor","getSpatialPoolChunkSize","getByteMultipler","poolAllocateCount","mapAllocateCount","boundsView","nodeBlock","heads","i","poolBlock","storeRawPointer","mapBlock","getSpatialMapCapacity","maxLevels","id","x","y","width","height","node","record","index","byId","entity","entities","unique","existing","mappings","newCount","count","nextIndex","block","offset","off","oldNode","newNode","lock","unlock","first","second","out","filter","start","write","read","maxResults","maxDistance","maxDistanceSquared","candidates","nodeCandidates","queue","MinPriorityQueue","root","distanceSquaredToRect","candidateLimit","candidate","duplicate","addCandidate","halfWidth","halfHeight","childLevel","children","child","distance","nearest","nodeX","nodeY","level","midX","midY","base","nextLevel","east","south","visit","childX","childY","keys","key","makeArrayView","nx","ny","nw","nh","west","north","headIndex","lockIndex","pool","hw","hh","overlapsWest","qx","overlapsEast","qw","overlapsNorth","qy","overlapsSouth","qh","head","next","prev","prevNext","code","getArrayTypeCode","type","typeCode"],"sources":["../../src/spatial/shared-quadtree.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 { lock, unlock } from '../lock/simple-lock';\nimport { getPointer, loadRawPointer, storeRawPointer } from '../utils/pointer';\nimport { ARRAY_TYPE, getArrayTypeCode, getByteMultipler, makeArrayView } from '../utils/array-type';\nimport {\n\tMinPriorityQueue, addCandidate, candidateLimit, distanceSquaredToRect,\n\ttype NeighborCandidate, type NearestNeighbor,\n} from './spatial-neighbors';\nimport { getSpatialMapCapacity, getSpatialPoolChunkSize, type SpatialEntity } from './spatial-entity';\n\n// Fixed-depth region quadtree (\"implicit\" / hierarchical grid) built for concurrent updates from many threads. Dynamic\n// subdivision is deliberately avoided: creating/redistributing/freeing nodes at runtime races with readers mid-traversal\n// (the same hazard MemoryBuffer disables compaction for). Here the tree of nodes is allocated once and never changes\n// shape, so concurrency reduces to per-cell content updates - different cells never contend.\n//\n// Node layout is implicit: node 0 is the root, the four children of node i are 4i+1..4i+4 (NW, NE, SW, SE). Bounds are\n// derived from the root bounds during descent, never stored. Each node owns an intrusive singly-linked bucket: the node\n// record holds a lock and the head item index, and each item record carries the next index. Items live in a SharedPool\n// (stable indices, recycling) and an id->itemIndex SharedMap makes update/remove O(depth) by entity id.\n//\n// Each entity is stored in the single deepest node that fully contains its rect (an item too large or straddling a\n// midline stays at an ancestor). search walks every node whose region intersects the query and returns a broad-phase\n// superset of candidate ids - the same guarantee quadtree-js's retrieve gives, without duplicating straddlers.\n//\n// The whole item record (id, coords, node, bucket link) lives in one pool at the configured precision. Float32 (the\n// default, matching a physics engine that keeps positions in Float32) keeps everything exact as long as entity ids and\n// the pool's index space both stay under 2^24 (~16.7M) - every id, pool index, node index and the NULL sentinel is a\n// Float32-exact integer there. Need more than that many entities (or ids >= 2^24)? Pass type: Float64Array.\n\n// Header (firstBlock) u32 layout\nconst NODE_POINTER_INDEX = 0;\nconst POOL_POINTER_INDEX = 1;\nconst MAP_POINTER_INDEX = 2;\nconst MAX_LEVELS_INDEX = 3;\nconst NODE_COUNT_INDEX = 4;\nconst TYPE_INDEX = 5;\n// bounds view starts at slot 6 (offset 24 bytes is 8-byte aligned, so a Float64 bounds view is valid)\nconst BOUNDS_INDEX = 6;\n\n// Per-node record: [lock, head]\nconst NODE_LOCK_OFFSET = 0;\nconst NODE_HEAD_OFFSET = 1;\nconst NODE_SIZE = 2;\n\n// Item record fields\nconst ITEM_ID = 0;\nconst ITEM_X = 1;\nconst ITEM_Y = 2;\nconst ITEM_W = 3;\nconst ITEM_H = 4;\nconst ITEM_NODE = 5;\nconst ITEM_NEXT = 6;\nconst ITEM_FIELDS = 7;\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\nconst DEFAULT_MAX_LEVELS = 4;\nconst DEFAULT_MAX_ENTITIES = 1_000_000;\nconst DEFAULT_COORD_TYPE = Float32Array;\n\ntype CoordArray = Float32Array | Float64Array;\ntype CoordArrayConstructor = Float32ArrayConstructor | Float64ArrayConstructor;\n\nexport default class SharedQuadtree {\n\tstatic readonly ALLOCATE_COUNT = 14;\n\n\tprivate memory: MemoryHeap;\n\tprivate firstBlock: AllocatedMemory;\n\tprivate pool: SharedPool<CoordArray>;\n\tprivate idMap: SharedMap<number>;\n\n\t// Reused to hand a full item record to pool.push without allocating a fresh array per insert (single writer per id)\n\tprivate insertScratch: Array<number> = [0, 0, 0, 0, 0, 0, 0];\n\n\t// Node block views over one contiguous region: Int32 for the per-node locks, Uint32 for the head indexes.\n\tprivate nodeInts: Int32Array;\n\tprivate nodeHeads: Uint32Array;\n\n\tprivate readonly maxLevels: number;\n\tprivate readonly nodeCount: number;\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// Root bounds, read once (stored at the configured precision, math done in float64)\n\tprivate readonly rootX: number;\n\tprivate readonly rootY: number;\n\tprivate readonly rootWidth: number;\n\tprivate readonly rootHeight: number;\n\n\t// Number of entities currently tracked\n\tget size(): number {\n\t\treturn this.idMap.length;\n\t}\n\n\tget bounds(): QuadtreeBounds {\n\t\treturn { x: this.rootX, y: this.rootY, width: this.rootWidth, height: this.rootHeight };\n\t}\n\n\t// Element type the record is 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?: SharedQuadtreeConfig | SharedQuadtreeMemory) {\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.pool = new SharedPool<CoordArray>(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, 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.maxLevels = this.firstBlock.data[MAX_LEVELS_INDEX];\n\t\t\tthis.nodeCount = this.firstBlock.data[NODE_COUNT_INDEX];\n\t\t\tthis.nullIndex = nullIndexFor(this.coordType);\n\t\t} else {\n\t\t\tlet bounds = config?.bounds ?? { x: 0, y: 0, width: 0, height: 0 };\n\t\t\tlet maxEntities = config?.maxEntities ?? DEFAULT_MAX_ENTITIES;\n\t\t\tthis.maxLevels = config?.maxLevels ?? DEFAULT_MAX_LEVELS;\n\t\t\tthis.nodeCount = SharedQuadtree.getNodeCount(this.maxLevels);\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) {\n\t\t\t\tthrow new Error(`Float32 SharedQuadtree supports at most ${FLOAT32_LIMIT} entities; pass type: Float64Array for more`);\n\t\t\t}\n\n\t\t\t// Inline the pool and id-map firstBlocks right after the header so the whole spine is one contiguous allocation\n\t\t\t// (the pool's own firstBlock already inlines its two stacks). The node block stays separate: it is large and\n\t\t\t// sized independently of these headers.\n\t\t\tlet poolConfig: SharedPoolConfig<CoordArray> = {\n\t\t\t\ttype: getCoordTypeConstructor(this.coordType),\n\t\t\t\tdataLength: ITEM_FIELDS,\n\t\t\t\tmaxLength: maxEntities,\n\t\t\t\tmaxChunkSize: getSpatialPoolChunkSize(maxEntities, ITEM_FIELDS, getByteMultipler(this.coordType), memory.maxAllocationLength),\n\t\t\t};\n\t\t\tlet poolAllocateCount = SharedPool.getAllocateCount(memory, poolConfig);\n\t\t\tlet mapAllocateCount = SharedMap.ALLOCATE_COUNT;\n\t\t\tthis.firstBlock = memory.allocUI32(SharedQuadtree.ALLOCATE_COUNT + poolAllocateCount + mapAllocateCount);\n\t\t\tthis.firstBlock.data[MAX_LEVELS_INDEX] = this.maxLevels;\n\t\t\tthis.firstBlock.data[NODE_COUNT_INDEX] = this.nodeCount;\n\t\t\tthis.firstBlock.data[TYPE_INDEX] = this.coordType;\n\n\t\t\tlet boundsView = this.getBoundsView();\n\t\t\tboundsView[0] = bounds.x;\n\t\t\tboundsView[1] = bounds.y;\n\t\t\tboundsView[2] = bounds.width;\n\t\t\tboundsView[3] = bounds.height;\n\n\t\t\t// Node block must fit one allocation - it is never resized. Every head starts as NULL (calloc leaves them 0,\n\t\t\t// a valid item index, so they must be initialized explicitly).\n\t\t\tlet nodeBlock = memory.allocUI32(this.nodeCount * NODE_SIZE);\n\t\t\tlet heads = new Uint32Array(nodeBlock.data.buffer, nodeBlock.bufferByteOffset, this.nodeCount * NODE_SIZE);\n\t\t\tfor(let i = 0; i < this.nodeCount; i++) {\n\t\t\t\theads[i * NODE_SIZE + NODE_HEAD_OFFSET] = this.nullIndex;\n\t\t\t}\n\t\t\tstoreRawPointer(this.firstBlock.data, NODE_POINTER_INDEX, nodeBlock.pointer);\n\n\t\t\tlet poolBlock = this.firstBlock.getSubAllocation(SharedQuadtree.ALLOCATE_COUNT, poolAllocateCount);\n\t\t\tthis.pool = new SharedPool<CoordArray>(memory, { firstBlock: poolBlock, ...poolConfig });\n\t\t\tstoreRawPointer(this.firstBlock.data, POOL_POINTER_INDEX, poolBlock.pointer);\n\n\t\t\tlet mapBlock = this.firstBlock.getSubAllocation(SharedQuadtree.ALLOCATE_COUNT + poolAllocateCount, 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\tlet boundsView = this.getBoundsView();\n\t\tthis.rootX = boundsView[0];\n\t\tthis.rootY = boundsView[1];\n\t\tthis.rootWidth = boundsView[2];\n\t\tthis.rootHeight = boundsView[3];\n\n\t\tlet nodeBlock = new AllocatedMemory(memory, getPointer(loadRawPointer(this.firstBlock.data, NODE_POINTER_INDEX), memory.positionBits));\n\t\tthis.nodeInts = new Int32Array(nodeBlock.data.buffer, nodeBlock.bufferByteOffset, this.nodeCount * NODE_SIZE);\n\t\tthis.nodeHeads = new Uint32Array(nodeBlock.data.buffer, nodeBlock.bufferByteOffset, this.nodeCount * NODE_SIZE);\n\t}\n\n\t// Total nodes in a complete quadtree of the given depth: sum of 4^level for level 0..maxLevels.\n\tstatic getNodeCount(maxLevels: number): number {\n\t\treturn (Math.pow(4, maxLevels + 1) - 1) / 3;\n\t}\n\n\tget pointer(): number {\n\t\treturn this.firstBlock.pointer;\n\t}\n\n\tget usedMemory(): number {\n\t\tlet nodeBlock = new AllocatedMemory(this.memory, getPointer(loadRawPointer(this.firstBlock.data, NODE_POINTER_INDEX), this.memory.positionBits));\n\t\treturn this.firstBlock.usedMemory + nodeBlock.usedMemory + this.pool.usedMemory + this.idMap.usedMemory;\n\t}\n\n\tinsert(id: number, x: number, y: number, width = 0, height = 0) {\n\t\tif(this.idMap.get(id) !== undefined) {\n\t\t\tthis.update(id, x, y, width, height);\n\t\t\treturn;\n\t\t}\n\n\t\tlet node = this.locate(x, y, width, height);\n\t\tlet record = this.insertScratch;\n\t\trecord[ITEM_ID] = id;\n\t\trecord[ITEM_X] = x;\n\t\trecord[ITEM_Y] = y;\n\t\trecord[ITEM_W] = width;\n\t\trecord[ITEM_H] = height;\n\t\trecord[ITEM_NODE] = node;\n\t\trecord[ITEM_NEXT] = this.nullIndex;\n\t\tlet index = this.pool.push(record);\n\t\tthis.linkIntoNode(node, index);\n\t\tthis.idMap.set(id, index);\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 newCount = existing.reduce<number>((count, index) => count + (index === undefined ? 1 : 0), 0);\n\t\tlet nextIndex = this.pool.reserveContiguous(newCount);\n\t\tfor(let i = 0; i < unique.length; i++) {\n\t\t\tlet entity = unique[i];\n\t\t\tlet width = entity.width ?? 0;\n\t\t\tlet height = entity.height ?? 0;\n\t\t\tif(existing[i] !== undefined) {\n\t\t\t\tthis.update(entity.id, entity.x, entity.y, width, height);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet node = this.locate(entity.x, entity.y, width, height);\n\t\t\tlet index = nextIndex++;\n\t\t\tlet block = this.pool.blockFor(index);\n\t\t\tlet offset = this.pool.blockOffset(index);\n\t\t\tblock[offset + ITEM_ID] = entity.id;\n\t\t\tblock[offset + ITEM_X] = entity.x;\n\t\t\tblock[offset + ITEM_Y] = entity.y;\n\t\t\tblock[offset + ITEM_W] = width;\n\t\t\tblock[offset + ITEM_H] = height;\n\t\t\tblock[offset + ITEM_NODE] = node;\n\t\t\tblock[offset + ITEM_NEXT] = this.nullIndex;\n\t\t\tthis.linkIntoNode(node, index);\n\t\t\tmappings.push([entity.id, index]);\n\t\t}\n\t\tthis.idMap.setAll(mappings);\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 item fields are stable until we lock its node(s).\n\tupdate(id: number, x: number, y: number, width = 0, height = 0) {\n\t\tlet index = this.idMap.get(id);\n\t\tif(index === undefined) {\n\t\t\tthis.insert(id, x, y, width, height);\n\t\t\treturn;\n\t\t}\n\n\t\tlet block = this.pool.blockFor(index);\n\t\tlet off = this.pool.blockOffset(index);\n\t\tlet oldNode = block[off + ITEM_NODE];\n\t\tlet newNode = this.locate(x, y, width, height);\n\n\t\tif(oldNode === newNode) {\n\t\t\t// Same cell: only the coordinates change, no relinking. Lock so a concurrent reader sees a consistent record.\n\t\t\tlock(this.nodeInts, oldNode * NODE_SIZE + NODE_LOCK_OFFSET);\n\t\t\tblock[off + ITEM_X] = x;\n\t\t\tblock[off + ITEM_Y] = y;\n\t\t\tblock[off + ITEM_W] = width;\n\t\t\tblock[off + ITEM_H] = height;\n\t\t\tunlock(this.nodeInts, oldNode * NODE_SIZE + NODE_LOCK_OFFSET);\n\t\t\treturn;\n\t\t}\n\n\t\t// Cross-cell move: hold both node locks, ordered by index to avoid deadlock with another thread moving the reverse way.\n\t\tlet first = Math.min(oldNode, newNode);\n\t\tlet second = Math.max(oldNode, newNode);\n\t\tlock(this.nodeInts, first * NODE_SIZE + NODE_LOCK_OFFSET);\n\t\tlock(this.nodeInts, second * NODE_SIZE + NODE_LOCK_OFFSET);\n\n\t\tthis.unlinkNoLock(oldNode, index);\n\t\tblock[off + ITEM_X] = x;\n\t\tblock[off + ITEM_Y] = y;\n\t\tblock[off + ITEM_W] = width;\n\t\tblock[off + ITEM_H] = height;\n\t\tblock[off + ITEM_NODE] = newNode;\n\t\tthis.linkNoLock(newNode, index);\n\n\t\tunlock(this.nodeInts, second * NODE_SIZE + NODE_LOCK_OFFSET);\n\t\tunlock(this.nodeInts, first * NODE_SIZE + NODE_LOCK_OFFSET);\n\t}\n\n\tremove(id: number): boolean {\n\t\tlet index = this.idMap.get(id);\n\t\tif(index === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet node = this.pool.get(index, ITEM_NODE);\n\t\tthis.unlinkFromNode(node, index);\n\t\tthis.pool.deleteIndex(index);\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 in a node whose region intersects the given rect. Result is a superset of true\n\t// overlaps (the caller does the narrow-phase check), matching quadtree-js retrieve.\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\tlet start = out.length;\n\t\tthis.collect(out, 0, this.rootX, this.rootY, this.rootWidth, this.rootHeight, 0, x, y, width, height);\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\tif(maxResults <= 0 || maxDistance < 0 || Number.isNaN(maxResults) || Number.isNaN(maxDistance)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tinterface Node {\n\t\t\tindex: number\n\t\t\tx: number\n\t\t\ty: number\n\t\t\twidth: number\n\t\t\theight: number\n\t\t\tlevel: number\n\t\t}\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\tif(maxResults === 1) {\n\t\t\treturn this.nearestNeighbor(x, y, maxDistanceSquared, filter);\n\t\t}\n\t\tlet candidates: Array<NeighborCandidate> = [];\n\t\tlet nodeCandidates: Array<NeighborCandidate> = [];\n\t\tlet queue = new MinPriorityQueue<Node>();\n\t\tlet root = { index: 0, x: this.rootX, y: this.rootY, width: this.rootWidth, height: this.rootHeight, level: 0 };\n\t\tqueue.push(root, distanceSquaredToRect(x, y, this.rootX, this.rootY, this.rootX + this.rootWidth, this.rootY + this.rootHeight));\n\n\t\twhile(queue.length > 0 && queue.priority <= candidateLimit(candidates, maxResults, maxDistanceSquared)) {\n\t\t\tlet node = queue.pop();\n\t\t\tif(node === undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tnodeCandidates.length = 0;\n\t\t\tthis.collectNeighborNode(nodeCandidates, node.index, x, y, maxDistanceSquared);\n\t\t\tfor(let candidate of nodeCandidates) {\n\t\t\t\tlet duplicate = false;\n\t\t\t\tfor(let existing of candidates) {\n\t\t\t\t\tif(existing.id === candidate.id) {\n\t\t\t\t\t\tduplicate = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(duplicate) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(filter === undefined || filter(candidate.id)) {\n\t\t\t\t\taddCandidate(candidates, candidate.id, candidate.distance, maxResults);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(node.level >= this.maxLevels) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet halfWidth = node.width / 2;\n\t\t\tlet halfHeight = node.height / 2;\n\t\t\tlet childLevel = node.level + 1;\n\t\t\tlet children: Array<Node> = [\n\t\t\t\t{ index: node.index * 4 + 1, x: node.x, y: node.y, width: halfWidth, height: halfHeight, level: childLevel },\n\t\t\t\t{ index: node.index * 4 + 2, x: node.x + halfWidth, y: node.y, width: halfWidth, height: halfHeight, level: childLevel },\n\t\t\t\t{ index: node.index * 4 + 3, x: node.x, y: node.y + halfHeight, width: halfWidth, height: halfHeight, level: childLevel },\n\t\t\t\t{ index: node.index * 4 + 4, x: node.x + halfWidth, y: node.y + halfHeight, width: halfWidth, height: halfHeight, level: childLevel },\n\t\t\t];\n\t\t\tfor(let child of children) {\n\t\t\t\tlet distance = distanceSquaredToRect(x, y, child.x, child.y, child.x + child.width, child.y + child.height);\n\t\t\t\tif(distance <= candidateLimit(candidates, maxResults, maxDistanceSquared)) {\n\t\t\t\t\tqueue.push(child, distance);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn candidates.map(candidate => candidate.id);\n\t}\n\n\tprivate nearestNeighbor(\n\t\tx: number, y: number, maxDistanceSquared: number, filter: ((id: number) => boolean) | undefined,\n\t): Array<number> {\n\t\tlet nearest: NearestNeighbor = { id: undefined, distance: maxDistanceSquared };\n\t\tlet nodeCandidates: Array<NeighborCandidate> = [];\n\t\tthis.findNearest(\n\t\t\t0, this.rootX, this.rootY, this.rootWidth, this.rootHeight, 0,\n\t\t\tx, y, nearest, nodeCandidates, filter,\n\t\t);\n\t\treturn nearest.id === undefined ? [] : [nearest.id];\n\t}\n\n\tprivate findNearest(\n\t\tnode: number, nodeX: number, nodeY: number, width: number, height: number, level: number,\n\t\tx: number, y: number, nearest: NearestNeighbor,\n\t\tnodeCandidates: Array<NeighborCandidate>, filter: ((id: number) => boolean) | undefined,\n\t) {\n\t\tif(distanceSquaredToRect(x, y, nodeX, nodeY, nodeX + width, nodeY + height) > nearest.distance) {\n\t\t\treturn;\n\t\t}\n\t\tif(filter === undefined) {\n\t\t\tthis.collectNearestNode(nearest, node, x, y);\n\t\t} else {\n\t\t\tnodeCandidates.length = 0;\n\t\t\tthis.collectNeighborNode(nodeCandidates, node, x, y, nearest.distance);\n\t\t\tfor(let candidate of nodeCandidates) {\n\t\t\t\tif(filter(candidate.id)\n\t\t\t\t\t&& (candidate.distance < nearest.distance\n\t\t\t\t\t\t|| (candidate.distance === nearest.distance && (nearest.id === undefined || candidate.id < nearest.id)))) {\n\t\t\t\t\tnearest.id = candidate.id;\n\t\t\t\t\tnearest.distance = candidate.distance;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(level >= this.maxLevels) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet halfWidth = width / 2;\n\t\tlet halfHeight = height / 2;\n\t\tlet midX = nodeX + halfWidth;\n\t\tlet midY = nodeY + halfHeight;\n\t\tlet base = node * 4;\n\t\tlet nextLevel = level + 1;\n\t\tlet east = x >= midX;\n\t\tlet south = y >= midY;\n\t\tlet visit = (index: number, childX: number, childY: number) => {\n\t\t\tthis.findNearest(\n\t\t\t\tindex, childX, childY, halfWidth, halfHeight, nextLevel,\n\t\t\t\tx, y, nearest, nodeCandidates, filter,\n\t\t\t);\n\t\t};\n\t\tif(south) {\n\t\t\tif(east) {\n\t\t\t\tvisit(base + 4, midX, midY);\n\t\t\t\tvisit(base + 3, nodeX, midY);\n\t\t\t\tvisit(base + 2, midX, nodeY);\n\t\t\t\tvisit(base + 1, nodeX, nodeY);\n\t\t\t} else {\n\t\t\t\tvisit(base + 3, nodeX, midY);\n\t\t\t\tvisit(base + 4, midX, midY);\n\t\t\t\tvisit(base + 1, nodeX, nodeY);\n\t\t\t\tvisit(base + 2, midX, nodeY);\n\t\t\t}\n\t\t} else if(east) {\n\t\t\tvisit(base + 2, midX, nodeY);\n\t\t\tvisit(base + 1, nodeX, nodeY);\n\t\t\tvisit(base + 4, midX, midY);\n\t\t\tvisit(base + 3, nodeX, midY);\n\t\t} else {\n\t\t\tvisit(base + 1, nodeX, nodeY);\n\t\t\tvisit(base + 2, midX, nodeY);\n\t\t\tvisit(base + 3, nodeX, midY);\n\t\t\tvisit(base + 4, midX, midY);\n\t\t}\n\t}\n\n\tclear() {\n\t\tfor(let i = 0; i < this.nodeCount; i++) {\n\t\t\tthis.nodeHeads[i * NODE_SIZE + NODE_HEAD_OFFSET] = this.nullIndex;\n\t\t}\n\t\tthis.pool.clear();\n\t\t// SharedMap has no clear(); drop every key. Not safe to run concurrently with writers (documented on clear()).\n\t\tlet keys: Array<number> = [];\n\t\tfor(let [key] of this.idMap) {\n\t\t\tkeys.push(key);\n\t\t}\n\t\tfor(let key of keys) {\n\t\t\tthis.idMap.delete(key);\n\t\t}\n\t}\n\n\tfree() {\n\t\tlet nodeBlock = new AllocatedMemory(this.memory, getPointer(loadRawPointer(this.firstBlock.data, NODE_POINTER_INDEX), this.memory.positionBits));\n\t\tnodeBlock.free();\n\t\tthis.pool.free();\n\t\tthis.idMap.free();\n\t\tthis.firstBlock.free();\n\t}\n\n\tgetSharedMemory(): SharedQuadtreeMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n\n\tprivate getBoundsView(): CoordArray {\n\t\treturn makeArrayView(\n\t\t\tthis.coordType,\n\t\t\tthis.firstBlock.data.buffer,\n\t\t\tthis.firstBlock.bufferByteOffset + BOUNDS_INDEX * Uint32Array.BYTES_PER_ELEMENT,\n\t\t\t4,\n\t\t) as CoordArray;\n\t}\n\n\t// Deepest node index that fully contains the rect. Descends into the one child that still fully contains it; stops at a\n\t// straddle or at max depth.\n\tprivate locate(x: number, y: number, width: number, height: number): number {\n\t\tlet node = 0;\n\t\tlet nx = this.rootX;\n\t\tlet ny = this.rootY;\n\t\tlet nw = this.rootWidth;\n\t\tlet nh = this.rootHeight;\n\n\t\tfor(let level = 0; level < this.maxLevels; level++) {\n\t\t\tlet midX = nx + nw / 2;\n\t\t\tlet midY = ny + nh / 2;\n\t\t\tlet west = x >= nx && x + width <= midX && (width > 0 || x < midX);\n\t\t\tlet east = x >= midX && x + width <= nx + nw;\n\t\t\tlet north = y >= ny && y + height <= midY && (height > 0 || y < midY);\n\t\t\tlet south = y >= midY && y + height <= ny + nh;\n\n\t\t\tif(north && west) {\n\t\t\t\tnode = node * 4 + 1;\n\t\t\t\tnw /= 2;\n\t\t\t\tnh /= 2;\n\t\t\t} else if(north && east) {\n\t\t\t\tnode = node * 4 + 2;\n\t\t\t\tnx = midX;\n\t\t\t\tnw /= 2;\n\t\t\t\tnh /= 2;\n\t\t\t} else if(south && west) {\n\t\t\t\tnode = node * 4 + 3;\n\t\t\t\tny = midY;\n\t\t\t\tnw /= 2;\n\t\t\t\tnh /= 2;\n\t\t\t} else if(south && east) {\n\t\t\t\tnode = node * 4 + 4;\n\t\t\t\tnx = midX;\n\t\t\t\tny = midY;\n\t\t\t\tnw /= 2;\n\t\t\t\tnh /= 2;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tprivate collect(out: Array<number>, node: number, nx: number, ny: number, nw: number, nh: number, level: number, qx: number, qy: number, qw: number, qh: number) {\n\t\t// Peek the head unlocked: an empty bucket has nothing to read, so the lock (and its atomics) is pure overhead. Most\n\t\t// nodes in a fixed-depth tree are empty, so skipping them dominates query cost. Taking the lock only to walk a\n\t\t// non-empty bucket preserves the snapshot guarantee - a concurrent insert we race is simply not in this snapshot.\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tif(this.nodeHeads[headIndex] !== this.nullIndex) {\n\t\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\t\tlock(this.nodeInts, lockIndex);\n\t\t\tlet index = this.nodeHeads[headIndex];\n\t\t\tlet pool = this.pool;\n\t\t\twhile(index !== this.nullIndex) {\n\t\t\t\t// One chunk resolve per item covers both fields it reads\n\t\t\t\tlet block = pool.blockFor(index);\n\t\t\t\tlet off = pool.blockOffset(index);\n\t\t\t\tout.push(block[off + ITEM_ID]);\n\t\t\t\tindex = block[off + ITEM_NEXT];\n\t\t\t}\n\t\t\tunlock(this.nodeInts, lockIndex);\n\t\t}\n\n\t\tif(level >= this.maxLevels) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet midX = nx + nw / 2;\n\t\tlet midY = ny + nh / 2;\n\t\tlet hw = nw / 2;\n\t\tlet hh = nh / 2;\n\t\tlet overlapsWest = qx < midX;\n\t\tlet overlapsEast = qx + qw > midX;\n\t\tlet overlapsNorth = qy < midY;\n\t\tlet overlapsSouth = qy + qh > midY;\n\n\t\tif(overlapsNorth && overlapsWest) {\n\t\t\tthis.collect(out, node * 4 + 1, nx, ny, hw, hh, level + 1, qx, qy, qw, qh);\n\t\t}\n\t\tif(overlapsNorth && overlapsEast) {\n\t\t\tthis.collect(out, node * 4 + 2, midX, ny, hw, hh, level + 1, qx, qy, qw, qh);\n\t\t}\n\t\tif(overlapsSouth && overlapsWest) {\n\t\t\tthis.collect(out, node * 4 + 3, nx, midY, hw, hh, level + 1, qx, qy, qw, qh);\n\t\t}\n\t\tif(overlapsSouth && overlapsEast) {\n\t\t\tthis.collect(out, node * 4 + 4, midX, midY, hw, hh, level + 1, qx, qy, qw, qh);\n\t\t}\n\t}\n\n\tprivate collectNeighborNode(\n\t\tout: Array<NeighborCandidate>, node: number, x: number, y: number, maxDistanceSquared: number,\n\t) {\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tif(this.nodeHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\tlock(this.nodeInts, lockIndex);\n\t\tlet index = this.nodeHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet block = this.pool.blockFor(index);\n\t\t\tlet off = this.pool.blockOffset(index);\n\t\t\tlet id = block[off + ITEM_ID];\n\t\t\tlet distance = distanceSquaredToRect(x, y, block[off + ITEM_X], block[off + ITEM_Y], block[off + ITEM_X] + block[off + ITEM_W], block[off + ITEM_Y] + block[off + ITEM_H]);\n\t\t\tif(distance <= maxDistanceSquared) {\n\t\t\t\tout.push({ id, distance });\n\t\t\t}\n\t\t\tindex = block[off + ITEM_NEXT];\n\t\t}\n\t\tunlock(this.nodeInts, lockIndex);\n\t}\n\n\tprivate collectNearestNode(nearest: NearestNeighbor, node: number, x: number, y: number) {\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tif(this.nodeHeads[headIndex] === this.nullIndex) {\n\t\t\treturn;\n\t\t}\n\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\tlock(this.nodeInts, lockIndex);\n\t\tlet index = this.nodeHeads[headIndex];\n\t\twhile(index !== this.nullIndex) {\n\t\t\tlet block = this.pool.blockFor(index);\n\t\t\tlet off = this.pool.blockOffset(index);\n\t\t\tlet id = block[off + ITEM_ID];\n\t\t\tlet distance = distanceSquaredToRect(\n\t\t\t\tx, y, block[off + ITEM_X], block[off + ITEM_Y],\n\t\t\t\tblock[off + ITEM_X] + block[off + ITEM_W], block[off + ITEM_Y] + block[off + ITEM_H],\n\t\t\t);\n\t\t\tif(distance < nearest.distance\n\t\t\t\t|| (distance === nearest.distance && (nearest.id === undefined || id < nearest.id))) {\n\t\t\t\tnearest.id = id;\n\t\t\t\tnearest.distance = distance;\n\t\t\t}\n\t\t\tindex = block[off + ITEM_NEXT];\n\t\t}\n\t\tunlock(this.nodeInts, lockIndex);\n\t}\n\n\tprivate linkIntoNode(node: number, index: number) {\n\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\tlock(this.nodeInts, lockIndex);\n\t\tthis.linkNoLock(node, index);\n\t\tunlock(this.nodeInts, lockIndex);\n\t}\n\t// Push the item onto the node's bucket head. Caller holds the node lock.\n\tprivate linkNoLock(node: number, index: number) {\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tthis.pool.set(index, ITEM_NEXT, this.nodeHeads[headIndex]);\n\t\tthis.nodeHeads[headIndex] = index;\n\t}\n\n\tprivate unlinkFromNode(node: number, index: number) {\n\t\tlet lockIndex = node * NODE_SIZE + NODE_LOCK_OFFSET;\n\t\tlock(this.nodeInts, lockIndex);\n\t\tthis.unlinkNoLock(node, index);\n\t\tunlock(this.nodeInts, lockIndex);\n\t}\n\t// Splice the item out of the node's bucket. Caller holds the node lock.\n\tprivate unlinkNoLock(node: number, index: number) {\n\t\tlet headIndex = node * NODE_SIZE + NODE_HEAD_OFFSET;\n\t\tlet head = this.nodeHeads[headIndex];\n\t\tlet next = this.pool.get(index, ITEM_NEXT);\n\t\tif(head === index) {\n\t\t\tthis.nodeHeads[headIndex] = next;\n\t\t\treturn;\n\t\t}\n\n\t\tlet prev = head;\n\t\twhile(prev !== this.nullIndex) {\n\t\t\tlet prevNext = this.pool.get(prev, ITEM_NEXT);\n\t\t\tif(prevNext === index) {\n\t\t\t\tthis.pool.set(prev, ITEM_NEXT, next);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprev = prevNext;\n\t\t}\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('SharedQuadtree 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}\n\ninterface QuadtreeBounds {\n\tx: number\n\ty: number\n\twidth: number\n\theight: number\n}\ninterface SharedQuadtreeConfig {\n\tbounds: QuadtreeBounds\n\tmaxLevels?: number\n\tmaxEntities?: number\n\ttype?: CoordArrayConstructor\n}\ninterface SharedQuadtreeMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedQuadtreeConfig, SharedQuadtreeMemory, QuadtreeBounds, SpatialEntity };\n"],"mappings":"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"}