7#include "../container/module.hpp"
8#include "../utility/utility.hpp"
9#include "../macros.hpp"
17hi_export_module(hikogui.codec.base_n);
24 bool case_insensitive;
34 template<std::
size_t StringLength>
36 char const (&str)[StringLength],
37 bool case_insensitive = StringLength <= 33,
38 char padding_char =
'\0') noexcept :
39 radix(narrow_cast<
long long>(StringLength - 1)), case_insensitive(case_insensitive), padding_char(padding_char)
41 static_assert(StringLength < 128);
44 for (
long long i = 0; i != 256; ++i) {
45 int_from_char_table[i] = -2;
49 int_from_char_table[std::bit_cast<uint8_t>(
' ')] = -1;
50 int_from_char_table[std::bit_cast<uint8_t>(
'\t')] = -1;
51 int_from_char_table[std::bit_cast<uint8_t>(
'\r')] = -1;
52 int_from_char_table[std::bit_cast<uint8_t>(
'\n')] = -1;
53 int_from_char_table[std::bit_cast<uint8_t>(
'\f')] = -1;
55 if (padding_char != 0) {
56 int_from_char_table[std::bit_cast<uint8_t>(padding_char)] = -1;
59 for (
long long i = 0; i != radix; ++i) {
61 char_from_int_table[i] = c;
63 int_from_char_table[std::bit_cast<uint8_t>(c)] = narrow_cast<int8_t>(i);
64 if constexpr (StringLength <= 33) {
66 if (c >=
'a' && c <=
'z') {
67 int_from_char_table[narrow_cast<uint8_t>((c -
'a') +
'A')] = narrow_cast<int8_t>(i);
68 }
else if (c >=
'A' && c <=
'Z') {
69 int_from_char_table[narrow_cast<uint8_t>((c -
'A') +
'a')] = narrow_cast<int8_t>(i);
81 return char_from_int_table[x];
84 constexpr int8_t int_from_char(
char c)
const noexcept
86 return int_from_char_table[std::bit_cast<uint8_t>(c)];
90constexpr auto base2_alphabet = base_n_alphabet{
"01"};
92constexpr auto base8_alphabet = base_n_alphabet{
"01234567"};
94constexpr auto base10_alphabet = base_n_alphabet{
"0123456789"};
96constexpr auto base16_alphabet = base_n_alphabet{
"0123456789ABCDEF"};
98constexpr auto base32_rfc4648_alphabet = base_n_alphabet{
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"};
100constexpr auto base32hex_rfc4648_alphabet = base_n_alphabet{
"0123456789ABCDEFGHIJKLMNOPQRSTUV"};
102constexpr auto base64_rfc4648_alphabet =
103 base_n_alphabet{
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
false,
'='};
105constexpr auto base64url_rfc4648_alphabet =
106 base_n_alphabet{
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
false,
'='};
108constexpr auto base85_rfc1924_alphabet =
109 base_n_alphabet{
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"};
111constexpr auto base85_btoa_alphabet =
112 base_n_alphabet{
"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu"};
116template<detail::base_n_alphabet Alphabet,
int CharsPerBlock,
int BytesPerBlock>
120 constexpr static char padding_char = alphabet.padding_char;
121 constexpr static long long radix = alphabet.radix;
122 constexpr static long long bytes_per_block = BytesPerBlock;
123 constexpr static long long chars_per_block = CharsPerBlock;
124 static_assert(bytes_per_block != 0,
"radix must be 16, 32, 64 or 85");
125 static_assert(chars_per_block != 0,
"radix must be 16, 32, 64 or 85");
128 constexpr static T int_from_char(
char c)
noexcept
130 return narrow_cast<T>(alphabet.int_from_char(c));
134 constexpr static char char_from_int(T x)
noexcept
145 template<
typename ItIn,
typename ItOut>
146 constexpr static void encode(ItIn ptr, ItIn last, ItOut output)
148 long long byte_index_in_block = 0;
151 while (ptr != last) {
153 hilet
shift = 8 * ((bytes_per_block - 1) - byte_index_in_block);
154 block |=
static_cast<long long>(*(ptr++)) <<
shift;
156 if (++byte_index_in_block == bytes_per_block) {
157 encode_block(block, bytes_per_block, output);
159 byte_index_in_block = 0;
163 if (byte_index_in_block != 0) {
164 encode_block(block, byte_index_in_block, output);
174 template<
typename ItIn>
189 return encode(begin(bytes), end(bytes));
199 template<
typename ItIn,
typename ItOut>
200 constexpr static ItIn
decode(ItIn ptr, ItIn last, ItOut output)
202 int char_index_in_block = 0;
205 for (; ptr != last; ++ptr) {
206 hilet digit = int_from_char<long long>(*ptr);
211 }
else if (digit == -2) {
219 if (++char_index_in_block == chars_per_block) {
220 decode_block(block, chars_per_block, output);
222 char_index_in_block = 0;
227 if (char_index_in_block != 0) {
229 for (
auto i = char_index_in_block; i != chars_per_block; ++i) {
232 decode_block(block, char_index_in_block, output);
237 static bstring decode(std::string_view str)
241 hi_check(i == end(str),
"base-n encoded string not completely decoded");
246 template<
typename ItOut>
247 static void encode_block(
long long block,
long long nr_bytes, ItOut output)
noexcept
249 hilet padding = bytes_per_block - nr_bytes;
253 for (
long long i = 0; i != chars_per_block; ++i) {
254 hilet v = block % radix;
259 if (padding_char != 0) {
260 char_block += padding_char;
263 char_block += char_from_int(v);
268 std::copy(rbegin(char_block), rend(char_block), output);
271 template<
typename ItOut>
272 constexpr static void decode_block(
long long block,
long long nr_chars, ItOut output)
274 hilet padding = chars_per_block - nr_chars;
276 if (block and bytes_per_block == padding) {
277 throw parse_error(
"Invalid number of character to decode.");
281 for (
long long i = 0; i != (bytes_per_block - padding); ++i) {
282 hilet
shift = 8 * ((bytes_per_block - 1) - i);
283 hilet
byte =
static_cast<std::byte
>((block >>
shift) & 0xff);
DOXYGEN BUG.
Definition algorithm.hpp:16
@ shift
The shift key is being held.
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
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:35
constexpr char char_from_int(int8_t x) const noexcept
Get a character from an integer.
Definition base_n.hpp:78
Definition base_n.hpp:117
static constexpr void encode(ItIn ptr, ItIn last, ItOut output)
Encode bytes into a string.
Definition base_n.hpp:146
static std::string encode(ItIn first, ItIn last) noexcept
Encode bytes into a string.
Definition base_n.hpp:175
static constexpr std::string encode(std::span< std::byte const > bytes) noexcept
Encode bytes into a string.
Definition base_n.hpp:187
static constexpr ItIn decode(ItIn ptr, ItIn last, ItOut output)
Decodes a UTF-8 string into bytes.
Definition base_n.hpp:200
T back_inserter(T... args)