-
-
Save 0x1306a94/79fddf4292125ff828aad8c9fc05245e to your computer and use it in GitHub Desktop.
A Base64 implementation using C++ template metaprogramming.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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