@nxtedition/slice 1.1.8 → 1.1.10
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 +33 -11
- package/lib/index.d.ts +2 -16
- package/lib/index.js +74 -48
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Node.js `Buffer.subarray()` is slow. Every call creates a new `Buffer` object
|
|
|
10
10
|
|
|
11
11
|
`Slice` avoids this entirely. It is a plain JavaScript object with `buffer`, `byteOffset`, and `byteLength` fields. Creating a slice is just setting three properties — no typed array wrapper creation, no GC pressure from short-lived `Buffer` objects. Operations like `toString`, `copy`, and `compare` delegate directly to the underlying buffer with the correct offsets.
|
|
12
12
|
|
|
13
|
-
`PoolAllocator` takes this further. Like Node's internal pool, it has management overhead — but
|
|
13
|
+
`PoolAllocator` takes this further. Like Node's internal pool, it has management overhead — but for in-pool sizes it never allocates new backing stores (only allocations larger than the 256 KB top bucket, or made once the contiguous pool is exhausted, fall back to a standalone `Buffer`), and because `Slice` is a plain object rather than a typed array, resizing or freeing a slice doesn't produce garbage for V8 to collect. It pre-allocates a large contiguous buffer and hands out regions using power-of-2 bucketing. When a slice is freed, its slot is recycled. When a slice is resized within the same bucket, no data moves at all — just a field update. This gives you `malloc`/`realloc`/`free` semantics with near-zero overhead per operation. The trade-off is upfront memory allocation and internal fragmentation from power-of-2 rounding — a 10-byte allocation uses a 16-byte slot. Buckets are also independent: a freed 16-byte slot cannot satisfy a 32-byte request, so the pool can become fragmented if allocation sizes are uneven. Use `stats` to monitor pool utilization and tune the pool size for your workload.
|
|
14
14
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
@@ -102,15 +102,24 @@ Creates a new slice. All parameters are optional — defaults to an empty slice.
|
|
|
102
102
|
#### Methods
|
|
103
103
|
|
|
104
104
|
- `reset(): void` — Clear the slice back to empty state. **Note:** this does not return the slot to the `PoolAllocator` — you must call `realloc(slice, 0)` to free pool memory.
|
|
105
|
-
- `copy(target:
|
|
106
|
-
- `compare(target:
|
|
105
|
+
- `copy(target: Uint8Array | Slice, targetStart?: number, sourceStart?: number, sourceEnd?: number): number` — Copy data to a `Uint8Array`/`Buffer` or `Slice`. Returns bytes copied.
|
|
106
|
+
- `compare(target: Uint8Array | Slice, targetStart?: number, targetEnd?: number, sourceStart?: number, sourceEnd?: number): -1 | 0 | 1` — Compare with a `Uint8Array`/`Buffer` or `Slice`
|
|
107
107
|
- `write(string: string, offset?: number, length?: number, encoding?: BufferEncoding): number` — Write a string into the slice. Returns bytes written.
|
|
108
|
-
- `set(source: Buffer | Slice | null | undefined, offset?: number): void` — Copy from a `Buffer` or `Slice` into this slice
|
|
109
|
-
- `at(index: number): number` — Read byte at index (supports negative indexing)
|
|
108
|
+
- `set(source: Buffer | Slice | null | undefined, offset?: number): void` — Copy from a `Buffer` or `Slice` into this slice. (A plain `Uint8Array` source is not accepted — it has no `copy` method.)
|
|
109
|
+
- `at(index: number): number` — Read byte at integer index (supports negative indexing)
|
|
110
110
|
- `test(expr: { test(buffer: Buffer, byteOffset: number, byteLength: number): boolean }): boolean` — Test the slice against an expression object
|
|
111
111
|
- `toString(encoding?: BufferEncoding, start?: number, end?: number): string` — Convert to string
|
|
112
112
|
- `toBuffer(start?: number, end?: number): Buffer` — Return a `Buffer` view
|
|
113
113
|
|
|
114
|
+
#### Validation & bounds
|
|
115
|
+
|
|
116
|
+
All offsets are **relative to the slice** (i.e. `0` is `byteOffset`). For a `Slice` target, target offsets are relative to that slice; for a raw `Buffer`/`Uint8Array` target they are absolute (passed straight through to the underlying `Buffer` method).
|
|
117
|
+
|
|
118
|
+
The rule is consistent across the API:
|
|
119
|
+
|
|
120
|
+
- **Start/offset arguments are validated** — `set`'s `offset`, `copy`/`compare`'s `sourceStart`/`targetStart`, `toString`/`toBuffer`'s `start`, `write`'s `offset`/`length`, and `at`'s `index` must be in-range integers. Out-of-range or non-integer values throw `RangeError`. This prevents a negative offset from resolving to a position **before** the slice and reading/writing adjacent (pool) memory.
|
|
121
|
+
- **End arguments are clamped** — `sourceEnd`/`targetEnd`/`end` are clamped to the slice's logical length (matching `Buffer`'s lenient end-of-range behavior), so over-long ranges never read past the slice's end.
|
|
122
|
+
|
|
114
123
|
#### Static
|
|
115
124
|
|
|
116
125
|
- `Slice.EMPTY_BUF: Buffer` — Shared empty buffer singleton
|
|
@@ -119,19 +128,32 @@ Creates a new slice. All parameters are optional — defaults to an empty slice.
|
|
|
119
128
|
|
|
120
129
|
Pre-allocates a contiguous memory pool and manages slices using power-of-2 bucketing.
|
|
121
130
|
|
|
122
|
-
#### `new PoolAllocator(
|
|
131
|
+
#### `new PoolAllocator(poolTotalOrBuffer?: number | Buffer | ArrayBufferView | ArrayBuffer | SharedArrayBuffer)`
|
|
132
|
+
|
|
133
|
+
Creates a pool allocator. Pass a byte size to allocate a fresh backing buffer (default 128 MB, must be a non-negative integer), or pass an existing `Buffer`/`ArrayBufferView`/`ArrayBuffer`/`SharedArrayBuffer` to back the pool with caller-provided memory.
|
|
123
134
|
|
|
124
|
-
|
|
135
|
+
> **Single-owner.** The allocator's bookkeeping lives in the instance, not in the backing buffer. When you supply your own buffer, that buffer must be owned exclusively by this allocator: do not build your own `Slice` views over it, do not share it with a second `PoolAllocator`, and (for a `SharedArrayBuffer`) do not allocate from more than one thread — the metadata is not shared or atomic, so doing any of these silently produces overlapping allocations.
|
|
125
136
|
|
|
126
137
|
#### Methods
|
|
127
138
|
|
|
128
|
-
- `realloc(
|
|
129
|
-
- `
|
|
139
|
+
- `realloc(byteLength: number): Slice` — Allocate a fresh slice.
|
|
140
|
+
- `realloc(slice: Slice, byteLength: number): Slice` — Resize a slice, or free it by passing `0`. **Contents are not preserved** — `realloc` has `malloc` semantics, not C `realloc` semantics; after a resize the bytes are undefined (a same-bucket resize happens to keep them in place, but do not rely on it). Only call `realloc` with a slice that belongs to this allocator (or a fresh/empty `Slice`); passing a slice from another pool, or freeing the same slice twice, corrupts the allocator's accounting.
|
|
141
|
+
- `isFromPool(slice: Slice | null | undefined): boolean` — Check if a slice's buffer is this pool's backing buffer. Note this is an identity check; it returns `true` for any slice over the same buffer, not only ones this allocator handed out.
|
|
142
|
+
|
|
143
|
+
Allocations larger than 256 KB (the largest bucket), or made when the contiguous pool is exhausted, fall back to a fresh standalone `Buffer` (`isFromPool` returns `false`) and are excluded from `size`/`stats`.
|
|
130
144
|
|
|
131
145
|
#### Properties
|
|
132
146
|
|
|
133
|
-
- `size: number` — Total
|
|
134
|
-
- `stats
|
|
147
|
+
- `size: number` — Total reserved bytes of all active **pool** allocations (sum of bucket sizes; equals `stats.poolSize`).
|
|
148
|
+
- `stats` — Detailed allocation statistics:
|
|
149
|
+
- `size` — same as the `size` getter (active pool bytes, including power-of-2 padding).
|
|
150
|
+
- `padding` — bytes lost to power-of-2 rounding across active pool slices.
|
|
151
|
+
- `ratio` — `size / (size - padding)`; `1` when there is no padding.
|
|
152
|
+
- `poolTotal` — capacity of the backing buffer in bytes.
|
|
153
|
+
- `poolUsed` — bump-pointer high-water mark; monotonic, never decreases.
|
|
154
|
+
- `poolSize` — active pool bytes (same as `size`).
|
|
155
|
+
- `poolCount` — number of distinct slots ever bump-allocated (monotonic high-water count, not a live count).
|
|
156
|
+
- `buckets` — per power-of-2 bucket: `{ free, used, size }`.
|
|
135
157
|
|
|
136
158
|
## License
|
|
137
159
|
|
package/lib/index.d.ts
CHANGED
|
@@ -4,27 +4,13 @@ export type SliceLike = {
|
|
|
4
4
|
byteOffset: number;
|
|
5
5
|
byteLength: number;
|
|
6
6
|
};
|
|
7
|
-
export declare class Slice {
|
|
7
|
+
export declare class Slice implements SliceLike {
|
|
8
8
|
buffer: Buffer;
|
|
9
9
|
byteOffset: number;
|
|
10
10
|
byteLength: number;
|
|
11
11
|
maxByteLength: number;
|
|
12
12
|
static get EMPTY_BUF(): Buffer;
|
|
13
|
-
|
|
14
|
-
* Fast factory for the common case of wrapping a full Buffer with no
|
|
15
|
-
* offset and no separate maxByteLength. Skips all the constructor's
|
|
16
|
-
* validation (Buffer instanceof check, byteOffset/byteLength range
|
|
17
|
-
* checks, integer checks, maxByteLength bounds). Use only when the
|
|
18
|
-
* caller already knows the input is a Buffer — e.g. wrapping freshly
|
|
19
|
-
* received network frames on a hot path.
|
|
20
|
-
*
|
|
21
|
-
* Note: instances produced here have a slightly different V8 hidden
|
|
22
|
-
* class than instances produced via `new Slice(buf)`. That introduces
|
|
23
|
-
* polymorphism at any downstream IC that reads slice fields. Measure
|
|
24
|
-
* end-to-end before adopting in code paths where consumers do heavy
|
|
25
|
-
* field access.
|
|
26
|
-
*/
|
|
27
|
-
static fromBuffer(buffer: Buffer): Slice;
|
|
13
|
+
static from(buffer: Buffer, byteOffset?: number, byteLength?: number): Slice;
|
|
28
14
|
constructor(buffer?: Buffer<ArrayBufferLike>, byteOffset?: number, byteLength?: number, maxByteLength?: number);
|
|
29
15
|
reset(): void;
|
|
30
16
|
get length(): number;
|
package/lib/index.js
CHANGED
|
@@ -8,7 +8,7 @@ const EMPTY_BUF = Buffer.alloc(0)
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
export class Slice
|
|
11
|
+
export class Slice {
|
|
12
12
|
buffer = EMPTY_BUF
|
|
13
13
|
byteOffset = 0
|
|
14
14
|
byteLength = 0
|
|
@@ -18,36 +18,7 @@ export class Slice {
|
|
|
18
18
|
return EMPTY_BUF
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
* Fast factory for the common case of wrapping a full Buffer with no
|
|
23
|
-
* offset and no separate maxByteLength. Skips all the constructor's
|
|
24
|
-
* validation (Buffer instanceof check, byteOffset/byteLength range
|
|
25
|
-
* checks, integer checks, maxByteLength bounds). Use only when the
|
|
26
|
-
* caller already knows the input is a Buffer — e.g. wrapping freshly
|
|
27
|
-
* received network frames on a hot path.
|
|
28
|
-
*
|
|
29
|
-
* Note: instances produced here have a slightly different V8 hidden
|
|
30
|
-
* class than instances produced via `new Slice(buf)`. That introduces
|
|
31
|
-
* polymorphism at any downstream IC that reads slice fields. Measure
|
|
32
|
-
* end-to-end before adopting in code paths where consumers do heavy
|
|
33
|
-
* field access.
|
|
34
|
-
*/
|
|
35
|
-
static fromBuffer(buffer ) {
|
|
36
|
-
const slice = Object.create(Slice.prototype)
|
|
37
|
-
const len = buffer.byteLength
|
|
38
|
-
slice.buffer = buffer
|
|
39
|
-
slice.byteOffset = 0
|
|
40
|
-
slice.byteLength = len
|
|
41
|
-
slice.maxByteLength = len
|
|
42
|
-
return slice
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
constructor(
|
|
46
|
-
buffer = Slice.EMPTY_BUF,
|
|
47
|
-
byteOffset = 0,
|
|
48
|
-
byteLength = buffer.byteLength,
|
|
49
|
-
maxByteLength = byteLength,
|
|
50
|
-
) {
|
|
21
|
+
static from(buffer , byteOffset = 0, byteLength = buffer.byteLength - byteOffset) {
|
|
51
22
|
if (!(buffer instanceof Buffer)) {
|
|
52
23
|
throw new TypeError('buffer must be a Buffer')
|
|
53
24
|
}
|
|
@@ -60,20 +31,21 @@ export class Slice {
|
|
|
60
31
|
throw new RangeError(`Invalid byteLength: ${byteLength}`)
|
|
61
32
|
}
|
|
62
33
|
|
|
63
|
-
if (
|
|
64
|
-
maxByteLength < byteLength ||
|
|
65
|
-
maxByteLength > buffer.byteLength ||
|
|
66
|
-
!Number.isInteger(maxByteLength)
|
|
67
|
-
) {
|
|
68
|
-
throw new RangeError(`Invalid maxByteLength: ${maxByteLength}`)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
34
|
if (byteOffset + byteLength > buffer.byteLength) {
|
|
72
35
|
throw new RangeError(
|
|
73
36
|
`byteOffset + byteLength (${byteOffset + byteLength}) exceeds buffer size (${buffer.byteLength})`,
|
|
74
37
|
)
|
|
75
38
|
}
|
|
76
39
|
|
|
40
|
+
return new Slice(buffer, byteOffset, byteLength)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
constructor(
|
|
44
|
+
buffer = Slice.EMPTY_BUF,
|
|
45
|
+
byteOffset = 0,
|
|
46
|
+
byteLength = buffer.byteLength,
|
|
47
|
+
maxByteLength = byteLength,
|
|
48
|
+
) {
|
|
77
49
|
this.buffer = buffer
|
|
78
50
|
this.byteOffset = byteOffset
|
|
79
51
|
this.byteLength = byteLength
|
|
@@ -102,6 +74,12 @@ export class Slice {
|
|
|
102
74
|
if (sourceStart === undefined) {
|
|
103
75
|
sourceStart = this.byteOffset
|
|
104
76
|
} else {
|
|
77
|
+
// Start offsets are validated (not clamped) so a negative offset can
|
|
78
|
+
// never resolve to a position before the slice and read adjacent
|
|
79
|
+
// (pool) memory.
|
|
80
|
+
if (sourceStart < 0 || sourceStart > this.byteLength || !Number.isInteger(sourceStart)) {
|
|
81
|
+
throw new RangeError(`Invalid sourceStart: ${sourceStart}`)
|
|
82
|
+
}
|
|
105
83
|
sourceStart += this.byteOffset
|
|
106
84
|
}
|
|
107
85
|
|
|
@@ -111,17 +89,23 @@ export class Slice {
|
|
|
111
89
|
sourceEnd += this.byteOffset
|
|
112
90
|
}
|
|
113
91
|
|
|
114
|
-
// Clamp against the logical slice length so copy() cannot read
|
|
115
|
-
// the slice's own end and leak adjacent (pool) memory.
|
|
92
|
+
// Clamp the end against the logical slice length so copy() cannot read
|
|
93
|
+
// past the slice's own end and leak adjacent (pool) memory.
|
|
116
94
|
if (sourceEnd > sliceEnd) {
|
|
117
95
|
sourceEnd = sliceEnd
|
|
118
96
|
}
|
|
97
|
+
if (sourceEnd < sourceStart) {
|
|
98
|
+
sourceEnd = sourceStart
|
|
99
|
+
}
|
|
119
100
|
|
|
120
101
|
if (target instanceof Slice) {
|
|
121
102
|
const targetEnd = target.byteOffset + target.byteLength
|
|
122
103
|
if (targetStart === undefined) {
|
|
123
104
|
targetStart = target.byteOffset
|
|
124
105
|
} else {
|
|
106
|
+
if (targetStart < 0 || targetStart > target.byteLength || !Number.isInteger(targetStart)) {
|
|
107
|
+
throw new RangeError(`Invalid targetStart: ${targetStart}`)
|
|
108
|
+
}
|
|
125
109
|
targetStart += target.byteOffset
|
|
126
110
|
}
|
|
127
111
|
|
|
@@ -166,6 +150,9 @@ export class Slice {
|
|
|
166
150
|
if (targetStart === undefined) {
|
|
167
151
|
targetStart = target.byteOffset
|
|
168
152
|
} else {
|
|
153
|
+
if (targetStart < 0 || targetStart > target.byteLength || !Number.isInteger(targetStart)) {
|
|
154
|
+
throw new RangeError(`Invalid targetStart: ${targetStart}`)
|
|
155
|
+
}
|
|
169
156
|
targetStart += target.byteOffset
|
|
170
157
|
}
|
|
171
158
|
|
|
@@ -178,12 +165,18 @@ export class Slice {
|
|
|
178
165
|
if (targetEnd > targetSliceEnd) {
|
|
179
166
|
targetEnd = targetSliceEnd
|
|
180
167
|
}
|
|
168
|
+
if (targetEnd < targetStart) {
|
|
169
|
+
targetEnd = targetStart
|
|
170
|
+
}
|
|
181
171
|
target = target.buffer
|
|
182
172
|
}
|
|
183
173
|
|
|
184
174
|
if (sourceStart === undefined) {
|
|
185
175
|
sourceStart = this.byteOffset
|
|
186
176
|
} else {
|
|
177
|
+
if (sourceStart < 0 || sourceStart > this.byteLength || !Number.isInteger(sourceStart)) {
|
|
178
|
+
throw new RangeError(`Invalid sourceStart: ${sourceStart}`)
|
|
179
|
+
}
|
|
187
180
|
sourceStart += this.byteOffset
|
|
188
181
|
}
|
|
189
182
|
|
|
@@ -196,6 +189,9 @@ export class Slice {
|
|
|
196
189
|
if (sourceEnd > sliceEnd) {
|
|
197
190
|
sourceEnd = sliceEnd
|
|
198
191
|
}
|
|
192
|
+
if (sourceEnd < sourceStart) {
|
|
193
|
+
sourceEnd = sourceStart
|
|
194
|
+
}
|
|
199
195
|
|
|
200
196
|
return this.buffer.compare(target, targetStart, targetEnd, sourceStart, sourceEnd)
|
|
201
197
|
}
|
|
@@ -206,7 +202,7 @@ export class Slice {
|
|
|
206
202
|
if (offset === undefined) {
|
|
207
203
|
offset = this.byteOffset
|
|
208
204
|
} else {
|
|
209
|
-
if (offset < 0 || offset > this.byteLength) {
|
|
205
|
+
if (offset < 0 || offset > this.byteLength || !Number.isInteger(offset)) {
|
|
210
206
|
throw new RangeError(`Invalid offset: ${offset}`)
|
|
211
207
|
}
|
|
212
208
|
offset += this.byteOffset
|
|
@@ -215,8 +211,13 @@ export class Slice {
|
|
|
215
211
|
const available = sliceEnd - offset
|
|
216
212
|
if (length === undefined) {
|
|
217
213
|
length = available
|
|
218
|
-
} else
|
|
219
|
-
length
|
|
214
|
+
} else {
|
|
215
|
+
if (length < 0 || !Number.isInteger(length)) {
|
|
216
|
+
throw new RangeError(`Invalid length: ${length}`)
|
|
217
|
+
}
|
|
218
|
+
if (length > available) {
|
|
219
|
+
length = available
|
|
220
|
+
}
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
return this.buffer.write(string, offset, length, encoding)
|
|
@@ -230,6 +231,11 @@ export class Slice {
|
|
|
230
231
|
if (offset === undefined) {
|
|
231
232
|
offset = this.byteOffset
|
|
232
233
|
} else {
|
|
234
|
+
// Validate (not clamp): a negative offset would resolve to a position
|
|
235
|
+
// before the slice and corrupt adjacent (pool) memory.
|
|
236
|
+
if (offset < 0 || offset > this.byteLength || !Number.isInteger(offset)) {
|
|
237
|
+
throw new RangeError(`Invalid offset: ${offset}`)
|
|
238
|
+
}
|
|
233
239
|
offset += this.byteOffset
|
|
234
240
|
}
|
|
235
241
|
|
|
@@ -243,7 +249,7 @@ export class Slice {
|
|
|
243
249
|
}
|
|
244
250
|
|
|
245
251
|
at(index ) {
|
|
246
|
-
if (index >= this.byteLength || index < -this.byteLength) {
|
|
252
|
+
if (!Number.isInteger(index) || index >= this.byteLength || index < -this.byteLength) {
|
|
247
253
|
throw new RangeError(`Index out of range: ${index}`)
|
|
248
254
|
}
|
|
249
255
|
return index >= 0
|
|
@@ -263,6 +269,9 @@ export class Slice {
|
|
|
263
269
|
if (start === undefined) {
|
|
264
270
|
start = this.byteOffset
|
|
265
271
|
} else {
|
|
272
|
+
if (start < 0 || start > this.byteLength || !Number.isInteger(start)) {
|
|
273
|
+
throw new RangeError(`Invalid start: ${start}`)
|
|
274
|
+
}
|
|
266
275
|
start += this.byteOffset
|
|
267
276
|
}
|
|
268
277
|
|
|
@@ -275,6 +284,9 @@ export class Slice {
|
|
|
275
284
|
if (end > sliceEnd) {
|
|
276
285
|
end = sliceEnd
|
|
277
286
|
}
|
|
287
|
+
if (end < start) {
|
|
288
|
+
end = start
|
|
289
|
+
}
|
|
278
290
|
|
|
279
291
|
return this.buffer.toString(encoding, start, end)
|
|
280
292
|
}
|
|
@@ -285,6 +297,9 @@ export class Slice {
|
|
|
285
297
|
if (start === undefined) {
|
|
286
298
|
start = this.byteOffset
|
|
287
299
|
} else {
|
|
300
|
+
if (start < 0 || start > this.byteLength || !Number.isInteger(start)) {
|
|
301
|
+
throw new RangeError(`Invalid start: ${start}`)
|
|
302
|
+
}
|
|
288
303
|
start += this.byteOffset
|
|
289
304
|
}
|
|
290
305
|
|
|
@@ -297,6 +312,9 @@ export class Slice {
|
|
|
297
312
|
if (end > sliceEnd) {
|
|
298
313
|
end = sliceEnd
|
|
299
314
|
}
|
|
315
|
+
if (end < start) {
|
|
316
|
+
end = start
|
|
317
|
+
}
|
|
300
318
|
|
|
301
319
|
return start === 0 && end === this.buffer.byteLength
|
|
302
320
|
? this.buffer
|
|
@@ -310,7 +328,13 @@ export class Slice {
|
|
|
310
328
|
[util.inspect.custom]() {
|
|
311
329
|
const MAX_BYTES = 32
|
|
312
330
|
const len = this.byteLength
|
|
313
|
-
|
|
331
|
+
|
|
332
|
+
// Never read past the underlying buffer. A malformed slice (byteOffset /
|
|
333
|
+
// byteLength extending beyond the buffer) is exactly the state a developer
|
|
334
|
+
// inspects while debugging pool corruption — inspect must not throw on it.
|
|
335
|
+
const available = this.buffer.byteLength - this.byteOffset
|
|
336
|
+
const safeLen = available > 0 ? (len < available ? len : available) : 0
|
|
337
|
+
const shown = safeLen < MAX_BYTES ? safeLen : MAX_BYTES
|
|
314
338
|
|
|
315
339
|
let hex = ''
|
|
316
340
|
for (let i = 0; i < shown; i++) {
|
|
@@ -323,8 +347,7 @@ export class Slice {
|
|
|
323
347
|
hex += ` ... (${len - shown} more)`
|
|
324
348
|
}
|
|
325
349
|
|
|
326
|
-
const
|
|
327
|
-
const str = this.buffer.toString('utf8', this.byteOffset, strEnd)
|
|
350
|
+
const str = this.buffer.toString('utf8', this.byteOffset, this.byteOffset + shown)
|
|
328
351
|
const truncated = shown < len ? '…' : ''
|
|
329
352
|
|
|
330
353
|
return `Slice(${len}): "${str}${truncated}" <${hex}>`
|
|
@@ -348,6 +371,9 @@ export class PoolAllocator {
|
|
|
348
371
|
1024,
|
|
349
372
|
) {
|
|
350
373
|
if (typeof poolTotalOrBuffer === 'number') {
|
|
374
|
+
if (!Number.isInteger(poolTotalOrBuffer) || poolTotalOrBuffer < 0) {
|
|
375
|
+
throw new RangeError(`Invalid pool size: ${poolTotalOrBuffer}`)
|
|
376
|
+
}
|
|
351
377
|
this.#poolBuffer = Buffer.allocUnsafeSlow(poolTotalOrBuffer)
|
|
352
378
|
} else if (poolTotalOrBuffer instanceof Buffer) {
|
|
353
379
|
this.#poolBuffer = poolTotalOrBuffer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxtedition/slice",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"tsd": "^0.33.0",
|
|
31
31
|
"typescript": "^5.9.3"
|
|
32
32
|
},
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "7c9c7457c885c644c7a1e70ef894d4727ce240d6"
|
|
34
34
|
}
|