Skip to content

Commit ab65b7f

Browse files
committed
buffer: add bufferPool to Buffer.of
1 parent fbef1cf commit ab65b7f

File tree

4 files changed

+81
-12
lines changed

4 files changed

+81
-12
lines changed

benchmark/buffers/buffer-of.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
5+
// Measure Buffer.of(...items) throughput for various lengths.
6+
// We prebuild the items array to avoid measuring array construction,
7+
// and vary the effective iterations with length to keep total work reasonable.
8+
9+
const bench = common.createBenchmark(main, {
10+
len: [0, 1, 8, 64, 256, 1024],
11+
n: [5e5],
12+
});
13+
14+
function main({ len, n }) {
15+
const items = new Array(len);
16+
for (let i = 0; i < len; i++) items[i] = i & 0xFF;
17+
18+
bench.start();
19+
for (let i = 0; i < n; i++) {
20+
Buffer.of(...items);
21+
}
22+
bench.end(n);
23+
}

doc/api/buffer.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -827,8 +827,9 @@ A `TypeError` will be thrown if `size` is not a number.
827827
The `Buffer` module pre-allocates an internal `Buffer` instance of
828828
size [`Buffer.poolSize`][] that is used as a pool for the fast allocation of new
829829
`Buffer` instances created using [`Buffer.allocUnsafe()`][], [`Buffer.from(array)`][],
830-
[`Buffer.from(string)`][], and [`Buffer.concat()`][] only when `size` is less than
831-
`Buffer.poolSize >>> 1` (floor of [`Buffer.poolSize`][] divided by two).
830+
[`Buffer.from(string)`][], [`Buffer.of(...items)`][], and [`Buffer.concat()`][]
831+
only when `size` is less than `Buffer.poolSize >>> 1` (floor of [`Buffer.poolSize`][]
832+
divided by two).
832833

833834
Use of this pre-allocated internal memory pool is a key difference between
834835
calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`.
@@ -1419,6 +1420,36 @@ appropriate for `Buffer.from()` variants.
14191420
[`Buffer.from(string)`][] may also use the internal `Buffer` pool like
14201421
[`Buffer.allocUnsafe()`][] does.
14211422

1423+
### Static method: `Buffer.of(...items)`
1424+
1425+
<!-- YAML
1426+
added: v5.10.0
1427+
-->
1428+
1429+
* `...items` {integer} A sequence of numeric byte values (0–255).
1430+
* Returns: {Buffer}
1431+
1432+
Creates a new `Buffer` from the given numeric arguments.
1433+
1434+
This is equivalent to the standard `TypedArray.of()` factory, but returns a
1435+
`Buffer` instead of a generic `Uint8Array`. Each argument provides the value of
1436+
the corresponding byte in the resulting buffer.
1437+
1438+
```mjs
1439+
import { Buffer } from 'node:buffer';
1440+
1441+
const buf = Buffer.of(0x62, 0x75, 0x66, 0x66, 0x65, 0x72);
1442+
```
1443+
1444+
```cjs
1445+
const { Buffer } = require('node:buffer');
1446+
1447+
const buf = Buffer.of(0x62, 0x75, 0x66, 0x66, 0x65, 0x72);
1448+
```
1449+
1450+
[`Buffer.of(...items)`][] may also use the internal `Buffer` pool like
1451+
[`Buffer.allocUnsafe()`][] does.
1452+
14221453
### Static method: `Buffer.isBuffer(obj)`
14231454

14241455
<!-- YAML
@@ -5461,8 +5492,9 @@ to one of these new APIs._
54615492
potentially sensitive.
54625493

54635494
`Buffer` instances returned by [`Buffer.allocUnsafe()`][], [`Buffer.from(string)`][],
5464-
[`Buffer.concat()`][] and [`Buffer.from(array)`][] _may_ be allocated off a shared
5465-
internal memory pool if `size` is less than or equal to half [`Buffer.poolSize`][].
5495+
[`Buffer.of(...items)`][], [`Buffer.concat()`][], and [`Buffer.from(array)`][]
5496+
_may_ be allocated off a shared internal memory pool if `size` is less than or
5497+
equal to half [`Buffer.poolSize`][].
54665498
Instances returned by [`Buffer.allocUnsafeSlow()`][] _never_ use the shared internal
54675499
memory pool.
54685500

@@ -5515,6 +5547,7 @@ introducing security vulnerabilities into an application.
55155547
[`Buffer.from(arrayBuf)`]: #static-method-bufferfromarraybuffer-byteoffset-length
55165548
[`Buffer.from(buffer)`]: #static-method-bufferfrombuffer
55175549
[`Buffer.from(string)`]: #static-method-bufferfromstring-encoding
5550+
[`Buffer.of(...items)`]: #static-method-bufferofitems
55185551
[`Buffer.poolSize`]: #bufferpoolsize
55195552
[`ERR_INVALID_BUFFER_SIZE`]: errors.md#err_invalid_buffer_size
55205553
[`ERR_OUT_OF_RANGE`]: errors.md#err_out_of_range

doc/api/webstreams.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -693,8 +693,8 @@ available.
693693
694694
Do not pass a pooled {Buffer} object instance in to this method.
695695
Pooled `Buffer` objects are created using `Buffer.allocUnsafe()`,
696-
or `Buffer.from()`, or are often returned by various `node:fs` module
697-
callbacks. These types of `Buffer`s use a shared underlying
696+
`Buffer.from()`, or `Buffer.of()` are often returned by various `node:fs`
697+
module callbacks. These types of `Buffer`s use a shared underlying
698698
{ArrayBuffer} object that contains all of the data from all of
699699
the pooled `Buffer` instances. When a `Buffer`, {TypedArray},
700700
or {DataView} is passed in to `readableStreamBYOBReader.read()`,

lib/buffer.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -375,17 +375,30 @@ Buffer.copyBytesFrom = function copyBytesFrom(view, offset, length) {
375375
TypedArrayPrototypeGetByteLength(view)));
376376
};
377377

378-
// Identical to the built-in %TypedArray%.of(), but avoids using the deprecated
379-
// Buffer() constructor. Must use arrow function syntax to avoid automatically
378+
// Identical to the built-in %TypedArray%.of(), but avoids using the deprecated Buffer()
379+
// constructor and may use the buffer pool. Must use arrow function syntax to avoid automatically
380380
// adding a `prototype` property and making the function a constructor.
381381
//
382382
// Refs: https://tc39.github.io/ecma262/#sec-%typedarray%.of
383383
// Refs: https://esdiscuss.org/topic/isconstructor#content-11
384384
const of = (...items) => {
385-
const newObj = createUnsafeBuffer(items.length);
386-
for (let k = 0; k < items.length; k++)
387-
newObj[k] = items[k];
388-
return newObj;
385+
const len = items.length;
386+
if (len === 0) return new FastBuffer();
387+
if (len < (Buffer.poolSize >>> 1)) {
388+
if (len > (poolSize - poolOffset))
389+
createPool();
390+
const b = new FastBuffer(allocPool, poolOffset, len);
391+
for (let k = 0; k < len; k++)
392+
b[k] = items[k];
393+
poolOffset += len;
394+
alignPool();
395+
return b;
396+
}
397+
398+
const b = createUnsafeBuffer(len);
399+
for (let k = 0; k < len; k++)
400+
b[k] = items[k];
401+
return b;
389402
};
390403
Buffer.of = of;
391404

0 commit comments

Comments
 (0)