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