HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
reflection.hpp
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "fixed_string.hpp"
8#include "misc.hpp"
9#include "../macros.hpp"
10#include "assert.hpp"
11#include "terminate.hpp"
12#include "exception.hpp"
13#include <type_traits>
14#include <string>
15#include <string_view>
16#include <typeinfo>
17
18hi_export_module(hikogui.utility.reflection);
19
20hi_export namespace hi { inline namespace v1 {
21
25 template<typename T>
26 [[nodiscard]] constexpr operator T() const noexcept
27 {
28 return {};
29 }
30};
31
32namespace detail {
33
34template<typename T, typename... C>
35[[nodiscard]] constexpr size_t count_data_members() noexcept
36{
37 static_assert(std::is_trivially_constructible_v<T>);
38
39 // Try the largest possible number of data members first. i.e. depth-first recursive.
40 if constexpr (sizeof...(C) < sizeof(T)) {
41 if constexpr (constexpr auto next = count_data_members<T, C..., convertible_to_any>()) {
42 // We found the number of data members, larger than the current size.
43 return next;
44 }
45 }
46
47 // Check if this number of arguments to the constructor is valid .
48 if constexpr (requires { T{C{}...}; }) {
49 // Yes, return the number of arguments.
50 return sizeof...(C);
51 } else {
52 // Nope, return false.
53 return 0;
54 }
55}
56
57[[nodiscard]] constexpr std::string_view type_name_token(std::string_view str) noexcept
58{
59 for (auto i = 0_uz; i != str.size(); ++i) {
60 auto const c = str[i];
61
62 if (not((c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z') or (c >= '0' and c <= '9') or c == '_')) {
63 // End of token.
64 return str.substr(0, i + 1);
65 }
66 }
67
68 return str;
69}
70
71[[nodiscard]] constexpr std::string type_name_short_hand(std::string_view type_name) noexcept
72{
73 if (type_name == "std::basic_string<char,std::char_traits<char>,std::allocator<char>>") {
74 return "std::string";
75 } else if (type_name == "std::basic_string<char,std::char_traits<char>,std::allocator<char>>&") {
76 return "std::string&";
77 } else if (type_name == "const std::basic_string<char,std::char_traits<char>,std::allocator<char>>&") {
78 return "const std::string&";
79 } else {
80 return std::string{type_name};
81 }
82}
83
84#if HI_COMPILER == HI_CC_MSVC
85template<typename T>
86[[nodiscard]] constexpr std::string type_name() noexcept
87{
88 // "std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl hi::v1::type_name<T>(void)
89 // noexcept"
90 auto signature = std::string_view{__FUNCSIG__};
91
92 // Extract the type passed to type_name().
93 auto first = signature.find("type_name<");
94 hi_assert(first != std::string_view::npos);
95 first += 10;
96
97 auto last = signature.rfind('>');
98 hi_assert(last != std::string_view::npos);
99
100 signature = signature.substr(first, last - first);
101
102 auto r = std::string{};
103 while (not signature.empty()) {
104 if (signature.starts_with("class ")) {
105 signature = signature.substr(6);
106 } else if (signature.starts_with("struct ")) {
107 signature = signature.substr(7);
108 } else if (signature.starts_with(" >")) {
109 r += '>';
110 signature = signature.substr(2);
111 } else if (signature.starts_with(" *")) {
112 r += '*';
113 signature = signature.substr(2);
114 } else {
115 auto token = type_name_token(signature);
116 r += token;
117 signature = signature.substr(token.size());
118 }
119 }
120
121 return type_name_short_hand(r);
122}
123#elif HI_COMPILER == HI_CC_CLANG
124template<typename T>
125[[nodiscard]] constexpr std::string type_name() noexcept
126{
127 // "std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl hi::v1::type_name<T>(void)
128 // noexcept"
129 auto signature = std::string_view{__PRETTY_FUNCTION__ };
130
131 // Extract the type passed to type_name().
132 auto first = signature.find("type_name<");
133 hi_assert(first != std::string_view::npos);
134 first += 10;
135
136 auto last = signature.rfind('>');
137 hi_assert(last != std::string_view::npos);
138
139 signature = signature.substr(first, last - first);
140
141 auto r = std::string{};
142 while (not signature.empty()) {
143 if (signature.starts_with("class ")) {
144 signature = signature.substr(6);
145 } else if (signature.starts_with("struct ")) {
146 signature = signature.substr(7);
147 } else if (signature.starts_with(" >")) {
148 r += '>';
149 signature = signature.substr(2);
150 } else if (signature.starts_with(" *")) {
151 r += '*';
152 signature = signature.substr(2);
153 } else {
154 auto token = type_name_token(signature);
155 r += token;
156 signature = signature.substr(token.size());
157 }
158 }
159
160 return type_name_short_hand(r);
161}
162#else
163template<typename T>
164[[nodiscard]] constexpr std::string type_name() noexcept
165{
166 return typeid(T).name();
167}
168#endif
169
170} // namespace detail
171
172template<typename T>
173struct number_of_data_members : std::integral_constant<size_t, detail::count_data_members<T>()> {};
174
175template<typename T>
176constexpr size_t number_of_data_members_v = number_of_data_members<T>::value;
177
178template<size_t Index, typename Type>
179constexpr decltype(auto) get_data_member(Type&& rhs) noexcept
180{
181#define HI_X_FORWARD(x) forward_like<Type>(x),
182
183 constexpr auto number_of_members = number_of_data_members<std::remove_cvref_t<Type>>();
184
185 if constexpr (number_of_members == 0) {
186 hi_static_no_default();
187
188 // clang-format off
189#define HI_X(count, ...) \
190 } else if constexpr (number_of_members == count) { \
191 auto&& [__VA_ARGS__] = rhs; \
192 return std::get<Index>(std::forward_as_tuple(hi_for_each(HI_X_FORWARD, __VA_ARGS__) 0));
193
194 HI_X( 1, a)
195 HI_X( 2, a,b)
196 HI_X( 3, a,b,c)
197 HI_X( 4, a,b,c,d)
198 HI_X( 5, a,b,c,d,e)
199 HI_X( 6, a,b,c,d,e,f)
200 HI_X( 7, a,b,c,d,e,f,g)
201 HI_X( 8, a,b,c,d,e,f,g,h)
202 HI_X( 9, a,b,c,d,e,f,g,h,i)
203 HI_X(10, a,b,c,d,e,f,g,h,i,j)
204 HI_X(11, a,b,c,d,e,f,g,h,i,j,k)
205 HI_X(12, a,b,c,d,e,f,g,h,i,j,k,l)
206 HI_X(13, a,b,c,d,e,f,g,h,i,j,k,l,m)
207 HI_X(14, a,b,c,d,e,f,g,h,i,j,k,l,m,n)
208 HI_X(15, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o)
209 HI_X(16, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)
210 HI_X(17, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q)
211 HI_X(18, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r)
212 HI_X(19, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s)
213 HI_X(20, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t)
214 HI_X(21, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u)
215 HI_X(22, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v)
216 HI_X(23, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w)
217 HI_X(24, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x)
218 HI_X(25, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y)
219 HI_X(26, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z)
220 HI_X(27, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A)
221 HI_X(28, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B)
222 HI_X(29, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C)
223 HI_X(30, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D)
224 HI_X(31, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E)
225 HI_X(32, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F)
226 HI_X(33, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G)
227 HI_X(34, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H)
228 HI_X(35, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I)
229 HI_X(36, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J)
230 HI_X(37, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K)
231 HI_X(38, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L)
232 HI_X(39, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M)
233 HI_X(40, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N)
234 HI_X(41, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O)
235 HI_X(42, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P)
236 HI_X(43, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q)
237 HI_X(44, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)
238 HI_X(45, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S)
239 HI_X(46, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T)
240 HI_X(47, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U)
241 HI_X(48, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V)
242 HI_X(49, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W)
243 HI_X(50, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X)
244 HI_X(51, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y)
245 HI_X(52, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z)
246 // clang-format on
247
248 } else {
249 hi_static_not_implemented();
250 }
251
252#undef HI_X
253#undef HI_X_FORWARD
254}
255
256#if HI_COMPILER == HI_CC_MSVC
257template<typename T>
258[[nodiscard]] constexpr auto type_name() noexcept
259{
260 return hi_to_fixed_string(detail::type_name<T>());
261}
262#endif
263
264}} // namespace hi::v1
Utilities to assert and bound check.
Utilities for throwing exceptions and terminating the application.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
A type that can be implicitly converted to any type.
Definition reflection.hpp:24
Definition reflection.hpp:173
T find(T... args)
T substr(T... args)