buffer: add Buffer.copyBytesFrom(...)

Fixes: https://github.com/nodejs/node/issues/43862
PR-URL: https://github.com/nodejs/node/pull/46500
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
James M Snell committed 2023-02-26 14:10:04 -08:00
1 parent 3c0131a419
commit 311fb041fa
3 files changed
+146 -1

No files matched your search

+22
View File
@@ -1058,6 +1058,28 @@ console.log(bufA.length);
`Buffer.concat()` may also use the internal `Buffer` pool like
[`Buffer.allocUnsafe()`][] does.
### Static method: `Buffer.copyBytesFrom(view[, offset[, length]])`
<!-- YAML
added: REPLACEME
-->
* `view` {TypedArray} The {TypedArray} to copy.
* `offset` {integer} The starting offset within `view`. **Default:**: `0`.
* `length` {integer} The number of elements from `view` to copy.
**Default:** `view.length - offset`.
Copies the underlying memory of `view` into a new `Buffer`.
```js
const u16 = new Uint16Array([0, 0xffff]);
const buf = Buffer.copyBytesFrom(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
+46
View File
@@ -43,9 +43,13 @@ const {
StringPrototypeTrim,
SymbolSpecies,
SymbolToPrimitive,
TypedArrayPrototypeGetBuffer,
TypedArrayPrototypeGetByteLength,
TypedArrayPrototypeGetByteOffset,
TypedArrayPrototypeFill,
TypedArrayPrototypeGetLength,
TypedArrayPrototypeSet,
TypedArrayPrototypeSlice,
Uint8Array,
Uint8ArrayPrototype,
} = primordials;
@@ -330,6 +334,48 @@ 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 {TypedArray} view
* @param {number} [offset]
* @param {number} [length]
* @returns {Buffer}
*/
Buffer.copyBytesFrom = function copyBytesFrom(view, offset, length) {
if (!isTypedArray(view)) {
throw new ERR_INVALID_ARG_TYPE('view', [ 'TypedArray' ], view);
}
const viewLength = TypedArrayPrototypeGetLength(view);
if (viewLength === 0) {
return Buffer.alloc(0);
}
if (offset !== undefined || length !== undefined) {
if (offset !== undefined) {
validateInteger(offset, 'offset', 0);
if (offset >= viewLength) return Buffer.alloc(0);
} else {
offset = 0;
}
let end;
if (length !== undefined) {
validateInteger(length, 'length', 0);
end = offset + length;
} else {
end = viewLength;
}
view = TypedArrayPrototypeSlice(view, offset, end);
}
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.
+78 -1
View File
@@ -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';
@@ -62,3 +62,80 @@ deepStrictEqual(
Buffer.allocUnsafe(10); // Should not throw.
Buffer.from('deadbeaf', 'hex'); // Should not throw.
{
const u16 = new Uint16Array([0xffff]);
const b16 = Buffer.copyBytesFrom(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.copyBytesFrom(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.copyBytesFrom(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.copyBytesFrom();
}, {
code: 'ERR_INVALID_ARG_TYPE',
});
['', Symbol(), true, false, {}, [], () => {}, 1, 1n, null, undefined].forEach(
(notTypedArray) => throws(() => {
Buffer.copyBytesFrom('nope');
}, {
code: 'ERR_INVALID_ARG_TYPE',
})
);
['', Symbol(), true, false, {}, [], () => {}, 1n].forEach((notANumber) =>
throws(() => {
Buffer.copyBytesFrom(new Uint8Array(1), notANumber);
}, {
code: 'ERR_INVALID_ARG_TYPE',
})
);
[-1, NaN, 1.1, -Infinity].forEach((outOfRange) =>
throws(() => {
Buffer.copyBytesFrom(new Uint8Array(1), outOfRange);
}, {
code: 'ERR_OUT_OF_RANGE',
})
);
['', Symbol(), true, false, {}, [], () => {}, 1n].forEach((notANumber) =>
throws(() => {
Buffer.copyBytesFrom(new Uint8Array(1), 0, notANumber);
}, {
code: 'ERR_INVALID_ARG_TYPE',
})
);
[-1, NaN, 1.1, -Infinity].forEach((outOfRange) =>
throws(() => {
Buffer.copyBytesFrom(new Uint8Array(1), 0, outOfRange);
}, {
code: 'ERR_OUT_OF_RANGE',
})
);