Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 805ebef

Browse filesBrowse files
aqrlnItalo A. Casas
authored andcommitted
buffer: optimize decoding wrapped base64 data
The fast base64 decoder used to switch to the slow one permanently when it saw a whitespace or other garbage character. Since the most common situation such characters may be encountered in is line-wrapped base64 data, a more profitable strategy is to decode a single 24-bit group with the slow decoder and then continue running the fast algorithm. PR-URL: #12146 Ref: #12114 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent fb34d9c commit 805ebef
Copy full SHA for 805ebef

File tree

Expand file treeCollapse file tree

2 files changed

+61
-34
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+61
-34
lines changed
Open diff view settings
Collapse file
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
5+
const bench = common.createBenchmark(main, {
6+
n: [32],
7+
});
8+
9+
function main(conf) {
10+
const n = +conf.n;
11+
const charsPerLine = 76;
12+
const linesCount = 8 << 16;
13+
const bytesCount = charsPerLine * linesCount / 4 * 3;
14+
15+
const line = 'abcd'.repeat(charsPerLine / 4) + '\n';
16+
const data = line.repeat(linesCount);
17+
// eslint-disable-next-line no-unescaped-regexp-dot
18+
data.match(/./); // Flatten the string
19+
const buffer = Buffer.alloc(bytesCount, line, 'base64');
20+
21+
bench.start();
22+
for (var i = 0; i < n; i++) {
23+
buffer.base64Write(data, 0, bytesCount);
24+
}
25+
bench.end(n);
26+
}
Collapse file

‎src/base64.h‎

Copy file name to clipboardExpand all lines: src/base64.h
+35-34Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -52,36 +52,33 @@ extern const int8_t unbase64_table[256];
5252

5353

5454
template <typename TypeName>
55-
size_t base64_decode_slow(char* dst, size_t dstlen,
56-
const TypeName* src, size_t srclen) {
55+
bool base64_decode_group_slow(char* const dst, const size_t dstlen,
56+
const TypeName* const src, const size_t srclen,
57+
size_t* const i, size_t* const k) {
5758
uint8_t hi;
5859
uint8_t lo;
59-
size_t i = 0;
60-
size_t k = 0;
61-
for (;;) {
6260
#define V(expr) \
63-
for (;;) { \
64-
const uint8_t c = src[i]; \
65-
lo = unbase64(c); \
66-
i += 1; \
67-
if (lo < 64) \
68-
break; /* Legal character. */ \
69-
if (c == '=' || i >= srclen) \
70-
return k; \
71-
} \
72-
expr; \
73-
if (i >= srclen) \
74-
return k; \
75-
if (k >= dstlen) \
76-
return k; \
77-
hi = lo;
78-
V(/* Nothing. */);
79-
V(dst[k++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4));
80-
V(dst[k++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2));
81-
V(dst[k++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0));
61+
for (;;) { \
62+
const uint8_t c = src[*i]; \
63+
lo = unbase64(c); \
64+
*i += 1; \
65+
if (lo < 64) \
66+
break; /* Legal character. */ \
67+
if (c == '=' || *i >= srclen) \
68+
return false; /* Stop decoding. */ \
69+
} \
70+
expr; \
71+
if (*i >= srclen) \
72+
return false; \
73+
if (*k >= dstlen) \
74+
return false; \
75+
hi = lo;
76+
V(/* Nothing. */);
77+
V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4));
78+
V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2));
79+
V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0));
8280
#undef V
83-
}
84-
UNREACHABLE();
81+
return true; // Continue decoding.
8582
}
8683

8784

@@ -90,8 +87,8 @@ size_t base64_decode_fast(char* const dst, const size_t dstlen,
9087
const TypeName* const src, const size_t srclen,
9188
const size_t decoded_size) {
9289
const size_t available = dstlen < decoded_size ? dstlen : decoded_size;
93-
const size_t max_i = srclen / 4 * 4;
9490
const size_t max_k = available / 3 * 3;
91+
size_t max_i = srclen / 4 * 4;
9592
size_t i = 0;
9693
size_t k = 0;
9794
while (i < max_i && k < max_k) {
@@ -102,16 +99,20 @@ size_t base64_decode_fast(char* const dst, const size_t dstlen,
10299
unbase64(src[i + 3]);
103100
// If MSB is set, input contains whitespace or is not valid base64.
104101
if (v & 0x80808080) {
105-
break;
102+
const size_t old_i = i;
103+
if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k))
104+
return k;
105+
max_i = old_i + (srclen - i) / 4 * 4; // Align max_i again.
106+
} else {
107+
dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03);
108+
dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F);
109+
dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F);
110+
i += 4;
111+
k += 3;
106112
}
107-
dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03);
108-
dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F);
109-
dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F);
110-
i += 4;
111-
k += 3;
112113
}
113114
if (i < srclen && k < dstlen) {
114-
return k + base64_decode_slow(dst + k, dstlen - k, src + i, srclen - i);
115+
base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k);
115116
}
116117
return k;
117118
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.