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