EnTT 3.14.0
Loading...
Searching...
No Matches
node.hpp
1#ifndef ENTT_META_NODE_HPP
2#define ENTT_META_NODE_HPP
3
4#include <cstddef>
5#include <memory>
6#include <type_traits>
7#include <utility>
8#include <vector>
9#include "../config/config.h"
10#include "../core/attribute.h"
11#include "../core/bit.hpp"
12#include "../core/enum.hpp"
13#include "../core/fwd.hpp"
14#include "../core/type_info.hpp"
15#include "../core/type_traits.hpp"
16#include "../core/utility.hpp"
17#include "context.hpp"
18#include "type_traits.hpp"
19
20namespace entt {
21
22class meta_any;
23class meta_type;
24struct meta_handle;
25
27namespace internal {
28
29enum class meta_traits : std::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_meta_pointer_like = 0x0200,
41 is_meta_sequence_container = 0x0400,
42 is_meta_associative_container = 0x0800,
43 _user_defined_traits = 0xFFFF,
44 _entt_enum_as_bitmask = 0xFFFF
45};
46
47template<typename Type>
48[[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept {
49 static_assert(std::is_enum_v<Type>, "Invalid enum type");
50 constexpr auto shift = popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
51 return Type{static_cast<std::underlying_type_t<Type>>(static_cast<std::underlying_type_t<meta_traits>>(traits) >> shift)};
52}
53
54template<typename Type>
55[[nodiscard]] auto user_to_meta_traits(const Type value) noexcept {
56 static_assert(std::is_enum_v<Type>, "Invalid enum type");
57 constexpr auto shift = popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
58 const auto traits = static_cast<std::underlying_type_t<internal::meta_traits>>(static_cast<std::underlying_type_t<Type>>(value));
59 ENTT_ASSERT(traits < ((~static_cast<std::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 type{};
67 std::shared_ptr<void> value{};
68};
69
70struct meta_prop_node {
71 id_type id{};
72 meta_type_node (*type)(const meta_context &) noexcept {};
73 std::shared_ptr<void> value{};
74};
75
76struct meta_base_node {
77 id_type type{};
78 meta_type_node (*resolve)(const meta_context &) noexcept {};
79 const void *(*cast)(const void *) noexcept {};
80};
81
82struct meta_conv_node {
83 id_type type{};
84 meta_any (*conv)(const meta_ctx &, const void *){};
85};
86
87struct meta_ctor_node {
88 using size_type = std::size_t;
89
90 id_type id{};
91 size_type arity{0u};
92 meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
93 meta_any (*invoke)(const meta_ctx &, meta_any *const){};
94};
95
96struct meta_dtor_node {
97 void (*dtor)(void *){};
98};
99
100struct meta_data_node {
101 using size_type = std::size_t;
102
103 id_type id{};
104 meta_traits traits{meta_traits::is_none};
105 size_type arity{0u};
106 meta_type_node (*type)(const meta_context &) noexcept {};
107 meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
108 bool (*set)(meta_handle, meta_any){};
109 meta_any (*get)(const meta_ctx &, meta_handle){};
110 meta_custom_node custom{};
111 std::vector<meta_prop_node> prop{};
112};
113
114struct meta_func_node {
115 using size_type = std::size_t;
116
117 id_type id{};
118 meta_traits traits{meta_traits::is_none};
119 size_type arity{0u};
120 meta_type_node (*ret)(const meta_context &) noexcept {};
121 meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
122 meta_any (*invoke)(const meta_ctx &, meta_handle, meta_any *const){};
123 std::shared_ptr<meta_func_node> next{};
124 meta_custom_node custom{};
125 std::vector<meta_prop_node> prop{};
126};
127
128struct meta_template_node {
129 using size_type = std::size_t;
130
131 size_type arity{0u};
132 meta_type_node (*resolve)(const meta_context &) noexcept {};
133 meta_type_node (*arg)(const meta_context &, const size_type) noexcept {};
134};
135
136struct meta_type_descriptor {
137 std::vector<meta_ctor_node> ctor{};
138 std::vector<meta_base_node> base{};
139 std::vector<meta_conv_node> conv{};
140 std::vector<meta_data_node> data{};
141 std::vector<meta_func_node> func{};
142 std::vector<meta_prop_node> prop{};
143};
144
145struct meta_type_node {
146 using size_type = std::size_t;
147
148 const type_info *info{};
149 id_type id{};
150 meta_traits traits{meta_traits::is_none};
151 size_type size_of{0u};
152 meta_type_node (*resolve)(const meta_context &) noexcept {};
153 meta_type_node (*remove_pointer)(const meta_context &) noexcept {};
154 meta_any (*default_constructor)(const meta_ctx &){};
155 double (*conversion_helper)(void *, const void *){};
156 meta_any (*from_void)(const meta_ctx &, void *, const void *){};
157 meta_template_node templ{};
158 meta_dtor_node dtor{};
159 meta_custom_node custom{};
160 std::shared_ptr<meta_type_descriptor> details{};
161};
162
163template<auto Member, typename Type, typename Value>
164[[nodiscard]] auto *find_member(Type &from, const Value value) {
165 for(auto &&elem: from) {
166 if((elem.*Member) == value) {
167 return &elem;
168 }
169 }
170
171 return static_cast<typename Type::value_type *>(nullptr);
172}
173
174[[nodiscard]] inline auto *find_overload(meta_func_node *curr, std::remove_pointer_t<decltype(meta_func_node::invoke)> *const ref) {
175 while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
176 return curr;
177}
178
179template<auto Member>
180[[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id) {
181 using value_type = typename std::remove_reference_t<decltype((node.details.get()->*Member))>::value_type;
182
183 if(node.details) {
184 if(auto *member = find_member<&value_type::id>((node.details.get()->*Member), id); member != nullptr) {
185 return member;
186 }
187
188 for(auto &&curr: node.details->base) {
189 if(auto *elem = look_for<Member>(context, curr.resolve(context), id); elem) {
190 return elem;
191 }
192 }
193 }
194
195 return static_cast<value_type *>(nullptr);
196}
197
198template<typename Type>
199meta_type_node resolve(const meta_context &) noexcept;
200
201template<typename... Args>
202[[nodiscard]] auto meta_arg_node(const meta_context &context, type_list<Args...>, [[maybe_unused]] const std::size_t index) noexcept {
203 [[maybe_unused]] std::size_t pos{};
204 meta_type_node (*value)(const meta_context &) noexcept = nullptr;
205 ((value = (pos++ == index ? &resolve<std::remove_cv_t<std::remove_reference_t<Args>>> : value)), ...);
206 ENTT_ASSERT(value != nullptr, "Out of bounds");
207 return value(context);
208}
209
210[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const meta_type_node &to, const void *instance) noexcept {
211 if((from.info != nullptr) && (to.info != nullptr) && *from.info == *to.info) {
212 return instance;
213 }
214
215 if(from.details) {
216 for(auto &&curr: from.details->base) {
217 if(const void *elem = try_cast(context, curr.resolve(context), to, curr.cast(instance)); elem) {
218 return elem;
219 }
220 }
221 }
222
223 return nullptr;
224}
225
226template<typename Func>
227[[nodiscard]] inline auto try_convert(const meta_context &context, const meta_type_node &from, const type_info &to, const bool arithmetic_or_enum, const void *instance, Func func) {
228 if(from.info && *from.info == to) {
229 return func(instance, from);
230 }
231
232 if(from.details) {
233 for(auto &&elem: from.details->conv) {
234 if(elem.type == to.hash()) {
235 return func(instance, elem);
236 }
237 }
238
239 for(auto &&curr: from.details->base) {
240 if(auto other = try_convert(context, curr.resolve(context), to, arithmetic_or_enum, curr.cast(instance), func); other) {
241 return other;
242 }
243 }
244 }
245
246 if(from.conversion_helper && arithmetic_or_enum) {
247 return func(instance, from.conversion_helper);
248 }
249
250 return func(instance);
251}
252
253[[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
254 const auto it = context.value.find(info.hash());
255 return it != context.value.end() ? &it->second : nullptr;
256}
257
258template<typename Type>
259[[nodiscard]] meta_type_node resolve(const meta_context &context) noexcept {
260 static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
261
262 if(auto *elem = try_resolve(context, type_id<Type>()); elem) {
263 return *elem;
264 }
265
266 meta_type_node node{
267 &type_id<Type>(),
268 type_id<Type>().hash(),
269 (std::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
270 | (std::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
271 | (std::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
272 | (std::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
273 | (std::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
274 | (std::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
275 | (std::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
276 | (is_meta_pointer_like_v<Type> ? meta_traits::is_meta_pointer_like : meta_traits::is_none)
277 | (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_meta_sequence_container : meta_traits::is_none)
278 | (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_meta_associative_container : meta_traits::is_none),
279 size_of_v<Type>,
280 &resolve<Type>,
281 &resolve<std::remove_cv_t<std::remove_pointer_t<Type>>>};
282
283 if constexpr(std::is_default_constructible_v<Type>) {
284 node.default_constructor = +[](const meta_ctx &ctx) {
285 return meta_any{ctx, std::in_place_type<Type>};
286 };
287 }
288
289 if constexpr(std::is_arithmetic_v<Type>) {
290 node.conversion_helper = +[](void *lhs, const void *rhs) {
291 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));
292 };
293 } else if constexpr(std::is_enum_v<Type>) {
294 node.conversion_helper = +[](void *lhs, const void *rhs) {
295 return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(static_cast<std::underlying_type_t<Type>>(*static_cast<const double *>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
296 };
297 }
298
299 if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
300 node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) {
301 if(elem) {
302 return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *static_cast<std::decay_t<Type> *>(elem)};
303 }
304
305 return meta_any{ctx, std::in_place_type<const std::decay_t<Type> &>, *static_cast<const std::decay_t<Type> *>(celem)};
306 };
307 }
308
309 if constexpr(is_complete_v<meta_template_traits<Type>>) {
310 node.templ = meta_template_node{
311 meta_template_traits<Type>::args_type::size,
312 &resolve<typename meta_template_traits<Type>::class_type>,
313 +[](const meta_context &area, const std::size_t index) noexcept { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
314 }
315
316 return node;
317}
318
319} // namespace internal
322} // namespace entt
323
324#endif
EnTT default namespace.
Definition dense_map.hpp:22
constexpr std::size_t size_of_v
Helper variable template.
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:14
constexpr bool is_complete_v
Helper variable template.
constexpr auto is_meta_pointer_like_v
Helper variable template.
meta_type resolve(const meta_ctx &ctx) noexcept
Returns the meta type associated with a given type.
Definition resolve.hpp:21
constexpr std::enable_if_t< std::is_unsigned_v< Type >, int > popcount(const Type value) noexcept
Returns the number of set bits in a value (waiting for C++20 and std::popcount).
Definition bit.hpp:19