Import Base64 implementation from old repo

This commit is contained in:
Viktor Soukup 2025-05-17 01:25:04 +02:00
parent e4735e2dfb
commit 6b493dcfda
8 changed files with 266 additions and 1 deletions

11
Garbage/CMakeLists.txt Normal file
View file

@ -0,0 +1,11 @@
add_library(Garbage INTERFACE)
target_compile_features(Garbage
INTERFACE
cxx_std_20
)
target_include_directories(Garbage
INTERFACE
"Include"
)

View file

@ -0,0 +1,143 @@
#ifndef GARBAGE_BASE64_HPP
#define GARBAGE_BASE64_HPP
#include <array>
#include <cstdint>
#include <span>
#include <string>
#include <string_view>
#include <vector>
namespace Garbage::Base64
{
namespace Internal
{
struct SmallBuffer
{
public:
[[nodiscard]] constexpr
SmallBuffer()
: mStoredBits(0), mData(0)
{}
constexpr
void Enqueue(std::uint8_t byte, std::size_t bits = 8)
{
std::uint8_t mask = (1u << bits) - 1;
mData = (mData << bits) | (byte & mask);
mStoredBits += bits;
}
[[nodiscard]] constexpr
std::uint8_t Dequeue(std::size_t bits = 8)
{
std::uint64_t mask = (1u << bits) - 1;
mStoredBits -= bits;
std::uint64_t out = (mData >> mStoredBits) & mask;
return out;
}
[[nodiscard]] constexpr
std::size_t Size()
{
return mStoredBits;
}
[[nodiscard]] constexpr
std::size_t Capacity()
{
return 64;
}
private:
std::size_t mStoredBits;
std::uint64_t mData;
};
static constexpr auto EncodeLUT = std::array {
'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', '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', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/',
};
static constexpr std::size_t DecodeOffset = '+';
static constexpr auto DecodeLUT = std::array {
0b111'110, /* + */ 0b000'000, /*---*/ 0b000'000, /*---*/ 0b000'000, /*---*/
0b111'111, /* / */ 0b110'100, /* 0 */ 0b110'101, /* 1 */ 0b110'110, /* 2 */
0b110'111, /* 3 */ 0b111'000, /* 4 */ 0b111'001, /* 5 */ 0b111'010, /* 6 */
0b111'011, /* 7 */ 0b111'100, /* 8 */ 0b111'101, /* 9 */ 0b000'000, /*---*/
0b000'000, /*---*/ 0b000'000, /*---*/ 0b000'000, /*---*/ 0b000'000, /*---*/
0b000'000, /*---*/ 0b000'000, /*---*/ 0b000'000, /* A */ 0b000'001, /* B */
0b000'010, /* C */ 0b000'011, /* D */ 0b000'100, /* E */ 0b000'101, /* F */
0b000'110, /* G */ 0b000'111, /* H */ 0b001'000, /* I */ 0b001'001, /* J */
0b001'010, /* K */ 0b001'011, /* L */ 0b001'100, /* M */ 0b001'101, /* N */
0b001'110, /* O */ 0b001'111, /* P */ 0b010'000, /* Q */ 0b010'001, /* R */
0b010'010, /* S */ 0b010'011, /* T */ 0b010'100, /* U */ 0b010'101, /* V */
0b010'110, /* W */ 0b010'111, /* X */ 0b011'000, /* Y */ 0b011'001, /* Z */
0b000'000, /*---*/ 0b000'000, /*---*/ 0b000'000, /*---*/ 0b000'000, /*---*/
0b000'000, /*---*/ 0b000'000, /*---*/ 0b011'010, /* a */ 0b011'011, /* b */
0b011'100, /* c */ 0b011'101, /* d */ 0b011'110, /* e */ 0b011'111, /* f */
0b100'000, /* g */ 0b100'001, /* h */ 0b100'010, /* i */ 0b100'011, /* j */
0b100'100, /* k */ 0b100'101, /* l */ 0b100'110, /* m */ 0b100'111, /* n */
0b101'000, /* o */ 0b101'001, /* p */ 0b101'010, /* q */ 0b101'011, /* r */
0b101'100, /* s */ 0b101'101, /* t */ 0b101'110, /* u */ 0b101'111, /* v */
0b110'000, /* w */ 0b110'001, /* x */ 0b110'010, /* y */ 0b110'011, /* z */
};
}
[[nodiscard]] constexpr
std::string Encode(std::span<std::uint8_t> data) {
std::string result;
result.reserve(data.size() + data.size() / 2);
Internal::SmallBuffer buffer;
std::size_t i = 0;
while (i < data.size()) {
while (buffer.Capacity() - buffer.Size() >= 8 && i < data.size()) {
buffer.Enqueue(data[i++]);
}
while (buffer.Size() >= 6) {
result.push_back(Internal::EncodeLUT[buffer.Dequeue(6)]);
}
}
if (buffer.Size() > 0) {
std::size_t remainingBits = buffer.Size();
std::uint8_t data = (buffer.Dequeue(remainingBits) << (6 - remainingBits));
result.push_back(Internal::EncodeLUT[data]);
}
if (data.size() % 3) {
result.append(std::string(4 - (result.size() % 4), '='));
}
return result;
}
[[nodiscard]] constexpr
std::vector<std::uint8_t> Decode(std::string_view data) {
std::vector<std::uint8_t> result;
result.reserve(data.size());
std::size_t end = data.size();
end -= (data.size() > 0 && data[data.size() - 1] == '=');
end -= (data.size() > 1 && data[data.size() - 2] == '=');
Internal::SmallBuffer buffer;
std::size_t i = 0;
while (i < end) {
while (buffer.Capacity() - buffer.Size() >= 6 && i < end) {
buffer.Enqueue(Internal::DecodeLUT[data[i++] - Internal::DecodeOffset], 6);
}
while (buffer.Size() >= 8) {
result.push_back(buffer.Dequeue(8));
}
}
return result;
}
}
#endif // GARBAGE_BASE64_HPP