/* @file stringliteral.hpp */ #pragma once #include #include #include #include namespace xo { namespace obs { // ----- stringliteral ----- /** @class stringliteral * * @brief class to represent a literal string at compile time, for use as template argument **/ template struct stringliteral { constexpr stringliteral() { if (N > 0) value_[0] = '\0'; } constexpr stringliteral(const char (&str)[N]) { std::copy_n(str, N, value_); } constexpr int size() const { return N; } constexpr char const * c_str() const { return value_; } char value_[N]; }; template < typename First, typename... Rest > constexpr auto all_same_v = std::conjunction_v< std::is_same... >; /** args and result must be stringliteral **/ template < typename... Ts> constexpr auto stringliteral_concat(Ts && ... args) { #ifdef NOT_USING static_assert(all_same_v...>, "string must share the same char type"); using char_type = std::remove_const_t< std::remove_pointer_t < std::common_type_t < Ts... > > >; #endif using char_type = char; /** n1: total number of bytes used by arguments **/ constexpr size_t n1 = (sizeof(Ts) + ...); /** z1: each string arg has a null terminator included in its size, * z1 is the number of arguments in parameter pack Ts, * which equals the number of null terminators used **/ constexpr size_t z1 = sizeof...(Ts); /** n: number of chars in concatenated string. +1 for final null **/ constexpr size_t n = (n1 / sizeof(char_type)) - z1 + 1; stringliteral result; size_t pos = 0; auto detail_concat = [ &pos, &result ](auto && arg) { constexpr auto count = (sizeof(arg) - sizeof(char_type)) / sizeof(char_type); std::copy_n(arg, count, result.value_ + pos); pos += count; }; (detail_concat(args), ...); return result; } template constexpr auto stringliteral_compare(stringliteral && s1, stringliteral && s2) { return std::string_view(s1.value_) <=> std::string_view(s2.value_); } // ----- literal_size ----- /** @brief compute number of chars needed to stringify an int **/ template < int d, bool signbit = std::signbit(d) > struct literal_size; template < int d > struct literal_size { /* d < 0 */ static constexpr int size = 1 + literal_size<-d, false>::size; }; template < int d > struct literal_size { /* d >= 0 */ static constexpr int size = 1 + literal_size::size; }; template <> struct literal_size<0, false> { static constexpr int size = 1; }; template <> struct literal_size<1, false> { static constexpr int size = 1; }; template <> struct literal_size<2, false> { static constexpr int size = 1; }; template <> struct literal_size<3, false> { static constexpr int size = 1; }; template <> struct literal_size<4, false> { static constexpr int size = 1; }; template <> struct literal_size<5, false> { static constexpr int size = 1; }; template <> struct literal_size<6, false> { static constexpr int size = 1; }; template <> struct literal_size<7, false> { static constexpr int size = 1; }; template <> struct literal_size<8, false> { static constexpr int size = 1; }; template <> struct literal_size<9, false> { static constexpr int size = 1; }; template < int d > constexpr int literal_size_v = literal_size::size; // ----- literal_from_digit ----- constexpr auto /*stringliteral<2>*/ stringliteral_from_digit( int d ) { return stringliteral({ static_cast('0' + d), '\0' }); } #ifdef NOT_YET_22mar24 template < int d > struct literal_from_digit; template <> struct literal_from_digit<0> { static constexpr auto value = stringliteral("0"); }; template <> struct literal_from_digit<1> { static constexpr auto value = stringliteral("1"); }; template <> struct literal_from_digit<2> { static constexpr auto value = stringliteral("2"); }; template <> struct literal_from_digit<3> { static constexpr auto value = stringliteral("3"); }; template <> struct literal_from_digit<4> { static constexpr auto value = stringliteral("4"); }; template <> struct literal_from_digit<5> { static constexpr auto value = stringliteral("5"); }; template <> struct literal_from_digit<6> { static constexpr auto value = stringliteral("6"); }; template <> struct literal_from_digit<7> { static constexpr auto value = stringliteral("7"); }; template <> struct literal_from_digit<8> { static constexpr auto value = stringliteral("8"); }; template <> struct literal_from_digit<9> { static constexpr auto value = stringliteral("9"); }; template < int d > constexpr auto literal_from_digit_v() { return literal_from_digit::value; } #endif // ----- stringliteral_from_int ----- template < int D, int N = literal_size_v, bool signbit = std::signbit(D) > struct stringliteral_from_int; template < int D, int N = literal_size_v, bool signbit = std::signbit(D) > constexpr auto stringliteral_from_int_v() { return stringliteral_from_int::value; } template < int D > struct stringliteral_from_int< D, 1, false > { static constexpr auto value = stringliteral_from_digit(D); }; template < int D, int N > struct stringliteral_from_int< D, N, false > { static constexpr auto _prefix = stringliteral_from_int_v< D / 10, N - 1, false >(); static constexpr auto _suffix = stringliteral_from_digit(D % 10); static constexpr auto value = stringliteral_concat(_prefix.value_, _suffix.value_); }; template < int D, int N > struct stringliteral_from_int< D, N, true > { static constexpr auto _suffix = stringliteral_from_int_v< -D, N - 1, false>(); static constexpr auto value = stringliteral_concat("-", _suffix.value_); }; } /*namespace obs*/ } /*namespace xo*/ /* end stringliteral.hpp */