EnTT 3.16.0
Loading...
Searching...
No Matches
node.hpp
1#ifndef ENTT_META_NODE_HPP
2#define ENTT_META_NODE_HPP
3
4#include <array>
5#include <cstddef>
6#include <memory>
7#include <type_traits>
8#include <utility>
9#include <vector>
10#include "../config/config.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;
24class 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_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>
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_base_node {
71 id_type type{};
72 const meta_type_node &(*resolve)(const meta_context &) noexcept {};
73 const void *(*cast)(const void *) noexcept {};
74};
75
76struct meta_conv_node {
77 id_type type{};
78 meta_any (*conv)(const meta_ctx &, const void *){};
79};
80
81struct meta_ctor_node {
82 using size_type = std::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 = std::size_t;
92
93 id_type id{};
94 const char *name{};
95 meta_traits traits{meta_traits::is_none};
96 size_type arity{0u};
97 const meta_type_node &(*type)(const meta_context &) noexcept {};
98 meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
99 bool (*set)(meta_handle, meta_any){};
100 meta_any (*get)(meta_handle){};
101 meta_custom_node custom{};
102};
103
104struct meta_func_node {
105 using size_type = std::size_t;
106
107 id_type id{};
108 const char *name{};
109 meta_traits traits{meta_traits::is_none};
110 size_type arity{0u};
111 const meta_type_node &(*ret)(const meta_context &) noexcept {};
112 meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
113 meta_any (*invoke)(meta_handle, meta_any *const){};
114 std::unique_ptr<meta_func_node> next;
115 meta_custom_node custom{};
116};
117
118struct meta_template_node {
119 using size_type = std::size_t;
120
121 size_type arity{0u};
122 const meta_type_node &(*resolve)(const meta_context &) noexcept {};
123 const meta_type_node &(*arg)(const meta_context &, const size_type) noexcept {};
124};
125
126struct meta_type_descriptor {
127 std::vector<meta_ctor_node> ctor{};
128 std::vector<meta_base_node> base{};
129 std::vector<meta_conv_node> conv{};
130 std::vector<meta_data_node> data{};
131 std::vector<meta_func_node> func{};
132};
133
134struct meta_type_node {
135 using size_type = std::size_t;
136
137 const type_info *info{};
138 id_type id{};
139 const char *name{};
140 meta_traits traits{meta_traits::is_none};
141 size_type size_of{0u};
142 const meta_type_node &(*remove_pointer)(const meta_context &) noexcept {};
143 meta_any (*default_constructor)(const meta_ctx &){};
144 double (*conversion_helper)(void *, const void *){};
145 meta_any (*from_void)(const meta_ctx &, void *, const void *){};
146 meta_template_node templ{};
147 meta_custom_node custom{};
148 std::unique_ptr<meta_type_descriptor> details{};
149};
150
151template<auto Member, typename Type, typename Value>
152[[nodiscard]] auto *find_member(Type &from, const Value value) {
153 for(auto &&elem: from) {
154 if((elem.*Member) == value) {
155 return &elem;
156 }
157 }
158
159 return static_cast<typename Type::value_type *>(nullptr);
160}
161
162[[nodiscard]] inline auto *find_overload(meta_func_node *curr, std::remove_pointer_t<decltype(meta_func_node::invoke)> *const ref) {
163 while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
164 return curr;
165}
166
167template<auto Member>
168[[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) {
169 using value_type = typename std::remove_reference_t<decltype((node.details.get()->*Member))>::value_type;
170
171 if(node.details) {
172 if(auto *member = find_member<&value_type::id>((node.details.get()->*Member), id); member != nullptr) {
173 return member;
174 }
175
176 if(recursive) {
177 for(auto &&curr: node.details->base) {
178 if(auto *elem = look_for<Member>(context, curr.resolve(context), id, recursive); elem) {
179 return elem;
180 }
181 }
182 }
183 }
184
185 return static_cast<value_type *>(nullptr);
186}
187
188template<typename Type>
189const meta_type_node &resolve(const meta_context &) noexcept;
190
191template<typename... Args>
192[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list<Args...>, const std::size_t index) noexcept {
193 using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept;
194 constexpr std::array<resolve_type, sizeof...(Args)> list{&resolve<std::remove_const_t<std::remove_reference_t<Args>>>...};
195 ENTT_ASSERT(index < sizeof...(Args), "Out of bounds");
196 return list[index](context);
197}
198
199[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const id_type to, const void *instance) noexcept {
200 if(from.details) {
201 for(auto &&curr: from.details->base) {
202 if(const void *other = curr.cast(instance); curr.type == to) {
203 return other;
204 } else if(const void *elem = try_cast(context, curr.resolve(context), to, other); elem) {
205 return elem;
206 }
207 }
208 }
209
210 return nullptr;
211}
212
213template<typename Type>
214auto setup_node_for() noexcept {
215 meta_type_node node{
216 &type_id<Type>(),
217 type_id<Type>().hash(),
218 nullptr,
219 (std::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
220 | (std::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
221 | (std::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
222 | (std::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
223 | (std::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
224 | (std::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
225 | (std::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
226 | (is_meta_pointer_like_v<Type> ? meta_traits::is_pointer_like : meta_traits::is_none)
227 | (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_sequence_container : meta_traits::is_none)
228 | (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_associative_container : meta_traits::is_none),
229 size_of_v<Type>,
230 &resolve<std::remove_const_t<std::remove_pointer_t<Type>>>};
231
232 if constexpr(std::is_default_constructible_v<Type>) {
233 node.default_constructor = +[](const meta_ctx &ctx) {
234 return meta_any{ctx, std::in_place_type<Type>};
235 };
236 }
237
238 if constexpr(std::is_arithmetic_v<Type>) {
239 node.conversion_helper = +[](void *lhs, const void *rhs) {
240 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));
241 };
242 } else if constexpr(std::is_enum_v<Type>) {
243 node.conversion_helper = +[](void *lhs, const void *rhs) {
244 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));
245 };
246 }
247
248 if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
249 node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) {
250 if(elem && celem) { // ownership construction request
251 return meta_any{ctx, std::in_place, static_cast<std::decay_t<Type> *>(elem)};
252 }
253
254 if(elem) { // non-const reference construction request
255 return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *static_cast<std::decay_t<Type> *>(elem)};
256 }
257
258 // const reference construction request
259 return meta_any{ctx, std::in_place_type<const std::decay_t<Type> &>, *static_cast<const std::decay_t<Type> *>(celem)};
260 };
261 }
262
263 if constexpr(is_complete_v<meta_template_traits<Type>>) {
264 node.templ = meta_template_node{
265 meta_template_traits<Type>::args_type::size,
266 &resolve<typename meta_template_traits<Type>::class_type>,
267 +[](const meta_context &area, const std::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
268 }
269
270 return node;
271}
272
273[[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
274 const auto it = context.value.find(info.hash());
275 return (it != context.value.end()) ? it->second.get() : nullptr;
276}
277
278template<typename Type>
279[[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept {
280 static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
281 static const meta_type_node node = setup_node_for<Type>();
282 const auto *elem = try_resolve(context, *node.info);
283 return (elem == nullptr) ? node : *elem;
284}
285
286} // namespace internal
288
289} // namespace entt
290
291#endif
Opaque wrapper for values of any type.
Definition meta.hpp:159
Opaque pointers to instances of any type.
Definition meta.hpp:663
Opaque wrapper for types.
Definition meta.hpp:1059
EnTT default namespace.
Definition dense_map.hpp:22
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
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