30#if HEGEL_HAS_REFLECTION
34namespace hegel::internal {
36 template <
typename T> std::string cpp_type_name();
37 template <
typename T> std::string repr(
const T& value);
42 template <
typename T>
constexpr std::string_view compiler_type_name() {
44 std::string_view p = __PRETTY_FUNCTION__;
45 auto start = p.find(
"T = ");
46 auto end = p.rfind(
']');
47 if (start == std::string_view::npos || end == std::string_view::npos) {
51 return p.substr(start, end - start);
52#elif defined(__GNUC__)
53 std::string_view p = __PRETTY_FUNCTION__;
54 auto start = p.find(
"T = ");
55 if (start == std::string_view::npos) {
59 auto end = p.find(
';', start);
60 if (end == std::string_view::npos) {
63 if (end == std::string_view::npos) {
66 return p.substr(start, end - start);
67#elif defined(_MSC_VER)
68 std::string_view p = __FUNCSIG__;
69 constexpr std::string_view marker =
"compiler_type_name<";
70 auto start = p.find(marker);
71 auto end = p.rfind(
">(");
72 if (start == std::string_view::npos || end == std::string_view::npos) {
75 start += marker.size();
76 return p.substr(start, end - start);
82 namespace repr_detail {
84 template <
typename T>
struct is_vector : std::false_type {};
86 struct is_vector<std::vector<T>> : std::true_type {};
88 template <
typename T>
struct is_set : std::false_type {};
89 template <
typename T>
struct is_set<std::set<T>> : std::true_type {};
91 template <
typename T>
struct is_map : std::false_type {};
92 template <
typename K,
typename V>
93 struct is_map<std::map<K, V>> : std::true_type {};
95 template <
typename T>
struct is_optional : std::false_type {};
97 struct is_optional<std::
optional<T>> : std::true_type {};
99 template <
typename T>
struct is_pair : std::false_type {};
100 template <
typename A,
typename B>
101 struct is_pair<std::pair<A, B>> : std::true_type {};
103 template <
typename T>
struct is_tuple : std::false_type {};
104 template <
typename... Ts>
105 struct is_tuple<std::tuple<Ts...>> : std::true_type {};
107 template <
typename T>
struct is_variant : std::false_type {};
108 template <
typename... Ts>
109 struct is_variant<std::
variant<Ts...>> : std::true_type {};
111 template <
typename T>
struct is_std_array : std::false_type {};
112 template <
typename E, std::
size_t N>
113 struct is_std_array<std::array<E, N>> : std::true_type {};
115 template <
typename T>
struct array_traits;
116 template <
typename E, std::
size_t N>
117 struct array_traits<std::array<E, N>> {
118 using element_type = E;
119 static constexpr std::size_t size = N;
122 template <
typename T,
typename =
void>
123 struct has_ostream_operator : std::false_type {};
124 template <
typename T>
125 struct has_ostream_operator<
126 T, std::void_t<decltype(std::declval<std::ostream&>()
127 << std::declval<const T&>())>>
130#if HEGEL_HAS_REFLECTION
131 template <typename T, typename = void>
132 struct is_reflectable_impl : std::false_type {};
133 template <typename T>
134 struct is_reflectable_impl<
135 T, std::void_t<decltype(rfl::to_view(std::declval<T&>()))>>
140 template <typename T>
141 struct is_reflectable
142 : std::conjunction<std::is_aggregate<T>, is_reflectable_impl<T>> {};
145 template <typename... Ts> std::string type_name_list() {
146 if constexpr (sizeof...(Ts) == 0) {
149 std::string names[] = {cpp_type_name<Ts>()...};
151 for (std::size_t i = 0; i < sizeof...(Ts); ++i) {
161 template <typename T> struct template_args;
162 template <typename... Ts> struct template_args<std::tuple<Ts...>> {
163 static std::string names() { return type_name_list<Ts...>(); }
165 template <typename... Ts> struct template_args<std::variant<Ts...>> {
166 static std::string names() { return type_name_list<Ts...>(); }
173 inline void append_escaped(std::string& out, unsigned char c,
203 if (c >= 0x20 && c < 0x7f) {
204 out += static_cast<char>(c);
208 std::snprintf(buf, sizeof(buf), "\\%03o", c);
215 template <typename T> std::string cpp_type_name() {
216 if constexpr (std::is_same_v<T, bool>) {
218 } else if constexpr (std::is_same_v<T, char>) {
220 } else if constexpr (std::is_same_v<T, signed char>) {
221 return "signed char";
222 } else if constexpr (std::is_same_v<T, unsigned char>) {
223 return "unsigned char";
224 } else if constexpr (std::is_same_v<T, short>) {
226 } else if constexpr (std::is_same_v<T, unsigned short>) {
227 return "unsigned short";
228 } else if constexpr (std::is_same_v<T, int>) {
230 } else if constexpr (std::is_same_v<T, unsigned int>) {
231 return "unsigned int";
232 } else if constexpr (std::is_same_v<T, long>) {
234 } else if constexpr (std::is_same_v<T, unsigned long>) {
235 return "unsigned long";
236 } else if constexpr (std::is_same_v<T, long long>) {
238 } else if constexpr (std::is_same_v<T, unsigned long long>) {
239 return "unsigned long long";
240 } else if constexpr (std::is_same_v<T, float>) {
242 } else if constexpr (std::is_same_v<T, double>) {
244 } else if constexpr (std::is_same_v<T, long double>) {
245 return "long double";
246 } else if constexpr (std::is_same_v<T, std::string>) {
247 return "std::string";
248 } else if constexpr (std::is_same_v<T, std::monostate>) {
249 return "std::monostate";
250 } else if constexpr (repr_detail::is_vector<T>::value) {
251 return "std::vector<" + cpp_type_name<typename T::value_type>() +
253 } else if constexpr (repr_detail::is_set<T>::value) {
254 return "std::set<" + cpp_type_name<typename T::value_type>() + ">";
255 } else if constexpr (repr_detail::is_map<T>::value) {
256 return "std::map<" + cpp_type_name<typename T::key_type>() + ", " +
257 cpp_type_name<typename T::mapped_type>() + ">";
258 } else if constexpr (repr_detail::is_optional<T>::value) {
259 return "std::optional<" + cpp_type_name<typename T::value_type>() +
261 } else if constexpr (repr_detail::is_pair<T>::value) {
262 return "std::pair<" + cpp_type_name<typename T::first_type>() +
263 ", " + cpp_type_name<typename T::second_type>() + ">";
264 } else if constexpr (repr_detail::is_tuple<T>::value) {
265 return "std::tuple<" + repr_detail::template_args<T>::names() + ">";
266 } else if constexpr (repr_detail::is_variant<T>::value) {
267 return "std::variant<" + repr_detail::template_args<T>::names() +
269 } else if constexpr (repr_detail::is_std_array<T>::value) {
270 using traits = repr_detail::array_traits<T>;
271 return "std::array<" +
272 cpp_type_name<typename traits::element_type>() + ", " +
273 std::to_string(traits::size) + ">";
275 return std::string(compiler_type_name<T>());
281 template <typename T> std::string repr(const T& value) {
282 if constexpr (std::is_same_v<T, bool>) {
283 return value ? "true" : "false";
284 } else if constexpr (std::is_same_v<T, char>) {
285 std::string out = "'";
286 repr_detail::append_escaped(out, static_cast<unsigned char>(value),
290 } else if constexpr (std::is_same_v<T, signed char> ||
291 std::is_same_v<T, unsigned char>) {
292 return "static_cast<" + cpp_type_name<T>() + ">(" +
293 std::to_string(static_cast<int>(value)) + ")";
294 } else if constexpr (std::is_same_v<T, int>) {
295 return std::to_string(value);
296 } else if constexpr (std::is_same_v<T, unsigned int>) {
297 return std::to_string(value) + "u";
298 } else if constexpr (std::is_same_v<T, long>) {
299 return std::to_string(value) + "l";
300 } else if constexpr (std::is_same_v<T, unsigned long>) {
301 return std::to_string(value) + "ul";
302 } else if constexpr (std::is_same_v<T, long long>) {
303 return std::to_string(value) + "ll";
304 } else if constexpr (std::is_same_v<T, unsigned long long>) {
305 return std::to_string(value) + "ull";
306 } else if constexpr (std::is_integral_v<T>) {
308 return "static_cast<" + cpp_type_name<T>() + ">(" +
309 std::to_string(value) + ")";
310 } else if constexpr (std::is_enum_v<T>) {
311 using underlying = std::underlying_type_t<T>;
312 return "static_cast<" + cpp_type_name<T>() + ">(" +
313 repr(static_cast<underlying>(value)) + ")";
314 } else if constexpr (std::is_floating_point_v<T>) {
315 if (std::isnan(value)) {
316 return "std::numeric_limits<" + cpp_type_name<T>() +
319 if (std::isinf(value)) {
320 std::string inf = "std::numeric_limits<" + cpp_type_name<T>() +
322 return value < 0 ? "-" + inf : inf;
325 constexpr int digits = std::numeric_limits<T>::max_digits10;
326 if constexpr (std::is_same_v<T, long double>) {
327 std::snprintf(buf, sizeof(buf), "%.*Lg", digits, value);
329 std::snprintf(buf, sizeof(buf), "%.*g", digits,
330 static_cast<double>(value));
332 std::string out = buf;
335 if (out.find('.') == std::string::npos &&
336 out.find('e') == std::string::npos &&
337 out.find('E') == std::string::npos) {
340 if constexpr (std::is_same_v<T, float>) {
342 } else if constexpr (std::is_same_v<T, long double>) {
346 } else if constexpr (std::is_same_v<T, std::string>) {
347 bool has_nul = value.find('\0') != std::string::npos;
348 std::string out = "std::string(\"";
349 for (char c : value) {
350 repr_detail::append_escaped(out, static_cast<unsigned char>(c),
356 out += ", " + std::to_string(value.size());
360 } else if constexpr (std::is_same_v<T, std::monostate>) {
361 return "std::monostate{}";
362 } else if constexpr (repr_detail::is_pair<T>::value) {
363 return cpp_type_name<T>() + "{" + repr(value.first) + ", " +
364 repr(value.second) + "}";
365 } else if constexpr (repr_detail::is_tuple<T>::value) {
366 std::string out = cpp_type_name<T>() + "{";
368 [&out](const auto&... elems) {
371 repr(elems) + (++i < sizeof...(elems) ? ", " : "")),
377 } else if constexpr (repr_detail::is_optional<T>::value) {
378 std::string name = cpp_type_name<T>();
379 return value.has_value() ? name + "{" + repr(*value) + "}"
381 } else if constexpr (repr_detail::is_variant<T>::value) {
384 std::string out = cpp_type_name<T>() + "{std::in_place_index<" +
385 std::to_string(value.index()) + ">, ";
386 std::visit([&out](const auto& v) { out += repr(v); }, value);
389 } else if constexpr (repr_detail::is_vector<T>::value ||
390 repr_detail::is_set<T>::value ||
391 repr_detail::is_std_array<T>::value) {
392 std::string out = cpp_type_name<T>() + "{";
394 for (const auto& element : value) {
399 out += repr(element);
403 } else if constexpr (repr_detail::is_map<T>::value) {
404 std::string out = cpp_type_name<T>() + "{";
406 for (const auto& entry : value) {
412 "{" + repr(entry.first) + ", " + repr(entry.second) + "}";
417#if HEGEL_HAS_REFLECTION
418 else if constexpr (repr_detail::is_reflectable<T>::value) {
419 std::string out = cpp_type_name<T>() + "{";
420 auto view = rfl::to_view(const_cast<T&>(value));
422 view.apply([&out, &first](const auto& field) {
430 out += repr(*field.value());
436 else if constexpr (repr_detail::has_ostream_operator<T>::value) {
437 std::ostringstream os;
441 return "<unprintable " + std::string(compiler_type_name<T>()) + ">";
Generator< std::variant< Ts... > > variant(Generator< Ts >... gens)
Generate std::variant from heterogeneous generators.
Definition combinators.h:235
Generator< std::optional< T > > optional(Generator< T > gen)
Generate optional values (present or absent).
Definition combinators.h:256