1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
| #include <type_traits>
#include <utility>
static constexpr std::size_t max_str_lit_len = 256;
template <std::size_t I, std::size_t N> constexpr char sl_at(const char (&str)[N])
{
if constexpr(I < N)
return str[I];
else
return '\0';
}
constexpr std::size_t sl_len(const char *str)
{
for (std::size_t i = 0; i < max_str_lit_len; i++)
if (str[i] == '\0')
return i;
return 0;
}
template <char ...C> struct str_lit
{
static constexpr char value[] {C..., '\0'};
static constexpr int size = sl_len(value);
template <typename F, typename ...P> struct concat_impl {using type = typename concat_impl<F>::type::template concat_impl<P...>::type;};
template <char ...CC> struct concat_impl<str_lit<CC...>> {using type = str_lit<C..., CC...>;};
template <typename ...P> using concat = typename concat_impl<P...>::type;
};
template <typename, const char *> struct trim_str_lit_impl;
template <std::size_t ...I, const char *S> struct trim_str_lit_impl<std::index_sequence<I...>, S>
{
using type = str_lit<S[I]...>;
};
template <std::size_t N, const char *S> using trim_str_lit = typename trim_str_lit_impl<std::make_index_sequence<N>, S>::type;
#define STR_LIT(str) ::trim_str_lit<::sl_len(str), ::str_lit<STR_TO_VA(str)>::value>
#define STR_TO_VA(str) STR_TO_VA_16(str,0),STR_TO_VA_16(str,16),STR_TO_VA_16(str,32),STR_TO_VA_16(str,48)
#define STR_TO_VA_16(str,off) STR_TO_VA_4(str,0+off),STR_TO_VA_4(str,4+off),STR_TO_VA_4(str,8+off),STR_TO_VA_4(str,12+off)
#define STR_TO_VA_4(str,off) ::sl_at<off+0>(str),::sl_at<off+1>(str),::sl_at<off+2>(str),::sl_at<off+3>(str)
template <char ...C> constexpr str_lit<C...> make_str_lit(str_lit<C...>) {return {};}
template <std::size_t N> constexpr auto make_str_lit(const char (&str)[N])
{
return trim_str_lit<sl_len((const char (&)[N])str), str>{};
}
template <std::size_t A, std::size_t B> struct cexpr_pow {static constexpr std::size_t value = A * cexpr_pow<A,B-1>::value;};
template <std::size_t A> struct cexpr_pow<A,0> {static constexpr std::size_t value = 1;};
template <std::size_t N, std::size_t X, typename = std::make_index_sequence<X>> struct num_to_str_lit_impl;
template <std::size_t N, std::size_t X, std::size_t ...Seq> struct num_to_str_lit_impl<N, X, std::index_sequence<Seq...>>
{
static constexpr auto func()
{
if constexpr (N >= cexpr_pow<10,X>::value)
return num_to_str_lit_impl<N, X+1>::func();
else
return str_lit<(N / cexpr_pow<10,X-1-Seq>::value % 10 + '0')...>{};
}
};
template <std::size_t N> using num_to_str_lit = decltype(num_to_str_lit_impl<N,1>::func());
using spa = str_lit<' '>;
using lpa = str_lit<'('>;
using rpa = str_lit<')'>;
using lbr = str_lit<'['>;
using rbr = str_lit<']'>;
using ast = str_lit<'*'>;
using amp = str_lit<'&'>;
using con = str_lit<'c','o','n','s','t'>;
using vol = str_lit<'v','o','l','a','t','i','l','e'>;
using con_vol = con::concat<spa, vol>;
using nsp = str_lit<':',':'>;
using com = str_lit<','>;
using unk = str_lit<'?','?'>;
using c_cla = str_lit<'c','l','a','s','s','?'>;
using c_uni = str_lit<'u','n','i','o','n','?'>;
using c_enu = str_lit<'e','n','u','m','?'>;
template <typename T> inline constexpr bool ptr_or_ref = std::is_pointer_v< T > || std::is_reference_v< T > || std::is_member_pointer_v< T >;
template <typename T> inline constexpr bool func_or_arr = std::is_function_v< T > || std::is_array_v< T >;
template <typename T> struct primitive_type_name {using value = unk;};
template <typename T, typename = std::enable_if_t<std::is_class_v< T >>> using enable_if_class = T;
template <typename T, typename = std::enable_if_t<std::is_union_v< T >>> using enable_if_union = T;
template <typename T, typename = std::enable_if_t<std::is_enum_v < T >>> using enable_if_enum = T;
template <typename T> struct primitive_type_name<enable_if_class< T >> {using value = c_cla;};
template <typename T> struct primitive_type_name<enable_if_union< T >> {using value = c_uni;};
template <typename T> struct primitive_type_name<enable_if_enum < T >> {using value = c_enu;};
template <typename T> struct type_name_impl;
template <typename T> using type_name_lit = std::conditional_t<std::is_same_v<typename primitive_type_name< T >::value::template concat<spa>,
typename type_name_impl< T >::l::template concat<typename type_name_impl< T >::r>>,
typename primitive_type_name< T >::value,
typename type_name_impl< T >::l::template concat<typename type_name_impl< T >::r>>;
template <typename T> inline constexpr const char *type_name = type_name_lit< T >::value;
template <typename T, typename = std::enable_if_t<!std::is_const_v< T > && !std::is_volatile_v< T >>> using enable_if_no_cv = T;
template <typename T> struct type_name_impl
{
using l = typename primitive_type_name< T >::value::template concat<spa>;
using r = str_lit<>;
};
template <typename T> struct type_name_impl<const T>
{
using new_T_l = std::conditional_t<type_name_impl< T >::l::size && !ptr_or_ref< T >,
spa::concat<typename type_name_impl< T >::l>,
typename type_name_impl< T >::l>;
using l = std::conditional_t<ptr_or_ref< T >,
typename new_T_l::template concat<con>,
con::concat<new_T_l>>;
using r = typename type_name_impl< T >::r;
};
template <typename T> struct type_name_impl<volatile T>
{
using new_T_l = std::conditional_t<type_name_impl< T >::l::size && !ptr_or_ref< T >,
spa::concat<typename type_name_impl< T >::l>,
typename type_name_impl< T >::l>;
using l = std::conditional_t<ptr_or_ref< T >,
typename new_T_l::template concat<vol>,
vol::concat<new_T_l>>;
using r = typename type_name_impl< T >::r;
};
template <typename T> struct type_name_impl<const volatile T>
{
using new_T_l = std::conditional_t<type_name_impl< T >::l::size && !ptr_or_ref< T >,
spa::concat<typename type_name_impl< T >::l>,
typename type_name_impl< T >::l>;
using l = std::conditional_t<ptr_or_ref< T >,
typename new_T_l::template concat<con_vol>,
con_vol::concat<new_T_l>>;
using r = typename type_name_impl< T >::r;
};
template <typename T> struct type_name_impl<T *>
{
using l = std::conditional_t<func_or_arr< T >,
typename type_name_impl< T >::l::template concat<lpa, ast>,
typename type_name_impl< T >::l::template concat< ast>>;
using r = std::conditional_t<func_or_arr< T >,
rpa::concat<typename type_name_impl< T >::r>,
typename type_name_impl< T >::r>;
};
template <typename T> struct type_name_impl<T &>
{
using l = std::conditional_t<func_or_arr< T >,
typename type_name_impl< T >::l::template concat<lpa, amp>,
typename type_name_impl< T >::l::template concat< amp>>;
using r = std::conditional_t<func_or_arr< T >,
rpa::concat<typename type_name_impl< T >::r>,
typename type_name_impl< T >::r>;
};
template <typename T> struct type_name_impl<T &&>
{
using l = std::conditional_t<func_or_arr< T >,
typename type_name_impl< T >::l::template concat<lpa, amp, amp>,
typename type_name_impl< T >::l::template concat< amp, amp>>;
using r = std::conditional_t<func_or_arr< T >,
rpa::concat<typename type_name_impl< T >::r>,
typename type_name_impl< T >::r>;
};
template <typename T, typename C> struct type_name_impl<T C::*>
{
using l = std::conditional_t<func_or_arr< T >,
typename type_name_impl< T >::l::template concat<lpa, type_name_lit<C>, nsp, ast>,
typename type_name_impl< T >::l::template concat< type_name_lit<C>, nsp, ast>>;
using r = std::conditional_t<func_or_arr< T >,
rpa::concat<typename type_name_impl< T >::r>,
typename type_name_impl< T >::r>;
};
template <typename T> struct type_name_impl<enable_if_no_cv<T[]>>
{
using l = typename type_name_impl< T >::l;
using r = lbr::concat<rbr, typename type_name_impl< T >::r>;
};
template <typename T, std::size_t N> struct type_name_impl<enable_if_no_cv<T[N]>>
{
using l = typename type_name_impl< T >::l;
using r = lbr::concat<num_to_str_lit<N>, rbr, typename type_name_impl< T >::r>;
};
template <typename T> struct type_name_impl<T()>
{
using l = typename type_name_impl< T >::l;
using r = lpa::concat<rpa, typename type_name_impl< T >::r>;
};
template <typename T, typename P1, typename ...P> struct type_name_impl<T(P1, P...)>
{
using l = typename type_name_impl< T >::l;
using r = lpa::concat<type_name_lit<P1>,
com::concat<type_name_lit<p>
>..., rpa, typename type_name_impl< T >::r>;
};
#define TYPE_NAME(t) template <> struct primitive_type_name< T > {using value = STR_LIT(#t);}; |