1 /*{{{
2 Copyright © 2014-2017 Matthias Kretz <kretz@kde.org>
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6     * Redistributions of source code must retain the above copyright
7       notice, this list of conditions and the following disclaimer.
8     * Redistributions in binary form must reproduce the above copyright
9       notice, this list of conditions and the following disclaimer in the
10       documentation and/or other materials provided with the distribution.
11     * Neither the names of contributing organizations nor the
12       names of its contributors may be used to endorse or promote products
13       derived from this software without specific prior written permission.
14 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
19 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 }}}*/
27 
28 #ifndef VIR_TYPETOSTRING_H_
29 #define VIR_TYPETOSTRING_H_
30 
31 #ifdef __has_include
32 #  if __has_include(<Vc/fwddecl.h>)
33 #    include <Vc/fwddecl.h>
34 #  endif
35 #elif defined COMPILE_FOR_UNIT_TESTS
36 #  include <Vc/fwddecl.h>
37 #endif
38 #include <array>
39 #include <sstream>
40 #include <string>
41 #include <type_traits>
42 #include <typeinfo>
43 #include <utility>  // for __cpp_lib_integer_sequence
44 #include <vector>
45 #include "typelist.h"
46 
47 #ifdef __has_include
48 #  if __has_include(<cxxabi.h>)
49 #    include <cxxabi.h>
50 #    define VIR_HAVE_CXXABI_H 1
51 #  endif
52 #elif defined HAVE_CXX_ABI_H
53 #  include <cxxabi.h>
54 #  define VIR_HAVE_CXXABI_H 1
55 #endif // __has_include
56 
57 #if defined __cpp_return_type_deduction && __cpp_return_type_deduction &&                \
58     __cpp_lib_integer_sequence
59 #define VIR_HAVE_CONSTEXPR_TYPESTRINGS 1
60 #define VIR_AUTO_OR_STRING constexpr auto
61 #define VIR_CONSTEXPR_STRING_RET(N_) constexpr constexpr_string<N_>
62 #else
63 #define VIR_AUTO_OR_STRING inline std::string
64 #define VIR_CONSTEXPR_STRING_RET(N_) inline std::string
65 #endif
66 
67 namespace vir
68 {
69 namespace detail
70 {
71 template <typename T> VIR_AUTO_OR_STRING typeToStringRecurse();
72 
73 template <int N> class constexpr_string
74 {
75 #ifdef VIR_HAVE_CONSTEXPR_TYPESTRINGS
76   const std::array<char, N + 1> chars;
77   static constexpr std::make_index_sequence<N> index_seq{};
78 
79   template <int M, std::size_t... Ls, std::size_t... Rs>
concat(const constexpr_string<M> & rhs,std::index_sequence<Ls...>,std::index_sequence<Rs...>)80   constexpr constexpr_string<N + M> concat(const constexpr_string<M> &rhs,
81                                            std::index_sequence<Ls...>,
82                                            std::index_sequence<Rs...>) const
83   {
84     return {chars[Ls]..., rhs[Rs]...};
85   }
86 
87 public:
constexpr_string(const char c)88   constexpr constexpr_string(const char c) : chars{{c, '\0'}} {}
constexpr_string(const std::initializer_list<char> & c)89   constexpr constexpr_string(const std::initializer_list<char> &c)
90       : constexpr_string(&*c.begin(), index_seq)
91   {
92   }
constexpr_string(const char str[N])93   constexpr constexpr_string(const char str[N]) : constexpr_string(str, index_seq) {}
94   template <std::size_t... Is>
constexpr_string(const char str[N],std::index_sequence<Is...>)95   constexpr constexpr_string(const char str[N], std::index_sequence<Is...>)
96       : chars{{str[Is]..., '\0'}}
97   {
98   }
99 
100   template <int M>
101   constexpr constexpr_string<N + M> operator+(const constexpr_string<M> &rhs) const
102   {
103     return concat(rhs, std::make_index_sequence<N>(), std::make_index_sequence<M>());
104   }
105 
106   constexpr char operator[](size_t i) const { return chars[i]; }
string()107   operator std::string() const { return {&chars[0], N}; }
c_str()108   const char *c_str() const { return chars.data(); }
109 
110   friend std::string operator+(const std::string &lhs, const constexpr_string &rhs)
111   {
112     return lhs + rhs.c_str();
113   }
114   friend std::string operator+(const constexpr_string &lhs, const std::string &rhs)
115   {
116     return lhs.c_str() + rhs;
117   }
118 
119   friend std::ostream &operator<<(std::ostream &lhs, const constexpr_string &rhs)
120   {
121     return lhs.write(&rhs.chars[0], N);
122   }
123 #else
124   constexpr_string(std::string &&tmp) : s(std::move(tmp)) {}
125 public:
126   std::string s;
127   constexpr_string(const char c) : s(1, c) {}
128   constexpr_string(const std::initializer_list<char> &c) : s(&*c.begin(), c.size()) {}
129   constexpr_string(const char str[N]) : s(str, N) {}
130   template <int M>
131   constexpr constexpr_string<N + M> operator+(const constexpr_string<M> &rhs) const
132   {
133     return s + rhs.s;
134   }
135   constexpr char operator[](size_t i) const { return s[i]; }
136   operator std::string() const { return s; }
137   const char *c_str() const { return s.c_str(); }
138   friend std::string operator+(const std::string &lhs, const constexpr_string &rhs)
139   {
140     return lhs + rhs.s;
141   }
142   friend std::string operator+(const constexpr_string &lhs, const std::string &rhs)
143   {
144     return lhs.s + rhs;
145   }
146 
147   friend std::ostream &operator<<(std::ostream &lhs, const constexpr_string &rhs)
148   {
149     return lhs << rhs.s;
150   }
151 #endif
152 };
153 
154 template <std::size_t N> using CStr = const char[N];
cs(const CStr<N> & str)155 template <std::size_t N> VIR_CONSTEXPR_STRING_RET(N - 1) cs(const CStr<N> &str)
156 {
157   return str;
158 }
cs(const char c)159 VIR_CONSTEXPR_STRING_RET(1) cs(const char c) { return constexpr_string<1>(c); }
160 
161 template <class T, T N>
162 VIR_CONSTEXPR_STRING_RET(1)
163 number_to_string(std::integral_constant<T, N>,
164                  typename std::enable_if<(N >= 0 && N <= 9)>::type * = nullptr)
165 {
166   return cs('0' + N);
167 }
168 
169 template <class T, T N>
170 VIR_AUTO_OR_STRING number_to_string(std::integral_constant<T, N>,
171                                     typename std::enable_if<(N >= 10)>::type * = nullptr)
172 {
173   return number_to_string(std::integral_constant<T, N / 10>()) + cs('0' + N % 10);
174 }
175 
176 template <class T, T N>
177 VIR_AUTO_OR_STRING number_to_string(std::integral_constant<T, N>,
178                                     typename std::enable_if<(N < 0)>::type * = nullptr)
179 {
180   return cs('-') + number_to_string(std::integral_constant<T, -N>());
181 }
182 
183 // std::array<T, N> {{{1
184 template <typename T, std::size_t N>
typeToString_impl(std::array<T,N> *)185 VIR_AUTO_OR_STRING typeToString_impl(std::array<T, N> *)
186 {
187   return cs("array<") + typeToStringRecurse<T>() + cs(", ") +
188          number_to_string(std::integral_constant<int, N>()) + cs('>');
189 }
190 
191 // std::vector<T> {{{1
typeToString_impl(std::vector<T> *)192 template <typename T> VIR_AUTO_OR_STRING typeToString_impl(std::vector<T> *)
193 {
194   return cs("vector<") + typeToStringRecurse<T>() + cs('>');
195 }
196 
197 // std::integral_constant<T, N> {{{1
198 template <typename T, T N>
typeToString_impl(std::integral_constant<T,N> *)199 VIR_AUTO_OR_STRING typeToString_impl(std::integral_constant<T, N> *)
200 {
201   return cs("integral_constant<") + typeToStringRecurse<T>() + cs(", ") +
202          number_to_string(std::integral_constant<T, N>()) + cs('>');
203 }
204 
205 // template parameter pack to a comma separated string {{{1
typelistToStringRecursive()206 VIR_AUTO_OR_STRING typelistToStringRecursive()
207 {
208   return cs('}');
209 }
210 template <typename T0, typename... Ts>
typelistToStringRecursive(T0 *,Ts * ...)211 VIR_AUTO_OR_STRING typelistToStringRecursive(T0 *, Ts *...)
212 {
213   return cs(", ") + typeToStringRecurse<T0>() +
214          typelistToStringRecursive(typename std::add_pointer<Ts>::type()...);
215 }
216 
217 template <typename T0, typename... Ts>
typeToString_impl(Typelist<T0,Ts...> *)218 VIR_AUTO_OR_STRING typeToString_impl(Typelist<T0, Ts...> *)
219 {
220   return cs('{') + typeToStringRecurse<T0>() +
221          typelistToStringRecursive(typename std::add_pointer<Ts>::type()...);
222 }
223 
typeToString_impl(Typelist<> *)224 VIR_CONSTEXPR_STRING_RET(2) typeToString_impl(Typelist<> *) { return "{}"; }
225 
226 // Vc::simd to string {{{1
227 #ifdef VC_FWDDECL_H_
typeToString_impl(Vc::simd_abi::fixed_size<N> *)228 template <int N> VIR_AUTO_OR_STRING typeToString_impl(Vc::simd_abi::fixed_size<N> *)
229 {
230   return number_to_string(std::integral_constant<int, N>());
231 }
typeToString_impl(Vc::simd_abi::scalar *)232 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(Vc::simd_abi::scalar *) { return "scalar"; }
typeToString_impl(Vc::simd_abi::__sse *)233 VIR_CONSTEXPR_STRING_RET(3) typeToString_impl(Vc::simd_abi::__sse *) { return "SSE"; }
typeToString_impl(Vc::simd_abi::__avx *)234 VIR_CONSTEXPR_STRING_RET(3) typeToString_impl(Vc::simd_abi::__avx *) { return "AVX"; }
typeToString_impl(Vc::simd_abi::__avx512 *)235 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(Vc::simd_abi::__avx512 *) { return "AVX512"; }
typeToString_impl(Vc::simd_abi::__neon *)236 VIR_CONSTEXPR_STRING_RET(4) typeToString_impl(Vc::simd_abi::__neon *) { return "NEON"; }
typeToString_impl(Vc::simd<T,A> *)237 template <class T, class A> VIR_AUTO_OR_STRING typeToString_impl(Vc::simd<T, A> *)
238 {
239   return cs("simd<") + typeToStringRecurse<T>() + cs(", ") + typeToStringRecurse<A>() +
240          cs('>');
241 }
typeToString_impl(Vc::simd_mask<T,A> *)242 template <class T, class A> VIR_AUTO_OR_STRING typeToString_impl(Vc::simd_mask<T, A> *)
243 {
244   return cs("simd_mask<") + typeToStringRecurse<T>() + cs(", ") + typeToStringRecurse<A>() +
245          cs('>');
246 }
247 #endif  // VC_FWDDECL_H_
248 
249 // generic fallback (typeid::name) {{{1
typeToString_impl(T *)250 template <typename T> inline std::string typeToString_impl(T *)
251 {
252 #ifdef VIR_HAVE_CXXABI_H
253   char buf[1024];
254   size_t size = 1024;
255   abi::__cxa_demangle(typeid(T).name(), buf, &size, nullptr);
256   return std::string{buf};
257 #else
258   return typeid(T).name();
259 #endif
260 }
261 
262 VIR_CONSTEXPR_STRING_RET(0) typeToString_impl(void *);// { return ""; }
typeToString_impl(long double *)263 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(long double *) { return "ldoubl"; }
typeToString_impl(double *)264 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(double *) { return "double"; }
typeToString_impl(float *)265 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(float *) { return " float"; }
typeToString_impl(long long *)266 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(long long *) { return " llong"; }
typeToString_impl(unsigned long long *)267 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(unsigned long long *) { return "ullong"; }
typeToString_impl(long *)268 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(long *) { return "  long"; }
typeToString_impl(unsigned long *)269 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(unsigned long *) { return " ulong"; }
typeToString_impl(int *)270 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(int *) { return "   int"; }
typeToString_impl(unsigned int *)271 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(unsigned int *) { return "  uint"; }
typeToString_impl(short *)272 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(short *) { return " short"; }
typeToString_impl(unsigned short *)273 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(unsigned short *) { return "ushort"; }
typeToString_impl(char *)274 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(char *) { return "  char"; }
typeToString_impl(unsigned char *)275 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(unsigned char *) { return " uchar"; }
typeToString_impl(signed char *)276 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(signed char *) { return " schar"; }
typeToString_impl(bool *)277 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(bool *)     { return "  bool"; }
typeToString_impl(wchar_t *)278 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(wchar_t *)  { return " wchar"; }
typeToString_impl(char16_t *)279 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(char16_t *) { return "char16"; }
typeToString_impl(char32_t *)280 VIR_CONSTEXPR_STRING_RET(6) typeToString_impl(char32_t *) { return "char32"; }
281 
typeToStringRecurse()282 template <typename T> VIR_AUTO_OR_STRING typeToStringRecurse()
283 {
284   using tag = T *;
285   return typeToString_impl(tag());
286 }
287 //}}}1
288 }  // namespace detail
289 
290 // typeToString specializations {{{1
typeToString()291 template <typename T> inline std::string typeToString()
292 {
293   using tag = T *;
294   return detail::typeToString_impl(tag());
295 }
296 
297 //}}}1
298 }  // namespace vir
299 
300 // vim: foldmethod=marker
301 #endif  // VIR_TYPETOSTRING_H_
302