Skip to content

Commit

Permalink
querystring: improve unescapeBuffer() performance
Browse files Browse the repository at this point in the history
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 <jasnell@gmail.com>
Reviewed-By: Roman Reiss <me@silverwind.io>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
mscdex authored and rvagg committed Feb 15, 2016
1 parent 301023b commit 27e323e
Showing 1 changed file with 27 additions and 31 deletions.
58 changes: 27 additions & 31 deletions lib/querystring.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,59 @@ const QueryString = exports;
const Buffer = require('buffer').Buffer;


function charCode(c) {
return c.charCodeAt(0);
}


// a safe fast alternative to decodeURIComponent
QueryString.unescapeBuffer = function(s, decodeSpaces) {
var out = new Buffer(s.length);
var state = 'CHAR'; // states: CHAR, HEX0, HEX1
var state = 0;
var n, m, hexchar;

for (var inIndex = 0, outIndex = 0; inIndex <= s.length; inIndex++) {
var c = s.charCodeAt(inIndex);
var c = inIndex < s.length ? s.charCodeAt(inIndex) : NaN;
switch (state) {
case 'CHAR':
case 0: // Any character
switch (c) {
case charCode('%'):
case 37: // '%'
n = 0;
m = 0;
state = 'HEX0';
state = 1;
break;
case charCode('+'):
if (decodeSpaces) c = charCode(' ');
case 43: // '+'
if (decodeSpaces)
c = 32; // ' '
// falls through
default:
out[outIndex++] = c;
break;
}
break;

case 'HEX0':
state = 'HEX1';
case 1: // First hex digit
hexchar = c;
if (charCode('0') <= c && c <= charCode('9')) {
n = c - charCode('0');
} else if (charCode('a') <= c && c <= charCode('f')) {
n = c - charCode('a') + 10;
} else if (charCode('A') <= c && c <= charCode('F')) {
n = c - charCode('A') + 10;
if (c >= 48/*0*/ && c <= 57/*9*/) {
n = c - 48/*0*/;
} else if (c >= 65/*A*/ && c <= 70/*F*/) {
n = c - 65/*A*/ + 10;
} else if (c >= 97/*a*/ && c <= 102/*f*/) {
n = c - 97/*a*/ + 10;
} else {
out[outIndex++] = charCode('%');
out[outIndex++] = 37/*%*/;
out[outIndex++] = c;
state = 'CHAR';
state = 0;
break;
}
state = 2;
break;

case 'HEX1':
state = 'CHAR';
if (charCode('0') <= c && c <= charCode('9')) {
m = c - charCode('0');
} else if (charCode('a') <= c && c <= charCode('f')) {
m = c - charCode('a') + 10;
} else if (charCode('A') <= c && c <= charCode('F')) {
m = c - charCode('A') + 10;
case 2: // Second hex digit
state = 0;
if (c >= 48/*0*/ && c <= 57/*9*/) {
m = c - 48/*0*/;
} else if (c >= 65/*A*/ && c <= 70/*F*/) {
m = c - 65/*A*/ + 10;
} else if (c >= 97/*a*/ && c <= 102/*f*/) {
m = c - 97/*a*/ + 10;
} else {
out[outIndex++] = charCode('%');
out[outIndex++] = 37/*%*/;
out[outIndex++] = hexchar;
out[outIndex++] = c;
break;
Expand Down

0 comments on commit 27e323e

Please sign in to comment.