Skip to content

Commit a0be723

Browse files
[crispy] base64: provide encoding via state machine based API.
1 parent dfacb3d commit a0be723

File tree

1 file changed

+86
-42
lines changed

1 file changed

+86
-42
lines changed

src/crispy/base64.h

Lines changed: 86 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -42,55 +42,99 @@ namespace detail
4242
};
4343
}
4444

45-
template <typename Iterator, typename Alphabet>
46-
std::string encode(Iterator begin, Iterator end, Alphabet alphabet)
45+
struct EncoderState
4746
{
48-
int const inputLength = static_cast<int>(std::distance(begin, end));
49-
int const outputLength = ((inputLength + 2) / 3 * 4) + 1;
47+
int modulo = 0;
48+
uint8_t pending[3];
49+
};
5050

51-
std::string output;
52-
output.resize(static_cast<unsigned>(outputLength));
51+
template <typename Alphabet, typename Sink>
52+
constexpr void encode(uint8_t _byte, Alphabet const& alphabet, EncoderState& _state, Sink&& _sink)
53+
{
54+
_state.pending[_state.modulo] = _byte;
55+
if (++_state.modulo != 3)
56+
return;
57+
58+
_state.modulo = 0;
59+
uint8_t const* input = _state.pending;
60+
char const out[4] = {
61+
alphabet[(input[0] >> 2) & 0x3F],
62+
alphabet[((input[0] & 0x03) << 4) | ((uint8_t)(input[1] & 0xF0) >> 4)],
63+
alphabet[((input[1] & 0x0F) << 2) | ((uint8_t)(input[2] & 0xC0) >> 6)],
64+
alphabet[input[2] & 0x3F]
65+
};
66+
_sink(std::string_view(out, 4));
67+
}
5368

54-
auto i = 0;
55-
auto const e = inputLength - 2;
56-
auto const input = begin;
57-
auto out = output.begin();
69+
namespace detail
70+
{
5871

59-
while (i < e)
60-
{
61-
*out++ = alphabet[(input[i] >> 2) & 0x3F];
72+
template <typename Alphabet, typename Sink>
73+
constexpr void finish(Alphabet const& alphabet, EncoderState& _state, Sink&& _sink)
74+
{
75+
if (_state.modulo == 0)
76+
return;
6277

63-
*out++ = alphabet[((input[i] & 0x03) << 4) |
64-
((uint8_t)(input[i + 1] & 0xF0) >> 4)];
78+
auto const* input = _state.pending;
6579

66-
*out++ = alphabet[((input[i + 1] & 0x0F) << 2) |
67-
((uint8_t)(input[i + 2] & 0xC0) >> 6)];
80+
switch (_state.modulo)
81+
{
82+
case 2:
83+
{
84+
char const out[4] = {
85+
alphabet[(input[0] >> 2) & 0x3F],
86+
alphabet[((input[0] & 0x03) << 4) | ((uint8_t)(input[1] & 0xF0) >> 4)],
87+
alphabet[((input[1] & 0x0F) << 2)],
88+
'='
89+
};
90+
_sink(std::string_view{out});
91+
}
92+
break;
93+
case 1:
94+
{
95+
char const out[4] = {
96+
alphabet[(input[0] >> 2) & 0x3F],
97+
alphabet[((input[0] & 0x03) << 4)],
98+
'=',
99+
'='
100+
};
101+
_sink(std::string_view{out});
102+
}
103+
break;
104+
case 0:
105+
break;
106+
}
107+
}
68108

69-
*out++ = alphabet[input[i + 2] & 0x3F];
109+
}
70110

71-
i += 3;
72-
}
111+
template <typename Sink>
112+
constexpr void encode(uint8_t _byte, EncoderState& _state, Sink _sink)
113+
{
114+
constexpr char alphabet[] =
115+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
116+
"abcdefghijklmnopqrstuvwxyz"
117+
"0123456789+/";
118+
return encode(_byte, alphabet, _state, std::forward<Sink>(_sink));
119+
//return encode(_byte, detail::indexmap, _state, std::forward<Sink>(_sink));
120+
}
73121

74-
if (i < inputLength)
75-
{
76-
*out++ = alphabet[(input[i] >> 2) & 0x3F];
122+
template <typename Sink>
123+
constexpr void finish(EncoderState& _state, Sink&& _sink)
124+
{
125+
finish(detail::indexmap, _state, std::forward<Sink>(_sink));
126+
}
77127

78-
if (i == (inputLength - 1))
79-
{
80-
*out++ = alphabet[((input[i] & 0x03) << 4)];
81-
*out++ = '=';
82-
}
83-
else
84-
{
85-
*out++ = alphabet[((input[i] & 0x03) << 4) |
86-
((uint8_t)(input[i + 1] & 0xF0) >> 4)];
87-
*out++ = alphabet[((input[i + 1] & 0x0F) << 2)];
88-
}
89-
*out++ = '=';
90-
}
128+
template <typename Iterator, typename Alphabet>
129+
std::string encode(Iterator begin, Iterator end, Alphabet const& alphabet)
130+
{
131+
std::string output;
132+
output.reserve(((std::distance(begin, end) + 2) / 3 * 4) + 1);
91133

92-
auto const outlen = std::distance(output.begin(), out);
93-
output.resize(static_cast<unsigned>(outlen));
134+
EncoderState state{};
135+
for (auto i = begin; i != end; ++i)
136+
encode(*i, alphabet, state, [&](std::string_view _data) { output += _data; });
137+
detail::finish(alphabet, state, [&](std::string_view _data) { output += _data; });
94138

95139
return output;
96140
}
@@ -106,9 +150,9 @@ std::string encode(Iterator begin, Iterator end)
106150
}
107151

108152

109-
inline std::string encode(const std::string_view& value)
153+
inline std::string encode(std::string_view _value)
110154
{
111-
return encode(value.begin(), value.end());
155+
return encode(_value.begin(), _value.end());
112156
}
113157

114158
template <typename Iterator, typename IndexTable>
@@ -195,12 +239,12 @@ size_t decode(Iterator begin, Iterator end, Output output)
195239
}
196240

197241
template <typename Output>
198-
size_t decode(std::string_view const& input, Output output)
242+
size_t decode(std::string_view input, Output output)
199243
{
200244
return decode(input.begin(), input.end(), output);
201245
}
202246

203-
inline std::string decode(const std::string_view& input)
247+
inline std::string decode(std::string_view input)
204248
{
205249
std::string output;
206250
output.resize(decodeLength(input));

0 commit comments

Comments
 (0)