Skip to content

Instantly share code, notes, and snippets.

@unixzii
Last active February 18, 2023 06:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save unixzii/4f1e702282b6470e0914be62524d7d70 to your computer and use it in GitHub Desktop.
Save unixzii/4f1e702282b6470e0914be62524d7d70 to your computer and use it in GitHub Desktop.
A Base64 implementation using C++ template metaprogramming.
template<auto... Val>
struct List;
template<>
struct List<> {
template<auto Elem>
using Append = List<Elem>;
};
template<auto Head, auto... _Rest>
struct List<Head, _Rest...> {
using Rest = List<_Rest...>;
template<auto Elem>
using Append = List<Head, _Rest..., Elem>;
static constexpr auto head = Head;
static constexpr decltype(head) array[] = { head, _Rest... };
};
template<const char Str[], int _Offset = 0>
struct StaticString {
template<int Offset>
using Slice = StaticString<Str, _Offset + Offset>;
static constexpr auto _length() {
int i = 0;
for (; Str[i] != '\0'; ++i) {
}
return i - _Offset;
}
static constexpr auto at(const int index) {
return Str[index + _Offset];
}
static constexpr auto value = Str;
static constexpr auto length = _length();
};
static constexpr const char encodingTable[] = {
'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 const int modTable[] = { 0, 2, 1 };
template<typename Str, typename AccRes, auto OrigStrLen = Str::length, auto = (Str::length <= 0)>
struct _Base64;
template<typename Str, typename AccRes, auto OrigStrLen>
struct _Base64<Str, AccRes, OrigStrLen, 0> {
private:
static constexpr int octet0 = (0 < Str::length) ? Str::at(0) : 0;
static constexpr int octet1 = (1 < Str::length) ? Str::at(1) : 0;
static constexpr int octet2 = (2 < Str::length) ? Str::at(2) : 0;
static constexpr int triple = (octet0 << 16) + (octet1 << 8) + octet2;
static constexpr auto output0 = encodingTable[(triple >> 3 * 6) & 0x3f];
static constexpr auto output1 = encodingTable[(triple >> 2 * 6) & 0x3f];
static constexpr auto output2 = encodingTable[(triple >> 1 * 6) & 0x3f];
static constexpr auto output3 = encodingTable[(triple >> 0 * 6) & 0x3f];
static constexpr auto paddingChars = modTable[OrigStrLen % 3];
static constexpr auto chunkNeedsPadding = Str::length < 3;
public:
using ValueType = typename _Base64<
typename Str::template Slice<3>,
typename AccRes::template Append<output0>
::template Append<(paddingChars > 2 && chunkNeedsPadding) ? '=' : output1>
::template Append<(paddingChars > 1 && chunkNeedsPadding) ? '=' : output2>
::template Append<(paddingChars > 0 && chunkNeedsPadding) ? '=' : output3>,
OrigStrLen
>::ValueType;
};
template<typename Str, typename AccRes, auto OrigStrLen>
struct _Base64<Str, AccRes, OrigStrLen, 1> {
using ValueType = AccRes;
};
template<typename Str>
struct Base64 {
using ValueType = typename _Base64<Str, List<>>::ValueType;
static constexpr auto value = ValueType::array;
};
constexpr const char input[] = "TMP Rocks!";
static const char *result = (const char *) Base64<StaticString<input>>::value;
#include <iostream>
int main() {
std::cout << result << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment