Skip to content

Commit 27e323e

Browse files
mscdexrvagg
authored andcommitted
querystring: improve unescapeBuffer() performance
Before this, v8 would deopt when an out of bounds `inIndex` would get passed to charCodeAt(). charCodeAt() returns NaN in such cases, so we directly emulate that behavior as well. Also, calls to charCodeAt() for constant strings have been replaced by the raw character codes and parser state is now stored as an integer instead of a string. Both of these provide a slight performance increase. PR-URL: #5012 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Roman Reiss <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent 301023b commit 27e323e

File tree

1 file changed

+27
-31
lines changed

1 file changed

+27
-31
lines changed

lib/querystring.js

+27-31
Original file line numberDiff line numberDiff line change
@@ -6,63 +6,59 @@ const QueryString = exports;
66
const Buffer = require('buffer').Buffer;
77

88

9-
function charCode(c) {
10-
return c.charCodeAt(0);
11-
}
12-
13-
149
// a safe fast alternative to decodeURIComponent
1510
QueryString.unescapeBuffer = function(s, decodeSpaces) {
1611
var out = new Buffer(s.length);
17-
var state = 'CHAR'; // states: CHAR, HEX0, HEX1
12+
var state = 0;
1813
var n, m, hexchar;
1914

2015
for (var inIndex = 0, outIndex = 0; inIndex <= s.length; inIndex++) {
21-
var c = s.charCodeAt(inIndex);
16+
var c = inIndex < s.length ? s.charCodeAt(inIndex) : NaN;
2217
switch (state) {
23-
case 'CHAR':
18+
case 0: // Any character
2419
switch (c) {
25-
case charCode('%'):
20+
case 37: // '%'
2621
n = 0;
2722
m = 0;
28-
state = 'HEX0';
23+
state = 1;
2924
break;
30-
case charCode('+'):
31-
if (decodeSpaces) c = charCode(' ');
25+
case 43: // '+'
26+
if (decodeSpaces)
27+
c = 32; // ' '
3228
// falls through
3329
default:
3430
out[outIndex++] = c;
3531
break;
3632
}
3733
break;
3834

39-
case 'HEX0':
40-
state = 'HEX1';
35+
case 1: // First hex digit
4136
hexchar = c;
42-
if (charCode('0') <= c && c <= charCode('9')) {
43-
n = c - charCode('0');
44-
} else if (charCode('a') <= c && c <= charCode('f')) {
45-
n = c - charCode('a') + 10;
46-
} else if (charCode('A') <= c && c <= charCode('F')) {
47-
n = c - charCode('A') + 10;
37+
if (c >= 48/*0*/ && c <= 57/*9*/) {
38+
n = c - 48/*0*/;
39+
} else if (c >= 65/*A*/ && c <= 70/*F*/) {
40+
n = c - 65/*A*/ + 10;
41+
} else if (c >= 97/*a*/ && c <= 102/*f*/) {
42+
n = c - 97/*a*/ + 10;
4843
} else {
49-
out[outIndex++] = charCode('%');
44+
out[outIndex++] = 37/*%*/;
5045
out[outIndex++] = c;
51-
state = 'CHAR';
46+
state = 0;
5247
break;
5348
}
49+
state = 2;
5450
break;
5551

56-
case 'HEX1':
57-
state = 'CHAR';
58-
if (charCode('0') <= c && c <= charCode('9')) {
59-
m = c - charCode('0');
60-
} else if (charCode('a') <= c && c <= charCode('f')) {
61-
m = c - charCode('a') + 10;
62-
} else if (charCode('A') <= c && c <= charCode('F')) {
63-
m = c - charCode('A') + 10;
52+
case 2: // Second hex digit
53+
state = 0;
54+
if (c >= 48/*0*/ && c <= 57/*9*/) {
55+
m = c - 48/*0*/;
56+
} else if (c >= 65/*A*/ && c <= 70/*F*/) {
57+
m = c - 65/*A*/ + 10;
58+
} else if (c >= 97/*a*/ && c <= 102/*f*/) {
59+
m = c - 97/*a*/ + 10;
6460
} else {
65-
out[outIndex++] = charCode('%');
61+
out[outIndex++] = 37/*%*/;
6662
out[outIndex++] = hexchar;
6763
out[outIndex++] = c;
6864
break;

0 commit comments

Comments
 (0)