Skip to content

Commit 24bebd0

Browse files
authored
buffer: speed up concat via TypedArray#set
PR-URL: #60399 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
1 parent f46152f commit 24bebd0

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

lib/buffer.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ function copyImpl(source, target, targetStart, sourceStart, sourceEnd) {
240240
return _copyActual(source, target, targetStart, sourceStart, sourceEnd);
241241
}
242242

243-
function _copyActual(source, target, targetStart, sourceStart, sourceEnd) {
243+
function _copyActual(source, target, targetStart, sourceStart, sourceEnd, isUint8Copy = false) {
244244
if (sourceEnd - sourceStart > target.byteLength - targetStart)
245245
sourceEnd = sourceStart + target.byteLength - targetStart;
246246

@@ -252,7 +252,11 @@ function _copyActual(source, target, targetStart, sourceStart, sourceEnd) {
252252
if (nb <= 0)
253253
return 0;
254254

255-
_copy(source, target, targetStart, sourceStart, nb);
255+
if (sourceStart === 0 && nb === sourceLen && (isUint8Copy || isUint8Array(target))) {
256+
TypedArrayPrototypeSet(target, source, targetStart);
257+
} else {
258+
_copy(source, target, targetStart, sourceStart, nb);
259+
}
256260

257261
return nb;
258262
}
@@ -600,7 +604,7 @@ Buffer.concat = function concat(list, length) {
600604
throw new ERR_INVALID_ARG_TYPE(
601605
`list[${i}]`, ['Buffer', 'Uint8Array'], list[i]);
602606
}
603-
pos += _copyActual(buf, buffer, pos, 0, buf.length);
607+
pos += _copyActual(buf, buffer, pos, 0, buf.length, true);
604608
}
605609

606610
// Note: `length` is always equal to `buffer.length` at this point

test/parallel/test-buffer-concat.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ assert.throws(() => {
7676
const random10 = common.hasCrypto ?
7777
require('crypto').randomBytes(10) :
7878
Buffer.alloc(10, 1);
79+
const derived18 = Buffer.alloc(18);
80+
for (let i = 0, j = 0; i < 18; i++) {
81+
if (i < 10)
82+
derived18[i] = random10[i];
83+
else
84+
derived18[i] = random10[j++];
85+
}
7986
const empty = Buffer.alloc(0);
8087

8188
assert.notDeepStrictEqual(random10, empty);
@@ -85,6 +92,7 @@ assert.deepStrictEqual(Buffer.concat([], 100), empty);
8592
assert.deepStrictEqual(Buffer.concat([random10], 0), empty);
8693
assert.deepStrictEqual(Buffer.concat([random10], 10), random10);
8794
assert.deepStrictEqual(Buffer.concat([random10, random10], 10), random10);
95+
assert.deepStrictEqual(Buffer.concat([random10, random10], 18), derived18);
8896
assert.deepStrictEqual(Buffer.concat([empty, random10]), random10);
8997
assert.deepStrictEqual(Buffer.concat([random10, empty, empty]), random10);
9098

test/parallel/test-buffer-copy.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,23 @@ b.copy(c, 'not a valid offset');
226226
// Make sure this acted like a regular copy with `0` offset.
227227
assert.deepStrictEqual(c, b.slice(0, c.length));
228228

229+
// Copy into a Uint16Array target; bytes are packed into 16-bit elements.
230+
{
231+
const x = new Uint16Array(4);
232+
const buf = Buffer.of(1, 2, 3, 4);
233+
const copied = buf.copy(x);
234+
assert.strictEqual(copied, 4);
235+
assert.ok(x instanceof Uint16Array);
236+
const bytes = new Uint8Array(x.buffer, x.byteOffset, 4);
237+
assert.deepStrictEqual(Array.from(bytes), [1, 2, 3, 4]);
238+
const remaining = new Uint8Array(
239+
x.buffer,
240+
x.byteOffset + 4,
241+
x.byteLength - 4
242+
);
243+
assert.ok(remaining.every((b) => b === 0));
244+
}
245+
229246
{
230247
c.fill('C');
231248
assert.throws(() => {

0 commit comments

Comments
 (0)