Skip to content

Commit e8bb1f3

Browse files
committed
buffer: refactor all read/write functions
There are a lot of changes in this commit: 1) Remove the `noAssert` argument from all read and write functions. 2) Improve the performance of all read floating point functions significantly. This is done by switching to TypedArrays as the write floating point write functions. 3) No implicit type coercion for offset and byteLength anymore. 4) Adds a lot of tests. 5) Moves the read and write functions to the internal buffer file to split the files in smaller chunks. 6) Reworked a lot of existing tests. 7) Improve the performane of all all read write functions by using a faster input validation and by improving function logic. 8) Significantly improved the performance of all read int functions. This is done by using a implementation without a loop. 9) Improved error handling. 10) Rename test file to use the correct subsystem. PR-URL: #18395 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
1 parent a6c490c commit e8bb1f3

21 files changed

+2015
-1839
lines changed

doc/api/buffer.md

Lines changed: 144 additions & 125 deletions
Large diffs are not rendered by default.

lib/buffer.js

Lines changed: 4 additions & 551 deletions
Large diffs are not rendered by default.

lib/internal/buffer.js

Lines changed: 785 additions & 1 deletion
Large diffs are not rendered by default.

test/parallel/test-buffer-arraybuffer.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ assert.throws(function() {
4242
Buffer.from(new AB());
4343
}, TypeError);
4444

45-
// write{Double,Float}{LE,BE} with noAssert should not crash, cf. #3766
46-
const b = Buffer.allocUnsafe(1);
47-
b.writeFloatLE(11.11, 0, true);
48-
b.writeFloatBE(11.11, 0, true);
49-
b.writeDoubleLE(11.11, 0, true);
50-
b.writeDoubleBE(11.11, 0, true);
51-
5245
// Test the byteOffset and length arguments
5346
{
5447
const ab = new Uint8Array(5);

test/parallel/test-buffer-read.js

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,11 @@ const assert = require('assert');
66
const buf = Buffer.from([0xa4, 0xfd, 0x48, 0xea, 0xcf, 0xff, 0xd9, 0x01, 0xde]);
77

88
function read(buff, funx, args, expected) {
9-
109
assert.strictEqual(buff[funx](...args), expected);
1110
common.expectsError(
1211
() => buff[funx](-1, args[1]),
13-
{
14-
code: 'ERR_INDEX_OUT_OF_RANGE'
15-
}
12+
{ code: 'ERR_OUT_OF_RANGE' }
1613
);
17-
18-
assert.strictEqual(buff[funx](...args, true), expected);
1914
}
2015

2116
// testing basic functionality of readDoubleBE() and readDoubleLE()
@@ -123,7 +118,7 @@ assert.throws(() => Buffer.allocUnsafe(8).readFloatLE(-1), RangeError);
123118
(0xFFFFFFFF >> (32 - bits)));
124119
});
125120

