Skip to content

Commit

Permalink
Improve enc.Base64 parse performance by x10.
Browse files Browse the repository at this point in the history
I replaced the linear map.indexOf() lookup with a reverse lookup table (an
array of charCodes turned out to be significantly faster than an object
with actual char keys, even though both are O(1)), for a speedup of about
x2 on large-ish strings.  The change is compatible with reuses of
enc.Base64 that provide a different map.

I also extracted the inner loop into its own function, since for some
reason Chrome was consistently de-optimizing the parse function when the
loop was embedded in it.  This way, both functions get optimized for an
additional speedup of about x5 in my tests.
  • Loading branch information
pkaminski committed Oct 12, 2016
1 parent 8940297 commit 2f7fa2b
Showing 1 changed file with 24 additions and 13 deletions.
37 changes: 24 additions & 13 deletions src/enc-base64.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,32 +73,43 @@
// Shortcuts
var base64StrLength = base64Str.length;
var map = this._map;
var reverseMap = this._reverseMap;

if (!reverseMap) {
reverseMap = this._reverseMap = [];
for (var j = 0; j < map.length; j++) {
reverseMap[map.charCodeAt(j)] = j;
}
}

// Ignore padding
var paddingChar = map.charAt(64);
if (paddingChar) {
var paddingIndex = base64Str.indexOf(paddingChar);
if (paddingIndex != -1) {
if (paddingIndex !== -1) {
base64StrLength = paddingIndex;
}
}

// Convert
var words = [];
var nBytes = 0;
for (var i = 0; i < base64StrLength; i++) {
if (i % 4) {
var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2);
var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2);
var bitsCombined = bits1 | bits2;
words[nBytes >>> 2] |= (bitsCombined) << (24 - (nBytes % 4) * 8);
nBytes++;
}
}
return parseLoop(base64Str, base64StrLength, reverseMap);

return WordArray.create(words, nBytes);
},

_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
};

function parseLoop(base64Str, base64StrLength, reverseMap) {
var words = [];
var nBytes = 0;
for (var i = 0; i < base64StrLength; i++) {
if (i % 4) {
var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2);
var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2);
words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8);
nBytes++;
}
}
return WordArray.create(words, nBytes);
}
}());

0 comments on commit 2f7fa2b

Please sign in to comment.