Skip to content

Commit 9b2f1e7

Browse files
committed
buffer: add Buffer.copyFrom(...)
Fixes: #43862
1 parent 03854f6 commit 9b2f1e7

File tree

3 files changed

+115
-1
lines changed

3 files changed

+115
-1
lines changed

doc/api/buffer.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,27 @@ console.log(bufA.length);
10581058
`Buffer.concat()` may also use the internal `Buffer` pool like
10591059
[`Buffer.allocUnsafe()`][] does.
10601060

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

10631084
<!-- YAML

lib/buffer.js

Lines changed: 50 additions & 0 deletions
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,52 @@ 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 {ArrayBufferView} view
341+
* @param {number} [offset]
342+
* @param {number} [length]
343+
* @returns {Buffer}
344+
*/
345+
Buffer.copyFrom = function copyFrom(view, offset, length) {
346+
if (!isArrayBufferView(view)) {
347+
throw new ERR_INVALID_ARG_TYPE('view', [ 'TypedArray', 'DataView' ], 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+
} else {
359+
offset = 0;
360+
}
361+
if (length !== undefined) {
362+
validateInteger(length, 'length', 0);
363+
} else {
364+
length = viewLength;
365+
}
366+
367+
offset = MathMin(offset, viewLength);
368+
length = MathMin(length, viewLength - offset);
369+
370+
if (length === 0) {
371+
return Buffer.alloc(0);
372+
}
373+
374+
view = TypedArrayPrototypeSlice(view, offset, offset + length);
375+
}
376+
377+
return fromArrayLike(new Uint8Array(
378+
TypedArrayPrototypeGetBuffer(view),
379+
TypedArrayPrototypeGetByteOffset(view),
380+
TypedArrayPrototypeGetByteLength(view)));
381+
};
382+
333383
// Identical to the built-in %TypedArray%.of(), but avoids using the deprecated
334384
// Buffer() constructor. Must use arrow function syntax to avoid automatically
335385
// adding a `prototype` property and making the function a constructor.

test/parallel/test-buffer-from.js

Lines changed: 44 additions & 1 deletion
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,46 @@ 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.copyFrom(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.copyFrom(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.copyFrom(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.copyFrom('nope');
99+
}, {
100+
code: 'ERR_INVALID_ARG_TYPE',
101+
});
102+
103+
throws(() => {
104+
Buffer.copyFrom(new Uint8Array(1), 'a');
105+
}, {
106+
code: 'ERR_INVALID_ARG_TYPE',
107+
});

0 commit comments

Comments
 (0)