verso-db 0.1.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.
- package/CHANGELOG.md +46 -0
- package/LICENSE +21 -0
- package/README.md +252 -0
- package/dist/BinaryHeap.d.ts +25 -0
- package/dist/BinaryHeap.d.ts.map +1 -0
- package/dist/Collection.d.ts +156 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/HNSWIndex.d.ts +357 -0
- package/dist/HNSWIndex.d.ts.map +1 -0
- package/dist/MaxBinaryHeap.d.ts +63 -0
- package/dist/MaxBinaryHeap.d.ts.map +1 -0
- package/dist/Storage.d.ts +54 -0
- package/dist/Storage.d.ts.map +1 -0
- package/dist/VectorDB.d.ts +44 -0
- package/dist/VectorDB.d.ts.map +1 -0
- package/dist/backends/DistanceBackend.d.ts +5 -0
- package/dist/backends/DistanceBackend.d.ts.map +1 -0
- package/dist/backends/JsDistanceBackend.d.ts +37 -0
- package/dist/backends/JsDistanceBackend.d.ts.map +1 -0
- package/dist/encoding/DeltaEncoder.d.ts +61 -0
- package/dist/encoding/DeltaEncoder.d.ts.map +1 -0
- package/dist/errors.d.ts +58 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3732 -0
- package/dist/presets.d.ts +91 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/quantization/ScalarQuantizer.d.ts +114 -0
- package/dist/quantization/ScalarQuantizer.d.ts.map +1 -0
- package/dist/storage/BatchWriter.d.ts +104 -0
- package/dist/storage/BatchWriter.d.ts.map +1 -0
- package/dist/storage/BunStorageBackend.d.ts +58 -0
- package/dist/storage/BunStorageBackend.d.ts.map +1 -0
- package/dist/storage/MemoryBackend.d.ts +44 -0
- package/dist/storage/MemoryBackend.d.ts.map +1 -0
- package/dist/storage/OPFSBackend.d.ts +59 -0
- package/dist/storage/OPFSBackend.d.ts.map +1 -0
- package/dist/storage/StorageBackend.d.ts +66 -0
- package/dist/storage/StorageBackend.d.ts.map +1 -0
- package/dist/storage/WriteAheadLog.d.ts +111 -0
- package/dist/storage/WriteAheadLog.d.ts.map +1 -0
- package/dist/storage/createStorageBackend.d.ts +40 -0
- package/dist/storage/createStorageBackend.d.ts.map +1 -0
- package/dist/storage/index.d.ts +30 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/package.json +98 -0
- package/src/BinaryHeap.ts +131 -0
- package/src/Collection.ts +695 -0
- package/src/HNSWIndex.ts +1839 -0
- package/src/MaxBinaryHeap.ts +175 -0
- package/src/Storage.ts +435 -0
- package/src/VectorDB.ts +109 -0
- package/src/backends/DistanceBackend.ts +17 -0
- package/src/backends/JsDistanceBackend.ts +227 -0
- package/src/encoding/DeltaEncoder.ts +217 -0
- package/src/errors.ts +110 -0
- package/src/index.ts +138 -0
- package/src/presets.ts +229 -0
- package/src/quantization/ScalarQuantizer.ts +383 -0
- package/src/storage/BatchWriter.ts +336 -0
- package/src/storage/BunStorageBackend.ts +161 -0
- package/src/storage/MemoryBackend.ts +120 -0
- package/src/storage/OPFSBackend.ts +250 -0
- package/src/storage/StorageBackend.ts +74 -0
- package/src/storage/WriteAheadLog.ts +326 -0
- package/src/storage/createStorageBackend.ts +137 -0
- package/src/storage/index.ts +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WriteAheadLog.d.ts","sourceRoot":"","sources":["../../src/storage/WriteAheadLog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,oBAAY,gBAAgB;IAC1B,UAAU,IAAI;IACd,aAAa,IAAI;IACjB,kBAAkB,IAAI;IACtB,UAAU,IAAI;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAa;IAE/B;;;;OAIG;gBACS,QAAQ,EAAE,MAAM,EAAE,cAAc,GAAE,MAAY;IAK1D;;OAEG;IACH,OAAO,IAAI,MAAM;IAIjB;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAKhC;;OAEG;IACG,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BnE;;OAEG;IACG,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA8BxF;;OAEG;IACG,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBnF;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAejC;;OAEG;IACH,OAAO,CAAC,cAAc;IAiBtB;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC5B;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IA4BxC;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,YAAY,CAAA;KAAE;IAQhF;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE;IAcrG;;OAEG;IACH,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAQ1F;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAS9B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Backend Factory
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects the best storage backend for the current environment:
|
|
5
|
+
* - Bun/Node.js: BunStorageBackend (file system)
|
|
6
|
+
* - Modern browsers: OPFSBackend (Origin Private File System)
|
|
7
|
+
* - Fallback: MemoryBackend (in-memory)
|
|
8
|
+
*/
|
|
9
|
+
import type { StorageBackend, StorageOptions } from './StorageBackend';
|
|
10
|
+
export type StorageType = 'auto' | 'bun' | 'opfs' | 'memory';
|
|
11
|
+
export interface CreateStorageOptions extends StorageOptions {
|
|
12
|
+
/** Force a specific storage type */
|
|
13
|
+
type?: StorageType;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create the optimal storage backend for the current environment
|
|
17
|
+
*
|
|
18
|
+
* @param options Configuration options
|
|
19
|
+
* @returns Initialized storage backend
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // Auto-detect best backend
|
|
24
|
+
* const storage = await createStorageBackend();
|
|
25
|
+
*
|
|
26
|
+
* // Force specific backend
|
|
27
|
+
* const bunStorage = await createStorageBackend({ type: 'bun', path: './data' });
|
|
28
|
+
* const memStorage = await createStorageBackend({ type: 'memory' });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function createStorageBackend(options?: CreateStorageOptions): Promise<StorageBackend>;
|
|
32
|
+
/**
|
|
33
|
+
* Get the recommended storage type for the current environment
|
|
34
|
+
*/
|
|
35
|
+
export declare function getRecommendedStorageType(): StorageType;
|
|
36
|
+
/**
|
|
37
|
+
* Check if a specific storage type is available
|
|
38
|
+
*/
|
|
39
|
+
export declare function isStorageTypeAvailable(type: StorageType): boolean;
|
|
40
|
+
//# sourceMappingURL=createStorageBackend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createStorageBackend.d.ts","sourceRoot":"","sources":["../../src/storage/createStorageBackend.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE7D,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC1D,oCAAoC;IACpC,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAmBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CA+ClG;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,WAAW,CAYvD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAajE"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Module
|
|
3
|
+
*
|
|
4
|
+
* Provides pluggable storage backends for vector index persistence.
|
|
5
|
+
* Supports multiple platforms:
|
|
6
|
+
* - Bun/Node.js: File system with Bun.file APIs
|
|
7
|
+
* - Modern browsers: OPFS (Origin Private File System)
|
|
8
|
+
* - Testing/fallback: In-memory storage
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { createStorageBackend, WriteAheadLog } from 'bun-vector-search/storage';
|
|
13
|
+
*
|
|
14
|
+
* // Auto-detect best storage for current environment
|
|
15
|
+
* const storage = await createStorageBackend();
|
|
16
|
+
*
|
|
17
|
+
* // Use WAL for incremental writes
|
|
18
|
+
* const wal = new WriteAheadLog('./index');
|
|
19
|
+
* await wal.appendVector(1, new Float32Array([1, 2, 3]));
|
|
20
|
+
* await wal.flush();
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export type { StorageBackend, StorageOptions } from './StorageBackend';
|
|
24
|
+
export { BunStorageBackend } from './BunStorageBackend';
|
|
25
|
+
export { MemoryBackend } from './MemoryBackend';
|
|
26
|
+
export { OPFSBackend } from './OPFSBackend';
|
|
27
|
+
export { createStorageBackend, getRecommendedStorageType, isStorageTypeAvailable, type StorageType, type CreateStorageOptions, } from './createStorageBackend';
|
|
28
|
+
export { WriteAheadLog, WALOperationType, type WALEntry, } from './WriteAheadLog';
|
|
29
|
+
export { BatchWriter, createBatchWriter, type BatchWriterOptions, } from './BatchWriter';
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,sBAAsB,EACtB,KAAK,WAAW,EAChB,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,KAAK,QAAQ,GACd,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "verso-db",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "High-performance vector search with HNSW indexing for Bun and Browser. 100% recall, 4x memory reduction with Int8 quantization.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"bun": "./src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"CHANGELOG.md"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target browser && bun run build:types",
|
|
29
|
+
"build:types": "tsc --emitDeclarationOnly --declaration --outDir ./dist",
|
|
30
|
+
"test": "bun test",
|
|
31
|
+
"test:browser": "vitest --config vitest.browser.config.ts run",
|
|
32
|
+
"test:browser:watch": "vitest --config vitest.browser.config.ts",
|
|
33
|
+
"test:browser:ui": "vitest --config vitest.browser.config.ts --ui",
|
|
34
|
+
"prepublishOnly": "bun run build",
|
|
35
|
+
"bench": "bun run benchmarks/vector_search.bench.ts && bun run benchmarks/hnsw.bench.ts && bun run benchmarks/storage.bench.ts",
|
|
36
|
+
"benchmark:recall": "bun run benchmarks/recall_validation.bench.ts",
|
|
37
|
+
"benchmark:memory": "bun run benchmarks/memory_usage_final.bench.ts",
|
|
38
|
+
"release": "semantic-release",
|
|
39
|
+
"publish:dry": "bunx npm publish --dry-run"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"vector",
|
|
43
|
+
"search",
|
|
44
|
+
"hnsw",
|
|
45
|
+
"embedding",
|
|
46
|
+
"similarity",
|
|
47
|
+
"nearest-neighbor",
|
|
48
|
+
"knn",
|
|
49
|
+
"ann",
|
|
50
|
+
"bun",
|
|
51
|
+
"browser",
|
|
52
|
+
"opfs",
|
|
53
|
+
"rag",
|
|
54
|
+
"ai",
|
|
55
|
+
"machine-learning",
|
|
56
|
+
"typescript"
|
|
57
|
+
],
|
|
58
|
+
"author": "Brian Sunter",
|
|
59
|
+
"license": "MIT",
|
|
60
|
+
"repository": {
|
|
61
|
+
"type": "git",
|
|
62
|
+
"url": "git+https://github.com/briansunter/verso.git"
|
|
63
|
+
},
|
|
64
|
+
"bugs": {
|
|
65
|
+
"url": "https://github.com/briansunter/verso/issues"
|
|
66
|
+
},
|
|
67
|
+
"homepage": "https://github.com/briansunter/verso#readme",
|
|
68
|
+
"engines": {
|
|
69
|
+
"bun": ">=1.0.0"
|
|
70
|
+
},
|
|
71
|
+
"peerDependencies": {
|
|
72
|
+
"typescript": "^5"
|
|
73
|
+
},
|
|
74
|
+
"devDependencies": {
|
|
75
|
+
"@huggingface/hub": "^2.7.0",
|
|
76
|
+
"@lancedb/lancedb": "^0.22.3",
|
|
77
|
+
"@qdrant/js-client-rest": "^1.16.1",
|
|
78
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
79
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
80
|
+
"@semantic-release/git": "^10.0.1",
|
|
81
|
+
"@semantic-release/github": "^12.0.2",
|
|
82
|
+
"@semantic-release/npm": "^13.1.3",
|
|
83
|
+
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
84
|
+
"@types/bun": "latest",
|
|
85
|
+
"@vitest/browser": "^4.0.14",
|
|
86
|
+
"@vitest/browser-playwright": "^4.0.14",
|
|
87
|
+
"hnsw": "^1.0.3",
|
|
88
|
+
"hyparquet": "^1.21.1",
|
|
89
|
+
"hyparquet-compressors": "^1.1.1",
|
|
90
|
+
"mitata": "^1.0.34",
|
|
91
|
+
"playwright": "^1.57.0",
|
|
92
|
+
"semantic-release": "^25.0.2",
|
|
93
|
+
"simsimd": "^6.5.5",
|
|
94
|
+
"typescript": "^5.0.0",
|
|
95
|
+
"vitest": "^4.0.14",
|
|
96
|
+
"wabt": "^1.0.39"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
export class BinaryHeap {
|
|
2
|
+
private ids: Uint32Array;
|
|
3
|
+
private dists: Float32Array;
|
|
4
|
+
private _size: number;
|
|
5
|
+
private capacity: number;
|
|
6
|
+
private lastPoppedValue: number = 0;
|
|
7
|
+
|
|
8
|
+
constructor(capacity: number) {
|
|
9
|
+
this.capacity = capacity;
|
|
10
|
+
this.ids = new Uint32Array(capacity);
|
|
11
|
+
this.dists = new Float32Array(capacity);
|
|
12
|
+
this._size = 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Push an element onto the heap.
|
|
17
|
+
* When at capacity, simply returns without adding (caller manages bounds).
|
|
18
|
+
* This is the correct behavior for HNSW candidate exploration.
|
|
19
|
+
*/
|
|
20
|
+
push(id: number, dist: number): void {
|
|
21
|
+
if (this._size >= this.capacity) {
|
|
22
|
+
// At capacity - don't add more elements.
|
|
23
|
+
// The caller is responsible for managing heap bounds.
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.ids[this._size] = id;
|
|
28
|
+
this.dists[this._size] = dist;
|
|
29
|
+
this._size++;
|
|
30
|
+
this.heapifyUp(this._size - 1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pop(): number {
|
|
34
|
+
if (this._size === 0) return -1;
|
|
35
|
+
|
|
36
|
+
const result = this.ids[0];
|
|
37
|
+
this.lastPoppedValue = this.dists[0];
|
|
38
|
+
this._size--;
|
|
39
|
+
if (this._size > 0) {
|
|
40
|
+
this.ids[0] = this.ids[this._size];
|
|
41
|
+
this.dists[0] = this.dists[this._size];
|
|
42
|
+
this.heapifyDown(0);
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
peek(): number {
|
|
48
|
+
return this._size > 0 ? this.ids[0] : -1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
peekValue(): number {
|
|
52
|
+
return this._size > 0 ? this.dists[0] : Infinity;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getLastPoppedValue(): number {
|
|
56
|
+
return this.lastPoppedValue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
size(): number {
|
|
60
|
+
return this._size;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
clear(): void {
|
|
64
|
+
this._size = 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
isEmpty(): boolean {
|
|
68
|
+
return this._size === 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getCapacity(): number {
|
|
72
|
+
return this.capacity;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private heapifyUp(index: number): void {
|
|
76
|
+
// Cache array references to avoid repeated property lookups
|
|
77
|
+
const ids = this.ids;
|
|
78
|
+
const dists = this.dists;
|
|
79
|
+
|
|
80
|
+
while (index > 0) {
|
|
81
|
+
// Use bitwise shift for faster integer division
|
|
82
|
+
const parentIndex = (index - 1) >> 1;
|
|
83
|
+
if (dists[parentIndex] <= dists[index]) break;
|
|
84
|
+
|
|
85
|
+
// Inline swap for performance
|
|
86
|
+
const tmpId = ids[index];
|
|
87
|
+
ids[index] = ids[parentIndex];
|
|
88
|
+
ids[parentIndex] = tmpId;
|
|
89
|
+
|
|
90
|
+
const tmpDist = dists[index];
|
|
91
|
+
dists[index] = dists[parentIndex];
|
|
92
|
+
dists[parentIndex] = tmpDist;
|
|
93
|
+
|
|
94
|
+
index = parentIndex;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private heapifyDown(index: number): void {
|
|
99
|
+
// Cache array references to avoid repeated property lookups
|
|
100
|
+
const ids = this.ids;
|
|
101
|
+
const dists = this.dists;
|
|
102
|
+
const size = this._size;
|
|
103
|
+
|
|
104
|
+
while (true) {
|
|
105
|
+
const leftChild = (index << 1) + 1; // 2 * index + 1
|
|
106
|
+
const rightChild = leftChild + 1; // 2 * index + 2
|
|
107
|
+
let smallest = index;
|
|
108
|
+
|
|
109
|
+
if (leftChild < size && dists[leftChild] < dists[smallest]) {
|
|
110
|
+
smallest = leftChild;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (rightChild < size && dists[rightChild] < dists[smallest]) {
|
|
114
|
+
smallest = rightChild;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (smallest === index) break;
|
|
118
|
+
|
|
119
|
+
// Inline swap for performance
|
|
120
|
+
const tmpId = ids[index];
|
|
121
|
+
ids[index] = ids[smallest];
|
|
122
|
+
ids[smallest] = tmpId;
|
|
123
|
+
|
|
124
|
+
const tmpDist = dists[index];
|
|
125
|
+
dists[index] = dists[smallest];
|
|
126
|
+
dists[smallest] = tmpDist;
|
|
127
|
+
|
|
128
|
+
index = smallest;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|