buffer: optimize toString()
PR-URL: https://github.com/nodejs/node/pull/12361 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
4a86803f60
commit
3ee4a1a281
@ -3,25 +3,47 @@
|
||||
const common = require('../common.js');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
arg: ['true', 'false'],
|
||||
encoding: ['', 'utf8', 'ascii', 'latin1', 'binary', 'hex', 'UCS-2'],
|
||||
args: [0, 1, 2, 3],
|
||||
len: [0, 1, 64, 1024],
|
||||
n: [1e7]
|
||||
});
|
||||
|
||||
function main(conf) {
|
||||
const arg = conf.arg === 'true';
|
||||
var encoding = conf.encoding;
|
||||
const args = conf.args | 0;
|
||||
const len = conf.len | 0;
|
||||
const n = conf.n | 0;
|
||||
const buf = Buffer.alloc(len, 42);
|
||||
|
||||
if (encoding.length === 0)
|
||||
encoding = undefined;
|
||||
|
||||
var i;
|
||||
bench.start();
|
||||
if (arg) {
|
||||
for (i = 0; i < n; i += 1)
|
||||
buf.toString('utf8');
|
||||
} else {
|
||||
for (i = 0; i < n; i += 1)
|
||||
buf.toString();
|
||||
switch (args) {
|
||||
case 1:
|
||||
bench.start();
|
||||
for (i = 0; i < n; i += 1)
|
||||
buf.toString(encoding);
|
||||
bench.end(n);
|
||||
break;
|
||||
case 2:
|
||||
bench.start();
|
||||
for (i = 0; i < n; i += 1)
|
||||
buf.toString(encoding, 0);
|
||||
bench.end(n);
|
||||
break;
|
||||
case 3:
|
||||
bench.start();
|
||||
for (i = 0; i < n; i += 1)
|
||||
buf.toString(encoding, 0, len);
|
||||
bench.end(n);
|
||||
break;
|
||||
default:
|
||||
bench.start();
|
||||
for (i = 0; i < n; i += 1)
|
||||
buf.toString();
|
||||
bench.end(n);
|
||||
break;
|
||||
}
|
||||
bench.end(n);
|
||||
}
|
||||
|
129
lib/buffer.js
129
lib/buffer.js
@ -483,82 +483,85 @@ Object.defineProperty(Buffer.prototype, 'offset', {
|
||||
});
|
||||
|
||||
|
||||
function slowToString(buf, encoding, start, end) {
|
||||
var loweredCase = false;
|
||||
|
||||
// No need to verify that "buf.length <= MAX_UINT32" since it's a read-only
|
||||
// property of a typed array.
|
||||
|
||||
// This behaves neither like String nor Uint8Array in that we set start/end
|
||||
// to their upper/lower bounds if the value passed is out of range.
|
||||
// undefined is handled specially as per ECMA-262 6th Edition,
|
||||
// Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
|
||||
if (start === undefined || start < 0)
|
||||
start = 0;
|
||||
// Return early if start > buf.length. Done here to prevent potential uint32
|
||||
// coercion fail below.
|
||||
if (start > buf.length)
|
||||
return '';
|
||||
|
||||
if (end === undefined || end > buf.length)
|
||||
end = buf.length;
|
||||
|
||||
if (end <= 0)
|
||||
return '';
|
||||
|
||||
// Force coersion to uint32. This will also coerce falsey/NaN values to 0.
|
||||
end >>>= 0;
|
||||
start >>>= 0;
|
||||
|
||||
if (end <= start)
|
||||
return '';
|
||||
|
||||
if (encoding === undefined) encoding = 'utf8';
|
||||
|
||||
while (true) {
|
||||
switch (encoding) {
|
||||
case 'hex':
|
||||
return buf.hexSlice(start, end);
|
||||
|
||||
case 'utf8':
|
||||
case 'utf-8':
|
||||
return buf.utf8Slice(start, end);
|
||||
|
||||
case 'ascii':
|
||||
return buf.asciiSlice(start, end);
|
||||
|
||||
case 'latin1':
|
||||
case 'binary':
|
||||
function stringSlice(buf, encoding, start, end) {
|
||||
if (encoding === undefined) return buf.utf8Slice(start, end);
|
||||
encoding += '';
|
||||
switch (encoding.length) {
|
||||
case 4:
|
||||
if (encoding === 'utf8') return buf.utf8Slice(start, end);
|
||||
if (encoding === 'ucs2') return buf.ucs2Slice(start, end);
|
||||
encoding = encoding.toLowerCase();
|
||||
if (encoding === 'utf8') return buf.utf8Slice(start, end);
|
||||
if (encoding === 'ucs2') return buf.ucs2Slice(start, end);
|
||||
break;
|
||||
case 5:
|
||||
if (encoding === 'utf-8') return buf.utf8Slice(start, end);
|
||||
if (encoding === 'ascii') return buf.asciiSlice(start, end);
|
||||
if (encoding === 'ucs-2') return buf.ucs2Slice(start, end);
|
||||
encoding = encoding.toLowerCase();
|
||||
if (encoding === 'utf-8') return buf.utf8Slice(start, end);
|
||||
if (encoding === 'ascii') return buf.asciiSlice(start, end);
|
||||
if (encoding === 'ucs-2') return buf.ucs2Slice(start, end);
|
||||
break;
|
||||
case 6:
|
||||
if (encoding === 'latin1' || encoding === 'binary')
|
||||
return buf.latin1Slice(start, end);
|
||||
|
||||
case 'base64':
|
||||
return buf.base64Slice(start, end);
|
||||
|
||||
case 'ucs2':
|
||||
case 'ucs-2':
|
||||
case 'utf16le':
|
||||
case 'utf-16le':
|
||||
if (encoding === 'base64') return buf.base64Slice(start, end);
|
||||
encoding = encoding.toLowerCase();
|
||||
if (encoding === 'latin1' || encoding === 'binary')
|
||||
return buf.latin1Slice(start, end);
|
||||
if (encoding === 'base64') return buf.base64Slice(start, end);
|
||||
break;
|
||||
case 3:
|
||||
if (encoding === 'hex' || encoding.toLowerCase() === 'hex')
|
||||
return buf.hexSlice(start, end);
|
||||
break;
|
||||
case 7:
|
||||
if (encoding === 'utf16le' || encoding.toLowerCase() === 'utf16le')
|
||||
return buf.ucs2Slice(start, end);
|
||||
|
||||
default:
|
||||
if (loweredCase)
|
||||
throw new TypeError('Unknown encoding: ' + encoding);
|
||||
encoding = (encoding + '').toLowerCase();
|
||||
loweredCase = true;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (encoding === 'utf-16le' || encoding.toLowerCase() === 'utf-16le')
|
||||
return buf.ucs2Slice(start, end);
|
||||
break;
|
||||
}
|
||||
throw new TypeError('Unknown encoding: ' + encoding);
|
||||
}
|
||||
|
||||
|
||||
Buffer.prototype.copy = function(target, targetStart, sourceStart, sourceEnd) {
|
||||
return binding.copy(this, target, targetStart, sourceStart, sourceEnd);
|
||||
};
|
||||
|
||||
// No need to verify that "buf.length <= MAX_UINT32" since it's a read-only
|
||||
// property of a typed array.
|
||||
// This behaves neither like String nor Uint8Array in that we set start/end
|
||||
// to their upper/lower bounds if the value passed is out of range.
|
||||
Buffer.prototype.toString = function(encoding, start, end) {
|
||||
let result;
|
||||
var result;
|
||||
if (arguments.length === 0) {
|
||||
result = this.utf8Slice(0, this.length);
|
||||
} else {
|
||||
result = slowToString(this, encoding, start, end);
|
||||
const len = this.length;
|
||||
if (len === 0)
|
||||
return '';
|
||||
|
||||
if (!start || start < 0)
|
||||
start = 0;
|
||||
else if (start >= len)
|
||||
return '';
|
||||
|
||||
if (end === undefined || end > len)
|
||||
end = len;
|
||||
else if (end <= 0)
|
||||
return '';
|
||||
|
||||
start |= 0;
|
||||
end |= 0;
|
||||
|
||||
if (end <= start)
|
||||
return '';
|
||||
result = stringSlice(this, encoding, start, end);
|
||||
}
|
||||
if (result === undefined)
|
||||
throw new Error('"toString()" failed');
|
||||
|
Loading…
x
Reference in New Issue
Block a user