Skip to content

Commit 6f70ab2

Browse files
committed
Optimize Base64Decode: pre-allocate buffer, decode 4 chars at a time, branchless loop
1 parent 62cb469 commit 6f70ab2

File tree

1 file changed

+39
-25
lines changed

1 file changed

+39
-25
lines changed

test/abstractServer.cpp

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -94,34 +94,48 @@ void AbstractServer::ResetConnectionCount() {
9494
unique_connections.clear();
9595
}
9696

97-
static const std::string base64_chars =
98-
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
99-
"abcdefghijklmnopqrstuvwxyz"
100-
"0123456789+/";
101-
/**
102-
* Decodes the given BASE64 string to a normal string.
103-
* Source: https://gist.github.com/williamdes/308b95ac9ef1ee89ae0143529c361d37
104-
**/
105-
std::string AbstractServer::Base64Decode(const std::string& in) {
106-
std::string out;
10797

108-
std::vector<int> T(256, -1);
109-
for (size_t i = 0; i < 64; i++)
110-
T[base64_chars[i]] = static_cast<int>(i);
98+
std::string AbstractServer::Base64Decode(const std::string& in) {
99+
static const unsigned char T[256] = []{
100+
unsigned char t[256];
101+
std::fill(std::begin(t), std::end(t), 0xFF);
102+
static const char base64_chars[] =
103+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
104+
"abcdefghijklmnopqrstuvwxyz"
105+
"0123456789+/";
106+
for (int i = 0; i < 64; i++)
107+
t[static_cast<unsigned char>(base64_chars[i])] = i;
108+
return t;
109+
}();
110+
111+
size_t in_len = in.size();
112+
if (in_len % 4 != 0) return {}; // invalid
113+
114+
size_t out_len = in_len / 4 * 3;
115+
if (in_len && in[in_len - 1] == '=') out_len--;
116+
if (in_len > 1 && in[in_len - 2] == '=') out_len--;
117+
118+
std::string out(out_len, '\0');
119+
size_t o = 0;
120+
121+
for (size_t i = 0; i < in_len; i += 4) {
122+
uint32_t n = (T[(unsigned char)in[i]] << 18) |
123+
(T[(unsigned char)in[i+1]] << 12) |
124+
(T[(unsigned char)in[i+2]] << 6) |
125+
(T[(unsigned char)in[i+3]]);
126+
127+
// we always write 3 bytes
128+
out[o++] = (n >> 16) & 0xFF;
129+
out[o++] = (n >> 8) & 0xFF;
130+
out[o++] = n & 0xFF;
131+
}
111132

112-
int val = 0;
113-
int valb = -8;
114-
for (unsigned char c : in) {
115-
if (T[c] == -1) {
116-
break;
117-
}
118-
val = (val << 6) + T[c];
119-
valb += 6;
120-
if (valb >= 0) {
121-
out.push_back(char((val >> valb) & 0xFF));
122-
valb -= 8;
123-
}
133+
// fix for padding '='
134+
if (in_len >= 2) {
135+
if (in[in_len - 1] == '=') out.pop_back();
136+
if (in[in_len - 2] == '=') out.pop_back();
124137
}
138+
125139
return out;
126140
}
127141

0 commit comments

Comments
 (0)