Skip to content
Snippets Groups Projects
Commit 2af9f1af authored by David Sehnal's avatar David Sehnal
Browse files

Chunked array tweaks

parent 5d342a30
No related branches found
No related tags found
No related merge requests found
......@@ -8,17 +8,23 @@ import { ChunkedArray } from '../chunked-array'
describe('Chunked Array', () => {
it('creation', () => {
const arr = ChunkedArray.create<number>(_ => [], 2, 2);
const arr = ChunkedArray.create<number>(Array, 2, 2);
ChunkedArray.add2(arr, 1, 2);
ChunkedArray.add2(arr, 3, 4);
expect(ChunkedArray.compact(arr)).toEqual([1, 2, 3, 4]);
});
it('initial', () => {
const arr = ChunkedArray.create<number>(s => new Int32Array(s), 2, 6, new Int32Array([1, 2, 3, 4]));
const arr = ChunkedArray.create<number>(Int32Array, 2, 6, new Int32Array([1, 2, 3, 4]));
ChunkedArray.add2(arr, 4, 3);
ChunkedArray.add2(arr, 2, 1);
ChunkedArray.add2(arr, 5, 6);
expect(ChunkedArray.compact(arr)).toEqual(new Int32Array([4, 3, 2, 1, 5, 6]));
});
it('add many', () => {
const arr = ChunkedArray.create<number>(Array, 2, 2);
ChunkedArray.addMany(arr, [1, 2, 3, 4]);
expect(ChunkedArray.compact(arr)).toEqual([1, 2, 3, 4]);
});
});
\ No newline at end of file
......@@ -8,16 +8,17 @@
/**
* A generic chunked array builder.
*
* When adding elements, the array growns by a specified number
* of elements (either linear or exponential growth) and no copying
* is done until ChunkedArray.compact is called.
* When adding elements, the array grows by a specified number
* of elements and no copying is done until ChunkedArray.compact
* is called.
*/
interface ChunkedArray<T> {
ctor: (size: number) => any,
ctor: { new (size: number): ArrayLike<T> },
elementSize: number,
growBy: number,
allocatedSize: number,
/** current size of the array */
elementCount: number,
currentSize: number,
......@@ -36,7 +37,7 @@ namespace ChunkedArray {
let nextSize = array.growBy * array.elementSize;
array.currentSize = nextSize;
array.currentIndex = 0;
array.currentChunk = array.ctor(nextSize);
array.currentChunk = new array.ctor(nextSize);
array.allocatedSize += nextSize;
array.chunks[array.chunks.length] = array.currentChunk;
}
......@@ -74,6 +75,20 @@ namespace ChunkedArray {
return array.elementCount++;
}
export function addMany<T>(array: ChunkedArray<T>, data: ArrayLike<T>) {
const { elementSize } = array;
for (let i = 0, _i = data.length; i < _i; i += elementSize) {
if (array.currentIndex >= array.currentSize) allocateNext(array);
const { currentChunk } = array;
for (let j = 0; j < elementSize; j++) {
currentChunk[array.currentIndex++] = data[i + j];
}
array.elementCount++;
}
return array.elementCount;
}
/** If doNotResizeSingleton = true and the data fit into a single chunk, do not resize it. */
export function compact<T>(array: ChunkedArray<T>, doNotResizeSingleton = false): ArrayLike<T> {
return _compact(array, doNotResizeSingleton);
}
......@@ -81,7 +96,7 @@ namespace ChunkedArray {
export function _compact<T>(array: ChunkedArray<T>, doNotResizeSingleton: boolean): ArrayLike<T> {
const { ctor, chunks, currentIndex } = array;
if (!chunks.length) return ctor(0);
if (!chunks.length) return new ctor(0);
if (chunks.length === 1) {
if (doNotResizeSingleton || currentIndex === array.allocatedSize) {
return chunks[0];
......@@ -92,7 +107,7 @@ namespace ChunkedArray {
for (let i = 0, _i = chunks.length - 1; i < _i; i++) size += chunks[i].length;
size += array.currentIndex;
const ret = ctor(size);
const ret = new ctor(size) as any;
let offset = 0;
if (ret.buffer) {
......@@ -118,12 +133,17 @@ namespace ChunkedArray {
return ret;
}
export function create<T>(ctor: (size: number) => any, elementSize: number, growBy: number, initialChunk?: ArrayLike<T>): ChunkedArray<T> {
export function create<T>(ctor: { new (size: number): ArrayLike<T> }, elementSize: number, chunkSize: number): ChunkedArray<T>
/** The size of the initial chunk is elementSize * initialCount */
export function create<T>(ctor: { new (size: number): ArrayLike<T> }, elementSize: number, chunkSize: number, initialCount: number): ChunkedArray<T>
/** Use the provided array as the initial chunk. The size of the array must be divisible by the elementSize */
export function create<T>(ctor: { new (size: number): ArrayLike<T> }, elementSize: number, chunkSize: number, initialChunk: ArrayLike<T>): ChunkedArray<T>
export function create<T>(ctor: { new (size: number): ArrayLike<T> }, elementSize: number, chunkSize: number, initialChunkOrCount?: number | ArrayLike<T>): ChunkedArray<T> {
const ret: ChunkedArray<T> = {
ctor,
elementSize,
growBy,
growBy: chunkSize,
allocatedSize: 0,
elementCount: 0,
......@@ -134,8 +154,17 @@ namespace ChunkedArray {
chunks: []
};
if (!initialChunk) return ret;
if (typeof initialChunkOrCount === 'undefined') return ret;
if (typeof initialChunkOrCount === 'number') {
ret.currentChunk = new ctor(initialChunkOrCount * elementSize);
ret.allocatedSize = initialChunkOrCount * elementSize;
ret.currentSize = ret.currentChunk.length;
ret.chunks[0] = ret.currentChunk;
return ret;
}
const initialChunk = initialChunkOrCount;
if (initialChunk.length % elementSize !== 0) throw new Error('initialChunk length must be a multiple of the element size.');
ret.currentChunk = initialChunk;
ret.allocatedSize = initialChunk.length;
......
......@@ -357,7 +357,7 @@ export namespace ArrayEncoding {
let map: any = Object.create(null);
let strings: string[] = [];
let accLength = 0;
let offsets = ChunkedArray.create<number>(s => new Int32Array(s), 1,
let offsets = ChunkedArray.create<number>(Int32Array, 1,
Math.min(1024, data.length < 32 ? data.length + 1 : Math.round(data.length / 8) + 1));
let output = new Int32Array(data.length);
......
......@@ -8,13 +8,13 @@ function testNative(size: number) {
}
function testChunkedTyped(size: number, chunk: number) {
const xs = ChunkedArray.create(s => new Int32Array(s), 1, chunk);
const xs = ChunkedArray.create(Int32Array, 1, chunk);
for (let i = 0; i < size; i++) ChunkedArray.add(xs, i * i);
return ChunkedArray.compact(xs);
}
function testChunkedNative(size: number, chunk: number) {
const xs = ChunkedArray.create(s => [], 1, chunk);
const xs = ChunkedArray.create(Array, 1, chunk);
for (let i = 0; i < size; i++) ChunkedArray.add(xs, i * i);
return ChunkedArray.compact(xs);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment