di 0.1.0
Loading...
Searching...
No Matches
base64.h
Go to the documentation of this file.
1#pragma once
2
11#include "di/format/prelude.h"
13#include "di/parser/prelude.h"
15
17template<concepts::ContainerOf<byte> Con = di::Vector<byte>>
18class Base64 {
19public:
20 using IsAtom = void;
21
22 Base64() = default;
23
24 constexpr explicit Base64(Con container) : m_container(di::move(container)) {}
25
26 constexpr auto container() const& -> Con const& { return m_container; }
27 constexpr auto container() && -> Con&& { return di::move(m_container); }
28
29 auto operator==(Base64 const& other) const -> bool = default;
30
31private:
32 constexpr static auto alphabet() {
33 auto result = di::Array<u8, 256> {};
34 result.fill(255);
35
36 auto v = u8(0);
37 for (auto ch : range('A', 'Z' + 1)) {
38 result[ch] = v++;
39 }
40 for (auto ch : range('a', 'z' + 1)) {
41 result[ch] = v++;
42 }
43 for (auto ch : range('0', '9' + 1)) {
44 result[ch] = v++;
45 }
46 result['+'] = v++;
47 result['/'] = v++;
48 result['='] = 0;
49 return result;
50 }
51
52 constexpr static auto reverse_alphabet() {
53 auto result = di::Array<char, 64> {};
54 for (auto [i, v] : di::enumerate(alphabet())) {
55 if (v != 255) {
56 result[v] = char(i);
57 }
58 }
59 return result;
60 }
61
62 constexpr static auto value_to_base64_digit(u8 value) -> char { return reverse_alphabet()[value]; }
63
64 constexpr static auto base64_digit_to_value(char value) -> u8 { return alphabet()[value]; }
65
66 template<concepts::Encoding Enc>
69 auto do_output = [](concepts::FormatContext auto& context,
70 concepts::DecaySameAs<Base64> auto&& base64) -> Result<> {
71 for (auto&& range : di::chunk(base64.m_container, 3)) {
72 auto it = begin(range);
73 switch (di::distance(range)) {
74 case 3: {
75 auto b0 = u8(*it);
76 auto b1 = u8(*++it);
77 auto b2 = u8(*++it);
78
79 auto v0 = ((b0 & 0xfc) >> 2);
80 auto v1 = ((b0 & 0x03) << 4) | ((b1 & 0xf0) >> 4);
81 auto v2 = ((b1 & 0x0f) << 2) | ((b2 & 0xc0) >> 6);
82 auto v3 = ((b2 & 0x3f) << 0);
83 (void) context.output(value_to_base64_digit(v0));
84 (void) context.output(value_to_base64_digit(v1));
85 (void) context.output(value_to_base64_digit(v2));
86 (void) context.output(value_to_base64_digit(v3));
87 break;
88 }
89 case 2: {
90 auto b0 = u8(*it);
91 auto b1 = u8(*++it);
92
93 auto v0 = ((b0 & 0xfc) >> 2);
94 auto v1 = ((b0 & 0x03) << 4) | ((b1 & 0xf0) >> 4);
95 auto v2 = ((b1 & 0x0f) << 2);
96 (void) context.output(value_to_base64_digit(v0));
97 (void) context.output(value_to_base64_digit(v1));
98 (void) context.output(value_to_base64_digit(v2));
99 (void) context.output('=');
100 break;
101 }
102 case 1: {
103 auto b0 = u8(*it);
104
105 auto v0 = (b0 & 0xfc) >> 2;
106 auto v1 = (b0 & 0x03) << 4;
107 (void) context.output(value_to_base64_digit(v0));
108 (void) context.output(value_to_base64_digit(v1));
109 (void) context.output('=');
110 (void) context.output('=');
111 }
112 default:
113 break;
114 }
115 }
116 return {};
117 };
118 return Result<decltype(do_output)>(di::move(do_output));
119 }
120
122 auto valid_base64 = ('0'_m - '9'_m || 'a'_m - 'z'_m || 'A'_m - 'Z'_m || '+'_m || '/'_m || '='_m);
123
124 return (parser::match_zero_or_more(valid_base64))
125 << []<typename Context>(
126 Context& context,
128 auto result = Base64 {};
129 auto got_equal = false;
130 for (auto group : chunk(results, 4)) {
131 if (distance(group) != 4) {
132 return Unexpected(context.make_error());
133 }
134
135 auto it = begin(group);
136 auto c0 = *it;
137 if (c0 == '=') {
138 return Unexpected(context.make_error());
139 }
140 auto c1 = *++it;
141 if (c1 == '=') {
142 return Unexpected(context.make_error());
143 }
144 auto c2 = *++it;
145 if (got_equal && c2 != '=') {
146 return Unexpected(context.make_error());
147 }
148 got_equal |= c2 == '=';
149 auto c3 = *++it;
150 if (got_equal && c3 != '=') {
151 return Unexpected(context.make_error());
152 }
153 got_equal |= c3 == '=';
154
155 auto v0 = base64_digit_to_value(char(c0));
156 auto v1 = base64_digit_to_value(char(c1));
157 auto v2 = base64_digit_to_value(char(c2));
158 auto v3 = base64_digit_to_value(char(c3));
159
160 auto b0 = ((v0 & 0x3f) << 2) | ((v1 & 0x30) >> 4);
161 auto b1 = ((v1 & 0x0f) << 4) | ((v2 & 0x3c) >> 2);
162 auto b2 = ((v2 & 0x03) << 6) | ((v3 & 0x3f) >> 0);
163
164 result.m_container.push_back(byte(b0));
165 if (c2 != '=') {
166 result.m_container.push_back(byte(b1));
167 }
168 if (c3 != '=') {
169 result.m_container.push_back(byte(b2));
170 }
171 }
172 return result;
173 };
174 }
175
176 Con m_container;
177};
178}
179
180namespace di {
181inline namespace literals {
182 inline namespace base64_literals {
183 constexpr auto operator""_base64(char const* data, usize size) -> serialization::Base64<> {
184 auto view = di::TransparentStringView { data, size };
186 }
187 }
188}
189}
190
191namespace di {
193
195}
196
197#if !defined(DI_NO_GLOBALS) && !defined(DI_NO_GLOBAL_BASE64_LITERALS)
198using namespace di::literals::base64_literals;
199#endif
Base64()=default
Definition format_parse_context.h:14
Definition base64.h:18
constexpr friend auto tag_invoke(types::Tag< parser::create_parser_in_place >, InPlaceType< Base64 >)
Definition base64.h:121
auto operator==(Base64 const &other) const -> bool=default
constexpr Base64(Con container)
Definition base64.h:24
constexpr friend auto tag_invoke(types::Tag< format::formatter_in_place >, InPlaceType< Base64 >, FormatParseContext< Enc > &)
Definition base64.h:67
void IsAtom
Definition base64.h:20
constexpr auto container() const &-> Con const &
Definition base64.h:26
constexpr auto container() &&-> Con &&
Definition base64.h:27
Definition unexpected.h:14
Definition operations.h:34
Definition util.h:59
Definition format_context.h:9
string::StringViewImpl< string::TransparentEncoding > TransparentStringView
Definition string_view.h:13
constexpr auto value
Definition value.h:34
Definition base64.h:182
vocab::Expected< T, meta::ParserContextError< Context > > ParserContextResult
Definition parser_context_result.h:8
constexpr auto match_zero_or_more
Definition match_zero_or_more.h:48
constexpr auto parse_unchecked
Definition parse_unchecked.h:25
Definition base64.h:16
size_t usize
Definition integers.h:33
__UINT8_TYPE__ u8
Definition integers.h:9
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
Expected< T, Error > Result
Definition result.h:8
Definition any_storable.h:9
constexpr auto distance
Definition distance.h:44
constexpr auto size
Definition size.h:62
constexpr auto data
Definition data.h:51
Base64< di::Span< byte const > > Base64View
Definition base64.h:194
constexpr auto begin
Definition begin.h:52
Definition in_place_type.h:5
Definition array.h:27
constexpr void fill(T const &value)
Definition array.h:88