Skip to content

Commit 2ceefef

Browse files
Add SharedArrayBuffer support (#48)
This PR adds support for SharedArrayBuffer which is a fully compatible alternative to ArrayBuffer. The implementation follows the style used for the PR that added SharedArrayBuffer support in flatbush.
1 parent 52ef3ed commit 2ceefef

File tree

3 files changed

+26
-12
lines changed

3 files changed

+26
-12
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,14 @@ Alternatively, there's a browser bundle with a `KDBush` global variable:
6868

6969
## API
7070

71-
#### new KDBush(numItems[, nodeSize, ArrayType])
71+
#### new KDBush(numItems[, nodeSize, ArrayType, ArrayBufferType])
7272

7373
Creates an index that will hold a given number of points (`numItems`). Additionally accepts:
7474

7575
- `nodeSize`: Size of the KD-tree node, `64` by default. Higher means faster indexing but slower search, and vise versa.
7676
- `ArrayType`: Array type to use for storing coordinate values. `Float64Array` by default, but if your coordinates are integer values, `Int32Array` makes the index faster and smaller.
77+
- `ArrayBufferType`: the array buffer type used to store data (`ArrayBuffer` by default);
78+
you may prefer `SharedArrayBuffer` if you want to share the index between threads (multiple `Worker`, `SharedWorker` or `ServiceWorker`).
7779

7880
#### index.add(x, y)
7981

@@ -89,7 +91,7 @@ Finds all items within a given radius from the query point and returns an array
8991

9092
#### `KDBush.from(data)`
9193

92-
Recreates a KDBush index from raw `ArrayBuffer` data
94+
Recreates a KDBush index from raw `ArrayBuffer` or `SharedArrayBuffer` data
9395
(that's exposed as `index.data` on a previously indexed KDBush instance).
9496
Very useful for transferring or sharing indices between threads or storing them in a file.
9597

index.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ export default class KDBush {
1313

1414
/**
1515
* Creates an index from raw `ArrayBuffer` data.
16-
* @param {ArrayBuffer} data
16+
* @param {ArrayBufferLike} data
1717
*/
1818
static from(data) {
19-
if (!(data instanceof ArrayBuffer)) {
20-
throw new Error('Data must be an instance of ArrayBuffer.');
19+
if (!(data instanceof ArrayBuffer) && !(data instanceof SharedArrayBuffer)) {
20+
throw new Error('Data must be an instance of ArrayBuffer or SharedArrayBuffer.');
2121
}
2222
const [magic, versionAndType] = new Uint8Array(data, 0, 2);
2323
if (magic !== 0xdb) {
@@ -34,17 +34,18 @@ export default class KDBush {
3434
const [nodeSize] = new Uint16Array(data, 2, 1);
3535
const [numItems] = new Uint32Array(data, 4, 1);
3636

37-
return new KDBush(numItems, nodeSize, ArrayType, data);
37+
return new KDBush(numItems, nodeSize, ArrayType, undefined, data);
3838
}
3939

4040
/**
4141
* Creates an index that will hold a given number of items.
4242
* @param {number} numItems
4343
* @param {number} [nodeSize=64] Size of the KD-tree node (64 by default).
4444
* @param {TypedArrayConstructor} [ArrayType=Float64Array] The array type used for coordinates storage (`Float64Array` by default).
45-
* @param {ArrayBuffer} [data] (For internal use only)
45+
* @param {ArrayBufferConstructor} [ArrayBufferType=ArrayBuffer] The array buffer type used for storage (`ArrayBuffer` by default).
46+
* @param {ArrayBufferLike} [data] (For internal use only)
4647
*/
47-
constructor(numItems, nodeSize = 64, ArrayType = Float64Array, data) {
48+
constructor(numItems, nodeSize = 64, ArrayType = Float64Array, ArrayBufferType = ArrayBuffer, data) {
4849
if (isNaN(numItems) || numItems < 0) throw new Error(`Unexpected numItems value: ${numItems}.`);
4950

5051
this.numItems = +numItems;
@@ -61,14 +62,14 @@ export default class KDBush {
6162
throw new Error(`Unexpected typed array class: ${ArrayType}.`);
6263
}
6364

64-
if (data && (data instanceof ArrayBuffer)) { // reconstruct an index from a buffer
65+
if ((data instanceof ArrayBuffer) || (data instanceof SharedArrayBuffer)) { // reconstruct an index from a buffer
6566
this.data = data;
6667
this.ids = new this.IndexArrayType(this.data, HEADER_SIZE, numItems);
6768
this.coords = new this.ArrayType(this.data, HEADER_SIZE + idsByteSize + padCoords, numItems * 2);
6869
this._pos = numItems * 2;
6970
this._finished = true;
7071
} else { // initialize a new index
71-
this.data = new ArrayBuffer(HEADER_SIZE + coordsByteSize + idsByteSize + padCoords);
72+
this.data = new ArrayBufferType(HEADER_SIZE + coordsByteSize + idsByteSize + padCoords);
7273
this.ids = new this.IndexArrayType(this.data, HEADER_SIZE, numItems);
7374
this.coords = new this.ArrayType(this.data, HEADER_SIZE + idsByteSize + padCoords, numItems * 2);
7475
this._pos = 0;

test.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ const coords = [
2727
53,49,60,50,68,57,70,56,77,63,86,71,90,52,83,71,82,72,81,94,51,75,53,95,39,78,53,88,62,84,72,77,73,99,76,73,81,88,
2828
87,96,98,96,82];
2929

30-
function makeIndex() {
31-
const index = new KDBush(points.length, 10);
30+
function makeIndex(ArrayBufferType = ArrayBuffer) {
31+
const index = new KDBush(points.length, 10, undefined, ArrayBufferType);
3232
for (const [x, y] of points) index.add(x, y);
3333
return index.finish();
3434
}
@@ -120,6 +120,17 @@ test('does not complain about zero items', () => {
120120
});
121121
});
122122

123+
test('creates an index using SharedArrayBuffer', () => {
124+
const index = makeIndex(SharedArrayBuffer);
125+
assert(index.data instanceof SharedArrayBuffer);
126+
});
127+
128+
test('reconstructs an index from a SharedArrayBuffer', () => {
129+
const index = makeIndex(SharedArrayBuffer);
130+
const index2 = KDBush.from(index.data);
131+
assert.deepEqual(index, index2);
132+
});
133+
123134
function sqDist(a, b) {
124135
const dx = a[0] - b[0];
125136
const dy = a[1] - b[1];

0 commit comments

Comments
 (0)