73 template <
typename T>
static std::string
encode(
const std::string& bin)
75 return encode(bin, T::data(), T::fill());
77 template <
typename T>
static std::string
decode(
const std::string&
base)
81 template <
typename T>
static std::string
pad(
const std::string&
base)
85 template <
typename T>
static std::string
trim(
const std::string&
base)
91 static std::string
encode(
const std::string& bin,
const std::array<char, 64>& alphabet,
92 const std::string& fill)
94 size_t size = bin.size();
98 size_t fast_size = size - size % 3;
99 for (
size_t i = 0; i < fast_size;)
101 uint32_t octet_a =
static_cast<unsigned char>(bin[i++]);
102 uint32_t octet_b =
static_cast<unsigned char>(bin[i++]);
103 uint32_t octet_c =
static_cast<unsigned char>(bin[i++]);
105 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
107 res += alphabet[(triple >> 3 * 6) & 0x3F];
108 res += alphabet[(triple >> 2 * 6) & 0x3F];
109 res += alphabet[(triple >> 1 * 6) & 0x3F];
110 res += alphabet[(triple >> 0 * 6) & 0x3F];
113 if (fast_size == size)
116 size_t mod = size % 3;
118 uint32_t octet_a = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
119 uint32_t octet_b = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
120 uint32_t octet_c = fast_size < size ? static_cast<unsigned char>(bin[fast_size++]) : 0;
122 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
127 res += alphabet[(triple >> 3 * 6) & 0x3F];
128 res += alphabet[(triple >> 2 * 6) & 0x3F];
133 res += alphabet[(triple >> 3 * 6) & 0x3F];
134 res += alphabet[(triple >> 2 * 6) & 0x3F];
135 res += alphabet[(triple >> 1 * 6) & 0x3F];
144 static std::string
decode(
const std::string& base,
const std::array<char, 64>& alphabet,
145 const std::string& fill)
147 size_t size = base.size();
150 while (size > fill.size())
152 if (base.substr(size - fill.size(), fill.size()) == fill)
157 throw std::runtime_error(
"Invalid input: too much fill");
163 if ((size + fill_cnt) % 4 != 0)
164 throw std::runtime_error(
"Invalid input: incorrect total size");
166 size_t out_size = size / 4 * 3;
168 res.reserve(out_size);
170 auto get_sextet = [&](
size_t offset)
172 for (
size_t i = 0; i < alphabet.size(); i++)
174 if (alphabet[i] == base[offset])
175 return static_cast<uint32_t
>(i);
177 throw std::runtime_error(
"Invalid input: not within alphabet");
180 size_t fast_size = size - size % 4;
181 for (
size_t i = 0; i < fast_size;)
183 uint32_t sextet_a = get_sextet(i++);
184 uint32_t sextet_b = get_sextet(i++);
185 uint32_t sextet_c = get_sextet(i++);
186 uint32_t sextet_d = get_sextet(i++);
188 uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) +
191 res +=
static_cast<char>((triple >> 2 * 8) & 0xFFU);
192 res +=
static_cast<char>((triple >> 1 * 8) & 0xFFU);
193 res +=
static_cast<char>((triple >> 0 * 8) & 0xFFU);
199 uint32_t triple = (get_sextet(fast_size) << 3 * 6) + (get_sextet(fast_size + 1) << 2 * 6);
204 triple |= (get_sextet(fast_size + 2) << 1 * 6);
205 res +=
static_cast<char>((triple >> 2 * 8) & 0xFFU);
206 res +=
static_cast<char>((triple >> 1 * 8) & 0xFFU);
208 case 2: res +=
static_cast<char>((triple >> 2 * 8) & 0xFFU);
break;
215 static std::string
pad(
const std::string& base,
const std::string& fill)
218 switch (base.size() % 4)
226 return base + padding;
229 static std::string
trim(
const std::string& base,
const std::string& fill)
231 auto pos = base.find(fill);
232 return base.substr(0, pos);