From e8bb1f35df079cf0111fc18a8a24ec0a2d66eb3e Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Tue, 30 Jan 2018 17:34:25 +0100 Subject: 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: https://github.com/nodejs/node/pull/18395 Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Anatoli Papirovski Reviewed-By: Ben Noordhuis --- doc/api/buffer.md | 269 +++++++++++++++++++++++++++++------------------------- 1 file changed, 144 insertions(+), 125 deletions(-) (limited to 'doc/api/buffer.md') diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 510848c3b0..06c69f5abc 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -1538,31 +1538,32 @@ deprecated: v8.0.0 The `buf.parent` property is a deprecated alias for `buf.buffer`. -### buf.readDoubleBE(offset[, noAssert]) -### buf.readDoubleLE(offset[, noAssert]) +### buf.readDoubleBE(offset) +### buf.readDoubleLE(offset) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 8`. -* `noAssert` {boolean} Skip `offset` validation? **Default:** `false` * Returns: {number} Reads a 64-bit double from `buf` at the specified `offset` with specified endian format (`readDoubleBE()` returns big endian, `readDoubleLE()` returns little endian). -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Examples: ```js const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]); -console.log(buf.readDoubleBE()); +console.log(buf.readDoubleBE(0)); // Prints: 8.20788039913184e-304 -console.log(buf.readDoubleLE()); +console.log(buf.readDoubleLE(0)); // Prints: 5.447603722011605e-270 console.log(buf.readDoubleLE(1)); // Throws an exception: RangeError: Index out of range @@ -1571,31 +1572,32 @@ console.log(buf.readDoubleLE(1, true)); // This will result in a segmentation fault! Don't do this! ``` -### buf.readFloatBE(offset[, noAssert]) -### buf.readFloatLE(offset[, noAssert]) +### buf.readFloatBE(offset) +### buf.readFloatLE(offset) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 4`. -* `noAssert` {boolean} Skip `offset` validation? **Default:** `false` * Returns: {number} Reads a 32-bit float from `buf` at the specified `offset` with specified endian format (`readFloatBE()` returns big endian, `readFloatLE()` returns little endian). -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Examples: ```js const buf = Buffer.from([1, 2, 3, 4]); -console.log(buf.readFloatBE()); +console.log(buf.readFloatBE(0)); // Prints: 2.387939260590663e-38 -console.log(buf.readFloatLE()); +console.log(buf.readFloatLE(0)); // Prints: 1.539989614439558e-36 console.log(buf.readFloatLE(1)); // Throws an exception: RangeError: Index out of range @@ -1604,20 +1606,21 @@ console.log(buf.readFloatLE(1, true)); // This will result in a segmentation fault! Don't do this! ``` -### buf.readInt8(offset[, noAssert]) +### buf.readInt8(offset) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 1`. -* `noAssert` {boolean} Skip `offset` validation? **Default:** `false` * Returns: {integer} Reads a signed 8-bit integer from `buf` at the specified `offset`. -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Integers read from a `Buffer` are interpreted as two's complement signed values. Examples: @@ -1633,23 +1636,24 @@ console.log(buf.readInt8(2)); // Throws an exception: RangeError: Index out of range ``` -### buf.readInt16BE(offset[, noAssert]) -### buf.readInt16LE(offset[, noAssert]) +### buf.readInt16BE(offset) +### buf.readInt16LE(offset) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 2`. -* `noAssert` {boolean} Skip `offset` validation? **Default:** `false` * Returns: {integer} Reads a signed 16-bit integer from `buf` at the specified `offset` with the specified endian format (`readInt16BE()` returns big endian, `readInt16LE()` returns little endian). -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Integers read from a `Buffer` are interpreted as two's complement signed values. Examples: @@ -1657,31 +1661,32 @@ Examples: ```js const buf = Buffer.from([0, 5]); -console.log(buf.readInt16BE()); +console.log(buf.readInt16BE(0)); // Prints: 5 -console.log(buf.readInt16LE()); +console.log(buf.readInt16LE(0)); // Prints: 1280 console.log(buf.readInt16LE(1)); // Throws an exception: RangeError: Index out of range ``` -### buf.readInt32BE(offset[, noAssert]) -### buf.readInt32LE(offset[, noAssert]) +### buf.readInt32BE(offset) +### buf.readInt32LE(offset) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 4`. -* `noAssert` {boolean} Skip `offset` validation? **Default:** `false` * Returns: {integer} Reads a signed 32-bit integer from `buf` at the specified `offset` with the specified endian format (`readInt32BE()` returns big endian, `readInt32LE()` returns little endian). -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Integers read from a `Buffer` are interpreted as two's complement signed values. Examples: @@ -1689,32 +1694,33 @@ Examples: ```js const buf = Buffer.from([0, 0, 0, 5]); -console.log(buf.readInt32BE()); +console.log(buf.readInt32BE(0)); // Prints: 5 -console.log(buf.readInt32LE()); +console.log(buf.readInt32LE(0)); // Prints: 83886080 console.log(buf.readInt32LE(1)); // Throws an exception: RangeError: Index out of range ``` -### buf.readIntBE(offset, byteLength[, noAssert]) -### buf.readIntLE(offset, byteLength[, noAssert]) +### buf.readIntBE(offset, byteLength) +### buf.readIntLE(offset, byteLength) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - byteLength`. * `byteLength` {integer} Number of bytes to read. Must satisfy: `0 < byteLength <= 6`. -* `noAssert` {boolean} Skip `offset` and `byteLength` validation? **Default:** `false`. * Returns: {integer} Reads `byteLength` number of bytes from `buf` at the specified `offset` and interprets the result as a two's complement signed value. Supports up to 48 bits of accuracy. -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Examples: ```js @@ -1730,20 +1736,21 @@ console.log(buf.readIntBE(1, 0).toString(16)); // Throws ERR_OUT_OF_RANGE: ``` -### buf.readUInt8(offset[, noAssert]) +### buf.readUInt8(offset) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 1`. -* `noAssert` {boolean} Skip `offset` validation? **Default:** `false` * Returns: {integer} Reads an unsigned 8-bit integer from `buf` at the specified `offset`. -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Examples: ```js @@ -1757,23 +1764,24 @@ console.log(buf.readUInt8(2)); // Throws an exception: RangeError: Index out of range ``` -### buf.readUInt16BE(offset[, noAssert]) -### buf.readUInt16LE(offset[, noAssert]) +### buf.readUInt16BE(offset) +### buf.readUInt16LE(offset) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 2`. -* `noAssert` {boolean} Skip `offset` validation? **Default:** `false` * Returns: {integer} Reads an unsigned 16-bit integer from `buf` at the specified `offset` with specified endian format (`readUInt16BE()` returns big endian, `readUInt16LE()` returns little endian). -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Examples: ```js @@ -1791,23 +1799,24 @@ console.log(buf.readUInt16LE(2).toString(16)); // Throws an exception: RangeError: Index out of range ``` -### buf.readUInt32BE(offset[, noAssert]) -### buf.readUInt32LE(offset[, noAssert]) +### buf.readUInt32BE(offset) +### buf.readUInt32LE(offset) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - 4`. -* `noAssert` {boolean} Skip `offset` validation? **Default:** `false` * Returns: {integer} Reads an unsigned 32-bit integer from `buf` at the specified `offset` with specified endian format (`readUInt32BE()` returns big endian, `readUInt32LE()` returns little endian). -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Examples: ```js @@ -1821,24 +1830,25 @@ console.log(buf.readUInt32LE(1).toString(16)); // Throws an exception: RangeError: Index out of range ``` -### buf.readUIntBE(offset, byteLength[, noAssert]) -### buf.readUIntLE(offset, byteLength[, noAssert]) +### buf.readUIntBE(offset, byteLength) +### buf.readUIntLE(offset, byteLength) * `offset` {integer} Number of bytes to skip before starting to read. Must satisfy: `0 <= offset <= buf.length - byteLength`. * `byteLength` {integer} Number of bytes to read. Must satisfy: `0 < byteLength <= 6`. -* `noAssert` {boolean} Skip `offset` and `byteLength` validation? **Default:** `false` * Returns: {integer} Reads `byteLength` number of bytes from `buf` at the specified `offset` and interprets the result as an unsigned integer. Supports up to 48 bits of accuracy. -Setting `noAssert` to `true` allows `offset` to be beyond the end of `buf`, but -the resulting behavior is undefined. - Examples: ```js @@ -2149,15 +2159,19 @@ console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`); // Prints: 12 bytes: ½ + ¼ = ¾ ``` -### buf.writeDoubleBE(value, offset[, noAssert]) -### buf.writeDoubleLE(value, offset[, noAssert]) +### buf.writeDoubleBE(value, offset) +### buf.writeDoubleLE(value, offset) * `value` {number} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 8`. -* `noAssert` {boolean} Skip `value` and `offset` validation? **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. Writes `value` to `buf` at the specified `offset` with specified endian @@ -2165,9 +2179,6 @@ format (`writeDoubleBE()` writes big endian, `writeDoubleLE()` writes little endian). `value` *should* be a valid 64-bit double. Behavior is undefined when `value` is anything other than a 64-bit double. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - Examples: ```js @@ -2184,15 +2195,19 @@ console.log(buf); // Prints: ``` -### buf.writeFloatBE(value, offset[, noAssert]) -### buf.writeFloatLE(value, offset[, noAssert]) +### buf.writeFloatBE(value, offset) +### buf.writeFloatLE(value, offset) * `value` {number} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 4`. -* `noAssert` {boolean} Skip `value` and `offset` validation? **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. Writes `value` to `buf` at the specified `offset` with specified endian @@ -2200,9 +2215,6 @@ format (`writeFloatBE()` writes big endian, `writeFloatLE()` writes little endian). `value` *should* be a valid 32-bit float. Behavior is undefined when `value` is anything other than a 32-bit float. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - Examples: ```js @@ -2219,23 +2231,24 @@ console.log(buf); // Prints: ``` -### buf.writeInt8(value, offset[, noAssert]) +### buf.writeInt8(value, offset) * `value` {integer} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 1`. -* `noAssert` {boolean} Skip `value` and `offset` validation? **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. Writes `value` to `buf` at the specified `offset`. `value` *should* be a valid signed 8-bit integer. Behavior is undefined when `value` is anything other than a signed 8-bit integer. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - `value` is interpreted and written as a two's complement signed integer. Examples: @@ -2250,15 +2263,19 @@ console.log(buf); // Prints: ``` -### buf.writeInt16BE(value, offset[, noAssert]) -### buf.writeInt16LE(value, offset[, noAssert]) +### buf.writeInt16BE(value, offset) +### buf.writeInt16LE(value, offset) * `value` {integer} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 2`. -* `noAssert` {boolean} Skip `value` and `offset` validation? **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. Writes `value` to `buf` at the specified `offset` with specified endian @@ -2266,9 +2283,6 @@ format (`writeInt16BE()` writes big endian, `writeInt16LE()` writes little endian). `value` *should* be a valid signed 16-bit integer. Behavior is undefined when `value` is anything other than a signed 16-bit integer. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - `value` is interpreted and written as a two's complement signed integer. Examples: @@ -2283,15 +2297,19 @@ console.log(buf); // Prints: ``` -### buf.writeInt32BE(value, offset[, noAssert]) -### buf.writeInt32LE(value, offset[, noAssert]) +### buf.writeInt32BE(value, offset) +### buf.writeInt32LE(value, offset) * `value` {integer} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 4`. -* `noAssert` {boolean} Skip `value` and `offset` validation? **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. Writes `value` to `buf` at the specified `offset` with specified endian @@ -2299,9 +2317,6 @@ format (`writeInt32BE()` writes big endian, `writeInt32LE()` writes little endian). `value` *should* be a valid signed 32-bit integer. Behavior is undefined when `value` is anything other than a signed 32-bit integer. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - `value` is interpreted and written as a two's complement signed integer. Examples: @@ -2316,26 +2331,26 @@ console.log(buf); // Prints: ``` -### buf.writeIntBE(value, offset, byteLength[, noAssert]) -### buf.writeIntLE(value, offset, byteLength[, noAssert]) +### buf.writeIntBE(value, offset, byteLength) +### buf.writeIntLE(value, offset, byteLength) * `value` {integer} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - byteLength`. * `byteLength` {integer} Number of bytes to write. Must satisfy: `0 < byteLength <= 6`. -* `noAssert` {boolean} Skip `value`, `offset`, and `byteLength` validation? - **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. Writes `byteLength` bytes of `value` to `buf` at the specified `offset`. Supports up to 48 bits of accuracy. Behavior is undefined when `value` is anything other than a signed integer. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - Examples: ```js @@ -2352,23 +2367,24 @@ console.log(buf); // Prints: ``` -### buf.writeUInt8(value, offset[, noAssert]) +### buf.writeUInt8(value, offset) * `value` {integer} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 1`. -* `noAssert` {boolean} Skip `value` and `offset` validation? **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. Writes `value` to `buf` at the specified `offset`. `value` *should* be a valid unsigned 8-bit integer. Behavior is undefined when `value` is anything other than an unsigned 8-bit integer. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - Examples: ```js @@ -2383,15 +2399,19 @@ console.log(buf); // Prints: ``` -### buf.writeUInt16BE(value, offset[, noAssert]) -### buf.writeUInt16LE(value, offset[, noAssert]) +### buf.writeUInt16BE(value, offset) +### buf.writeUInt16LE(value, offset) * `value` {integer} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 2`. -* `noAssert` {boolean} Skip `value` and `offset` validation? **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. Writes `value` to `buf` at the specified `offset` with specified endian @@ -2399,9 +2419,6 @@ format (`writeUInt16BE()` writes big endian, `writeUInt16LE()` writes little endian). `value` should be a valid unsigned 16-bit integer. Behavior is undefined when `value` is anything other than an unsigned 16-bit integer. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - Examples: ```js @@ -2420,15 +2437,19 @@ console.log(buf); // Prints: ``` -### buf.writeUInt32BE(value, offset[, noAssert]) -### buf.writeUInt32LE(value, offset[, noAssert]) +### buf.writeUInt32BE(value, offset) +### buf.writeUInt32LE(value, offset) * `value` {integer} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - 4`. -* `noAssert` {boolean} Skip `value` and `offset` validation? **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. Writes `value` to `buf` at the specified `offset` with specified endian @@ -2436,9 +2457,6 @@ format (`writeUInt32BE()` writes big endian, `writeUInt32LE()` writes little endian). `value` should be a valid unsigned 32-bit integer. Behavior is undefined when `value` is anything other than an unsigned 32-bit integer. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - Examples: ```js @@ -2455,16 +2473,20 @@ console.log(buf); // Prints: ``` -### buf.writeUIntBE(value, offset, byteLength[, noAssert]) -### buf.writeUIntLE(value, offset, byteLength[, noAssert]) +### buf.writeUIntBE(value, offset, byteLength) +### buf.writeUIntLE(value, offset, byteLength) * `value` {integer} Number to be written to `buf`. * `offset` {integer} Number of bytes to skip before starting to write. Must satisfy: `0 <= offset <= buf.length - byteLength`. * `byteLength` {integer} Number of bytes to write. Must satisfy: `0 < byteLength <= 6`. -* `noAssert` {boolean} Skip `value`, `offset`, and `byteLength` validation? **Default:** `false` * Returns: {integer} `offset` plus the number of bytes written. @@ -2472,9 +2494,6 @@ Writes `byteLength` bytes of `value` to `buf` at the specified `offset`. Supports up to 48 bits of accuracy. Behavior is undefined when `value` is anything other than an unsigned integer. -Setting `noAssert` to `true` allows the encoded form of `value` to extend beyond -the end of `buf`, but the resulting behavior is undefined. - Examples: ```js -- cgit v1.2.3