EnTT 4.0.0
Loading...
Searching...
No Matches
node.hpp
1#ifndef ENTT_META_NODE_HPP
2#define ENTT_META_NODE_HPP
3
4#include "../config/config.h"
5#include "../core/bit.hpp"
6#include "../core/concepts.hpp"
7#include "../core/enum.hpp"
8#include "../core/fwd.hpp"
9#include "../core/type_info.hpp"
10#include "../core/type_traits.hpp"
11#include "../core/utility.hpp"
12#include "../stl/array.hpp"
13#include "../stl/bit.hpp"
14#include "../stl/cstddef.hpp"
15#include "../stl/cstdint.hpp"
16#include "../stl/memory.hpp"
17#include "../stl/type_traits.hpp"
18#include "../stl/utility.hpp"
19#include "../stl/vector.hpp"
20#include "context.hpp"
21#include "fwd.hpp"
22#include "type_traits.hpp"
23
24namespace entt {
25
27namespace internal {
28
29enum class meta_traits : stl::uint32_t {
30 is_none = 0x0000,
31 is_const = 0x0001,
32 is_static = 0x0002,
33 is_arithmetic = 0x0004,
34 is_integral = 0x0008,
35 is_signed = 0x0010,
36 is_array = 0x0020,
37 is_enum = 0x0040,
38 is_class = 0x0080,
39 is_pointer = 0x0100,
40 is_pointer_like = 0x0200,
41 is_sequence_container = 0x0400,
42 is_associative_container = 0x0800,
43 _user_defined_traits = 0xFFFF,
44 _entt_enum_as_bitmask = 0xFFFF
45};
46
47template<typename Type>
48requires stl::is_enum_v<Type>
49[[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept {
50 constexpr auto shift = stl::popcount(static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
51 return Type{static_cast<stl::underlying_type_t<Type>>(static_cast<stl::underlying_type_t<meta_traits>>(traits) >> shift)};
52}
53
54template<typename Type>
55requires stl::is_enum_v<Type>
56[[nodiscard]] auto user_to_meta_traits(const Type value) noexcept {
57 constexpr auto shift = stl::popcount(static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
58 const auto traits = static_cast<stl::underlying_type_t<internal::meta_traits>>(static_cast<stl::underlying_type_t<Type>>(value));
59 ENTT_ASSERT(traits < ((~static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits");
60 return meta_traits{traits << shift};
61}
62
63struct meta_type_node;
64
65struct meta_custom_node {
66 id_type id{};
67 stl::shared_ptr<void> value{};
68};
69
70struct meta_base_node {
71 id_type id{};
72 const meta_type_node &(*type)(const meta_context &) noexcept {};
73 const void *(*cast)(const void *) noexcept {};
74};
75
76struct meta_conv_node {
77 id_type id{};
78 meta_any (*conv)(const meta_ctx &, const void *){};
79};
80
81struct meta_ctor_node {
82 using size_type = stl::size_t;
83
84 id_type id{};
85 size_type arity{0u};
86 meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
87 meta_any (*invoke)(const meta_ctx &, meta_any *const){};
88};
89
90struct meta_data_node {
91 using size_type = stl::size_t;
92
93 id_type id{};
94 const char *name{};
95 meta_traits traits{meta_traits::is_none};
96 size_type set_arity{0u};
97 size_type get_arity{0u};
98 meta_type (*set_arg)(const meta_ctx &, const size_type) noexcept {};
99 meta_type (*get_arg)(const meta_ctx &, const size_type) noexcept {};
100 const meta_type_node &(*type)(const meta_context &) noexcept {};
101 bool (*set)(meta_handle, meta_any *const){};
102 meta_any (*get)(meta_handle, meta_any *const){};
103 meta_custom_node custom{};
104};
105
106struct meta_func_node {
107 using size_type = stl::size_t;
108
109 id_type id{};
110 const char *name{};
111 meta_traits traits{meta_traits::is_none};
112 size_type arity{0u};
113 const meta_type_node &(*ret)(const meta_context &) noexcept {};
114 meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
115 meta_any (*invoke)(meta_handle, meta_any *const){};
116 stl::unique_ptr<meta_func_node> next;
117 meta_custom_node custom{};
118};
119
120struct meta_template_node {
121 using size_type = stl::size_t;
122
123 size_type arity{0u};
124 const meta_type_node &(*resolve)(const meta_context &) noexcept {};
125 const meta_type_node &(*arg)(const meta_context &, const size_type) noexcept {};
126};
127
128struct meta_type_descriptor {
129 stl::vector<meta_ctor_node> ctor{};
130 stl::vector<meta_base_node> base{};
131 stl::vector<meta_conv_node> conv{};
132 stl::vector<meta_data_node> data{};
133 stl::vector<meta_func_node> func{};
134};
135
136struct meta_type_node {
137 using size_type = stl::size_t;
138
139 const type_info *info{};
140 id_type alias{};
141 const char *name{};
142 meta_traits traits{meta_traits::is_none};
143 size_type size_of{0u};
144 const meta_type_node &(*remove_pointer)(const meta_context &) noexcept {};
145 meta_any (*default_constructor)(const meta_ctx &){};
146 double (*conversion_helper)(void *, const void *){};
147 meta_any (*from_void)(const meta_ctx &, void *, const void *){};
148 meta_template_node templ{};
149 meta_custom_node custom{};
150 stl::unique_ptr<meta_type_descriptor> details{};
151};
152
153template<typename Type, typename Value>
154[[nodiscard]] auto *find_member(Type &from, const Value value) {
155 for(auto &&elem: from) {
156 if(elem.id == value) {
157 return &elem;
158 }
159 }
160
161 return static_cast<Type::value_type *>(nullptr);
162}
163
164[[nodiscard]] inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t<decltype(meta_func_node::invoke)> *const ref) {
165 while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
166 return curr;
167}
168
169template<auto Member>
170[[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) {
171 using value_type = stl::remove_reference_t<decltype((node.details.get()->*Member))>::value_type;
172
173 if(node.details) {
174 if(auto *member = find_member((node.details.get()->*Member), id); member != nullptr) {
175 return member;
176 }
177
178 if(recursive) {
179 for(auto &&curr: node.details->base) {
180 if(auto *elem = look_for<Member>(context, curr.type(context), id, recursive); elem) {
181 return elem;
182 }
183 }
184 }
185 }
186
187 return static_cast<value_type *>(nullptr);
188}
189
190template<cvref_unqualified Type>
191const meta_type_node &resolve(const meta_context &) noexcept;
192
193template<typename... Args>
194[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list<Args...>, const stl::size_t index) noexcept {
195 using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept;
196 constexpr stl::array<resolve_type, sizeof...(Args)> list{&resolve<stl::remove_cvref_t<Args>>...};
197 ENTT_ASSERT(index < sizeof...(Args), "Out of bounds");
198 return list[index](context);
199}
200
201[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const id_type to, const void *instance) noexcept {
202 if(from.details) {
203 for(auto &&curr: from.details->base) {
204 if(const void *other = curr.cast(instance); curr.id == to) {
205 return other;
206 } else if(const void *elem = try_cast(context, curr.type(context), to, other); elem) {
207 return elem;
208 }
209 }
210 }
211
212 return nullptr;
213}
214
215template<typename Type>
216auto setup_node_for() noexcept {
217 meta_type_node node{
218 &type_id<Type>(),
219 type_id<Type>().hash(),
220 nullptr,
221 (stl::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
222 | (stl::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
223 | (stl::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
224 | (stl::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
225 | (stl::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
226 | (stl::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
227 | (stl::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
228 | (is_meta_pointer_like_v<Type> ? meta_traits::is_pointer_like : meta_traits::is_none)
229 | (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_sequence_container : meta_traits::is_none)
230 | (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_associative_container : meta_traits::is_none),
231 size_of_v<Type>,
232 &resolve<stl::remove_const_t<stl::remove_pointer_t<Type>>>};
233
234 if constexpr(stl::is_default_constructible_v<Type>) {
235 node.default_constructor = +[](const meta_ctx &ctx) {
236 return meta_any{ctx, stl::in_place_type<Type>};
237 };
238 }
239
240 if constexpr(stl::is_arithmetic_v<Type>) {
241 node.conversion_helper = +[](void *lhs, const void *rhs) {
242 return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(*static_cast<const double *>(rhs))) : static_cast<double>(*static_cast<const Type *>(rhs));
243 };
244 } else if constexpr(stl::is_enum_v<Type>) {
245 node.conversion_helper = +[](void *lhs, const void *rhs) {
246 return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(static_cast<stl::underlying_type_t<Type>>(*static_cast<const double *>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
247 };
248 }
249
250 if constexpr(!stl::is_void_v<Type> && !stl::is_function_v<Type>) {
251 node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) {
252 if(elem && celem) { // ownership construction request
253 return meta_any{ctx, stl::in_place, static_cast<stl::decay_t<Type> *>(elem)};
254 }
255
256 if(elem) { // non-const reference construction request
257 return meta_any{ctx, stl::in_place_type<stl::decay_t<Type> &>, *static_cast<stl::decay_t<Type> *>(elem)};
258 }
259
260 // const reference construction request
261 return meta_any{ctx, stl::in_place_type<const stl::decay_t<Type> &>, *static_cast<const stl::decay_t<Type> *>(celem)};
262 };
263 }
264
265 if constexpr(is_complete_v<meta_template_traits<Type>>) {
266 node.templ = meta_template_node{
267 meta_template_traits<Type>::args_type::size,
268 &resolve<typename meta_template_traits<Type>::class_type>,
269 +[](const meta_context &area, const stl::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
270 }
271
272 return node;
273}
274
275template<cvref_unqualified Type>
276[[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept {
277 static const meta_type_node node = setup_node_for<Type>();
278 const auto it = context.bucket.find(node.info->hash());
279 return (it == context.bucket.cend()) ? node : *it->second;
280}
281
282} // namespace internal
284
285} // namespace entt
286
287#endif
EnTT default namespace.
Definition dense_map.hpp:25
meta_type resolve(const meta_ctx &ctx) noexcept
Returns the meta type associated with a given type.
Definition resolve.hpp:21
stl::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29