Skip to content

Commit

Permalink
buffer: add Buffer.copyFrom(...)
Browse files Browse the repository at this point in the history
Fixes: #43862
  • Loading branch information
jasnell committed Feb 5, 2023
1 parent 03854f6 commit 9b2f1e7
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 1 deletion.
21 changes: 21 additions & 0 deletions doc/api/buffer.md
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,27 @@ console.log(bufA.length);
`Buffer.concat()` may also use the internal `Buffer` pool like
[`Buffer.allocUnsafe()`][] does.

### Static method: `Buffer.copyFrom(view[, offset[, length]])`

<!-- YAML
added: REPLACEME
-->

* `view` {TypedArray|DataView} The {TypedArray} or {DataView} to copy
* `offset` {integer} The starting offset within `view`
* `length` {integer} The number of elements from `view` to copy.

Copies the underlying memory of `view` into a new `Buffer`.

```js
const u16 = new Uint16Array([0, 0xffff]);
const buf = Buffer.copyFrom(u16, 0, 1);
u16[1] = 0;
console.log(buf.length); // 2
console.log(buf[0]); // 255
console.log(buf[1]); // 255
```

### Static method: `Buffer.from(array)`

<!-- YAML
Expand Down
50 changes: 50 additions & 0 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,13 @@ const {
StringPrototypeTrim,
SymbolSpecies,
SymbolToPrimitive,
TypedArrayPrototypeGetBuffer,
TypedArrayPrototypeGetByteLength,
TypedArrayPrototypeGetByteOffset,
TypedArrayPrototypeFill,
TypedArrayPrototypeGetLength,
TypedArrayPrototypeSet,
TypedArrayPrototypeSlice,
Uint8Array,
Uint8ArrayPrototype,
} = primordials;
Expand Down Expand Up @@ -330,6 +334,52 @@ Buffer.from = function from(value, encodingOrOffset, length) {
);
};

/**
* Creates the Buffer as a copy of the underlying ArrayBuffer of the view
* rather than the contents of the view.
* @param {ArrayBufferView} view
* @param {number} [offset]
* @param {number} [length]
* @returns {Buffer}
*/
Buffer.copyFrom = function copyFrom(view, offset, length) {
if (!isArrayBufferView(view)) {
throw new ERR_INVALID_ARG_TYPE('view', [ 'TypedArray', 'DataView' ], view);
}

const viewLength = TypedArrayPrototypeGetLength(view);
if (viewLength === 0) {
return Buffer.alloc(0);
}

if (offset !== undefined || length !== undefined) {
if (offset !== undefined) {
validateInteger(offset, 'offset', 0);
} else {
offset = 0;
}
if (length !== undefined) {
validateInteger(length, 'length', 0);
} else {
length = viewLength;
}

offset = MathMin(offset, viewLength);
length = MathMin(length, viewLength - offset);

if (length === 0) {
return Buffer.alloc(0);
}

view = TypedArrayPrototypeSlice(view, offset, offset + length);
}

return fromArrayLike(new Uint8Array(
TypedArrayPrototypeGetBuffer(view),
TypedArrayPrototypeGetByteOffset(view),
TypedArrayPrototypeGetByteLength(view)));
};

// Identical to the built-in %TypedArray%.of(), but avoids using the deprecated
// Buffer() constructor. Must use arrow function syntax to avoid automatically
// adding a `prototype` property and making the function a constructor.
Expand Down
45 changes: 44 additions & 1 deletion test/parallel/test-buffer-from.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const common = require('../common');
const { deepStrictEqual, throws } = require('assert');
const { deepStrictEqual, strictEqual, throws } = require('assert');
const { runInNewContext } = require('vm');

const checkString = 'test';
Expand Down Expand Up @@ -62,3 +62,46 @@ deepStrictEqual(

Buffer.allocUnsafe(10); // Should not throw.
Buffer.from('deadbeaf', 'hex'); // Should not throw.


{
const u16 = new Uint16Array([0xffff]);
const b16 = Buffer.copyFrom(u16);
u16[0] = 0;
strictEqual(b16.length, 2);
strictEqual(b16[0], 255);
strictEqual(b16[1], 255);
}

{
const u16 = new Uint16Array([0, 0xffff]);
const b16 = Buffer.copyFrom(u16, 1, 5);
u16[0] = 0xffff;
u16[1] = 0;
strictEqual(b16.length, 2);
strictEqual(b16[0], 255);
strictEqual(b16[1], 255);
}

{
const u32 = new Uint32Array([0xffffffff]);
const b32 = Buffer.copyFrom(u32);
u32[0] = 0;
strictEqual(b32.length, 4);
strictEqual(b32[0], 255);
strictEqual(b32[1], 255);
strictEqual(b32[2], 255);
strictEqual(b32[3], 255);
}

throws(() => {
Buffer.copyFrom('nope');
}, {
code: 'ERR_INVALID_ARG_TYPE',
});

throws(() => {
Buffer.copyFrom(new Uint8Array(1), 'a');
}, {
code: 'ERR_INVALID_ARG_TYPE',
});

0 comments on commit 9b2f1e7

Please sign in to comment.