@nxtedition/slice 1.1.3 → 1.1.5

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/lib/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export declare class Slice {
9
9
  byteOffset: number;
10
10
  byteLength: number;
11
11
  maxByteLength: number;
12
- static EMPTY_BUF: Buffer;
12
+ static get EMPTY_BUF(): Buffer;
13
13
  constructor(buffer?: Buffer<ArrayBufferLike>, byteOffset?: number, byteLength?: number, maxByteLength?: number);
14
14
  reset(): void;
15
15
  get length(): number;
@@ -24,11 +24,11 @@ export declare class Slice {
24
24
  toString(encoding?: BufferEncoding, start?: number, end?: number): string;
25
25
  toBuffer(start?: number, end?: number): Buffer;
26
26
  get [Symbol.toStringTag](): string;
27
- [util.inspect.custom](depth: number, options: util.InspectOptionsStylized, inspect: typeof util.inspect): string;
27
+ [util.inspect.custom](): string;
28
28
  }
29
29
  export declare class PoolAllocator {
30
30
  #private;
31
- constructor(poolTotal?: number);
31
+ constructor(poolTotalOrBuffer?: Buffer | ArrayBufferView | ArrayBuffer | SharedArrayBuffer | number);
32
32
  get size(): number;
33
33
  isFromPool(slice: Slice | null | undefined): boolean;
34
34
  realloc(byteLength: number): Slice;
package/lib/index.js CHANGED
@@ -14,7 +14,9 @@ export class Slice {
14
14
  byteLength = 0
15
15
  maxByteLength = 0
16
16
 
17
- static EMPTY_BUF = EMPTY_BUF
17
+ static get EMPTY_BUF() {
18
+ return EMPTY_BUF
19
+ }
18
20
 
19
21
  constructor(
20
22
  buffer = Slice.EMPTY_BUF,
@@ -71,6 +73,8 @@ export class Slice {
71
73
  sourceStart ,
72
74
  sourceEnd ,
73
75
  ) {
76
+ const sliceEnd = this.byteOffset + this.byteLength
77
+
74
78
  if (sourceStart === undefined) {
75
79
  sourceStart = this.byteOffset
76
80
  } else {
@@ -78,15 +82,19 @@ export class Slice {
78
82
  }
79
83
 
80
84
  if (sourceEnd === undefined) {
81
- sourceEnd = this.byteLength + this.byteOffset
85
+ sourceEnd = sliceEnd
82
86
  } else {
83
87
  sourceEnd += this.byteOffset
84
88
  }
85
89
 
86
- let targetEnd
90
+ // Clamp against the logical slice length so copy() cannot read past
91
+ // the slice's own end and leak adjacent (pool) memory.
92
+ if (sourceEnd > sliceEnd) {
93
+ sourceEnd = sliceEnd
94
+ }
87
95
 
88
96
  if (target instanceof Slice) {
89
- targetEnd = target.byteOffset + target.byteLength
97
+ const targetEnd = target.byteOffset + target.byteLength
90
98
  if (targetStart === undefined) {
91
99
  targetStart = target.byteOffset
92
100
  } else {
@@ -94,7 +102,9 @@ export class Slice {
94
102
  }
95
103
 
96
104
  target = target.buffer
97
- sourceEnd = Math.min(sourceEnd, sourceStart + (targetEnd - targetStart))
105
+ if (sourceEnd - sourceStart > targetEnd - targetStart) {
106
+ sourceEnd = sourceStart + (targetEnd - targetStart)
107
+ }
98
108
  }
99
109
 
100
110
  if (
@@ -115,7 +125,20 @@ export class Slice {
115
125
  sourceStart ,
116
126
  sourceEnd ,
117
127
  ) {
128
+ if (
129
+ target === this &&
130
+ targetStart === undefined &&
131
+ targetEnd === undefined &&
132
+ sourceStart === undefined &&
133
+ sourceEnd === undefined
134
+ ) {
135
+ return 0
136
+ }
137
+
138
+ const sliceEnd = this.byteOffset + this.byteLength
139
+
118
140
  if (target instanceof Slice) {
141
+ const targetSliceEnd = target.byteOffset + target.byteLength
119
142
  if (targetStart === undefined) {
120
143
  targetStart = target.byteOffset
121
144
  } else {
@@ -123,11 +146,14 @@ export class Slice {
123
146
  }
124
147
 
125
148
  if (targetEnd === undefined) {
126
- targetEnd = target.byteLength + target.byteOffset
149
+ targetEnd = targetSliceEnd
127
150
  } else {
128
151
  targetEnd += target.byteOffset
129
152
  }
130
153
 
154
+ if (targetEnd > targetSliceEnd) {
155
+ targetEnd = targetSliceEnd
156
+ }
131
157
  target = target.buffer
132
158
  }
133
159
 
@@ -138,23 +164,35 @@ export class Slice {
138
164
  }
139
165
 
140
166
  if (sourceEnd === undefined) {
141
- sourceEnd = this.byteLength + this.byteOffset
167
+ sourceEnd = sliceEnd
142
168
  } else {
143
169
  sourceEnd += this.byteOffset
144
170
  }
145
171
 
172
+ if (sourceEnd > sliceEnd) {
173
+ sourceEnd = sliceEnd
174
+ }
175
+
146
176
  return this.buffer.compare(target, targetStart, targetEnd, sourceStart, sourceEnd)
147
177
  }
148
178
 
149
179
  write(string , offset , length , encoding ) {
180
+ const sliceEnd = this.byteOffset + this.byteLength
181
+
150
182
  if (offset === undefined) {
151
183
  offset = this.byteOffset
152
184
  } else {
185
+ if (offset < 0 || offset > this.byteLength) {
186
+ throw new RangeError(`Invalid offset: ${offset}`)
187
+ }
153
188
  offset += this.byteOffset
154
189
  }
155
190
 
191
+ const available = sliceEnd - offset
156
192
  if (length === undefined) {
157
- length = this.byteLength + this.byteOffset - offset
193
+ length = available
194
+ } else if (length > available) {
195
+ length = available
158
196
  }
159
197
 
160
198
  return this.buffer.write(string, offset, length, encoding)
@@ -190,6 +228,8 @@ export class Slice {
190
228
  }
191
229
 
192
230
  toString(encoding , start , end ) {
231
+ const sliceEnd = this.byteOffset + this.byteLength
232
+
193
233
  if (start === undefined) {
194
234
  start = this.byteOffset
195
235
  } else {
@@ -197,15 +237,21 @@ export class Slice {
197
237
  }
198
238
 
199
239
  if (end === undefined) {
200
- end = this.byteLength + this.byteOffset
240
+ end = sliceEnd
201
241
  } else {
202
242
  end += this.byteOffset
203
243
  }
204
244
 
245
+ if (end > sliceEnd) {
246
+ end = sliceEnd
247
+ }
248
+
205
249
  return this.buffer.toString(encoding, start, end)
206
250
  }
207
251
 
208
252
  toBuffer(start , end ) {
253
+ const sliceEnd = this.byteOffset + this.byteLength
254
+
209
255
  if (start === undefined) {
210
256
  start = this.byteOffset
211
257
  } else {
@@ -213,30 +259,45 @@ export class Slice {
213
259
  }
214
260
 
215
261
  if (end === undefined) {
216
- end = this.byteLength + this.byteOffset
262
+ end = sliceEnd
217
263
  } else {
218
264
  end += this.byteOffset
219
265
  }
220
266
 
267
+ if (end > sliceEnd) {
268
+ end = sliceEnd
269
+ }
270
+
221
271
  return start === 0 && end === this.buffer.byteLength
222
272
  ? this.buffer
223
273
  : this.buffer.subarray(start, end)
224
274
  }
225
275
 
226
276
  get [Symbol.toStringTag]() {
227
- return this.toString()
277
+ return 'Slice'
228
278
  }
229
279
 
230
- [util.inspect.custom](
231
- depth ,
232
- options ,
233
- inspect ,
234
- ) {
235
- const bytes = []
236
- for (let i = 0; i < this.byteLength; i++) {
237
- bytes.push(this.buffer[this.byteOffset + i].toString(16).padStart(2, '0'))
280
+ [util.inspect.custom]() {
281
+ const MAX_BYTES = 32
282
+ const len = this.byteLength
283
+ const shown = len < MAX_BYTES ? len : MAX_BYTES
284
+
285
+ let hex = ''
286
+ for (let i = 0; i < shown; i++) {
287
+ if (i !== 0) {
288
+ hex += ' '
289
+ }
290
+ hex += this.buffer[this.byteOffset + i].toString(16).padStart(2, '0')
291
+ }
292
+ if (shown < len) {
293
+ hex += ` ... (${len - shown} more)`
238
294
  }
239
- return `Slice: "${this.toString()}" <${bytes.join(' ')}>`
295
+
296
+ const strEnd = shown < len ? this.byteOffset + shown : this.byteOffset + len
297
+ const str = this.buffer.toString('utf8', this.byteOffset, strEnd)
298
+ const truncated = shown < len ? '…' : ''
299
+
300
+ return `Slice(${len}): "${str}${truncated}" <${hex}>`
240
301
  }
241
302
  }
242
303
 
@@ -251,8 +312,32 @@ export class PoolAllocator {
251
312
  #poolSize = 0
252
313
  #poolCount = 0
253
314
 
254
- constructor(poolTotal = 128 * 1024 * 1024) {
255
- this.#poolBuffer = Buffer.allocUnsafe(Number.isFinite(poolTotal) ? poolTotal : 0)
315
+ constructor(
316
+ poolTotalOrBuffer = 128 *
317
+ 1024 *
318
+ 1024,
319
+ ) {
320
+ if (typeof poolTotalOrBuffer === 'number') {
321
+ this.#poolBuffer = Buffer.allocUnsafeSlow(poolTotalOrBuffer)
322
+ } else if (poolTotalOrBuffer instanceof Buffer) {
323
+ this.#poolBuffer = poolTotalOrBuffer
324
+ } else if (ArrayBuffer.isView(poolTotalOrBuffer)) {
325
+ this.#poolBuffer = Buffer.from(
326
+ poolTotalOrBuffer.buffer,
327
+ poolTotalOrBuffer.byteOffset,
328
+ poolTotalOrBuffer.byteLength,
329
+ )
330
+ } else if (
331
+ poolTotalOrBuffer instanceof ArrayBuffer ||
332
+ poolTotalOrBuffer instanceof SharedArrayBuffer
333
+ ) {
334
+ this.#poolBuffer = Buffer.from(poolTotalOrBuffer)
335
+ } else {
336
+ throw new TypeError(
337
+ 'Invalid poolTotalOrBuffer: must be a Buffer, ArrayBufferView, ArrayBuffer, SharedArrayBuffer, or number',
338
+ )
339
+ }
340
+
256
341
  for (let n = 0; 2 ** n <= 256 * 1024; n++) {
257
342
  this.#poolsBucket.push([])
258
343
  this.#poolsBucketUsed.push(0)
@@ -279,9 +364,13 @@ export class PoolAllocator {
279
364
  throw new TypeError(`Invalid byteLength: ${byteLength}`)
280
365
  }
281
366
 
282
- if (slice == null) {
283
- slice = new Slice()
284
- } else if (slice.byteLength === byteLength) {
367
+ // 2^30 is the largest power-of-two that fits a 32-bit signed int; a
368
+ // larger request overflows `1 << dstIdx` to a negative bucket size.
369
+ if (byteLength > 1 << 30) {
370
+ throw new RangeError(`byteLength too large: ${byteLength} (max ${1 << 30})`)
371
+ }
372
+
373
+ if (slice.byteLength === byteLength) {
285
374
  return slice
286
375
  }
287
376
 
@@ -317,15 +406,8 @@ export class PoolAllocator {
317
406
  }
318
407
 
319
408
  const maxByteLength = 1 << dstIdx
320
- if (
321
- this.#poolsBucket.length > 32 ||
322
- maxByteLength < byteLength ||
323
- (maxByteLength & 0x7) !== 0
324
- ) {
325
- throw new Error(`Invalid pool state`)
326
- }
327
409
 
328
- if (dstIdx < this.#poolsBucket.length && this.#poolsBucket[dstIdx]?.length) {
410
+ if (dstIdx < this.#poolsBucket.length && this.#poolsBucket[dstIdx].length) {
329
411
  slice.buffer = this.#poolBuffer
330
412
  slice.byteOffset = this.#poolsBucket[dstIdx].pop()
331
413
  slice.byteLength = byteLength
@@ -364,7 +446,7 @@ export class PoolAllocator {
364
446
  return {
365
447
  size: this.#size,
366
448
  padding: this.#padding,
367
- ratio: this.#size > 0 ? this.#size / (this.#size - this.#padding) : 1,
449
+ ratio: this.#size > this.#padding ? this.#size / (this.#size - this.#padding) : 1,
368
450
  poolTotal: this.#poolBuffer.byteLength,
369
451
  poolUsed: this.#poolOffset,
370
452
  poolSize: this.#poolSize,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/slice",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
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": "a95ef1b72677b853fd7943f7071c266f1789e134"
33
+ "gitHead": "b3ff34d7bea69e295919bdfdae8bc2e6ff9ab0ff"
34
34
  }
@@ -1 +0,0 @@
1
- export {};