Skip to content

Commit 64744a2

Browse files
GaryGSCBethGriggs
authored andcommitted
buffer: add{read|write}Big[U]Int64{BE|LE} methods
Backport-PR-URL: #30361 PR-URL: #19691 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Tiancheng "Timothy" Gu <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent 1cfb457 commit 64744a2

File tree

5 files changed

+313
-0
lines changed

5 files changed

+313
-0
lines changed

‎benchmark/buffers/buffer-read.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
constcommon=require('../common.js');
33

44
consttypes=[
5+
'BigUInt64LE',
6+
'BigUInt64BE',
7+
'BigInt64LE',
8+
'BigInt64BE',
59
'UInt8',
610
'UInt16LE',
711
'UInt16BE',

‎benchmark/buffers/buffer-write.js‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
constcommon=require('../common.js');
33

44
consttypes=[
5+
'BigUInt64LE',
6+
'BigUInt64BE',
7+
'BigInt64LE',
8+
'BigInt64BE',
59
'UInt8',
610
'UInt16LE',
711
'UInt16BE',
@@ -32,11 +36,17 @@ const INT8 = 0x7f;
3236
constINT16=0x7fff;
3337
constINT32=0x7fffffff;
3438
constINT48=0x7fffffffffff;
39+
constINT64=0x7fffffffffffffffn;
3540
constUINT8=0xff;
3641
constUINT16=0xffff;
3742
constUINT32=0xffffffff;
43+
constUINT64=0xffffffffffffffffn;
3844

3945
constmod={
46+
writeBigInt64BE: INT64,
47+
writeBigInt64LE: INT64,
48+
writeBigUInt64BE: UINT64,
49+
writeBigUInt64LE: UINT64,
4050
writeInt8: INT8,
4151
writeInt16BE: INT16,
4252
writeInt16LE: INT16,
@@ -67,12 +77,23 @@ function main({n, buf, type }){
6777

6878
if(!/\d/.test(fn))
6979
benchSpecialInt(buff,fn,n);
80+
elseif(/BigU?Int/.test(fn))
81+
benchBigInt(buff,fn,BigInt(n));
7082
elseif(/Int/.test(fn))
7183
benchInt(buff,fn,n);
7284
else
7385
benchFloat(buff,fn,n);
7486
}
7587

88+
functionbenchBigInt(buff,fn,n){
89+
constm=mod[fn];
90+
bench.start();
91+
for(vari=0n;i!==n;i++){
92+
buff[fn](i&m,0);
93+
}
94+
bench.end(Number(n));
95+
}
96+
7697
functionbenchInt(buff,fn,n){
7798
constm=mod[fn];
7899
bench.start();

‎doc/api/buffer.md‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,47 @@ deprecated: v8.0.0
15291529
15301530
The `buf.parent` property is a deprecated alias for `buf.buffer`.
15311531

1532+
### buf.readBigInt64BE(offset)
1533+
### buf.readBigInt64LE(offset)
1534+
<!-- YAML
1535+
added: REPLACEME
1536+
-->
1537+
1538+
*`offset`{integer} Number of bytes to skip before starting to read. Must
1539+
satisfy: `0 <= offset <= buf.length - 8`. **Default:**`0`.
1540+
* Returns:{bigint}
1541+
1542+
Reads a signed 64-bit integer from `buf` at the specified `offset` with
1543+
the specified endian format (`readBigInt64BE()` returns big endian,
1544+
`readBigInt64LE()` returns little endian).
1545+
1546+
Integers read from a `Buffer` are interpreted as two's complement signed values.
1547+
1548+
### buf.readBigUInt64BE(offset)
1549+
### buf.readBigUInt64LE(offset)
1550+
<!-- YAML
1551+
added: REPLACEME
1552+
-->
1553+
1554+
*`offset`{integer} Number of bytes to skip before starting to read. Must
1555+
satisfy: `0 <= offset <= buf.length - 8`. **Default:**`0`.
1556+
* Returns:{bigint}
1557+
1558+
Reads an unsigned 64-bit integer from `buf` at the specified `offset` with
1559+
specified endian format (`readBigUInt64BE()` returns big endian,
1560+
`readBigUInt64LE()` returns little endian).
1561+
1562+
```js
1563+
constbuf=Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);
1564+
1565+
console.log(buf.readBigUInt64BE(0));
1566+
// Prints: 4294967295n
1567+
1568+
console.log(buf.readBigUInt64LE(0));
1569+
// Prints: 18446744069414584320n
1570+
```
1571+
1572+
15321573
### buf.readDoubleBE(offset)
15331574
### buf.readDoubleLE(offset)
15341575
<!-- YAML
@@ -2132,6 +2173,56 @@ console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
21322173
// Prints: 12 bytes: ½ + ¼ = ¾
21332174
```
21342175

2176+
### buf.writeBigInt64BE(value, offset)
2177+
### buf.writeBigInt64LE(value, offset)
2178+
<!-- YAML
2179+
added: REPLACEME
2180+
-->
2181+
2182+
*`value`{bigint} Number to be written to `buf`.
2183+
*`offset`{integer} Number of bytes to skip before starting to write. Must
2184+
satisfy: `0 <= offset <= buf.length - 8`. **Default:**`0`.
2185+
* Returns:{integer} `offset` plus the number of bytes written.
2186+
2187+
Writes `value` to `buf` at the specified `offset` with specified endian
2188+
format (`writeBigInt64BE()` writes big endian, `writeBigInt64LE()` writes little
2189+
endian).
2190+
2191+
`value` is interpreted and written as a two's complement signed integer.
2192+
2193+
```js
2194+
constbuf=Buffer.allocUnsafe(8);
2195+
2196+
buf.writeBigInt64BE(0x0102030405060708n, 0);
2197+
2198+
console.log(buf);
2199+
// Prints: <Buffer 01 02 03 04 05 06 07 08>
2200+
```
2201+
2202+
### buf.writeBigUInt64BE(value, offset)
2203+
### buf.writeBigUInt64LE(value, offset)
2204+
<!-- YAML
2205+
added: REPLACEME
2206+
-->
2207+
2208+
*`value`{bigint} Number to be written to `buf`.
2209+
*`offset`{integer} Number of bytes to skip before starting to write. Must
2210+
satisfy: `0 <= offset <= buf.length - 8`. **Default:**`0`.
2211+
* Returns:{integer} `offset` plus the number of bytes written.
2212+
2213+
Writes `value` to `buf` at the specified `offset` with specified endian
2214+
format (`writeBigUInt64BE()` writes big endian, `writeBigUInt64LE()` writes
2215+
little endian).
2216+
2217+
```js
2218+
constbuf=Buffer.allocUnsafe(8);
2219+
2220+
buf.writeBigUInt64LE(0xdecafafecacefaden, 0);
2221+
2222+
console.log(buf);
2223+
// Prints: <Buffer de fa ce ca fe fa ca de>
2224+
```
2225+
21352226
### buf.writeDoubleBE(value, offset)
21362227
### buf.writeDoubleLE(value, offset)
21372228
<!-- YAML

‎lib/internal/buffer.js‎

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,82 @@ function boundsError(value, length, type){
5252
}
5353

5454
// Read integers.
55+
functionreadBigUInt64LE(offset=0){
56+
validateNumber(offset,'offset');
57+
constfirst=this[offset];
58+
constlast=this[offset+7];
59+
if(first===undefined||last===undefined)
60+
boundsError(offset,this.length-8);
61+
62+
constlo=first+
63+
this[++offset]*2**8+
64+
this[++offset]*2**16+
65+
this[++offset]*2**24;
66+
67+
consthi=this[++offset]+
68+
this[++offset]*2**8+
69+
this[++offset]*2**16+
70+
last*2**24;
71+
72+
returnBigInt(lo)+(BigInt(hi)<<32n);
73+
}
74+
75+
functionreadBigUInt64BE(offset=0){
76+
validateNumber(offset,'offset');
77+
constfirst=this[offset];
78+
constlast=this[offset+7];
79+
if(first===undefined||last===undefined)
80+
boundsError(offset,this.length-8);
81+
82+
consthi=first*2**24+
83+
this[++offset]*2**16+
84+
this[++offset]*2**8+
85+
this[++offset];
86+
87+
constlo=this[++offset]*2**24+
88+
this[++offset]*2**16+
89+
this[++offset]*2**8+
90+
last;
91+
92+
return(BigInt(hi)<<32n)+BigInt(lo);
93+
}
94+
95+
functionreadBigInt64LE(offset=0){
96+
validateNumber(offset,'offset');
97+
constfirst=this[offset];
98+
constlast=this[offset+7];
99+
if(first===undefined||last===undefined)
100+
boundsError(offset,this.length-8);
101+
102+
constval=this[offset+4]+
103+
this[offset+5]*2**8+
104+
this[offset+6]*2**16+
105+
(last<<24);// Overflow
106+
return(BigInt(val)<<32n)+
107+
BigInt(first+
108+
this[++offset]*2**8+
109+
this[++offset]*2**16+
110+
this[++offset]*2**24);
111+
}
112+
113+
functionreadBigInt64BE(offset=0){
114+
validateNumber(offset,'offset');
115+
constfirst=this[offset];
116+
constlast=this[offset+7];
117+
if(first===undefined||last===undefined)
118+
boundsError(offset,this.length-8);
119+
120+
constval=(first<<24)+// Overflow
121+
this[++offset]*2**16+
122+
this[++offset]*2**8+
123+
this[++offset];
124+
return(BigInt(val)<<32n)+
125+
BigInt(this[++offset]*2**24+
126+
this[++offset]*2**16+
127+
this[++offset]*2**8+
128+
last);
129+
}
130+
55131
functionreadUIntLE(offset,byteLength){
56132
if(byteLength===6)
57133
returnreadUInt48LE(this,offset);
@@ -454,6 +530,68 @@ function readDoubleForwards(offset = 0){
454530
}
455531

456532
// Write integers.
533+
functionwriteBigU_Int64LE(buf,value,offset,min,max){
534+
checkInt(value,min,max,buf,offset,7);
535+
536+
letlo=Number(value&0xffffffffn);
537+
buf[offset++]=lo;
538+
lo=lo>>8;
539+
buf[offset++]=lo;
540+
lo=lo>>8;
541+
buf[offset++]=lo;
542+
lo=lo>>8;
543+
buf[offset++]=lo;
544+
lethi=Number(value>>32n&0xffffffffn);
545+
buf[offset++]=hi;
546+
hi=hi>>8;
547+
buf[offset++]=hi;
548+
hi=hi>>8;
549+
buf[offset++]=hi;
550+
hi=hi>>8;
551+
buf[offset++]=hi;
552+
returnoffset;
553+
}
554+
555+
functionwriteBigUInt64LE(value,offset=0){
556+
returnwriteBigU_Int64LE(this,value,offset,0n,0xffffffffffffffffn);
557+
}
558+
559+
functionwriteBigU_Int64BE(buf,value,offset,min,max){
560+
checkInt(value,min,max,buf,offset,7);
561+
562+
letlo=Number(value&0xffffffffn);
563+
buf[offset+7]=lo;
564+
lo=lo>>8;
565+
buf[offset+6]=lo;
566+
lo=lo>>8;
567+
buf[offset+5]=lo;
568+
lo=lo>>8;
569+
buf[offset+4]=lo;
570+
lethi=Number(value>>32n&0xffffffffn);
571+
buf[offset+3]=hi;
572+
hi=hi>>8;
573+
buf[offset+2]=hi;
574+
hi=hi>>8;
575+
buf[offset+1]=hi;
576+
hi=hi>>8;
577+
buf[offset]=hi;
578+
returnoffset+8;
579+
}
580+
581+
functionwriteBigUInt64BE(value,offset=0){
582+
returnwriteBigU_Int64BE(this,value,offset,0n,0xffffffffffffffffn);
583+
}
584+
585+
functionwriteBigInt64LE(value,offset=0){
586+
returnwriteBigU_Int64LE(
587+
this,value,offset,-0x8000000000000000n,0x7fffffffffffffffn);
588+
}
589+
590+
functionwriteBigInt64BE(value,offset=0){
591+
returnwriteBigU_Int64BE(
592+
this,value,offset,-0x8000000000000000n,0x7fffffffffffffffn);
593+
}
594+
457595
functionwriteUIntLE(value,offset=0,byteLength){
458596
if(byteLength===6)
459597
returnwriteU_Int48LE(this,value,offset,0,0xffffffffffff);
@@ -773,6 +911,14 @@ module.exports ={
773911
setupBufferJS,
774912
// Container to export all read write functions.
775913
readWrites: {
914+
readBigUInt64LE,
915+
readBigUInt64BE,
916+
readBigInt64LE,
917+
readBigInt64BE,
918+
writeBigUInt64LE,
919+
writeBigUInt64BE,
920+
writeBigInt64LE,
921+
writeBigInt64BE,
776922
readUIntLE,
777923
readUInt32LE,
778924
readUInt16LE,
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
require('../common');
3+
constassert=require('assert');
4+
5+
constbuf=Buffer.allocUnsafe(8);
6+
7+
['LE','BE'].forEach(function(endianness){
8+
// Should allow simple BigInts to be written and read
9+
letval=123456789n;
10+
buf['writeBigInt64'+endianness](val,0);
11+
letrtn=buf['readBigInt64'+endianness](0);
12+
assert.strictEqual(val,rtn);
13+
14+
// Should allow INT64_MAX to be written and read
15+
val=0x7fffffffffffffffn;
16+
buf['writeBigInt64'+endianness](val,0);
17+
rtn=buf['readBigInt64'+endianness](0);
18+
assert.strictEqual(val,rtn);
19+
20+
// Should read and write a negative signed 64-bit integer
21+
val=-123456789n;
22+
buf['writeBigInt64'+endianness](val,0);
23+
assert.strictEqual(val,buf['readBigInt64'+endianness](0));
24+
25+
// Should read and write an unsigned 64-bit integer
26+
val=123456789n;
27+
buf['writeBigUInt64'+endianness](val,0);
28+
assert.strictEqual(val,buf['readBigUInt64'+endianness](0));
29+
30+
// Should throw a RangeError upon INT64_MAX+1 being written
31+
assert.throws(function(){
32+
constval=0x8000000000000000n;
33+
buf['writeBigInt64'+endianness](val,0);
34+
},RangeError);
35+
36+
// Should throw a RangeError upon UINT64_MAX+1 being written
37+
assert.throws(function(){
38+
constval=0x10000000000000000n;
39+
buf['writeBigUInt64'+endianness](val,0);
40+
},RangeError);
41+
42+
// Should throw a TypeError upon invalid input
43+
assert.throws(function(){
44+
buf['writeBigInt64'+endianness]('bad',0);
45+
},TypeError);
46+
47+
// Should throw a TypeError upon invalid input
48+
assert.throws(function(){
49+
buf['writeBigUInt64'+endianness]('bad',0);
50+
},TypeError);
51+
});

0 commit comments

Comments
(0)