bumparena 0.0.6 → 0.0.8
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/README.md +56 -40
- package/dist/arena.d.ts +64 -0
- package/dist/arena.js +223 -0
- package/package.json +2 -2
- package/bench/bench.md +0 -38
package/README.md
CHANGED
|
@@ -1,74 +1,90 @@
|
|
|
1
|
-
|
|
1
|
+
# BumpArena
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**4x faster than standard arrays and uses only ~40% of the RAM!** 🚀💾
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
BumpArena is a high-performance memory arena for JavaScript and TypeScript. It provides contiguous memory allocation, fast pointer-based access, and minimal garbage collection overhead, making it ideal for handling large datasets efficiently.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Features
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- Contiguous memory buffer for fast allocations
|
|
12
|
+
- Pointer-based access with generation tracking
|
|
13
|
+
- Recycled buckets for efficient memory reuse
|
|
14
|
+
- Compact memory footprint
|
|
15
|
+
- Compatible with TypeScript and JavaScript
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
```bash
|
|
22
|
+
npm install bumparena
|
|
23
|
+
```
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
Data insertion does not allocate JavaScript objects. All writes are performed directly against the buffer. The engine reuses the same execution paths without producing heap garbage.
|
|
25
|
+
or using Yarn:
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
```bash
|
|
28
|
+
yarn add bumparena
|
|
29
|
+
```
|
|
23
30
|
|
|
24
31
|
---
|
|
25
32
|
|
|
26
|
-
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { Arena } from "bumparena";
|
|
27
37
|
|
|
28
|
-
|
|
38
|
+
// Create a new arena with default settings
|
|
39
|
+
const arena = new Arena();
|
|
29
40
|
|
|
30
|
-
|
|
41
|
+
// Allocate some data
|
|
42
|
+
const data = new Uint8Array([1, 2, 3, 4, 5]);
|
|
43
|
+
const ptr = arena.alloc(data);
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
// Read the data back
|
|
46
|
+
const readData = arena.read(ptr);
|
|
47
|
+
console.log(readData); // Uint8Array [1,2,3,4,5]
|
|
35
48
|
|
|
36
|
-
|
|
49
|
+
// Free the allocation
|
|
50
|
+
arena.free(ptr);
|
|
37
51
|
|
|
38
|
-
|
|
52
|
+
// Reserve a block for manual writes
|
|
53
|
+
const reserved = arena.reserve(10);
|
|
54
|
+
reserved.set(new Uint8Array([10, 20, 30]));
|
|
55
|
+
console.log(reserved);
|
|
56
|
+
```
|
|
39
57
|
|
|
40
58
|
---
|
|
41
59
|
|
|
42
|
-
|
|
60
|
+
## Advanced Usage
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
- Direct allocation from existing buffers with `directAlloc()`
|
|
63
|
+
- Custom headers for allocations (`header0`, `header1`, `header2`)
|
|
64
|
+
- Iterate all allocations using `label()`
|
|
65
|
+
- Estimate memory usage with `estimate(size, amount)`
|
|
45
66
|
|
|
46
|
-
|
|
47
|
-
- **Low 32 bits** → Generation ID
|
|
67
|
+
---
|
|
48
68
|
|
|
49
|
-
|
|
69
|
+
## Benchmarks
|
|
50
70
|
|
|
51
|
-
|
|
52
|
-
|
|
71
|
+
| Implementation | Time | Heap Used | Notes |
|
|
72
|
+
|-----------------------|------------|-----------|------------|
|
|
73
|
+
| BumpArena (Optimized) | 183,098 ms | 4.82 GB | 50M items |
|
|
74
|
+
| Standard Array | 765,961 ms | 11.22 GB | 50M items |
|
|
53
75
|
|
|
54
|
-
|
|
76
|
+
> ~4x faster and uses ~40% of the RAM compared to standard JavaScript arrays
|
|
55
77
|
|
|
56
78
|
---
|
|
57
79
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
The integrated test suite doubles as a **reference implementation**.
|
|
61
|
-
See the `// --- SHOWCASE & TESTS ---` section at the end of the source file for:
|
|
62
|
-
|
|
63
|
-
- Stress tests for dynamic resizing
|
|
64
|
-
- Validation of pointer expiration semantics
|
|
65
|
-
- Advanced bucket reuse and fragmentation behavior
|
|
66
|
-
- Edge cases around generation rollover
|
|
80
|
+
## Compatibility
|
|
67
81
|
|
|
68
|
-
|
|
82
|
+
- Node.js ✅
|
|
83
|
+
- Bun ✅
|
|
84
|
+
- Browser (via compiled JS) ✅
|
|
69
85
|
|
|
70
86
|
---
|
|
71
87
|
|
|
72
|
-
|
|
88
|
+
## License
|
|
73
89
|
|
|
74
|
-
MIT
|
|
90
|
+
MIT © eugen252009
|
package/dist/arena.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type ArenaLocation = bigint & {
|
|
2
|
+
readonly __data_pointer: unique symbol;
|
|
3
|
+
};
|
|
4
|
+
export interface ArenaOptions {
|
|
5
|
+
initalSize?: number;
|
|
6
|
+
littleEndian?: boolean;
|
|
7
|
+
allignment?: 8 | 16 | 32 | 64;
|
|
8
|
+
bucketOffsets?: number[];
|
|
9
|
+
bucketCapacities?: number[];
|
|
10
|
+
}
|
|
11
|
+
export interface ArenaCustomHeaders {
|
|
12
|
+
header0: number;
|
|
13
|
+
header1: number;
|
|
14
|
+
header2: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ArenaHeaders {
|
|
17
|
+
totalLength: number;
|
|
18
|
+
payloadlength: number;
|
|
19
|
+
deleted: boolean;
|
|
20
|
+
header0: number;
|
|
21
|
+
header1: number;
|
|
22
|
+
header2: number;
|
|
23
|
+
}
|
|
24
|
+
export declare class Arena {
|
|
25
|
+
private HEADER_SIZE_BYTES;
|
|
26
|
+
private _buffer;
|
|
27
|
+
private _view8;
|
|
28
|
+
private _view32;
|
|
29
|
+
private _offset;
|
|
30
|
+
private _emptySpots;
|
|
31
|
+
private _allignMask;
|
|
32
|
+
private _allignShift;
|
|
33
|
+
private _bucketOffsets;
|
|
34
|
+
private _bucketCapacities;
|
|
35
|
+
private _bucketcount;
|
|
36
|
+
constructor(options?: ArenaOptions);
|
|
37
|
+
private _u;
|
|
38
|
+
private _idx32;
|
|
39
|
+
private _makePtr;
|
|
40
|
+
private _getOffset;
|
|
41
|
+
private _getBucketCount;
|
|
42
|
+
private _setBucketCount;
|
|
43
|
+
private _getBucketOffset;
|
|
44
|
+
private _setBucketOffset;
|
|
45
|
+
private _initBlock;
|
|
46
|
+
alloc(data: Uint8Array, headers?: ArenaCustomHeaders): ArenaLocation;
|
|
47
|
+
read(location: ArenaLocation): Uint8Array | null;
|
|
48
|
+
free(location: ArenaLocation): ArenaLocation;
|
|
49
|
+
private _checkForSpace;
|
|
50
|
+
private _resize;
|
|
51
|
+
size(): number;
|
|
52
|
+
getBuffer(): Uint8Array;
|
|
53
|
+
reserve(size: number): Uint8Array;
|
|
54
|
+
translate(ptr: ArenaLocation): {
|
|
55
|
+
start: number;
|
|
56
|
+
generation: bigint;
|
|
57
|
+
};
|
|
58
|
+
readWithHeaders(ptr: ArenaLocation): Uint8Array | null;
|
|
59
|
+
label(): Array<ArenaLocation>;
|
|
60
|
+
getHeaders(ptr: ArenaLocation): ArenaHeaders;
|
|
61
|
+
estimate(size: number, amnt: number): number;
|
|
62
|
+
directAlloc(source: Uint8Array, startn: number, endn: number): ArenaLocation;
|
|
63
|
+
clear(): void;
|
|
64
|
+
}
|
package/dist/arena.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
var HEADERS;
|
|
2
|
+
(function (HEADERS) {
|
|
3
|
+
HEADERS[HEADERS["TOTAL_LENGTH_0_32"] = 0] = "TOTAL_LENGTH_0_32";
|
|
4
|
+
HEADERS[HEADERS["PAYLOAD_LENGTH_0_32"] = 1] = "PAYLOAD_LENGTH_0_32";
|
|
5
|
+
HEADERS[HEADERS["GENERATION_BYTE_0_32"] = 2] = "GENERATION_BYTE_0_32";
|
|
6
|
+
HEADERS[HEADERS["DELETED_8"] = 12] = "DELETED_8";
|
|
7
|
+
HEADERS[HEADERS["USER_STATUS_0_8"] = 13] = "USER_STATUS_0_8";
|
|
8
|
+
HEADERS[HEADERS["USER_STATUS_1_8"] = 14] = "USER_STATUS_1_8";
|
|
9
|
+
HEADERS[HEADERS["USER_STATUS_2_8"] = 15] = "USER_STATUS_2_8";
|
|
10
|
+
})(HEADERS || (HEADERS = {}));
|
|
11
|
+
export class Arena {
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.HEADER_SIZE_BYTES = 16;
|
|
14
|
+
this._buffer = new ArrayBuffer(options?.initalSize || 64 * 1024);
|
|
15
|
+
this._view8 = new Uint8Array(this._buffer);
|
|
16
|
+
this._view32 = new Uint32Array(this._buffer);
|
|
17
|
+
this._offset = 0;
|
|
18
|
+
//@ts-ignore
|
|
19
|
+
this._allignMask = ((options?.allignment || 8) - 1);
|
|
20
|
+
this._allignShift = Math.log2(this._allignMask + 1);
|
|
21
|
+
this._bucketCapacities = options?.bucketCapacities || [1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024];
|
|
22
|
+
this._bucketOffsets = [];
|
|
23
|
+
this._bucketcount = this._bucketCapacities.length;
|
|
24
|
+
let currentOffset = 0;
|
|
25
|
+
for (const cap of this._bucketCapacities) {
|
|
26
|
+
this._bucketOffsets.push(currentOffset);
|
|
27
|
+
currentOffset += (cap + 1);
|
|
28
|
+
}
|
|
29
|
+
this._emptySpots = new Uint32Array(currentOffset);
|
|
30
|
+
}
|
|
31
|
+
_u(n) {
|
|
32
|
+
return n >>> 0;
|
|
33
|
+
}
|
|
34
|
+
_idx32(byteOffset) {
|
|
35
|
+
return (byteOffset >>> 0) >> 2;
|
|
36
|
+
}
|
|
37
|
+
_makePtr(offset, gen) {
|
|
38
|
+
const bOffset = BigInt(offset >>> 0);
|
|
39
|
+
const bGen = BigInt(gen ?? 0);
|
|
40
|
+
return ((bOffset << 32n) | (bGen & 0xffffffffn));
|
|
41
|
+
}
|
|
42
|
+
_getOffset(ptr) {
|
|
43
|
+
return Number(BigInt(ptr) >> 32n) >>> 0;
|
|
44
|
+
}
|
|
45
|
+
_getBucketCount(bucketIdx) {
|
|
46
|
+
return this._emptySpots[this._bucketOffsets[bucketIdx]];
|
|
47
|
+
}
|
|
48
|
+
_setBucketCount(bucketIdx, count) {
|
|
49
|
+
this._emptySpots[this._bucketOffsets[bucketIdx]] = count;
|
|
50
|
+
}
|
|
51
|
+
_getBucketOffset(bucketIdx, slotIdx) {
|
|
52
|
+
return this._emptySpots[this._bucketOffsets[bucketIdx] + slotIdx + 1];
|
|
53
|
+
}
|
|
54
|
+
_setBucketOffset(bucketIdx, slotIdx, offset) {
|
|
55
|
+
this._emptySpots[this._bucketOffsets[bucketIdx] + slotIdx + 1] = offset;
|
|
56
|
+
}
|
|
57
|
+
_initBlock(start, dataLength, headers) {
|
|
58
|
+
const idx = this._idx32(start);
|
|
59
|
+
const { header0: h0, header1: h1, header2: h2 } = headers;
|
|
60
|
+
this._view32[idx + HEADERS.TOTAL_LENGTH_0_32] = this._u((dataLength + this.HEADER_SIZE_BYTES + this._allignMask) & ~this._allignMask);
|
|
61
|
+
this._view32[idx + HEADERS.PAYLOAD_LENGTH_0_32] = dataLength;
|
|
62
|
+
this._view32[idx + (HEADERS.DELETED_8 >> 2)] = ((h2 || 0) << 24) | ((h1 || 0) << 16) | ((h0 || 0) << 8);
|
|
63
|
+
this._view8[start + HEADERS.DELETED_8] = 0;
|
|
64
|
+
}
|
|
65
|
+
alloc(data, headers) {
|
|
66
|
+
headers || (headers = { header0: 0, header1: 0, header2: 0 });
|
|
67
|
+
const needed = (data.byteLength + this.HEADER_SIZE_BYTES + this._allignMask) & ~this._allignMask;
|
|
68
|
+
const bucketIdx = (needed >> this._allignShift) - 1;
|
|
69
|
+
if (bucketIdx >= 0 && bucketIdx < this._bucketcount) {
|
|
70
|
+
const count = this._getBucketCount(bucketIdx);
|
|
71
|
+
if (count > 0) {
|
|
72
|
+
const recycledOffset = this._u(this._getBucketOffset(bucketIdx, count - 1));
|
|
73
|
+
this._setBucketCount(bucketIdx, count - 1);
|
|
74
|
+
this._initBlock(recycledOffset, data.byteLength, headers);
|
|
75
|
+
const gen = this._view32[this._idx32(recycledOffset) + HEADERS.GENERATION_BYTE_0_32];
|
|
76
|
+
return this._makePtr(recycledOffset, gen);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const start = this._u(this._offset);
|
|
80
|
+
if (this._checkForSpace(needed))
|
|
81
|
+
this._resize();
|
|
82
|
+
this._initBlock(start, data.byteLength, headers);
|
|
83
|
+
this._view8.set(data, start + this.HEADER_SIZE_BYTES);
|
|
84
|
+
this._offset = this._u((start + needed) & ~this._allignMask);
|
|
85
|
+
const gen = this._view32[this._idx32(start) + HEADERS.GENERATION_BYTE_0_32];
|
|
86
|
+
return this._makePtr(start, gen);
|
|
87
|
+
}
|
|
88
|
+
read(location) {
|
|
89
|
+
const { start, generation } = this.translate(location);
|
|
90
|
+
const idx = this._idx32(start);
|
|
91
|
+
const currgen = BigInt(this._view32[idx + HEADERS.GENERATION_BYTE_0_32]);
|
|
92
|
+
if (generation !== currgen)
|
|
93
|
+
return null;
|
|
94
|
+
if (this._view8[start + HEADERS.DELETED_8] === 1)
|
|
95
|
+
return null;
|
|
96
|
+
const dataLength = this._view32[idx + HEADERS.PAYLOAD_LENGTH_0_32];
|
|
97
|
+
return this._view8.subarray(start + this.HEADER_SIZE_BYTES, start + this.HEADER_SIZE_BYTES + dataLength);
|
|
98
|
+
}
|
|
99
|
+
free(location) {
|
|
100
|
+
const { start, generation: _ } = this.translate(location);
|
|
101
|
+
const idx = this._idx32(start);
|
|
102
|
+
const currgen = this._view32[idx + HEADERS.GENERATION_BYTE_0_32];
|
|
103
|
+
this._view32[idx + HEADERS.GENERATION_BYTE_0_32] = currgen + 1;
|
|
104
|
+
this._view8[this._u(start) + HEADERS.DELETED_8] = 1;
|
|
105
|
+
const totalBlockSize = this._view32[this._idx32(start) + HEADERS.TOTAL_LENGTH_0_32];
|
|
106
|
+
const bucketIdx = (totalBlockSize >> this._allignShift) - 1;
|
|
107
|
+
if (bucketIdx >= 0 && bucketIdx < this._bucketcount) {
|
|
108
|
+
const count = this._getBucketCount(bucketIdx);
|
|
109
|
+
const capacity = this._bucketCapacities[bucketIdx];
|
|
110
|
+
if (count < capacity) {
|
|
111
|
+
this._setBucketOffset(bucketIdx, count, start);
|
|
112
|
+
this._setBucketCount(bucketIdx, count + 1);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return this._makePtr(0, 0);
|
|
116
|
+
}
|
|
117
|
+
_checkForSpace(size) {
|
|
118
|
+
if (this._buffer.byteLength >= (this._offset + size))
|
|
119
|
+
return false;
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
_resize() {
|
|
123
|
+
//@ts-ignore
|
|
124
|
+
if (this._buffer.transfer)
|
|
125
|
+
this._buffer = this._buffer.transfer(this._buffer.byteLength * 2);
|
|
126
|
+
else {
|
|
127
|
+
const newBuffer = new ArrayBuffer(this._buffer.byteLength * 2);
|
|
128
|
+
new Uint8Array(newBuffer).set(this._view8);
|
|
129
|
+
this._buffer = newBuffer;
|
|
130
|
+
}
|
|
131
|
+
this._view8 = new Uint8Array(this._buffer);
|
|
132
|
+
this._view32 = new Uint32Array(this._buffer);
|
|
133
|
+
}
|
|
134
|
+
size() {
|
|
135
|
+
return this._buffer.byteLength;
|
|
136
|
+
}
|
|
137
|
+
getBuffer() {
|
|
138
|
+
return this._view8.subarray(0, this._u(this._offset));
|
|
139
|
+
}
|
|
140
|
+
reserve(size) {
|
|
141
|
+
const start = this._u(this._offset);
|
|
142
|
+
this._checkForSpace((this.HEADER_SIZE_BYTES + size + this._allignMask) & ~this._allignMask) && this._resize();
|
|
143
|
+
this._initBlock(start, size, { header0: 0, header1: 0, header2: 0 });
|
|
144
|
+
this._offset = ((this._offset + size + this.HEADER_SIZE_BYTES + this._allignMask) & ~this._allignMask) >>> 0;
|
|
145
|
+
return this._view8.subarray(start + this.HEADER_SIZE_BYTES, start + this.HEADER_SIZE_BYTES + size);
|
|
146
|
+
}
|
|
147
|
+
translate(ptr) {
|
|
148
|
+
const start = this._getOffset(ptr);
|
|
149
|
+
const generation = ptr & 0xffffffffn;
|
|
150
|
+
return { start, generation };
|
|
151
|
+
}
|
|
152
|
+
readWithHeaders(ptr) {
|
|
153
|
+
const { start, generation } = this.translate(ptr);
|
|
154
|
+
let idx32 = this._idx32(start);
|
|
155
|
+
let length = this._view32[idx32 + HEADERS.PAYLOAD_LENGTH_0_32];
|
|
156
|
+
if (BigInt(this._view32[idx32 + HEADERS.GENERATION_BYTE_0_32]) !== generation)
|
|
157
|
+
return null;
|
|
158
|
+
return this._view8.subarray(start + 12, start + this.HEADER_SIZE_BYTES + Number(length));
|
|
159
|
+
}
|
|
160
|
+
label() {
|
|
161
|
+
const ptrArray = new Array();
|
|
162
|
+
const limit = this._offset;
|
|
163
|
+
let pos = 0;
|
|
164
|
+
while (this._u(pos) < this._u(limit)) {
|
|
165
|
+
const totalLength = this._view32[this._idx32(pos)];
|
|
166
|
+
if (totalLength === 0) {
|
|
167
|
+
pos = this._idx32((pos + 16) & ~15);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const isDeleted = this._view8[this._u(pos) + HEADERS.DELETED_8] === 1;
|
|
171
|
+
if (!isDeleted) {
|
|
172
|
+
ptrArray.push(this._makePtr(pos, this._view32[this._idx32(pos) + HEADERS.GENERATION_BYTE_0_32]));
|
|
173
|
+
}
|
|
174
|
+
pos += totalLength;
|
|
175
|
+
if (totalLength === 0)
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
return ptrArray;
|
|
179
|
+
}
|
|
180
|
+
getHeaders(ptr) {
|
|
181
|
+
const { start, generation: _ } = this.translate(ptr);
|
|
182
|
+
const idx = this._u(start);
|
|
183
|
+
return {
|
|
184
|
+
totalLength: Number(this._view32[this._idx32(start) + HEADERS.TOTAL_LENGTH_0_32].toString()),
|
|
185
|
+
payloadlength: Number(this._view32[this._idx32(start) + HEADERS.PAYLOAD_LENGTH_0_32].toString()),
|
|
186
|
+
deleted: this._view8[idx + HEADERS.DELETED_8] === 1,
|
|
187
|
+
header0: Number(this._view8[idx + HEADERS.USER_STATUS_0_8].toString()),
|
|
188
|
+
header1: Number(this._view8[idx + HEADERS.USER_STATUS_1_8].toString()),
|
|
189
|
+
header2: Number(this._view8[idx + HEADERS.USER_STATUS_2_8].toString()),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
estimate(size, amnt) {
|
|
193
|
+
return (((size + this._allignMask) & ~this._allignMask) + this.HEADER_SIZE_BYTES) * amnt;
|
|
194
|
+
}
|
|
195
|
+
directAlloc(source, startn, endn) {
|
|
196
|
+
const start = this._u(this._offset);
|
|
197
|
+
const len = endn - startn;
|
|
198
|
+
const needed = (len + this.HEADER_SIZE_BYTES + this._allignMask) & ~this._allignMask;
|
|
199
|
+
const bucketIdx = (needed >> this._allignShift) - 1;
|
|
200
|
+
if (bucketIdx >= 0 && bucketIdx < this._bucketcount) {
|
|
201
|
+
const count = this._getBucketCount(bucketIdx);
|
|
202
|
+
if (count > 0) {
|
|
203
|
+
const recycledOffset = this._u(this._getBucketOffset(bucketIdx, count - 1));
|
|
204
|
+
this._setBucketCount(bucketIdx, count - 1);
|
|
205
|
+
this._initBlock(recycledOffset, len, { header0: 0, header1: 0, header2: 0 });
|
|
206
|
+
const gen = this._view32[this._idx32(recycledOffset) + HEADERS.GENERATION_BYTE_0_32];
|
|
207
|
+
this._view8.set(source.subarray(startn, endn), recycledOffset + this.HEADER_SIZE_BYTES);
|
|
208
|
+
return this._makePtr(recycledOffset, gen);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (this._checkForSpace(needed))
|
|
212
|
+
this._resize();
|
|
213
|
+
this._initBlock(start, len, { header0: 0, header1: 0, header2: 0 });
|
|
214
|
+
this._offset = this._u((start + needed) & ~this._allignMask);
|
|
215
|
+
this._view8.set(source.subarray(startn, endn), start + this.HEADER_SIZE_BYTES);
|
|
216
|
+
const gen = this._view32[this._idx32(start) + HEADERS.GENERATION_BYTE_0_32];
|
|
217
|
+
return this._makePtr(start, gen);
|
|
218
|
+
}
|
|
219
|
+
clear() {
|
|
220
|
+
this._offset = 0;
|
|
221
|
+
this._emptySpots.fill(0);
|
|
222
|
+
}
|
|
223
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bumparena",
|
|
3
|
-
"version":"0.0.
|
|
3
|
+
"version":"0.0.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/arena.js",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"test": "node ./dist/test/test.test.js",
|
|
13
|
-
"
|
|
13
|
+
"push": "bun test && tsc && npm pub"
|
|
14
14
|
},
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
package/bench/bench.md
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# Benchmark 1
|
|
2
|
-
|
|
3
|
-
## bun arena.ts;
|
|
4
|
-
183098.55 ms
|
|
5
|
-
{
|
|
6
|
-
rss: 11240919040,
|
|
7
|
-
heapTotal: 8595075072,
|
|
8
|
-
heapUsed: 4817152633,
|
|
9
|
-
external: 2157456969,
|
|
10
|
-
arrayBuffers: 2156686216,
|
|
11
|
-
}
|
|
12
|
-
arenasize: 2097152 KB
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
## bun array.ts
|
|
17
|
-
765961.27 ms
|
|
18
|
-
Count: 50000000
|
|
19
|
-
{
|
|
20
|
-
rss: 28036014080,
|
|
21
|
-
heapTotal: 9476152320,
|
|
22
|
-
heapUsed: 11222438346,
|
|
23
|
-
external: 7170077276,
|
|
24
|
-
arrayBuffers: 2921230601,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Direct Comparison
|
|
30
|
-
|
|
31
|
-
| Metric | Arena Implementation (Optimized) | Standard Array Implementation | Difference / Factor |
|
|
32
|
-
| :--- | :--- | :--- | :--- |
|
|
33
|
-
| **Total Time** | **183,098 ms** (3.05 min) | **765,961 ms** (12.76 min) | **~4.2x Faster** |
|
|
34
|
-
| **Time per 50M Lines** | **~18.3 sec** | **~76.6 sec** | **- 58.3 sec / Round** |
|
|
35
|
-
| **RAM Usage (RSS)** | **11.24 GB** | **28.04 GB** | **16.8 GB Saved** |
|
|
36
|
-
| **Heap Used (JS Objects)** | **4.82 GB** | **11.22 GB** | **2.3x More Efficient** |
|
|
37
|
-
| **External (Buffer)** | **2.16 GB** | **7.17 GB** | **Compact Memory Footprint** |
|
|
38
|
-
|