Skip to content

Commit 2f7fa2b

Browse files
committed
Improve enc.Base64 parse performance by x10.
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.
1 parent 8940297 commit 2f7fa2b

File tree

1 file changed

+24
-13
lines changed

1 file changed

+24
-13
lines changed

src/enc-base64.js

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,32 +73,43 @@
7373
// Shortcuts
7474
var base64StrLength = base64Str.length;
7575
var map = this._map;
76+
var reverseMap = this._reverseMap;
77+
78+
if (!reverseMap) {
79+
reverseMap = this._reverseMap = [];
80+
for (var j = 0; j < map.length; j++) {
81+
reverseMap[map.charCodeAt(j)] = j;
82+
}
83+
}
7684

7785
// Ignore padding
7886
var paddingChar = map.charAt(64);
7987
if (paddingChar) {
8088
var paddingIndex = base64Str.indexOf(paddingChar);
81-
if (paddingIndex != -1) {
89+
if (paddingIndex !== -1) {
8290
base64StrLength = paddingIndex;
8391
}
8492
}
8593

8694
// Convert
87-
var words = [];
88-
var nBytes = 0;
89-
for (var i = 0; i < base64StrLength; i++) {
90-
if (i % 4) {
91-
var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2);
92-
var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2);
93-
var bitsCombined = bits1 | bits2;
94-
words[nBytes >>> 2] |= (bitsCombined) << (24 - (nBytes % 4) * 8);
95-
nBytes++;
96-
}
97-
}
95+
return parseLoop(base64Str, base64StrLength, reverseMap);
9896

99-
return WordArray.create(words, nBytes);
10097
},
10198

10299
_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
103100
};
101+
102+
function parseLoop(base64Str, base64StrLength, reverseMap) {
103+
var words = [];
104+
var nBytes = 0;
105+
for (var i = 0; i < base64StrLength; i++) {
106+
if (i % 4) {
107+
var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2);
108+
var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2);
109+
words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8);
110+
nBytes++;
111+
}
112+
}
113+
return WordArray.create(words, nBytes);
114+
}
104115
}());

0 commit comments

Comments
 (0)