Created
February 18, 2023 02:39
-
-
Save EmingK/dc134a2c525c4c29114f5ba850836076 to your computer and use it in GitHub Desktop.
A Base64 Encoding 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
#include <iostream> | |
#include <type_traits> | |
template <char ...chars> | |
using TString = std::integer_sequence<char, chars...>; | |
template <typename T, T ...chars> | |
constexpr TString<chars...> operator""_tstr() { return { }; } | |
template <typename> | |
char const FromTString[] = { 0 }; | |
template <char ..._Bytes> | |
char const FromTString<TString<_Bytes...>>[] = { _Bytes..., 0 }; | |
template <char _First, typename> | |
struct TStringPrepend {} ; | |
template <char _First, char ..._Bytes> | |
struct TStringPrepend<_First, TString<_Bytes...>> { | |
using type = TString<_First, _Bytes...>; | |
}; | |
constexpr char Base64Lookup(int idx) { | |
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[idx]; | |
} | |
template <int _Bits, int _Data, char _First, char ..._Rest> | |
struct Base64Inner; | |
template <int _Bits, int _Data> | |
struct Base64Last; | |
template <int _Bits, int _Encoded, int _NextBits, int _Next, char _First, char ..._Rest> | |
struct Base64EncodeNextType { | |
using type = typename TStringPrepend<_Encoded, typename Base64Inner<_NextBits, _Next, _Rest...>::StringType>::type; | |
}; | |
template <int _Encoded, int _Next, int _NextBits, char _First, char ..._Rest> | |
struct Base64EncodeNextType<6, _Encoded, _NextBits, _Next, _First, _Rest...> { | |
using type = typename TStringPrepend<_Encoded, typename Base64Inner<0, 0, _First, _Rest...>::StringType>::type; | |
}; | |
template <int _Bits, int _Data, char _First, char ..._Rest> | |
struct Base64Inner { | |
static constexpr int EncodeBits = 6 - _Bits; | |
static constexpr int ShiftBits = 8 - EncodeBits; | |
static constexpr int EncodedByte = Base64Lookup((_Data << EncodeBits) | (((unsigned char)_First) >> ShiftBits)); | |
static constexpr int StagedByte = _First & ((1 << ShiftBits) - 1); | |
using StringType = typename Base64EncodeNextType<_Bits, EncodedByte, ShiftBits, StagedByte, _First, _Rest...>::type; | |
}; | |
template <int _Data, char _Only> | |
struct Base64Inner<6, _Data, _Only> { | |
using StringType = typename TStringPrepend<Base64Lookup(_Data), typename Base64Inner<0, 0, _Only>::StringType>::type; | |
}; | |
template <int _Bits, int _Data, char _Only> | |
struct Base64Inner<_Bits, _Data, _Only> { | |
static constexpr int EncodeBits = 6 - _Bits; | |
static constexpr int ShiftBits = 8 - EncodeBits; | |
static constexpr int EncodedByte = Base64Lookup((_Data << EncodeBits) | (((unsigned char)_Only) >> ShiftBits)); | |
static constexpr int StagedByte = _Only & ((1 << ShiftBits) - 1); | |
using StringType = typename TStringPrepend<EncodedByte, typename Base64Last<ShiftBits, StagedByte>::StringType>::type; | |
}; | |
template <int _Bits, int _Data> | |
struct Base64Last {}; | |
template <int _Data> | |
struct Base64Last<2, _Data> { | |
using StringType = TString<Base64Lookup(_Data), '=', '='>; | |
}; | |
template <int _Data> | |
struct Base64Last<4, _Data> { | |
using StringType = TString<Base64Lookup(_Data), '='>; | |
}; | |
template <int _Data> | |
struct Base64Last<6, _Data> { | |
using StringType = TString<Base64Lookup(_Data)>; | |
}; | |
template <char ..._Bytes> | |
using Base64Impl = typename Base64Inner<0, 0, _Bytes...>::StringType; | |
template <typename> | |
struct Base64 {}; | |
template <char ..._Bytes> | |
struct Base64<TString<_Bytes...>> { | |
using StringType = Base64Impl<_Bytes...>; | |
}; | |
int main() { | |
const char *encoded = FromTString<Base64<decltype("偶像好帅"_tstr)>::StringType>; | |
std::cout << encoded << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment