Skip to content

Commit 2fece54

Browse files
jasnelltargos
authored andcommitted
buffer: add Buffer.copyBytesFrom(...)
Fixes: #43862 PR-URL: #46500 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent e11f08e commit 2fece54

File tree

3 files changed

+146
-1
lines changed

3 files changed

+146
-1
lines changed

doc/api/buffer.md

+22
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,28 @@ console.log(bufA.length);
10581058
`Buffer.concat()` may also use the internal `Buffer` pool like
10591059
[`Buffer.allocUnsafe()`][] does.
10601060

1061+
### Static method: `Buffer.copyBytesFrom(view[, offset[, length]])`
1062+
1063+
<!-- YAML
1064+
added: REPLACEME
1065+
-->
1066+
1067+
* `view` {TypedArray} The {TypedArray} to copy.
1068+
* `offset` {integer} The starting offset within `view`. **Default:**: `0`.
1069+
* `length` {integer} The number of elements from `view` to copy.
1070+
**Default:** `view.length - offset`.
1071+
1072+
Copies the underlying memory of `view` into a new `Buffer`.
1073+
1074+
```js
1075+
const u16 = new Uint16Array([0, 0xffff]);
1076+
const buf = Buffer.copyBytesFrom(u16, 0, 1);
1077+
u16[1] = 0;
1078+
console.log(buf.length); // 2
1079+
console.log(buf[0]); // 255
1080+
console.log(buf[1]); // 255
1081+
```
1082+
10611083
### Static method: `Buffer.from(array)`
10621084

10631085
<!-- YAML

lib/buffer.js

+46
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,13 @@ const {
4343
StringPrototypeTrim,
4444
SymbolSpecies,
4545
SymbolToPrimitive,
46+
TypedArrayPrototypeGetBuffer,
4647
TypedArrayPrototypeGetByteLength,
48+
TypedArrayPrototypeGetByteOffset,
4749
TypedArrayPrototypeFill,
50+
TypedArrayPrototypeGetLength,
4851
TypedArrayPrototypeSet,
52+
TypedArrayPrototypeSlice,
4953
Uint8Array,
5054
Uint8ArrayPrototype,
5155
} = primordials;
@@ -330,6 +334,48 @@ Buffer.from = function from(value, encodingOrOffset, length) {
330334
);
331335
};
332336

337+
/**
338+
* Creates the Buffer as a copy of the underlying ArrayBuffer of the view
339+
* rather than the contents of the view.
340+
* @param {TypedArray} view
341+
* @param {number} [offset]
342+
* @param {number} [length]
343+
* @returns {Buffer}
344+
*/
345+
Buffer.copyBytesFrom = function copyBytesFrom(view, offset, length) {
346+
if (!isTypedArray(view)) {
347+
throw new ERR_INVALID_ARG_TYPE('view', [ 'TypedArray' ], view);
348+
}
349+
350+
const viewLength = TypedArrayPrototypeGetLength(view);
351+
if (viewLength === 0) {
352+
return Buffer.alloc(0);
353+
}
354+
355+
if (offset !== undefined || length !== undefined) {
356+
if (offset !== undefined) {
357+
validateInteger(offset, 'offset', 0);
358+
if (offset >= viewLength) return Buffer.alloc(0);
359+
} else {
360+
offset = 0;
361+
}
362+
let end;
363+
if (length !== undefined) {
364+
validateInteger(length, 'length', 0);
365+
end = offset + length;
366+
} else {
367+
end = viewLength;
368+
}
369+
370+
view = TypedArrayPrototypeSlice(view, offset, end);
371+
}
372+
373+
return fromArrayLike(new Uint8Array(
374+
TypedArrayPrototypeGetBuffer(view),
375+
TypedArrayPrototypeGetByteOffset(view),
376+
TypedArrayPrototypeGetByteLength(view)));
377+
};
378+
333379
// Identical to the built-in %TypedArray%.of(), but avoids using the deprecated
334380
// Buffer() constructor. Must use arrow function syntax to avoid automatically
335381
// adding a `prototype` property and making the function a constructor.

test/parallel/test-buffer-from.js

+78-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
const common = require('../common');
4-
const { deepStrictEqual, throws } = require('assert');
4+
const { deepStrictEqual, strictEqual, throws } = require('assert');
55
const { runInNewContext } = require('vm');
66

77
const checkString = 'test';
@@ -62,3 +62,80 @@ deepStrictEqual(
6262

6363
Buffer.allocUnsafe(10); // Should not throw.
6464
Buffer.from('deadbeaf', 'hex'); // Should not throw.
65+
66+
67+
{
68+
const u16 = new Uint16Array([0xffff]);
69+
const b16 = Buffer.copyBytesFrom(u16);
70+
u16[0] = 0;
71+
strictEqual(b16.length, 2);
72+
strictEqual(b16[0], 255);
73+
strictEqual(b16[1], 255);
74+
}
75+
76+
{
77+
const u16 = new Uint16Array([0, 0xffff]);
78+
const b16 = Buffer.copyBytesFrom(u16, 1, 5);
79+
u16[0] = 0xffff;
80+
u16[1] = 0;
81+
strictEqual(b16.length, 2);
82+
strictEqual(b16[0], 255);
83+
strictEqual(b16[1], 255);
84+
}
85+
86+
{
87+
const u32 = new Uint32Array([0xffffffff]);
88+
const b32 = Buffer.copyBytesFrom(u32);
89+
u32[0] = 0;
90+
strictEqual(b32.length, 4);
91+
strictEqual(b32[0], 255);
92+
strictEqual(b32[1], 255);
93+
strictEqual(b32[2], 255);
94+
strictEqual(b32[3], 255);
95+
}
96+
97+
throws(() => {
98+
Buffer.copyBytesFrom();
99+
}, {
100+
code: 'ERR_INVALID_ARG_TYPE',
101+
});
102+
103+
['', Symbol(), true, false, {}, [], () => {}, 1, 1n, null, undefined].forEach(
104+
(notTypedArray) => throws(() => {
105+
Buffer.copyBytesFrom('nope');
106+
}, {
107+
code: 'ERR_INVALID_ARG_TYPE',
108+
})
109+
);
110+
111+
['', Symbol(), true, false, {}, [], () => {}, 1n].forEach((notANumber) =>
112+
throws(() => {
113+
Buffer.copyBytesFrom(new Uint8Array(1), notANumber);
114+
}, {
115+
code: 'ERR_INVALID_ARG_TYPE',
116+
})
117+
);
118+
119+
[-1, NaN, 1.1, -Infinity].forEach((outOfRange) =>
120+
throws(() => {
121+
Buffer.copyBytesFrom(new Uint8Array(1), outOfRange);
122+
}, {
123+
code: 'ERR_OUT_OF_RANGE',
124+
})
125+
);
126+
127+
['', Symbol(), true, false, {}, [], () => {}, 1n].forEach((notANumber) =>
128+
throws(() => {
129+
Buffer.copyBytesFrom(new Uint8Array(1), 0, notANumber);
130+
}, {
131+
code: 'ERR_INVALID_ARG_TYPE',
132+
})
133+
);
134+
135+
[-1, NaN, 1.1, -Infinity].forEach((outOfRange) =>
136+
throws(() => {
137+
Buffer.copyBytesFrom(new Uint8Array(1), 0, outOfRange);
138+
}, {
139+
code: 'ERR_OUT_OF_RANGE',
140+
})
141+
);

0 commit comments

Comments
 (0)