diff options
author | Brian White <mscdex@mscdex.net> | 2017-04-10 05:03:57 -0400 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2017-04-14 22:35:59 +0200 |
commit | 4a86803f6005cc0b67a093fb852109b343cb8654 (patch) | |
tree | 11a1f4cbd125f1cc5cd1c15ff1a6cc71e3f2672e /lib | |
parent | 46f202690b83bda6ba4b49291a8fd107f7ef1496 (diff) | |
download | android-node-v8-4a86803f6005cc0b67a093fb852109b343cb8654.tar.gz android-node-v8-4a86803f6005cc0b67a093fb852109b343cb8654.tar.bz2 android-node-v8-4a86803f6005cc0b67a093fb852109b343cb8654.zip |
buffer: optimize from() and byteLength()
PR-URL: https://github.com/nodejs/node/pull/12361
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/buffer.js | 156 | ||||
-rw-r--r-- | lib/util.js | 5 |
2 files changed, 92 insertions, 69 deletions
diff --git a/lib/buffer.js b/lib/buffer.js index 05e0b74033..0469f4147e 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -23,8 +23,7 @@ const binding = process.binding('buffer'); const { compare: compare_, compareOffset } = binding; -const { isArrayBuffer, isSharedArrayBuffer, isUint8Array } = - process.binding('util'); +const { isAnyArrayBuffer, isUint8Array } = process.binding('util'); const bindingObj = {}; const internalUtil = require('internal/util'); @@ -116,16 +115,19 @@ function Buffer(arg, encodingOrOffset, length) { * Buffer.from(arrayBuffer[, byteOffset[, length]]) **/ Buffer.from = function(value, encodingOrOffset, length) { - if (typeof value === 'number') - throw new TypeError('"value" argument must not be a number'); + if (typeof value === 'string') + return fromString(value, encodingOrOffset); - if (isArrayBuffer(value) || isSharedArrayBuffer(value)) + if (isAnyArrayBuffer(value)) return fromArrayBuffer(value, encodingOrOffset, length); - if (typeof value === 'string') - return fromString(value, encodingOrOffset); + var b = fromObject(value); + if (b) + return b; - return fromObject(value); + if (typeof value === 'number') + throw new TypeError('"value" argument must not be a number'); + throw new TypeError(kFromErrorMsg); }; Object.setPrototypeOf(Buffer, Uint8Array); @@ -218,16 +220,19 @@ function allocate(size) { function fromString(string, encoding) { - if (typeof encoding !== 'string' || encoding === '') + var length; + if (typeof encoding !== 'string' || encoding.length === 0) { encoding = 'utf8'; - - if (!Buffer.isEncoding(encoding)) - throw new TypeError('"encoding" must be a valid string encoding'); - - if (string.length === 0) - return new FastBuffer(); - - var length = byteLength(string, encoding); + if (string.length === 0) + return new FastBuffer(); + length = binding.byteLengthUtf8(string); + } else { + length = byteLength(string, encoding, true); + if (length === -1) + throw new TypeError('"encoding" must be a valid string encoding'); + if (string.length === 0) + return new FastBuffer(); + } if (length >= (Buffer.poolSize >>> 1)) return binding.createFromString(string, encoding); @@ -235,7 +240,7 @@ function fromString(string, encoding) { if (length > (poolSize - poolOffset)) createPool(); var b = new FastBuffer(allocPool, poolOffset, length); - var actual = b.write(string, encoding); + const actual = b.write(string, encoding); if (actual !== length) { // byteLength() may overestimate. That's a rare case, though. b = new FastBuffer(allocPool, poolOffset, actual); @@ -255,8 +260,14 @@ function fromArrayLike(obj) { function fromArrayBuffer(obj, byteOffset, length) { // convert byteOffset to integer - byteOffset = +byteOffset; - byteOffset = byteOffset ? Math.trunc(byteOffset) : 0; + if (byteOffset === undefined) { + byteOffset = 0; + } else { + byteOffset = +byteOffset; + // check for NaN + if (byteOffset !== byteOffset) + byteOffset = 0; + } const maxLength = obj.byteLength - byteOffset; @@ -268,11 +279,17 @@ function fromArrayBuffer(obj, byteOffset, length) { } else { // convert length to non-negative integer length = +length; - length = length ? Math.trunc(length) : 0; - length = length <= 0 ? 0 : Math.min(length, Number.MAX_SAFE_INTEGER); - - if (length > maxLength) - throw new RangeError("'length' is out of bounds"); + // Check for NaN + if (length !== length) { + length = 0; + } else if (length > 0) { + length = (length < Number.MAX_SAFE_INTEGER ? + length : Number.MAX_SAFE_INTEGER); + if (length > maxLength) + throw new RangeError("'length' is out of bounds"); + } else { + length = 0; + } } return new FastBuffer(obj, byteOffset, length); @@ -289,9 +306,8 @@ function fromObject(obj) { return b; } - if (obj) { - if (obj.length !== undefined || isArrayBuffer(obj.buffer) || - isSharedArrayBuffer(obj.buffer)) { + if (obj != undefined) { + if (obj.length !== undefined || isAnyArrayBuffer(obj.buffer)) { if (typeof obj.length !== 'number' || obj.length !== obj.length) { return new FastBuffer(); } @@ -302,8 +318,6 @@ function fromObject(obj) { return fromArrayLike(obj.data); } } - - throw new TypeError(kFromErrorMsg); } @@ -388,53 +402,63 @@ function base64ByteLength(str, bytes) { function byteLength(string, encoding) { if (typeof string !== 'string') { - if (ArrayBuffer.isView(string) || isArrayBuffer(string) || - isSharedArrayBuffer(string)) { + if (ArrayBuffer.isView(string) || isAnyArrayBuffer(string)) { return string.byteLength; } throw new TypeError('"string" must be a string, Buffer, or ArrayBuffer'); } - var len = string.length; - if (len === 0) + const len = string.length; + const mustMatch = (arguments.length > 2 && arguments[2] === true); + if (!mustMatch && len === 0) return 0; - // Use a for loop to avoid recursion - var loweredCase = false; - for (;;) { - switch (encoding) { - case 'ascii': - case 'latin1': - case 'binary': - return len; - - case 'utf8': - case 'utf-8': - case undefined: - return binding.byteLengthUtf8(string); - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': + if (!encoding) + return (mustMatch ? -1 : binding.byteLengthUtf8(string)); + + encoding += ''; + switch (encoding.length) { + case 4: + if (encoding === 'utf8') return binding.byteLengthUtf8(string); + if (encoding === 'ucs2') return len * 2; + encoding = encoding.toLowerCase(); + if (encoding === 'utf8') return binding.byteLengthUtf8(string); + if (encoding === 'ucs2') return len * 2; + break; + case 5: + if (encoding === 'utf-8') return binding.byteLengthUtf8(string); + if (encoding === 'ascii') return len; + if (encoding === 'ucs-2') return len * 2; + encoding = encoding.toLowerCase(); + if (encoding === 'utf-8') return binding.byteLengthUtf8(string); + if (encoding === 'ascii') return len; + if (encoding === 'ucs-2') return len * 2; + break; + case 7: + if (encoding === 'utf16le' || encoding.toLowerCase() === 'utf16le') return len * 2; - - case 'hex': + break; + case 8: + if (encoding === 'utf-16le' || encoding.toLowerCase() === 'utf-16le') + return len * 2; + break; + case 6: + if (encoding === 'latin1' || encoding === 'binary') return len; + if (encoding === 'base64') return base64ByteLength(string, len); + encoding = encoding.toLowerCase(); + if (encoding === 'latin1' || encoding === 'binary') return len; + if (encoding === 'base64') return base64ByteLength(string, len); + break; + case 3: + if (encoding === 'hex' || encoding.toLowerCase() === 'hex') return len >>> 1; - - case 'base64': - return base64ByteLength(string, len); - - default: - // The C++ binding defaulted to UTF8, we should too. - if (loweredCase) - return binding.byteLengthUtf8(string); - - encoding = ('' + encoding).toLowerCase(); - loweredCase = true; - } + break; } + if (mustMatch) + throw new TypeError('Unknown encoding: ' + encoding); + else + return binding.byteLengthUtf8(string); } Buffer.byteLength = byteLength; diff --git a/lib/util.js b/lib/util.js index 12280e412a..2631f0a2c3 100644 --- a/lib/util.js +++ b/lib/util.js @@ -452,7 +452,7 @@ function formatValue(ctx, value, recurseTimes) { // Fast path for ArrayBuffer and SharedArrayBuffer. // Can't do the same for DataView because it has a non-primitive // .buffer property that we need to recurse for. - if (binding.isArrayBuffer(value) || binding.isSharedArrayBuffer(value)) { + if (binding.isAnyArrayBuffer(value)) { return `${constructor.name}` + ` { byteLength: ${formatNumber(ctx, value.byteLength)} }`; } @@ -494,8 +494,7 @@ function formatValue(ctx, value, recurseTimes) { keys.unshift('size'); empty = value.size === 0; formatter = formatMap; - } else if (binding.isArrayBuffer(value) || - binding.isSharedArrayBuffer(value)) { + } else if (binding.isAnyArrayBuffer(value)) { braces = ['{', '}']; keys.unshift('byteLength'); visibleKeys.byteLength = true; |