Skip to content

Commit

Permalink
Accept byteOffset when creating an index from a buffer (#55)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
kylebarron and mourner authored Jan 20, 2024
1 parent b6c480f commit 5d079a6
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 8 deletions.
24 changes: 16 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,20 @@ export default class Flatbush {
/**
* Recreate a Flatbush index from raw `ArrayBuffer` or `SharedArrayBuffer` data.
* @param {ArrayBuffer | SharedArrayBuffer} data
* @param {number} [byteOffset=0] byte offset to the start of the Flatbush buffer in the referenced ArrayBuffer.
* @returns {Flatbush} index
*/
static from(data) {
static from(data, byteOffset = 0) {
if (byteOffset % 8 !== 0) {
throw new Error('byteOffset must be 8-byte aligned.');
}

// @ts-expect-error duck typing array buffers
if (!data || data.byteLength === undefined || data.buffer) {
throw new Error('Data must be an instance of ArrayBuffer or SharedArrayBuffer.');
}
const [magic, versionAndType] = new Uint8Array(data, 0, 2);

const [magic, versionAndType] = new Uint8Array(data, byteOffset + 0, 2);
if (magic !== 0xfb) {
throw new Error('Data does not appear to be in a Flatbush format.');
}
Expand All @@ -29,10 +35,10 @@ export default class Flatbush {
if (!ArrayType) {
throw new Error('Unrecognized array type.');
}
const [nodeSize] = new Uint16Array(data, 2, 1);
const [numItems] = new Uint32Array(data, 4, 1);
const [nodeSize] = new Uint16Array(data, byteOffset + 2, 1);
const [numItems] = new Uint32Array(data, byteOffset + 4, 1);

return new Flatbush(numItems, nodeSize, ArrayType, undefined, data);
return new Flatbush(numItems, nodeSize, ArrayType, undefined, data, byteOffset);
}

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

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

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

this._pos = numNodes * 4;
this.minX = this._boxes[this._pos - 4];
Expand Down
29 changes: 29 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,35 @@ test('reconstructs an index from array buffer', () => {
assert.deepEqual(index, index2);
});

test('throws an error when reconstructing an index from array buffer if not 8-byte aligned', () => {
const index = createIndex();
const byteOffset = 12;
const newArrayBuffer = new ArrayBuffer(index.data.byteLength + byteOffset);
const newView = new Uint8Array(newArrayBuffer, byteOffset);
newView.set(new Uint8Array(index.data));

assert.throws(() => {
Flatbush.from(newArrayBuffer, byteOffset);
});
});

test('reconstructs an index from a Uint8Array', () => {
const index = createIndex();
const byteOffset = 16;
const newArrayBuffer = new ArrayBuffer(index.data.byteLength + byteOffset);
const newView = new Uint8Array(newArrayBuffer, byteOffset);
newView.set(new Uint8Array(index.data));

const index2 = Flatbush.from(newArrayBuffer, byteOffset);

assert.deepEqual(index._boxes, index2._boxes);
assert.deepEqual(index._indices, index2._indices);
assert.equal(index.numItems, index2.numItems);
assert.equal(index.nodeSize, index2.nodeSize);
assert.deepEqual(index._levelBounds, index2._levelBounds);
assert.notEqual(index.byteOffset, index2.byteOffset);
});

test('throws an error if added less items than the index size', () => {
assert.throws(() => {
const index = new Flatbush(data.length / 4);
Expand Down

0 comments on commit 5d079a6

Please sign in to comment.