summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benchmark/buffers/buffer-read.js4
-rw-r--r--benchmark/buffers/buffer-write.js21
-rw-r--r--doc/api/buffer.md90
-rw-r--r--lib/internal/buffer.js147
-rw-r--r--test/parallel/test-buffer-bigint64.js51
5 files changed, 313 insertions, 0 deletions
diff --git a/benchmark/buffers/buffer-read.js b/benchmark/buffers/buffer-read.js
index 38a9a847b3..06e2c6c70e 100644
--- a/benchmark/buffers/buffer-read.js
+++ b/benchmark/buffers/buffer-read.js
@@ -2,6 +2,10 @@
const common = require('../common.js');
const types = [
+ 'BigUInt64LE',
+ 'BigUInt64BE',
+ 'BigInt64LE',
+ 'BigInt64BE',
'UInt8',
'UInt16LE',
'UInt16BE',
diff --git a/benchmark/buffers/buffer-write.js b/benchmark/buffers/buffer-write.js
index 33d33a63fc..be5a6adc8e 100644
--- a/benchmark/buffers/buffer-write.js
+++ b/benchmark/buffers/buffer-write.js
@@ -2,6 +2,10 @@
const common = require('../common.js');
const types = [
+ 'BigUInt64LE',
+ 'BigUInt64BE',
+ 'BigInt64LE',
+ 'BigInt64BE',
'UInt8',
'UInt16LE',
'UInt16BE',
@@ -32,11 +36,17 @@ const INT8 = 0x7f;
const INT16 = 0x7fff;
const INT32 = 0x7fffffff;
const INT48 = 0x7fffffffffff;
+const INT64 = 0x7fffffffffffffffn;
const UINT8 = 0xff;
const UINT16 = 0xffff;
const UINT32 = 0xffffffff;
+const UINT64 = 0xffffffffffffffffn;
const mod = {
+ writeBigInt64BE: INT64,
+ writeBigInt64LE: INT64,
+ writeBigUInt64BE: UINT64,
+ writeBigUInt64LE: UINT64,
writeInt8: INT8,
writeInt16BE: INT16,
writeInt16LE: INT16,
@@ -67,12 +77,23 @@ function main({ n, buf, type }) {
if (!/\d/.test(fn))
benchSpecialInt(buff, fn, n);
+ else if (/BigU?Int/.test(fn))
+ benchBigInt(buff, fn, BigInt(n));
else if (/Int/.test(fn))
benchInt(buff, fn, n);
else
benchFloat(buff, fn, n);
}
+function benchBigInt(buff, fn, n) {
+ const m = mod[fn];
+ bench.start();
+ for (var i = 0n; i !== n; i++) {
+ buff[fn](i & m, 0);
+ }
+ bench.end(Number(n));
+}
+
function benchInt(buff, fn, n) {
const m = mod[fn];
bench.start();
diff --git a/doc/api/buffer.md b/doc/api/buffer.md
index 202bd84171..13b6ce589c 100644
--- a/doc/api/buffer.md
+++ b/doc/api/buffer.md
@@ -1546,6 +1546,46 @@ deprecated: v8.0.0
The `buf.parent` property is a deprecated alias for `buf.buffer`.
+### buf.readBigInt64BE([offset])
+### buf.readBigInt64LE([offset])
+<!-- YAML
+added: REPLACEME
+-->
+
+* `offset` {integer} Number of bytes to skip before starting to read. Must
+ satisfy: `0 <= offset <= buf.length - 8`. **Default:** `0`.
+* Returns: {bigint}
+
+Reads a signed 64-bit integer from `buf` at the specified `offset` with
+the specified endian format (`readBigInt64BE()` returns big endian,
+`readBigInt64LE()` returns little endian).
+
+Integers read from a `Buffer` are interpreted as two's complement signed values.
+
+### buf.readBigUInt64BE([offset])
+### buf.readBigUInt64LE([offset])
+<!-- YAML
+added: REPLACEME
+-->
+
+* `offset` {integer} Number of bytes to skip before starting to read. Must
+ satisfy: `0 <= offset <= buf.length - 8`. **Default:** `0`.
+* Returns: {bigint}
+
+Reads an unsigned 64-bit integer from `buf` at the specified `offset` with
+specified endian format (`readBigUInt64BE()` returns big endian,
+`readBigUInt64LE()` returns little endian).
+
+```js
+const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);
+
+console.log(buf.readBigUInt64BE(0));
+// Prints: 4294967295n
+
+console.log(buf.readBigUInt64LE(0));
+// Prints: 18446744069414584320n
+```
+
### buf.readDoubleBE([offset])
### buf.readDoubleLE([offset])
<!-- YAML
@@ -2149,6 +2189,56 @@ console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
// Prints: 12 bytes: ½ + ¼ = ¾
```
+### buf.writeBigInt64BE(value[, offset])
+### buf.writeBigInt64LE(value[, offset])
+<!-- YAML
+added: REPLACEME
+-->
+
+* `value` {bigint} Number to be written to `buf`.
+* `offset` {integer} Number of bytes to skip before starting to write. Must
+ satisfy: `0 <= offset <= buf.length - 8`. **Default:** `0`.
+* Returns: {integer} `offset` plus the number of bytes written.
+
+Writes `value` to `buf` at the specified `offset` with specified endian
+format (`writeBigInt64BE()` writes big endian, `writeBigInt64LE()` writes little
+endian).
+
+`value` is interpreted and written as a two's complement signed integer.
+
+```js
+const buf = Buffer.allocUnsafe(8);
+
+buf.writeBigInt64BE(0x0102030405060708n, 0);
+
+console.log(buf);
+// Prints: <Buffer 01 02 03 04 05 06 07 08>
+```
+
+### buf.writeBigUInt64BE(value[, offset])
+### buf.writeBigUInt64LE(value[, offset])
+<!-- YAML
+added: REPLACEME
+-->
+
+* `value` {bigint} Number to be written to `buf`.
+* `offset` {integer} Number of bytes to skip before starting to write. Must
+ satisfy: `0 <= offset <= buf.length - 8`. **Default:** `0`.
+* Returns: {integer} `offset` plus the number of bytes written.
+
+Writes `value` to `buf` at the specified `offset` with specified endian
+format (`writeBigUInt64BE()` writes big endian, `writeBigUInt64LE()` writes
+little endian).
+
+```js
+const buf = Buffer.allocUnsafe(8);
+
+buf.writeBigUInt64LE(0xdecafafecacefaden, 0);
+
+console.log(buf);
+// Prints: <Buffer de fa ce ca fe fa ca de>
+```
+
### buf.writeDoubleBE(value[, offset])
### buf.writeDoubleLE(value[, offset])
<!-- YAML
diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js
index 64c026002c..9a70dd4c89 100644
--- a/lib/internal/buffer.js
+++ b/lib/internal/buffer.js
@@ -63,6 +63,82 @@ function boundsError(value, length, type) {
}
// Read integers.
+function readBigUInt64LE(offset = 0) {
+ validateNumber(offset, 'offset');
+ const first = this[offset];
+ const last = this[offset + 7];
+ if (first === undefined || last === undefined)
+ boundsError(offset, this.length - 8);
+
+ const lo = first +
+ this[++offset] * 2 ** 8 +
+ this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 24;
+
+ const hi = this[++offset] +
+ this[++offset] * 2 ** 8 +
+ this[++offset] * 2 ** 16 +
+ last * 2 ** 24;
+
+ return BigInt(lo) + (BigInt(hi) << 32n);
+}
+
+function readBigUInt64BE(offset = 0) {
+ validateNumber(offset, 'offset');
+ const first = this[offset];
+ const last = this[offset + 7];
+ if (first === undefined || last === undefined)
+ boundsError(offset, this.length - 8);
+
+ const hi = first * 2 ** 24 +
+ this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 +
+ this[++offset];
+
+ const lo = this[++offset] * 2 ** 24 +
+ this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 +
+ last;
+
+ return (BigInt(hi) << 32n) + BigInt(lo);
+}
+
+function readBigInt64LE(offset = 0) {
+ validateNumber(offset, 'offset');
+ const first = this[offset];
+ const last = this[offset + 7];
+ if (first === undefined || last === undefined)
+ boundsError(offset, this.length - 8);
+
+ const val = this[offset + 4] +
+ this[offset + 5] * 2 ** 8 +
+ this[offset + 6] * 2 ** 16 +
+ (last << 24); // Overflow
+ return (BigInt(val) << 32n) +
+ BigInt(first +
+ this[++offset] * 2 ** 8 +
+ this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 24);
+}
+
+function readBigInt64BE(offset = 0) {
+ validateNumber(offset, 'offset');
+ const first = this[offset];
+ const last = this[offset + 7];
+ if (first === undefined || last === undefined)
+ boundsError(offset, this.length - 8);
+
+ const val = (first << 24) + // Overflow
+ this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 +
+ this[++offset];
+ return (BigInt(val) << 32n) +
+ BigInt(this[++offset] * 2 ** 24 +
+ this[++offset] * 2 ** 16 +
+ this[++offset] * 2 ** 8 +
+ last);
+}
+
function readUIntLE(offset, byteLength) {
if (offset === undefined)
throw new ERR_INVALID_ARG_TYPE('offset', 'number', offset);
@@ -473,6 +549,68 @@ function readDoubleForwards(offset = 0) {
}
// Write integers.
+function writeBigU_Int64LE(buf, value, offset, min, max) {
+ checkInt(value, min, max, buf, offset, 7);
+
+ let lo = Number(value & 0xffffffffn);
+ buf[offset++] = lo;
+ lo = lo >> 8;
+ buf[offset++] = lo;
+ lo = lo >> 8;
+ buf[offset++] = lo;
+ lo = lo >> 8;
+ buf[offset++] = lo;
+ let hi = Number(value >> 32n & 0xffffffffn);
+ buf[offset++] = hi;
+ hi = hi >> 8;
+ buf[offset++] = hi;
+ hi = hi >> 8;
+ buf[offset++] = hi;
+ hi = hi >> 8;
+ buf[offset++] = hi;
+ return offset;
+}
+
+function writeBigUInt64LE(value, offset = 0) {
+ return writeBigU_Int64LE(this, value, offset, 0n, 0xffffffffffffffffn);
+}
+
+function writeBigU_Int64BE(buf, value, offset, min, max) {
+ checkInt(value, min, max, buf, offset, 7);
+
+ let lo = Number(value & 0xffffffffn);
+ buf[offset + 7] = lo;
+ lo = lo >> 8;
+ buf[offset + 6] = lo;
+ lo = lo >> 8;
+ buf[offset + 5] = lo;
+ lo = lo >> 8;
+ buf[offset + 4] = lo;
+ let hi = Number(value >> 32n & 0xffffffffn);
+ buf[offset + 3] = hi;
+ hi = hi >> 8;
+ buf[offset + 2] = hi;
+ hi = hi >> 8;
+ buf[offset + 1] = hi;
+ hi = hi >> 8;
+ buf[offset] = hi;
+ return offset + 8;
+}
+
+function writeBigUInt64BE(value, offset = 0) {
+ return writeBigU_Int64BE(this, value, offset, 0n, 0xffffffffffffffffn);
+}
+
+function writeBigInt64LE(value, offset = 0) {
+ return writeBigU_Int64LE(
+ this, value, offset, -0x8000000000000000n, 0x7fffffffffffffffn);
+}
+
+function writeBigInt64BE(value, offset = 0) {
+ return writeBigU_Int64BE(
+ this, value, offset, -0x8000000000000000n, 0x7fffffffffffffffn);
+}
+
function writeUIntLE(value, offset, byteLength) {
if (byteLength === 6)
return writeU_Int48LE(this, value, offset, 0, 0xffffffffffff);
@@ -790,6 +928,15 @@ function writeFloatBackwards(val, offset = 0) {
class FastBuffer extends Uint8Array {}
function addBufferPrototypeMethods(proto) {
+ proto.readBigUInt64LE = readBigUInt64LE,
+ proto.readBigUInt64BE = readBigUInt64BE,
+ proto.readBigInt64LE = readBigInt64LE,
+ proto.readBigInt64BE = readBigInt64BE,
+ proto.writeBigUInt64LE = writeBigUInt64LE,
+ proto.writeBigUInt64BE = writeBigUInt64BE,
+ proto.writeBigInt64LE = writeBigInt64LE,
+ proto.writeBigInt64BE = writeBigInt64BE,
+
proto.readUIntLE = readUIntLE;
proto.readUInt32LE = readUInt32LE;
proto.readUInt16LE = readUInt16LE;
diff --git a/test/parallel/test-buffer-bigint64.js b/test/parallel/test-buffer-bigint64.js
new file mode 100644
index 0000000000..859a40811e
--- /dev/null
+++ b/test/parallel/test-buffer-bigint64.js
@@ -0,0 +1,51 @@
+'use strict';
+require('../common');
+const assert = require('assert');
+
+const buf = Buffer.allocUnsafe(8);
+
+['LE', 'BE'].forEach(function(endianness) {
+ // Should allow simple BigInts to be written and read
+ let val = 123456789n;
+ buf['writeBigInt64' + endianness](val, 0);
+ let rtn = buf['readBigInt64' + endianness](0);
+ assert.strictEqual(val, rtn);
+
+ // Should allow INT64_MAX to be written and read
+ val = 0x7fffffffffffffffn;
+ buf['writeBigInt64' + endianness](val, 0);
+ rtn = buf['readBigInt64' + endianness](0);
+ assert.strictEqual(val, rtn);
+
+ // Should read and write a negative signed 64-bit integer
+ val = -123456789n;
+ buf['writeBigInt64' + endianness](val, 0);
+ assert.strictEqual(val, buf['readBigInt64' + endianness](0));
+
+ // Should read and write an unsigned 64-bit integer
+ val = 123456789n;
+ buf['writeBigUInt64' + endianness](val, 0);
+ assert.strictEqual(val, buf['readBigUInt64' + endianness](0));
+
+ // Should throw a RangeError upon INT64_MAX+1 being written
+ assert.throws(function() {
+ const val = 0x8000000000000000n;
+ buf['writeBigInt64' + endianness](val, 0);
+ }, RangeError);
+
+ // Should throw a RangeError upon UINT64_MAX+1 being written
+ assert.throws(function() {
+ const val = 0x10000000000000000n;
+ buf['writeBigUInt64' + endianness](val, 0);
+ }, RangeError);
+
+ // Should throw a TypeError upon invalid input
+ assert.throws(function() {
+ buf['writeBigInt64' + endianness]('bad', 0);
+ }, TypeError);
+
+ // Should throw a TypeError upon invalid input
+ assert.throws(function() {
+ buf['writeBigUInt64' + endianness]('bad', 0);
+ }, TypeError);
+});