126-
// test for common read(U)IntLE/BE
121+
// Test for common read(U)IntLE/BE
127122
{
128123
const buf = Buffer.from([0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
129124

@@ -144,19 +139,3 @@ assert.throws(() => Buffer.allocUnsafe(8).readFloatLE(-1), RangeError);
144139
assert.strictEqual(buf.readIntLE(0, 6), 0x060504030201);
145140
assert.strictEqual(buf.readIntBE(0, 6), 0x010203040506);
146141
}
147-
148-
// test for byteLength parameter not between 1 and 6 (inclusive)
149-
common.expectsError(() => { buf.readIntLE(1); }, { code: 'ERR_OUT_OF_RANGE' });
150-
common.expectsError(() => { buf.readIntLE(1, 'string'); },
151-
{ code: 'ERR_OUT_OF_RANGE' });
152-
common.expectsError(() => { buf.readIntLE(1, 0); },
153-
{ code: 'ERR_OUT_OF_RANGE' });
154-
common.expectsError(() => { buf.readIntLE(1, 7); },
155-
{ code: 'ERR_OUT_OF_RANGE' });
156-
common.expectsError(() => { buf.readIntBE(1); }, { code: 'ERR_OUT_OF_RANGE' });
157-
common.expectsError(() => { buf.readIntBE(1, 'string'); },
158-
{ code: 'ERR_OUT_OF_RANGE' });
159-
common.expectsError(() => { buf.readIntBE(1, 0); },
160-
{ code: 'ERR_OUT_OF_RANGE' });
161-
common.expectsError(() => { buf.readIntBE(1, 7); },
162-
{ code: 'ERR_OUT_OF_RANGE' });
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('assert');
5+
6+
// Test (64 bit) double
7+
const buffer = Buffer.allocUnsafe(8);
8+
9+
buffer[0] = 0x55;
10+
buffer[1] = 0x55;
11+
buffer[2] = 0x55;
12+
buffer[3] = 0x55;
13+
buffer[4] = 0x55;
14+
buffer[5] = 0x55;
15+
buffer[6] = 0xd5;
16+
buffer[7] = 0x3f;
17+
assert.strictEqual(buffer.readDoubleBE(0), 1.1945305291680097e+103);
18+
assert.strictEqual(buffer.readDoubleLE(0), 0.3333333333333333);
19+
20+
buffer[0] = 1;
21+
buffer[1] = 0;
22+
buffer[2] = 0;
23+
buffer[3] = 0;
24+
buffer[4] = 0;
25+
buffer[5] = 0;
26+
buffer[6] = 0xf0;
27+
buffer[7] = 0x3f;
28+
assert.strictEqual(buffer.readDoubleBE(0), 7.291122019655968e-304);
29+
assert.strictEqual(buffer.readDoubleLE(0), 1.0000000000000002);
30+
31+
buffer[0] = 2;
32+
assert.strictEqual(buffer.readDoubleBE(0), 4.778309726801735e-299);
33+
assert.strictEqual(buffer.readDoubleLE(0), 1.0000000000000004);
34+
35+
buffer[0] = 1;
36+
buffer[6] = 0;
37+
buffer[7] = 0;
38+
assert.strictEqual(buffer.readDoubleBE(0), 7.291122019556398e-304);
39+
assert.strictEqual(buffer.readDoubleLE(0), 5e-324);
40+
41+
buffer[0] = 0xff;
42+
buffer[1] = 0xff;
43+
buffer[2] = 0xff;
44+
buffer[3] = 0xff;
45+
buffer[4] = 0xff;
46+
buffer[5] = 0xff;
47+
buffer[6] = 0x0f;
48+
buffer[7] = 0x00;
49+
assert.ok(Number.isNaN(buffer.readDoubleBE(0)));
50+
assert.strictEqual(buffer.readDoubleLE(0), 2.225073858507201e-308);
51+
52+
buffer[6] = 0xef;
53+
buffer[7] = 0x7f;
54+
assert.ok(Number.isNaN(buffer.readDoubleBE(0)));
55+
assert.strictEqual(buffer.readDoubleLE(0), 1.7976931348623157e+308);
56+
57+
buffer[0] = 0;
58+
buffer[1] = 0;
59+
buffer[2] = 0;
60+
buffer[3] = 0;
61+
buffer[4] = 0;
62+
buffer[5] = 0;
63+
buffer[6] = 0xf0;
64+
buffer[7] = 0x3f;
65+
assert.strictEqual(buffer.readDoubleBE(0), 3.03865e-319);
66+
assert.strictEqual(buffer.readDoubleLE(0), 1);
67+
68+
buffer[6] = 0;
69+
buffer[7] = 0x40;
70+
assert.strictEqual(buffer.readDoubleBE(0), 3.16e-322);
71+
assert.strictEqual(buffer.readDoubleLE(0), 2);
72+
73+
buffer[7] = 0xc0;
74+
assert.strictEqual(buffer.readDoubleBE(0), 9.5e-322);
75+
assert.strictEqual(buffer.readDoubleLE(0), -2);
76+
77+
buffer[6] = 0x10;
78+
buffer[7] = 0;
79+
assert.strictEqual(buffer.readDoubleBE(0), 2.0237e-320);
80+
assert.strictEqual(buffer.readDoubleLE(0), 2.2250738585072014e-308);
81+
82+
buffer[6] = 0;
83+
assert.strictEqual(buffer.readDoubleBE(0), 0);
84+
assert.strictEqual(buffer.readDoubleLE(0), 0);
85+
assert.ok(1 / buffer.readDoubleLE(0) >= 0);
86+
87+
buffer[7] = 0x80;
88+
assert.strictEqual(buffer.readDoubleBE(0), 6.3e-322);
89+
assert.strictEqual(buffer.readDoubleLE(0), -0);
90+
assert.ok(1 / buffer.readDoubleLE(0) < 0);
91+
92+
buffer[6] = 0xf0;
93+
buffer[7] = 0x7f;
94+
assert.strictEqual(buffer.readDoubleBE(0), 3.0418e-319);
95+
assert.strictEqual(buffer.readDoubleLE(0), Infinity);
96+
97+
buffer[7] = 0xff;
98+
assert.strictEqual(buffer.readDoubleBE(0), 3.04814e-319);
99+
assert.strictEqual(buffer.readDoubleLE(0), -Infinity);
100+
101+
['readDoubleLE', 'readDoubleBE'].forEach((fn) => {
102+
['', '0', null, undefined, {}, [], () => {}, true, false].forEach((off) => {
103+
assert.throws(
104+
() => buffer[fn](off),
105+
{ code: 'ERR_INVALID_ARG_TYPE' }
106+
);
107+
});
108+
109+
[Infinity, -1, 1].forEach((offset) => {
110+
assert.throws(
111+
() => buffer[fn](offset),
112+
{
113+
code: 'ERR_OUT_OF_RANGE',
114+
name: 'RangeError [ERR_OUT_OF_RANGE]',
115+
message: 'The value of "offset" is out of range. ' +
116+
`It must be >= 0 and <= 0. Received ${offset}`
117+
});
118+
});
119+
120+
assert.throws(
121+
() => Buffer.alloc(1)[fn](1),
122+
{
123+
code: 'ERR_BUFFER_OUT_OF_BOUNDS',
124+
name: 'RangeError [ERR_BUFFER_OUT_OF_BOUNDS]',
125+
message: 'Attempt to write outside buffer bounds'
126+
});
127+
128+
[NaN, 1.01].forEach((offset) => {
129+
assert.throws(
130+
() => buffer[fn](offset),
131+
{
132+
code: 'ERR_OUT_OF_RANGE',
133+
name: 'RangeError [ERR_OUT_OF_RANGE]',
134+
message: 'The value of "offset" is out of range. ' +
135+
`It must be an integer. Received ${offset}`
136+
});
137+
});
138+
});
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('assert');
5+
6+
// Test 32 bit float
7+
const buffer = Buffer.alloc(4);
8+
9+
buffer[0] = 0;
10+
buffer[1] = 0;
11+
buffer[2] = 0x80;
12+
buffer[3] = 0x3f;
13+
assert.strictEqual(buffer.readFloatBE(0), 4.600602988224807e-41);
14+
assert.strictEqual(buffer.readFloatLE(0), 1);
15+
16+
buffer[0] = 0;
17+
buffer[1] = 0;
18+
buffer[2] = 0;
19+
buffer[3] = 0xc0;
20+
assert.strictEqual(buffer.readFloatBE(0), 2.6904930515036488e-43);
21+
assert.strictEqual(buffer.readFloatLE(0), -2);
22+
23+
buffer[0] = 0xff;
24+
buffer[1] = 0xff;
25+
buffer[2] = 0x7f;
26+
buffer[3] = 0x7f;
27+
assert.ok(Number.isNaN(buffer.readFloatBE(0)));
28+
assert.strictEqual(buffer.readFloatLE(0), 3.4028234663852886e+38);
29+
30+
buffer[0] = 0xab;
31+
buffer[1] = 0xaa;
32+
buffer[2] = 0xaa;
33+
buffer[3] = 0x3e;
34+
assert.strictEqual(buffer.readFloatBE(0), -1.2126478207002966e-12);
35+
assert.strictEqual(buffer.readFloatLE(0), 0.3333333432674408);
36+
37+
buffer[0] = 0;
38+
buffer[1] = 0;
39+
buffer[2] = 0;
40+
buffer[3] = 0;
41+
assert.strictEqual(buffer.readFloatBE(0), 0);
42+
assert.strictEqual(buffer.readFloatLE(0), 0);
43+
assert.ok(1 / buffer.readFloatLE(0) >= 0);
44+
45+
buffer[3] = 0x80;
46+
assert.strictEqual(buffer.readFloatBE(0), 1.793662034335766e-43);
47+
assert.strictEqual(buffer.readFloatLE(0), -0);
48+
assert.ok(1 / buffer.readFloatLE(0) < 0);
49+
50+
buffer[0] = 0;
51+
buffer[1] = 0;
52+
buffer[2] = 0x80;
53+
buffer[3] = 0x7f;
54+
assert.strictEqual(buffer.readFloatBE(0), 4.609571298396486e-41);
55+
assert.strictEqual(buffer.readFloatLE(0), Infinity);
56+
57+
buffer[0] = 0;
58+
buffer[1] = 0;
59+
buffer[2] = 0x80;
60+
buffer[3] = 0xff;
61+
assert.strictEqual(buffer.readFloatBE(0), 4.627507918739843e-41);
62+
assert.strictEqual(buffer.readFloatLE(0), -Infinity);
63+
64+
['readFloatLE', 'readFloatBE'].forEach((fn) => {
65+
['', '0', null, undefined, {}, [], () => {}, true, false].forEach((off) => {
66+
assert.throws(
67+
() => buffer[fn](off),
68+
{ code: 'ERR_INVALID_ARG_TYPE' }
69+
);
70+
});
71+
72+
[Infinity, -1, 1].forEach((offset) => {
73+
assert.throws(
74+
() => buffer[fn](offset),
75+
{
76+
code: 'ERR_OUT_OF_RANGE',
77+
name: 'RangeError [ERR_OUT_OF_RANGE]',
78+
message: 'The value of "offset" is out of range. ' +
79+
`It must be >= 0 and <= 0. Received ${offset}`
80+
});
81+
});
82+
83+
assert.throws(
84+
() => Buffer.alloc(1)[fn](1),
85+
{
86+
code: 'ERR_BUFFER_OUT_OF_BOUNDS',
87+
name: 'RangeError [ERR_BUFFER_OUT_OF_BOUNDS]',
88+
message: 'Attempt to write outside buffer bounds'
89+
});
90+
91+
[NaN, 1.01].forEach((offset) => {
92+
assert.throws(
93+
() => buffer[fn](offset),
94+
{
95+
code: 'ERR_OUT_OF_RANGE',
96+
name: 'RangeError [ERR_OUT_OF_RANGE]',
97+
message: 'The value of "offset" is out of range. ' +
98+
`It must be an integer. Received ${offset}`
99+
});
100+
});
101+
});

0 commit comments

Comments
 (0)