Skip to content

Commit 5d079a6

Browse files
kylebarronmourner
andauthored
Accept byteOffset when creating an index from a buffer (#55)
* Support Uint8Array input * extra space * address comments * commit test changes * Update index.js Co-authored-by: Volodymyr Agafonkin <[email protected]> * Update index.js Co-authored-by: Volodymyr Agafonkin <[email protected]> * Update index.js Co-authored-by: Volodymyr Agafonkin <[email protected]> * Update index.js Co-authored-by: Volodymyr Agafonkin <[email protected]> * address comments --------- Co-authored-by: Volodymyr Agafonkin <[email protected]>
1 parent b6c480f commit 5d079a6

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

index.js

+16-8
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,20 @@ export default class Flatbush {
1010
/**
1111
* Recreate a Flatbush index from raw `ArrayBuffer` or `SharedArrayBuffer` data.
1212
* @param {ArrayBuffer | SharedArrayBuffer} data
13+
* @param {number} [byteOffset=0] byte offset to the start of the Flatbush buffer in the referenced ArrayBuffer.
1314
* @returns {Flatbush} index
1415
*/
15-
static from(data) {
16+
static from(data, byteOffset = 0) {
17+
if (byteOffset % 8 !== 0) {
18+
throw new Error('byteOffset must be 8-byte aligned.');
19+
}
20+
1621
// @ts-expect-error duck typing array buffers
1722
if (!data || data.byteLength === undefined || data.buffer) {
1823
throw new Error('Data must be an instance of ArrayBuffer or SharedArrayBuffer.');
1924
}
20-
const [magic, versionAndType] = new Uint8Array(data, 0, 2);
25+
26+
const [magic, versionAndType] = new Uint8Array(data, byteOffset + 0, 2);
2127
if (magic !== 0xfb) {
2228
throw new Error('Data does not appear to be in a Flatbush format.');
2329
}
@@ -29,10 +35,10 @@ export default class Flatbush {
2935
if (!ArrayType) {
3036
throw new Error('Unrecognized array type.');
3137
}
32-
const [nodeSize] = new Uint16Array(data, 2, 1);
33-
const [numItems] = new Uint32Array(data, 4, 1);
38+
const [nodeSize] = new Uint16Array(data, byteOffset + 2, 1);
39+
const [numItems] = new Uint32Array(data, byteOffset + 4, 1);
3440

35-
return new Flatbush(numItems, nodeSize, ArrayType, undefined, data);
41+
return new Flatbush(numItems, nodeSize, ArrayType, undefined, data, byteOffset);
3642
}
3743

3844
/**
@@ -42,13 +48,15 @@ export default class Flatbush {
4248
* @param {TypedArrayConstructor} [ArrayType=Float64Array] The array type used for coordinates storage (`Float64Array` by default).
4349
* @param {ArrayBufferConstructor | SharedArrayBufferConstructor} [ArrayBufferType=ArrayBuffer] The array buffer type used to store data (`ArrayBuffer` by default).
4450
* @param {ArrayBuffer | SharedArrayBuffer} [data] (Only used internally)
51+
* @param {number} [byteOffset=0] (Only used internally)
4552
*/
46-
constructor(numItems, nodeSize = 16, ArrayType = Float64Array, ArrayBufferType = ArrayBuffer, data) {
53+
constructor(numItems, nodeSize = 16, ArrayType = Float64Array, ArrayBufferType = ArrayBuffer, data, byteOffset = 0) {
4754
if (numItems === undefined) throw new Error('Missing required argument: numItems.');
4855
if (isNaN(numItems) || numItems <= 0) throw new Error(`Unexpected numItems value: ${numItems}.`);
4956

5057
this.numItems = +numItems;
5158
this.nodeSize = Math.min(Math.max(+nodeSize, 2), 65535);
59+
this.byteOffset = byteOffset;
5260

5361
// calculate the total number of nodes in the R-tree to allocate space for
5462
// and the index of each tree level (used in search later)
@@ -74,8 +82,8 @@ export default class Flatbush {
7482
// @ts-expect-error duck typing array buffers
7583
if (data && data.byteLength !== undefined && !data.buffer) {
7684
this.data = data;
77-
this._boxes = new this.ArrayType(this.data, 8, numNodes * 4);
78-
this._indices = new this.IndexArrayType(this.data, 8 + nodesByteSize, numNodes);
85+
this._boxes = new this.ArrayType(this.data, byteOffset + 8, numNodes * 4);
86+
this._indices = new this.IndexArrayType(this.data, byteOffset + 8 + nodesByteSize, numNodes);
7987

8088
this._pos = numNodes * 4;
8189
this.minX = this._boxes[this._pos - 4];

test.js

+29
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,35 @@ test('reconstructs an index from array buffer', () => {
117117
assert.deepEqual(index, index2);
118118
});
119119

120+
test('throws an error when reconstructing an index from array buffer if not 8-byte aligned', () => {
121+
const index = createIndex();
122+
const byteOffset = 12;
123+
const newArrayBuffer = new ArrayBuffer(index.data.byteLength + byteOffset);
124+
const newView = new Uint8Array(newArrayBuffer, byteOffset);
125+
newView.set(new Uint8Array(index.data));
126+
127+
assert.throws(() => {
128+
Flatbush.from(newArrayBuffer, byteOffset);
129+
});
130+
});
131+
132+
test('reconstructs an index from a Uint8Array', () => {
133+
const index = createIndex();
134+
const byteOffset = 16;
135+
const newArrayBuffer = new ArrayBuffer(index.data.byteLength + byteOffset);
136+
const newView = new Uint8Array(newArrayBuffer, byteOffset);
137+
newView.set(new Uint8Array(index.data));
138+
139+
const index2 = Flatbush.from(newArrayBuffer, byteOffset);
140+
141+
assert.deepEqual(index._boxes, index2._boxes);
142+
assert.deepEqual(index._indices, index2._indices);
143+
assert.equal(index.numItems, index2.numItems);
144+
assert.equal(index.nodeSize, index2.nodeSize);
145+
assert.deepEqual(index._levelBounds, index2._levelBounds);
146+
assert.notEqual(index.byteOffset, index2.byteOffset);
147+
});
148+
120149
test('throws an error if added less items than the index size', () => {
121150
assert.throws(() => {
122151
const index = new Flatbush(data.length / 4);

0 commit comments

Comments
 (0)