5#include "../byte_string.hpp"
6#include "../required.hpp"
7#include "../assert.hpp"
23 bool case_insensitive;
33 template<
size_t StringLength>
35 char const (&str)[StringLength],
36 bool case_insensitive = StringLength <= 33,
37 char padding_char =
'\0') noexcept :
38 radix(narrow_cast<
long long>(StringLength - 1)), case_insensitive(case_insensitive), padding_char(padding_char)
40 static_assert(StringLength < 128);
43 for (
long long i = 0; i != 256; ++i) {
44 int_from_char_table[i] = -2;
48 int_from_char_table[narrow_cast<size_t>(
' ')] = -1;
49 int_from_char_table[narrow_cast<size_t>(
'\t')] = -1;
50 int_from_char_table[narrow_cast<size_t>(
'\r')] = -1;
51 int_from_char_table[narrow_cast<size_t>(
'\n')] = -1;
52 int_from_char_table[narrow_cast<size_t>(
'\f')] = -1;
54 if (padding_char != 0) {
55 int_from_char_table[narrow_cast<size_t>(padding_char)] = -1;
58 for (
long long i = 0; i != radix; ++i) {
60 char_from_int_table[i] = c;
62 int_from_char_table[narrow_cast<size_t>(c)] = narrow_cast<int8_t>(i);
63 if constexpr (StringLength <= 33) {
65 if (c >=
'a' && c <=
'z') {
66 int_from_char_table[narrow_cast<size_t>((c -
'a') +
'A')] = narrow_cast<int8_t>(i);
67 }
else if (c >=
'A' && c <=
'Z') {
68 int_from_char_table[narrow_cast<size_t>((c -
'A') +
'a')] = narrow_cast<int8_t>(i);
80 return char_from_int_table[x];
83 constexpr int8_t int_from_char(
char c)
const noexcept
85 return int_from_char_table[narrow_cast<size_t>(c)];
89constexpr auto base2_alphabet = base_n_alphabet{
"01"};
91constexpr auto base8_alphabet = base_n_alphabet{
"01234567"};
93constexpr auto base10_alphabet = base_n_alphabet{
"0123456789"};
95constexpr auto base16_alphabet = base_n_alphabet{
"0123456789ABCDEF"};
97constexpr auto base32_rfc4648_alphabet = base_n_alphabet{
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"};
99constexpr auto base32hex_rfc4648_alphabet = base_n_alphabet{
"0123456789ABCDEFGHIJKLMNOPQRSTUV"};
101constexpr auto base64_rfc4648_alphabet =
102 base_n_alphabet{
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
false,
'='};
104constexpr auto base64url_rfc4648_alphabet =
105 base_n_alphabet{
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
false,
'='};
107constexpr auto base85_rfc1924_alphabet =
108 base_n_alphabet{
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"};
110constexpr auto base85_btoa_alphabet =
111 base_n_alphabet{
"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu"};
115template<detail::base_n_alphabet Alphabet,
int CharsPerBlock,
int BytesPerBlock>
119 static constexpr char padding_char = alphabet.padding_char;
120 static constexpr long long radix = alphabet.radix;
121 static constexpr long long bytes_per_block = BytesPerBlock;
122 static constexpr long long chars_per_block = CharsPerBlock;
123 static_assert(bytes_per_block != 0,
"radix must be 16, 32, 64 or 85");
124 static_assert(chars_per_block != 0,
"radix must be 16, 32, 64 or 85");
127 static constexpr T int_from_char(
char c)
noexcept
129 return narrow_cast<T>(alphabet.int_from_char(c));
133 static constexpr char char_from_int(T x)
noexcept
144 template<
typename ItIn,
typename ItOut>
145 static constexpr void encode(ItIn ptr, ItIn last, ItOut output)
147 long long byte_index_in_block = 0;
150 while (ptr != last) {
152 ttlet shift = 8 * ((bytes_per_block - 1) - byte_index_in_block);
153 block |=
static_cast<long long>(*(ptr++)) << shift;
155 if (++byte_index_in_block == bytes_per_block) {
156 encode_block(block, bytes_per_block, output);
158 byte_index_in_block = 0;
162 if (byte_index_in_block != 0) {
163 encode_block(block, byte_index_in_block, output);
173 template<
typename ItIn>
188 return encode(begin(bytes), end(bytes));
198 template<
typename ItIn,
typename ItOut>
199 static constexpr ItIn
decode(ItIn ptr, ItIn last, ItOut output)
noexcept
201 int char_index_in_block = 0;
204 for (; ptr != last; ++ptr) {
205 ttlet digit = int_from_char<long long>(*ptr);
210 }
else if (digit == -2) {
218 if (++char_index_in_block == chars_per_block) {
219 decode_block(block, chars_per_block, output);
221 char_index_in_block = 0;
226 if (char_index_in_block != 0) {
228 for (
auto i = char_index_in_block; i != chars_per_block; ++i) {
231 decode_block(block, char_index_in_block, output);
240 tt_parse_check(i == end(str));
245 template<
typename ItOut>
246 static constexpr void encode_block(
long long block,
long long nr_bytes, ItOut output)
noexcept
248 ttlet padding = bytes_per_block - nr_bytes;
252 for (
long long i = 0; i != chars_per_block; ++i) {
253 ttlet v = block % radix;
258 if (padding_char != 0) {
259 char_block += padding_char;
262 char_block += char_from_int(v);
267 std::copy(rbegin(char_block), rend(char_block), output);
270 template<
typename ItOut>
271 static constexpr void decode_block(
long long block,
long long nr_chars, ItOut output)
noexcept
273 ttlet padding = chars_per_block - nr_chars;
276 for (
long long i = 0; i != (bytes_per_block - padding); ++i) {
277 ttlet shift = 8 * ((bytes_per_block - 1) - i);
278 ttlet
byte =
static_cast<std::byte
>((block >> shift) & 0xff);
288using base2 = base_n<detail::base2_alphabet, 8, 1>;
289using base8 = base_n<detail::base8_alphabet, 8, 3>;
290using base16 = base_n<detail::base16_alphabet, 2, 1>;
291using base32 = base_n<detail::base32_rfc4648_alphabet, 8, 5>;
292using base32hex = base_n<detail::base32hex_rfc4648_alphabet, 8, 5>;
293using base64 = base_n<detail::base64_rfc4648_alphabet, 4, 3>;
294using base64url = base_n<detail::base64url_rfc4648_alphabet, 4, 3>;
295using base85 = base_n<detail::base85_rfc1924_alphabet, 5, 4>;
296using ascii85 = base_n<detail::base85_btoa_alphabet, 5, 4>;
constexpr char char_from_int(int8_t x) const noexcept
Get a character from an integer.
Definition base_n.hpp:77
constexpr base_n_alphabet(char const (&str)[StringLength], bool case_insensitive=StringLength<=33, char padding_char='\0') noexcept
Construct an alphabet.
Definition base_n.hpp:34
Definition base_n.hpp:116
static constexpr ItIn decode(ItIn ptr, ItIn last, ItOut output) noexcept
Decodes a UTF-8 string into bytes.
Definition base_n.hpp:199
static constexpr std::string encode(ItIn first, ItIn last) noexcept
Encode bytes into a string.
Definition base_n.hpp:174
static constexpr std::string encode(std::span< std::byte const > bytes) noexcept
Encode bytes into a string.
Definition base_n.hpp:186
static constexpr void encode(ItIn ptr, ItIn last, ItOut output)
Encode bytes into a string.
Definition base_n.hpp:145
T back_inserter(T... args)