13[[nodiscard]]
static constexpr char encode(uint8_t c)
15 constexpr std::array<char, 64> base64_chars = {
16 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
17 'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
18 '0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'+',
'/',
21 return base64_chars[c];
24[[nodiscard]]
static constexpr uint8_t decode(uint8_t c)
26 if (
'A' <= c && c <=
'Z') {
28 }
else if (
'a' <= c && c <=
'z') {
30 }
else if (
'0' <= c && c <=
'9') {
32 }
else if (c ==
'+') {
34 }
else if (c ==
'/') {
41std::string encode(std::span<const uint8_t> input)
43 constexpr int CHUNKS = 19;
44 constexpr int IN_CHUNKS = 3 * CHUNKS;
45 constexpr int OUT_CHUNKS = 4 * CHUNKS;
47 auto outSize = ((input.size() + (IN_CHUNKS - 1)) / IN_CHUNKS) * (OUT_CHUNKS + 1);
48 std::string ret(outSize, 0);
51 while (!input.empty()) {
52 if (out) ret[out++] =
'\n';
53 auto n = std::min<size_t>(IN_CHUNKS, input.size());
54 for (; n >= 3; n -= 3) {
55 ret[out++] = encode(uint8_t( (input[0] & 0xfc) >> 2));
56 ret[out++] = encode(uint8_t(((input[0] & 0x03) << 4) +
57 ((input[1] & 0xf0) >> 4)));
58 ret[out++] = encode(uint8_t(((input[1] & 0x0f) << 2) +
59 ((input[2] & 0xc0) >> 6)));
60 ret[out++] = encode(uint8_t( (input[2] & 0x3f) >> 0));
61 input = input.subspan(3);
64 std::array<uint8_t, 3> buf3 = {0, 0, 0};
66 input = input.subspan(n);
68 std::array<uint8_t, 4> buf4;
69 buf4[0] = uint8_t( (buf3[0] & 0xfc) >> 2);
70 buf4[1] = uint8_t(((buf3[0] & 0x03) << 4) +
71 ((buf3[1] & 0xf0) >> 4));
72 buf4[2] = uint8_t(((buf3[1] & 0x0f) << 2) +
73 ((buf3[2] & 0xc0) >> 6));
74 buf4[3] = uint8_t( (buf3[2] & 0x3f) >> 0);
75 for (
auto j :
xrange(n + 1)) {
76 ret[out++] = encode(buf4[j]);
84 assert(outSize >= out);
89std::pair<MemBuffer<uint8_t>,
size_t> decode(std::string_view input)
91 auto outSize = (input.size() * 3 + 3) / 4;
96 std::array<uint8_t, 4> buf4;
97 for (
auto c : input) {
98 uint8_t d = decode(c);
99 if (d == uint8_t(-1))
continue;
103 ret[out++] = char(((buf4[0] & 0xff) << 2) + ((buf4[1] & 0x30) >> 4));
104 ret[out++] = char(((buf4[1] & 0x0f) << 4) + ((buf4[2] & 0x3c) >> 2));
105 ret[out++] = char(((buf4[2] & 0x03) << 6) + ((buf4[3] & 0xff) >> 0));
109 for (
auto j :
xrange(i, 4u)) {
112 std::array<uint8_t, 3> buf3;
113 buf3[0] = narrow_cast<uint8_t>(((buf4[0] & 0xff) << 2) + ((buf4[1] & 0x30) >> 4));
114 buf3[1] = narrow_cast<uint8_t>(((buf4[1] & 0x0f) << 4) + ((buf4[2] & 0x3c) >> 2));
115 buf3[2] = narrow_cast<uint8_t>(((buf4[2] & 0x03) << 6) + ((buf4[3] & 0xff) >> 0));
116 for (
auto j :
xrange(i - 1)) {
117 ret[out++] = buf3[j];
121 assert(outSize >= out);
123 return {std::move(ret), out};
128 auto outSize = output.size();
131 std::array<uint8_t, 4> buf4;
132 for (
auto c : input) {
133 uint8_t d = decode(c);
134 if (d == uint8_t(-1))
continue;
138 if ((out + 3) > outSize) [[unlikely]]
return false;
139 output[out++] = char(((buf4[0] & 0xff) << 2) + ((buf4[1] & 0x30) >> 4));
140 output[out++] = char(((buf4[1] & 0x0f) << 4) + ((buf4[2] & 0x3c) >> 2));
141 output[out++] = char(((buf4[2] & 0x03) << 6) + ((buf4[3] & 0xff) >> 0));
145 for (
auto j :
xrange(i, 4u)) {
148 std::array<uint8_t, 3> buf3;
149 buf3[0] = narrow_cast<uint8_t>(((buf4[0] & 0xff) << 2) + ((buf4[1] & 0x30) >> 4));
150 buf3[1] = narrow_cast<uint8_t>(((buf4[1] & 0x0f) << 4) + ((buf4[2] & 0x3c) >> 2));
151 buf3[2] = narrow_cast<uint8_t>(((buf4[2] & 0x03) << 6) + ((buf4[3] & 0xff) >> 0));
152 for (
auto j :
xrange(i - 1)) {
153 if (out == outSize) [[unlikely]]
return false;
154 output[out++] = buf3[j];
158 return out == outSize;
This class manages the lifetime of a block of memory.
void resize(size_t size)
Grow or shrink the memory block.
bool decode_inplace(std::string_view input, std::span< uint8_t > output)
auto copy(InputRange &&range, OutputIter out)
constexpr auto xrange(T e)