Skip to content

Commit 3d8532f

Browse files
seishunmcollina
authored andcommitted
buffer: add{read|write}Big[U]Int64{BE|LE} methods
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 dd89a11 commit 3d8532f

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: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,46 @@ deprecated: v8.0.0
15461546
15471547
The `buf.parent` property is a deprecated alias for `buf.buffer`.
15481548

1549+
### buf.readBigInt64BE([offset])
1550+
### buf.readBigInt64LE([offset])
1551+
<!-- YAML
1552+
added: REPLACEME
1553+
-->
1554+
1555+
*`offset`{integer} Number of bytes to skip before starting to read. Must
1556+
satisfy: `0 <= offset <= buf.length - 8`. **Default:**`0`.
1557+
* Returns:{bigint}
1558+
1559+
Reads a signed 64-bit integer from `buf` at the specified `offset` with
1560+
the specified endian format (`readBigInt64BE()` returns big endian,
1561+
`readBigInt64LE()` returns little endian).
1562+
1563+
Integers read from a `Buffer` are interpreted as two's complement signed values.
1564+
1565+
### buf.readBigUInt64BE([offset])
1566+
### buf.readBigUInt64LE([offset])
1567+
<!-- YAML
1568+
added: REPLACEME
1569+
-->
1570+
1571+
*`offset`{integer} Number of bytes to skip before starting to read. Must
1572+
satisfy: `0 <= offset <= buf.length - 8`. **Default:**`0`.
1573+
* Returns:{bigint}
1574+
1575+
Reads an unsigned 64-bit integer from `buf` at the specified `offset` with
1576+
specified endian format (`readBigUInt64BE()` returns big endian,
1577+
`readBigUInt64LE()` returns little endian).
1578+
1579+
```js
1580+
constbuf=Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);
1581+
1582+
console.log(buf.readBigUInt64BE(0));
1583+
// Prints: 4294967295n
1584+
1585+
console.log(buf.readBigUInt64LE(0));
1586+
// Prints: 18446744069414584320n
1587+
```
1588+
15491589
### buf.readDoubleBE([offset])
15501590
### buf.readDoubleLE([offset])
15511591
<!-- YAML
@@ -2149,6 +2189,56 @@ console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
21492189
// Prints: 12 bytes: ½ + ¼ = ¾
21502190
```
21512191

2192+
### buf.writeBigInt64BE(value[, offset])
2193+
### buf.writeBigInt64LE(value[, offset])
2194+
<!-- YAML
2195+
added: REPLACEME
2196+
-->
2197+
2198+
*`value`{bigint} Number to be written to `buf`.
2199+
*`offset`{integer} Number of bytes to skip before starting to write. Must
2200+
satisfy: `0 <= offset <= buf.length - 8`. **Default:**`0`.
2201+
* Returns:{integer} `offset` plus the number of bytes written.
2202+
2203+
Writes `value` to `buf` at the specified `offset` with specified endian
2204+
format (`writeBigInt64BE()` writes big endian, `writeBigInt64LE()` writes little
2205+
endian).
2206+
2207+
`value` is interpreted and written as a two's complement signed integer.
2208+
2209+
```js
2210+
constbuf=Buffer.allocUnsafe(8);
2211+
2212+
buf.writeBigInt64BE(0x0102030405060708n, 0);
2213+
2214+
console.log(buf);
2215+
// Prints: <Buffer 01 02 03 04 05 06 07 08>
2216+
```
2217+
2218+
### buf.writeBigUInt64BE(value[, offset])
2219+
### buf.writeBigUInt64LE(value[, offset])
2220+
<!-- YAML
2221+
added: REPLACEME
2222+
-->
2223+
2224+
*`value`{bigint} Number to be written to `buf`.
2225+
*`offset`{integer} Number of bytes to skip before starting to write. Must
2226+
satisfy: `0 <= offset <= buf.length - 8`. **Default:**`0`.
2227+
* Returns:{integer} `offset` plus the number of bytes written.
2228+
2229+
Writes `value` to `buf` at the specified `offset` with specified endian
2230+
format (`writeBigUInt64BE()` writes big endian, `writeBigUInt64LE()` writes
2231+
little endian).
2232+
2233+
```js
2234+
constbuf=Buffer.allocUnsafe(8);
2235+
2236+
buf.writeBigUInt64LE(0xdecafafecacefaden, 0);
2237+
2238+
console.log(buf);
2239+
// Prints: <Buffer de fa ce ca fe fa ca de>
2240+
```
2241+
21522242
### buf.writeDoubleBE(value[, offset])
21532243
### buf.writeDoubleLE(value[, offset])
21542244
<!-- YAML

‎lib/internal/buffer.js‎

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,82 @@ function boundsError(value, length, type){
6363
}
6464

6565
// Read integers.
66+
functionreadBigUInt64LE(offset=0){
67+
validateNumber(offset,'offset');
68+
constfirst=this[offset];
69+
constlast=this[offset+7];
70+
if(first===undefined||last===undefined)
71+
boundsError(offset,this.length-8);
72+
73+
constlo=first+
74+
this[++offset]*2**8+
75+
this[++offset]*2**16+
76+
this[++offset]*2**24;
77+
78+
consthi=this[++offset]+
79+
this[++offset]*2**8+
80+
this[++offset]*2**16+
81+
last*2**24;
82+
83+
returnBigInt(lo)+(BigInt(hi)<<32n);
84+
}
85+
86+
functionreadBigUInt64BE(offset=0){
87+
validateNumber(offset,'offset');
88+
constfirst=this[offset];
89+
constlast=this[offset+7];
90+
if(first===undefined||last===undefined)
91+
boundsError(offset,this.length-8);
92+
93+
consthi=first*2**24+
94+
this[++offset]*2**16+
95+
this[++offset]*2**8+
96+
this[++offset];
97+
98+
constlo=this[++offset]*2**24+
99+
this[++offset]*2**16+
100+
this[++offset]*2**8+
101+
last;
102+
103+
return(BigInt(hi)<<32n)+BigInt(lo);
104+
}
105+
106+
functionreadBigInt64LE(offset=0){
107+
validateNumber(offset,'offset');
108+
constfirst=this[offset];
109+
constlast=this[offset+7];
110+
if(first===undefined||last===undefined)
111+
boundsError(offset,this.length-8);
112+
113+
constval=this[offset+4]+
114+
this[offset+5]*2**8+
115+
this[offset+6]*2**16+
116+
(last<<24);// Overflow
117+
return(BigInt(val)<<32n)+
118+
BigInt(first+
119+
this[++offset]*2**8+
120+
this[++offset]*2**16+
121+
this[++offset]*2**24);
122+
}
123+
124+
functionreadBigInt64BE(offset=0){
125+
validateNumber(offset,'offset');
126+
constfirst=this[offset];
127+
constlast=this[offset+7];
128+
if(first===undefined||last===undefined)
129+
boundsError(offset,this.length-8);
130+
131+
constval=(first<<24)+// Overflow
132+
this[++offset]*2**16+
133+
this[++offset]*2**8+
134+
this[++offset];
135+
return(BigInt(val)<<32n)+
136+
BigInt(this[++offset]*2**24+
137+
this[++offset]*2**16+
138+
this[++offset]*2**8+
139+
last);
140+
}
141+
66142
functionreadUIntLE(offset,byteLength){
67143
if(offset===undefined)
68144
thrownewERR_INVALID_ARG_TYPE('offset','number',offset);
@@ -473,6 +549,68 @@ function readDoubleForwards(offset = 0){
473549
}
474550

475551
// Write integers.
552+
functionwriteBigU_Int64LE(buf,value,offset,min,max){
553+
checkInt(value,min,max,buf,offset,7);
554+
555+
letlo=Number(value&0xffffffffn);
556+
buf[offset++]=lo;
557+
lo=lo>>8;
558+
buf[offset++]=lo;
559+
lo=lo>>8;
560+
buf[offset++]=lo;
561+
lo=lo>>8;
562+
buf[offset++]=lo;
563+
lethi=Number(value>>32n&0xffffffffn);
564+
buf[offset++]=hi;
565+
hi=hi>>8;
566+
buf[offset++]=hi;
567+
hi=hi>>8;
568+
buf[offset++]=hi;
569+
hi=hi>>8;
570+
buf[offset++]=hi;
571+
returnoffset;
572+
}
573+
574+
functionwriteBigUInt64LE(value,offset=0){
575+
returnwriteBigU_Int64LE(this,value,offset,0n,0xffffffffffffffffn);
576+
}
577+
578+
functionwriteBigU_Int64BE(buf,value,offset,min,max){
579+
checkInt(value,min,max,buf,offset,7);
580+
581+
letlo=Number(value&0xffffffffn);
582+
buf[offset+7]=lo;
583+
lo=lo>>8;
584+
buf[offset+6]=lo;
585+
lo=lo>>8;
586+
buf[offset+5]=lo;
587+
lo=lo>>8;
588+
buf[offset+4]=lo;
589+
lethi=Number(value>>32n&0xffffffffn);
590+
buf[offset+3]=hi;
591+
hi=hi>>8;
592+
buf[offset+2]=hi;
593+
hi=hi>>8;
594+
buf[offset+1]=hi;
595+
hi=hi>>8;
596+
buf[offset]=hi;
597+
returnoffset+8;
598+
}
599+
600+
functionwriteBigUInt64BE(value,offset=0){
601+
returnwriteBigU_Int64BE(this,value,offset,0n,0xffffffffffffffffn);
602+
}
603+
604+
functionwriteBigInt64LE(value,offset=0){
605+
returnwriteBigU_Int64LE(
606+
this,value,offset,-0x8000000000000000n,0x7fffffffffffffffn);
607+
}
608+
609+
functionwriteBigInt64BE(value,offset=0){
610+
returnwriteBigU_Int64BE(
611+
this,value,offset,-0x8000000000000000n,0x7fffffffffffffffn);
612+
}
613+
476614
functionwriteUIntLE(value,offset,byteLength){
477615
if(byteLength===6)
478616
returnwriteU_Int48LE(this,value,offset,0,0xffffffffffff);
@@ -790,6 +928,15 @@ function writeFloatBackwards(val, offset = 0){
790928
classFastBufferextendsUint8Array{}
791929

792930
functionaddBufferPrototypeMethods(proto){
931+
proto.readBigUInt64LE=readBigUInt64LE,
932+
proto.readBigUInt64BE=readBigUInt64BE,
933+
proto.readBigInt64LE=readBigInt64LE,
934+
proto.readBigInt64BE=readBigInt64BE,
935+
proto.writeBigUInt64LE=writeBigUInt64LE,
936+
proto.writeBigUInt64BE=writeBigUInt64BE,
937+
proto.writeBigInt64LE=writeBigInt64LE,
938+
proto.writeBigInt64BE=writeBigInt64BE,
939+
793940
proto.readUIntLE=readUIntLE;
794941
proto.readUInt32LE=readUInt32LE;
795942
proto.readUInt16LE=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)