@osmix/core 0.2.0 → 0.3.0
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 +31 -0
- package/README.md +54 -7
- package/dist/contracts.d.ts +2 -1
- package/dist/contracts.d.ts.map +1 -1
- package/dist/entities.d.ts +21 -1
- package/dist/entities.d.ts.map +1 -1
- package/dist/entities.js +52 -3
- package/dist/entities.js.map +1 -1
- package/dist/ids.d.ts +18 -5
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +68 -18
- package/dist/ids.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/indirect-kd-index.d.ts +28 -0
- package/dist/indirect-kd-index.d.ts.map +1 -0
- package/dist/indirect-kd-index.js +163 -0
- package/dist/indirect-kd-index.js.map +1 -0
- package/dist/limits.d.ts +30 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +51 -0
- package/dist/limits.js.map +1 -0
- package/dist/nodes.d.ts +28 -13
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +181 -51
- package/dist/nodes.js.map +1 -1
- package/dist/osm.d.ts +59 -3
- package/dist/osm.d.ts.map +1 -1
- package/dist/osm.js +31 -2
- package/dist/osm.js.map +1 -1
- package/dist/relations.d.ts +10 -4
- package/dist/relations.d.ts.map +1 -1
- package/dist/relations.js +66 -28
- package/dist/relations.js.map +1 -1
- package/dist/renumber.d.ts +23 -0
- package/dist/renumber.d.ts.map +1 -0
- package/dist/renumber.js +64 -0
- package/dist/renumber.js.map +1 -0
- package/dist/stringtable.d.ts +2 -1
- package/dist/stringtable.d.ts.map +1 -1
- package/dist/stringtable.js +5 -1
- package/dist/stringtable.js.map +1 -1
- package/dist/tags.d.ts +44 -11
- package/dist/tags.d.ts.map +1 -1
- package/dist/tags.js +153 -27
- package/dist/tags.js.map +1 -1
- package/dist/typed-arrays.d.ts +63 -48
- package/dist/typed-arrays.d.ts.map +1 -1
- package/dist/typed-arrays.js +184 -107
- package/dist/typed-arrays.js.map +1 -1
- package/dist/ways.d.ts +50 -2
- package/dist/ways.d.ts.map +1 -1
- package/dist/ways.js +212 -35
- package/dist/ways.js.map +1 -1
- package/package.json +11 -12
- package/src/contracts.ts +2 -1
- package/src/entities.ts +67 -4
- package/src/ids.ts +72 -22
- package/src/index.ts +13 -7
- package/src/indirect-kd-index.ts +212 -0
- package/src/limits.ts +73 -0
- package/src/nodes.ts +228 -54
- package/src/osm.ts +90 -4
- package/src/relations.ts +80 -30
- package/src/renumber.ts +80 -0
- package/src/stringtable.ts +15 -1
- package/src/tags.ts +173 -31
- package/src/typed-arrays.ts +225 -113
- package/src/ways.ts +233 -38
- package/test/entity-index-errors.test.ts +41 -0
- package/test/ids.bench.ts +11 -7
- package/test/ids.test.ts +38 -0
- package/test/limits.test.ts +83 -0
- package/test/no-shared-array-buffer.test.ts +41 -0
- package/test/nodes-spatial-index.test.ts +261 -0
- package/test/osm-bbox.test.ts +30 -0
- package/test/relations.bench.ts +9 -4
- package/test/relations.test.ts +52 -29
- package/test/renumber.test.ts +54 -0
- package/test/spatial-index-rebuild.test.ts +33 -0
- package/test/storage-compaction.test.ts +269 -0
- package/test/tags-search.test.ts +13 -0
- package/test/typed-arrays.test.ts +178 -59
- package/src/types/geokdbush.d.ts +0 -32
- package/src/types/kdbush.d.ts +0 -47
package/src/typed-arrays.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { isSharedArrayBuffer } from "@osmix/shared/backing-buffers";
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Use SharedArrayBuffer if the runtime supports it, otherwise fall back to ArrayBuffer.
|
|
12
14
|
* SharedArrayBuffer enables zero-copy transfer between workers.
|
|
@@ -38,8 +40,56 @@ export type TypedArray<B extends BufferType = BufferType> =
|
|
|
38
40
|
* Constructor interface for typed arrays.
|
|
39
41
|
*/
|
|
40
42
|
export interface TypedArrayConstructor<T extends TypedArray<BufferType> = TypedArray<BufferType>> {
|
|
41
|
-
new (buffer: BufferType): T;
|
|
43
|
+
new (buffer: BufferType, byteOffset?: number, length?: number): T;
|
|
42
44
|
readonly BYTES_PER_ELEMENT: number;
|
|
45
|
+
readonly name: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type TypedBufferAllocationOperation = "create" | "grow" | "compact";
|
|
49
|
+
export type TypedBufferType = "array-buffer" | "shared-array-buffer";
|
|
50
|
+
|
|
51
|
+
/** Structured allocation failure suitable for transport across worker boundaries. */
|
|
52
|
+
export class TypedBufferAllocationError extends Error {
|
|
53
|
+
readonly code = "TYPED_BUFFER_ALLOCATION_FAILED";
|
|
54
|
+
readonly stage = "typed-buffer-allocation";
|
|
55
|
+
readonly operation: TypedBufferAllocationOperation;
|
|
56
|
+
readonly typedArray: string;
|
|
57
|
+
readonly bufferType: TypedBufferType;
|
|
58
|
+
readonly elementCount: number;
|
|
59
|
+
readonly bytesPerElement: number;
|
|
60
|
+
readonly requiredBytes: number;
|
|
61
|
+
|
|
62
|
+
constructor(
|
|
63
|
+
args: {
|
|
64
|
+
operation: TypedBufferAllocationOperation;
|
|
65
|
+
typedArray: string;
|
|
66
|
+
bufferType: TypedBufferType;
|
|
67
|
+
elementCount: number;
|
|
68
|
+
bytesPerElement: number;
|
|
69
|
+
requiredBytes: number;
|
|
70
|
+
},
|
|
71
|
+
cause: unknown,
|
|
72
|
+
) {
|
|
73
|
+
super(
|
|
74
|
+
`${args.typedArray} ${args.operation} requires ${args.requiredBytes.toLocaleString()} bytes in a single ${args.bufferType === "shared-array-buffer" ? "SharedArrayBuffer" : "ArrayBuffer"}.`,
|
|
75
|
+
{ cause },
|
|
76
|
+
);
|
|
77
|
+
this.name = "TypedBufferAllocationError";
|
|
78
|
+
this.operation = args.operation;
|
|
79
|
+
this.typedArray = args.typedArray;
|
|
80
|
+
this.bufferType = args.bufferType;
|
|
81
|
+
this.elementCount = args.elementCount;
|
|
82
|
+
this.bytesPerElement = args.bytesPerElement;
|
|
83
|
+
this.requiredBytes = args.requiredBytes;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type BufferConstructorType = SharedArrayBufferConstructor | ArrayBufferConstructor;
|
|
88
|
+
|
|
89
|
+
function getBufferType(BC: BufferConstructorType): TypedBufferType {
|
|
90
|
+
return typeof SharedArrayBuffer !== "undefined" && BC === SharedArrayBuffer
|
|
91
|
+
? "shared-array-buffer"
|
|
92
|
+
: "array-buffer";
|
|
43
93
|
}
|
|
44
94
|
|
|
45
95
|
/**
|
|
@@ -51,63 +101,60 @@ export interface TypedArrayConstructor<T extends TypedArray<BufferType> = TypedA
|
|
|
51
101
|
*/
|
|
52
102
|
export const IdArrayType = Float64Array;
|
|
53
103
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* so Uint32Array provides the best balance of range and memory efficiency.
|
|
59
|
-
*/
|
|
60
|
-
export const IndexArrayType = Uint32Array;
|
|
104
|
+
const MiB = 2 ** 20;
|
|
105
|
+
|
|
106
|
+
/** Starting capacity of a new column. Growth is in place, so small columns stay small. */
|
|
107
|
+
const INITIAL_BYTES = 64 * 1024;
|
|
61
108
|
|
|
62
109
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
110
|
+
* Address space a growing column reserves so that it grows in place, without copying.
|
|
111
|
+
* Reserved pages hold no memory until written. Chromium's V8 sandbox has room for about 250
|
|
112
|
+
* reservations of this size, and a load builds about 35 columns at once. A reservation that
|
|
113
|
+
* fails falls back to growing by reallocation.
|
|
65
114
|
*/
|
|
66
|
-
|
|
115
|
+
const GROWTH_RESERVE_BYTES = 4 * 2 ** 30;
|
|
116
|
+
|
|
117
|
+
/** Above this size a column grows by 1.5× instead of 2×, so it overshoots less. */
|
|
118
|
+
const DOUBLING_LIMIT_BYTES = 256 * MiB;
|
|
67
119
|
|
|
68
120
|
/**
|
|
69
121
|
* Auto-expanding typed array wrapper.
|
|
70
122
|
*
|
|
71
|
-
* - `push()`
|
|
72
|
-
*
|
|
73
|
-
* -
|
|
123
|
+
* - `push()` / `pushMany()` append, growing the buffer in place when the runtime supports
|
|
124
|
+
* growable buffers, otherwise by reallocating.
|
|
125
|
+
* - `array` is a view of the stored items only; `compact()` shrinks the buffer to fit them.
|
|
126
|
+
* - `from()` wraps a finished (transferred) buffer, which can still grow.
|
|
74
127
|
*/
|
|
75
128
|
export class ResizeableTypedArray<TA extends TypedArray> {
|
|
76
129
|
/** The typed array constructor for this instance */
|
|
77
|
-
ArrayType: TypedArrayConstructor<TA>;
|
|
78
|
-
/** The current typed array view into the buffer */
|
|
79
|
-
array: TA;
|
|
80
|
-
/** Number of items actually stored (may be less than array.length) */
|
|
81
|
-
items = 0;
|
|
82
|
-
|
|
83
|
-
/** The underlying ArrayBuffer or SharedArrayBuffer */
|
|
84
|
-
buffer: BufferType;
|
|
85
|
-
/** Current buffer size in bytes */
|
|
86
|
-
bufferSize: number;
|
|
87
|
-
/** Maximum byte length for growable buffers */
|
|
88
|
-
maxByteLength: number;
|
|
89
|
-
|
|
130
|
+
readonly ArrayType: TypedArrayConstructor<TA>;
|
|
90
131
|
/** Buffer constructor (SharedArrayBuffer or ArrayBuffer) */
|
|
91
|
-
BC:
|
|
132
|
+
private readonly BC: BufferConstructorType;
|
|
133
|
+
/** View of the whole buffer: stored items, then spare capacity. */
|
|
134
|
+
private view: TA;
|
|
135
|
+
/** Number of items actually stored (may be less than the capacity). */
|
|
136
|
+
private items = 0;
|
|
92
137
|
|
|
93
138
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
139
|
+
* The buffer size a new column reaches when it is filled one `push` at a time to
|
|
140
|
+
* `requiredBytes`, for projecting peak memory before a load.
|
|
141
|
+
*/
|
|
142
|
+
static capacityBytesFor(requiredBytes: number, bytesPerElement: number): number {
|
|
143
|
+
let bytes = INITIAL_BYTES;
|
|
144
|
+
while (bytes < requiredBytes) {
|
|
145
|
+
bytes = nextByteLength(bytes, bytes + bytesPerElement, bytesPerElement);
|
|
146
|
+
}
|
|
147
|
+
return bytes;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Wrap an existing buffer, as after transferring it between workers. Every element of the
|
|
152
|
+
* buffer is a stored item. Nothing is allocated until the array grows.
|
|
102
153
|
*/
|
|
103
154
|
static from<TA extends TypedArray>(ArrayType: TypedArrayConstructor<TA>, buffer: BufferType) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
);
|
|
108
|
-
rta.buffer = buffer;
|
|
109
|
-
rta.array = new ArrayType(buffer);
|
|
110
|
-
rta.items = rta.array.length;
|
|
155
|
+
const BC = isSharedArrayBuffer(buffer) ? SharedArrayBuffer : ArrayBuffer;
|
|
156
|
+
const rta = new ResizeableTypedArray<TA>(ArrayType, BC, new ArrayType(buffer));
|
|
157
|
+
rta.items = rta.view.length;
|
|
111
158
|
return rta;
|
|
112
159
|
}
|
|
113
160
|
|
|
@@ -119,85 +166,62 @@ export class ResizeableTypedArray<TA extends TypedArray> {
|
|
|
119
166
|
*/
|
|
120
167
|
constructor(
|
|
121
168
|
ArrayType: TypedArrayConstructor<TA>,
|
|
122
|
-
BC:
|
|
169
|
+
BC: BufferConstructorType = BufferConstructor,
|
|
170
|
+
/** @internal A view to wrap instead of allocating; used by `from()`. */
|
|
171
|
+
view?: TA,
|
|
123
172
|
) {
|
|
124
173
|
this.ArrayType = ArrayType;
|
|
125
|
-
this.bufferSize = DEFAULT_BUFFER_SIZE;
|
|
126
|
-
this.maxByteLength = DEFAULT_BUFFER_SIZE * 2;
|
|
127
174
|
this.BC = BC;
|
|
128
|
-
this.
|
|
129
|
-
maxByteLength: this.maxByteLength,
|
|
130
|
-
});
|
|
131
|
-
this.array = new this.ArrayType(this.buffer);
|
|
175
|
+
this.view = view ?? new ArrayType(this.allocate("create", INITIAL_BYTES, GROWTH_RESERVE_BYTES));
|
|
132
176
|
}
|
|
133
177
|
|
|
134
|
-
/**
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
[Symbol.iterator](): ArrayIterator<number> {
|
|
138
|
-
return this.array[Symbol.iterator]();
|
|
178
|
+
/** The stored items. Before `compact()`, a view that excludes the spare capacity. */
|
|
179
|
+
get array(): TA {
|
|
180
|
+
return this.items === this.view.length ? this.view : (this.view.subarray(0, this.items) as TA);
|
|
139
181
|
}
|
|
140
182
|
|
|
141
|
-
/**
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
// Can grow/resize the existing buffer in place
|
|
159
|
-
if (this.buffer instanceof SharedArrayBuffer && this.buffer.growable) {
|
|
160
|
-
this.buffer.grow(this.bufferSize);
|
|
161
|
-
} else if (this.buffer instanceof ArrayBuffer && this.buffer.resizable) {
|
|
162
|
-
this.buffer.resize(this.bufferSize);
|
|
163
|
-
} else {
|
|
164
|
-
throw Error("Buffer is not growable or resizable");
|
|
165
|
-
}
|
|
166
|
-
}
|
|
183
|
+
/** The underlying buffer, including any spare capacity. */
|
|
184
|
+
get buffer(): BufferType {
|
|
185
|
+
return this.view.buffer as BufferType;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
get length() {
|
|
189
|
+
return this.items;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Number of items the current buffer can hold before it must grow. */
|
|
193
|
+
get capacity() {
|
|
194
|
+
return this.view.length;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Iterate over the stored values. */
|
|
198
|
+
[Symbol.iterator](): ArrayIterator<number> {
|
|
199
|
+
return this.array[Symbol.iterator]();
|
|
167
200
|
}
|
|
168
201
|
|
|
169
202
|
/**
|
|
170
203
|
* Get the value at an index. Handles negative indices.
|
|
171
204
|
*/
|
|
172
205
|
at(index: number): number {
|
|
173
|
-
if (index
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const result = this.array[index];
|
|
177
|
-
if (result === undefined) throw Error(`No value at index: ${index}`);
|
|
178
|
-
return result;
|
|
206
|
+
if (index >= 0 && index < this.items) return this.view[index]!;
|
|
207
|
+
if (index < 0 && index >= -this.items) return this.view[this.items + index]!;
|
|
208
|
+
throw Error(`Index out of bounds: ${index}. Length: ${this.items}`);
|
|
179
209
|
}
|
|
180
210
|
|
|
181
211
|
/**
|
|
182
|
-
* Get a
|
|
212
|
+
* Get a copy of a range of the stored items.
|
|
183
213
|
*/
|
|
184
214
|
slice(start: number, end: number) {
|
|
185
215
|
return this.array.slice(start, end);
|
|
186
216
|
}
|
|
187
217
|
|
|
188
|
-
get length() {
|
|
189
|
-
return this.items;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
218
|
/**
|
|
193
219
|
* Push a value to the end of the array.
|
|
194
220
|
*/
|
|
195
221
|
push(value: number): number {
|
|
196
|
-
if (this.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
this.array[this.items++] = value;
|
|
200
|
-
return this.length - 1;
|
|
222
|
+
if (this.items === this.view.length) this.ensureCapacity(this.items + 1);
|
|
223
|
+
this.view[this.items] = value;
|
|
224
|
+
return this.items++;
|
|
201
225
|
}
|
|
202
226
|
|
|
203
227
|
/**
|
|
@@ -205,19 +229,19 @@ export class ResizeableTypedArray<TA extends TypedArray> {
|
|
|
205
229
|
*/
|
|
206
230
|
set(index: number, value: number) {
|
|
207
231
|
if (index < 0) throw Error("Index out of bounds");
|
|
208
|
-
if (index >= this.
|
|
209
|
-
|
|
232
|
+
if (index >= this.items) {
|
|
233
|
+
this.ensureCapacity(index + 1);
|
|
210
234
|
this.items = index + 1;
|
|
211
235
|
}
|
|
212
|
-
this.
|
|
236
|
+
this.view[index] = value;
|
|
213
237
|
}
|
|
214
238
|
|
|
215
239
|
/**
|
|
216
240
|
* Push multiple values to the end of the array.
|
|
217
241
|
*/
|
|
218
|
-
pushMany(values: number
|
|
219
|
-
|
|
220
|
-
this.
|
|
242
|
+
pushMany(values: ArrayLike<number>) {
|
|
243
|
+
this.ensureCapacity(this.items + values.length);
|
|
244
|
+
this.view.set(values, this.items);
|
|
221
245
|
this.items += values.length;
|
|
222
246
|
}
|
|
223
247
|
|
|
@@ -226,16 +250,104 @@ export class ResizeableTypedArray<TA extends TypedArray> {
|
|
|
226
250
|
* Buffer becomes fixed-length after compacting.
|
|
227
251
|
*/
|
|
228
252
|
compact() {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
253
|
+
const requiredBytes = this.items * this.ArrayType.BYTES_PER_ELEMENT;
|
|
254
|
+
const buffer = this.buffer;
|
|
255
|
+
let compacted: BufferType;
|
|
256
|
+
try {
|
|
257
|
+
compacted = isSharedArrayBuffer(buffer)
|
|
258
|
+
? // A SharedArrayBuffer cannot shrink: copy the items into a fixed-size buffer.
|
|
259
|
+
buffer.slice(0, requiredBytes)
|
|
260
|
+
: buffer.transferToFixedLength(requiredBytes);
|
|
261
|
+
} catch (cause) {
|
|
262
|
+
throw this.allocationError("compact", requiredBytes, cause);
|
|
263
|
+
}
|
|
264
|
+
this.view = new this.ArrayType(compacted);
|
|
265
|
+
return this.view;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Make room for `count` items: grow in place if the buffer can, otherwise reallocate. */
|
|
269
|
+
private ensureCapacity(count: number) {
|
|
270
|
+
if (count <= this.view.length) return;
|
|
271
|
+
const bytesPerElement = this.ArrayType.BYTES_PER_ELEMENT;
|
|
272
|
+
const buffer = this.buffer;
|
|
273
|
+
const byteLength = nextByteLength(buffer.byteLength, count * bytesPerElement, bytesPerElement);
|
|
274
|
+
if (buffer.maxByteLength >= byteLength && growInPlace(buffer, byteLength)) {
|
|
275
|
+
// A resized buffer keeps a length-tracking view: take a fresh fixed-length one.
|
|
276
|
+
this.view = new this.ArrayType(buffer, 0, byteLength / bytesPerElement);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const next = this.allocate("grow", byteLength, GROWTH_RESERVE_BYTES);
|
|
280
|
+
const view = new this.ArrayType(next, 0, byteLength / bytesPerElement);
|
|
281
|
+
view.set(this.array);
|
|
282
|
+
this.view = view;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Allocate `byteLength` bytes that can grow in place up to `reserveBytes` when the runtime
|
|
287
|
+
* allows. A failed reservation falls back to a buffer that doubles once, then to fixed size.
|
|
288
|
+
*/
|
|
289
|
+
private allocate(
|
|
290
|
+
operation: TypedBufferAllocationOperation,
|
|
291
|
+
byteLength: number,
|
|
292
|
+
reserveBytes: number,
|
|
293
|
+
): BufferType {
|
|
294
|
+
for (const maxByteLength of [Math.max(reserveBytes, byteLength), byteLength * 2]) {
|
|
295
|
+
try {
|
|
296
|
+
return new this.BC(byteLength, { maxByteLength });
|
|
297
|
+
} catch {
|
|
298
|
+
// The runtime refused the reservation: try a smaller one, then a fixed buffer.
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
return new this.BC(byteLength);
|
|
303
|
+
} catch (cause) {
|
|
304
|
+
throw this.allocationError(operation, byteLength, cause);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private allocationError(
|
|
309
|
+
operation: TypedBufferAllocationOperation,
|
|
310
|
+
requiredBytes: number,
|
|
311
|
+
cause: unknown,
|
|
312
|
+
): TypedBufferAllocationError {
|
|
313
|
+
return new TypedBufferAllocationError(
|
|
314
|
+
{
|
|
315
|
+
operation,
|
|
316
|
+
typedArray: this.ArrayType.name,
|
|
317
|
+
bufferType: getBufferType(this.BC),
|
|
318
|
+
elementCount: Math.ceil(requiredBytes / this.ArrayType.BYTES_PER_ELEMENT),
|
|
319
|
+
bytesPerElement: this.ArrayType.BYTES_PER_ELEMENT,
|
|
320
|
+
requiredBytes,
|
|
321
|
+
},
|
|
322
|
+
cause,
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* The next buffer size for a column that needs `requiredBytes`: double while small, then grow
|
|
329
|
+
* by 1.5×, and never less than required. Rounded up to a multiple of 8 bytes so every element
|
|
330
|
+
* type divides it.
|
|
331
|
+
*/
|
|
332
|
+
function nextByteLength(currentBytes: number, requiredBytes: number, bytesPerElement: number) {
|
|
333
|
+
const current = Math.max(currentBytes, bytesPerElement);
|
|
334
|
+
const grown = current < DOUBLING_LIMIT_BYTES ? current * 2 : Math.ceil(current * 1.5);
|
|
335
|
+
return Math.ceil(Math.max(grown, requiredBytes) / 8) * 8;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Grow a growable or resizable buffer to `byteLength`. False if it cannot grow in place. */
|
|
339
|
+
function growInPlace(buffer: BufferType, byteLength: number): boolean {
|
|
340
|
+
try {
|
|
341
|
+
if (isSharedArrayBuffer(buffer)) {
|
|
342
|
+
if (!buffer.growable) return false;
|
|
343
|
+
buffer.grow(byteLength);
|
|
344
|
+
return true;
|
|
237
345
|
}
|
|
238
|
-
|
|
239
|
-
|
|
346
|
+
if (!buffer.resizable) return false;
|
|
347
|
+
buffer.resize(byteLength);
|
|
348
|
+
return true;
|
|
349
|
+
} catch {
|
|
350
|
+
// Committing the pages failed: fall back to reallocating, which reports its own error.
|
|
351
|
+
return false;
|
|
240
352
|
}
|
|
241
353
|
}
|