@nxtedition/slice 1.1.4 → 1.1.6

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)
@@ -171,7 +209,13 @@ export class Slice {
171
209
  offset += this.byteOffset
172
210
  }
173
211
 
174
- source.copy(this.buffer, offset)
212
+ const available = this.byteOffset + this.byteLength - offset
213
+ if (available <= 0) {
214
+ return
215
+ }
216
+
217
+ const end = source.byteLength < available ? source.byteLength : available
218
+ source.copy(this.buffer, offset, 0, end)
175
219
  }
176
220
 
177
221
  at(index ) {
@@ -190,6 +234,8 @@ export class Slice {
190
234
  }
191
235
 
192
236
  toString(encoding , start , end ) {
237
+ const sliceEnd = this.byteOffset + this.byteLength
238
+
193
239
  if (start === undefined) {
194
240
  start = this.byteOffset
195
241
  } else {
@@ -197,15 +243,21 @@ export class Slice {
197
243
  }
198
244
 
199
245
  if (end === undefined) {
200
- end = this.byteLength + this.byteOffset
246
+ end = sliceEnd
201
247
  } else {
202
248
  end += this.byteOffset
203
249
  }
204
250
 
251
+ if (end > sliceEnd) {
252
+ end = sliceEnd
253
+ }
254
+
205
255
  return this.buffer.toString(encoding, start, end)
206
256
  }
207
257
 
208
258
  toBuffer(start , end ) {
259
+ const sliceEnd = this.byteOffset + this.byteLength
260
+
209
261
  if (start === undefined) {
210
262
  start = this.byteOffset
211
263
  } else {
@@ -213,30 +265,45 @@ export class Slice {
213
265
  }
214
266
 
215
267
  if (end === undefined) {
216
- end = this.byteLength + this.byteOffset
268
+ end = sliceEnd
217
269
  } else {
218
270
  end += this.byteOffset
219
271
  }
220
272
 
273
+ if (end > sliceEnd) {
274
+ end = sliceEnd
275
+ }
276
+
221
277
  return start === 0 && end === this.buffer.byteLength
222
278
  ? this.buffer
223
279
  : this.buffer.subarray(start, end)
224
280
  }
225
281
 
226
282
  get [Symbol.toStringTag]() {
227
- return this.toString()
283
+ return 'Slice'
228
284
  }
229
285
 
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'))
286
+ [util.inspect.custom]() {
287
+ const MAX_BYTES = 32
288
+ const len = this.byteLength
289
+ const shown = len < MAX_BYTES ? len : MAX_BYTES
290
+
291
+ let hex = ''
292
+ for (let i = 0; i < shown; i++) {
293
+ if (i !== 0) {
294
+ hex += ' '
295
+ }
296
+ hex += this.buffer[this.byteOffset + i].toString(16).padStart(2, '0')
238
297
  }
239
- return `Slice: "${this.toString()}" <${bytes.join(' ')}>`
298
+ if (shown < len) {
299
+ hex += ` ... (${len - shown} more)`
300
+ }
301
+
302
+ const strEnd = shown < len ? this.byteOffset + shown : this.byteOffset + len
303
+ const str = this.buffer.toString('utf8', this.byteOffset, strEnd)
304
+ const truncated = shown < len ? '…' : ''
305
+
306
+ return `Slice(${len}): "${str}${truncated}" <${hex}>`
240
307
  }
241
308
  }
242
309
 
@@ -251,8 +318,32 @@ export class PoolAllocator {
251
318
  #poolSize = 0
252
319
  #poolCount = 0
253
320
 
254
- constructor(poolTotal = 128 * 1024 * 1024) {
255
- this.#poolBuffer = Buffer.allocUnsafe(Number.isFinite(poolTotal) ? poolTotal : 0)
321
+ constructor(
322
+ poolTotalOrBuffer = 128 *
323
+ 1024 *
324
+ 1024,
325
+ ) {
326
+ if (typeof poolTotalOrBuffer === 'number') {
327
+ this.#poolBuffer = Buffer.allocUnsafeSlow(poolTotalOrBuffer)
328
+ } else if (poolTotalOrBuffer instanceof Buffer) {
329
+ this.#poolBuffer = poolTotalOrBuffer
330
+ } else if (ArrayBuffer.isView(poolTotalOrBuffer)) {
331
+ this.#poolBuffer = Buffer.from(
332
+ poolTotalOrBuffer.buffer,
333
+ poolTotalOrBuffer.byteOffset,
334
+ poolTotalOrBuffer.byteLength,
335
+ )
336
+ } else if (
337
+ poolTotalOrBuffer instanceof ArrayBuffer ||
338
+ poolTotalOrBuffer instanceof SharedArrayBuffer
339
+ ) {
340
+ this.#poolBuffer = Buffer.from(poolTotalOrBuffer)
341
+ } else {
342
+ throw new TypeError(
343
+ 'Invalid poolTotalOrBuffer: must be a Buffer, ArrayBufferView, ArrayBuffer, SharedArrayBuffer, or number',
344
+ )
345
+ }
346
+
256
347
  for (let n = 0; 2 ** n <= 256 * 1024; n++) {
257
348
  this.#poolsBucket.push([])
258
349
  this.#poolsBucketUsed.push(0)
@@ -279,9 +370,13 @@ export class PoolAllocator {
279
370
  throw new TypeError(`Invalid byteLength: ${byteLength}`)
280
371
  }
281
372
 
282
- if (slice == null) {
283
- slice = new Slice()
284
- } else if (slice.byteLength === byteLength) {
373
+ // 2^30 is the largest power-of-two that fits a 32-bit signed int; a
374
+ // larger request overflows `1 << dstIdx` to a negative bucket size.
375
+ if (byteLength > 1 << 30) {
376
+ throw new RangeError(`byteLength too large: ${byteLength} (max ${1 << 30})`)
377
+ }
378
+
379
+ if (slice.byteLength === byteLength) {
285
380
  return slice
286
381
  }
287
382
 
@@ -317,15 +412,8 @@ export class PoolAllocator {
317
412
  }
318
413
 
319
414
  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
415
 
328
- if (dstIdx < this.#poolsBucket.length && this.#poolsBucket[dstIdx]?.length) {
416
+ if (dstIdx < this.#poolsBucket.length && this.#poolsBucket[dstIdx].length) {
329
417
  slice.buffer = this.#poolBuffer
330
418
  slice.byteOffset = this.#poolsBucket[dstIdx].pop()
331
419
  slice.byteLength = byteLength
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/slice",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
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": "a29e479679bd053fa37ff8868d47918a8983ee48"
33
+ "gitHead": "472a4cdfd11ff9f1a7dcf8b81599bc1d9270bc90"
34
34
  }