Last active
November 18, 2020 14:32
-
-
Save Crspy/f9c1f9a03e84741f68f66874fc1d60fb to your computer and use it in GitHub Desktop.
C++11 constexpr numbers (any base) to string (array of chars) conversion also supports prefixes
This file contains hidden or 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 <cstdio> | |
| #include <cstdint> | |
| #include <type_traits> | |
| namespace fast | |
| { | |
| namespace detail | |
| { | |
| constexpr auto numbers = "0123456789ABCDEF"; | |
| template <bool prefixed, uint8_t base, uint8_t... digits> | |
| struct positive_to_chars | |
| { | |
| static const char value[]; | |
| }; | |
| template <bool prefixed, uint8_t base, uint8_t... digits> | |
| const char positive_to_chars<prefixed, base, digits...>::value[] = {(numbers[digits])..., 0}; | |
| // zero case | |
| template <bool prefixed, uint8_t base> | |
| struct positive_to_chars<prefixed,base> | |
| { | |
| static const char value[]; | |
| }; | |
| template <bool prefixed, uint8_t base> | |
| const char positive_to_chars<prefixed, base>::value[] = {'0', 0}; | |
| template <uint8_t... digits> | |
| struct positive_to_chars<true, 2, digits...> | |
| { | |
| static const char value[]; | |
| }; | |
| template <uint8_t... digits> | |
| const char positive_to_chars<true, 2, digits...>::value[] = {'0', 'b', (numbers[digits])..., 0}; | |
| template <uint8_t... digits> | |
| struct positive_to_chars<true, 16, digits...> | |
| { | |
| static const char value[]; | |
| }; | |
| template <uint8_t... digits> | |
| const char positive_to_chars<true, 16, digits...>::value[] = {'0', 'x', (numbers[digits])..., 0}; | |
| // negative numbers | |
| template <uint8_t base, uint8_t... digits> | |
| struct negative_to_chars | |
| { | |
| static const char value[]; | |
| }; | |
| template <uint8_t base, uint8_t... digits> | |
| const char negative_to_chars<base, digits...>::value[] = {'-', (numbers[digits])..., 0}; | |
| template <uint8_t base, bool prefix, bool neg, uint8_t... digits> | |
| struct to_chars : positive_to_chars<prefix, base, digits...> | |
| { | |
| }; | |
| template <uint8_t base, uint8_t... digits> | |
| struct to_chars<base, true, false, digits...> : positive_to_chars<true, base, digits...> | |
| { | |
| }; | |
| template <uint8_t base, bool prefix, uint8_t... digits> | |
| struct to_chars<base, prefix, true, digits...> : negative_to_chars<base, digits...> | |
| { | |
| }; | |
| template <uint8_t base, bool prefix, bool neg, uintmax_t rem, uint8_t... digits> | |
| struct to_digits : to_digits<base, prefix, neg, rem / base, rem % base, digits...> | |
| { | |
| }; | |
| template <uint8_t base, bool prefix, bool neg, uint8_t... digits> | |
| struct to_digits<base, prefix, neg, 0, digits...> : to_chars<base, prefix, neg, digits...> | |
| { | |
| }; | |
| template <typename T, T num> | |
| constexpr uintmax_t cabs() | |
| { | |
| return (num < 0) ? -static_cast<uintmax_t>(num) : num; | |
| } | |
| template <typename T, T num> | |
| constexpr typename std::make_unsigned<T>::type binary_cabs() | |
| { | |
| return static_cast<typename std::make_unsigned<T>::type>(num); | |
| } | |
| } // namespace detail | |
| template <typename T, T num, uint8_t base = 10, bool prefix = false> | |
| struct to_string | |
| : detail::to_digits < | |
| base, | |
| prefix, | |
| num<0 && base == 10, | |
| base == 10 ? detail::cabs<T, num>() : detail::binary_cabs<T, num>()> | |
| { | |
| static_assert( | |
| base == 2 || | |
| base == 4 || | |
| base == 8 || | |
| base == 10 || | |
| base == 16, | |
| "base has to be one of the following {2,4,8,10,16}"); | |
| }; | |
| } // namespace fast | |
| int main() { | |
| using namespace fast; // couldn't find a good name for the namespace xD | |
| // generates compiler warning or an error (depending on the compiler) that an overflow happened | |
| constexpr auto str3 = to_string<signed char, -128, 10>::value; | |
| printf("%s\n",str3); | |
| constexpr auto str12 = to_string<signed char, 127, 2 , true>::value; // 0b1111111 | |
| printf("%s\n",str12); | |
| constexpr auto str8 = to_string<int, -2147483648, 10>::value; | |
| printf("%s\n",str8); | |
| constexpr auto str9 = to_string<int, 2147483647, 10>::value; | |
| printf("%s\n",str9); | |
| constexpr auto str10 = to_string<int, -1, 16, true>::value; // 0xFFFFFFFF | |
| printf("%s\n",str10); | |
| constexpr auto str11 = to_string<char, -1, 16>::value; // FF | |
| printf("%s\n",str11); | |
| constexpr auto str4 = to_string<unsigned int, 4294967295, 10>::value; | |
| printf("%s\n",str4); | |
| // generates compiler warning or an error (depending on the compiler) that an overflow happened | |
| // constexpr auto str6 = to_string<unsigned int, 4294967296, 10>::value; | |
| // printf("%s\n",str6); | |
| constexpr auto str7 = to_string<long long, 9223372036854775807, 10>::value; | |
| printf("%s\n",str7); | |
| constexpr auto str5 = to_string<int, 0, 10>::value; | |
| printf("%s\n",str5); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment