EnTT 3.15.0
Loading...
Searching...
No Matches
factory.hpp
1#ifndef ENTT_META_FACTORY_HPP
2#define ENTT_META_FACTORY_HPP
3
4#include <cstddef>
5#include <cstdint>
6#include <functional>
7#include <memory>
8#include <tuple>
9#include <type_traits>
10#include <utility>
11#include "../config/config.h"
12#include "../core/bit.hpp"
13#include "../core/fwd.hpp"
14#include "../core/type_info.hpp"
15#include "../core/type_traits.hpp"
16#include "../locator/locator.hpp"
17#include "context.hpp"
18#include "meta.hpp"
19#include "node.hpp"
20#include "policy.hpp"
21#include "range.hpp"
22#include "resolve.hpp"
23#include "utility.hpp"
24
25namespace entt {
26
28namespace internal {
29
30class basic_meta_factory {
31 using invoke_type = std::remove_pointer_t<decltype(meta_func_node::invoke)>;
32
33 auto *find_member_or_assert() {
34 auto *member = find_member<&meta_data_node::id>(details->data, bucket);
35 ENTT_ASSERT(member != nullptr, "Cannot find member");
36 return member;
37 }
38
39 auto *find_overload_or_assert() {
40 auto *overload = find_overload(find_member<&meta_func_node::id>(details->func, bucket), invoke);
41 ENTT_ASSERT(overload != nullptr, "Cannot find overload");
42 return overload;
43 }
44
45 void reset_bucket(const id_type id, invoke_type *const ref = nullptr) {
46 invoke = ref;
47 bucket = id;
48 }
49
50protected:
51 void type(const id_type id) noexcept {
52 reset_bucket(parent);
53 auto &&elem = meta_context::from(*ctx).value[parent];
54 ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier");
55 elem.id = id;
56 }
57
58 template<typename Type>
59 void insert_or_assign(Type node) {
60 reset_bucket(parent);
61
62 if constexpr(std::is_same_v<Type, meta_base_node>) {
63 auto *member = find_member<&meta_base_node::type>(details->base, node.type);
64 member ? (*member = node) : details->base.emplace_back(node);
65 } else if constexpr(std::is_same_v<Type, meta_conv_node>) {
66 auto *member = find_member<&meta_conv_node::type>(details->conv, node.type);
67 member ? (*member = node) : details->conv.emplace_back(node);
68 } else {
69 static_assert(std::is_same_v<Type, meta_ctor_node>, "Unexpected type");
70 auto *member = find_member<&meta_ctor_node::id>(details->ctor, node.id);
71 member ? (*member = node) : details->ctor.emplace_back(node);
72 }
73 }
74
75 void dtor(meta_dtor_node node) {
76 reset_bucket(parent);
77 meta_context::from(*ctx).value[parent].dtor = node;
78 }
79
80 void data(meta_data_node node) {
81 reset_bucket(node.id);
82
83 if(auto *member = find_member<&meta_data_node::id>(details->data, node.id); member == nullptr) {
84 details->data.emplace_back(std::move(node));
85 } else if(member->set != node.set || member->get != node.get) {
86 *member = std::move(node);
87 }
88 }
89
90 void func(meta_func_node node) {
91 reset_bucket(node.id, node.invoke);
92
93 if(auto *member = find_member<&meta_func_node::id>(details->func, node.id); member == nullptr) {
94 details->func.emplace_back(std::move(node));
95 } else if(auto *overload = find_overload(member, node.invoke); overload == nullptr) {
96 while(member->next != nullptr) { member = member->next.get(); }
97 member->next = std::make_shared<meta_func_node>(std::move(node));
98 }
99 }
100
101 void traits(const meta_traits value) {
102 if(bucket == parent) {
103 meta_context::from(*ctx).value[bucket].traits |= value;
104 } else if(invoke == nullptr) {
105 find_member_or_assert()->traits |= value;
106 } else {
107 find_overload_or_assert()->traits |= value;
108 }
109 }
110
111 void custom(meta_custom_node node) {
112 if(bucket == parent) {
113 meta_context::from(*ctx).value[bucket].custom = std::move(node);
114 } else if(invoke == nullptr) {
115 find_member_or_assert()->custom = std::move(node);
116 } else {
117 find_overload_or_assert()->custom = std::move(node);
118 }
119 }
120
121public:
122 basic_meta_factory(meta_ctx &area, meta_type_node node)
123 : ctx{&area},
124 parent{node.info->hash()},
125 bucket{parent},
126 details{node.details.get()} {
127 if(details == nullptr) {
128 node.details = std::make_shared<meta_type_descriptor>();
129 meta_context::from(*ctx).value[parent] = node;
130 details = node.details.get();
131 }
132 }
133
134private:
135 meta_ctx *ctx{};
136 id_type parent{};
137 id_type bucket{};
138 invoke_type *invoke{};
139 meta_type_descriptor *details{};
140};
141
142} // namespace internal
144
149template<typename Type>
150class meta_factory: private internal::basic_meta_factory {
151 using base_type = internal::basic_meta_factory;
152
153 template<typename Setter, auto Getter, typename Policy, std::size_t... Index>
154 [[deprecated("use variant types or conversion support")]]
155 void data(const id_type id, std::index_sequence<Index...>) noexcept {
156 using data_type = std::invoke_result_t<decltype(Getter), Type &>;
157 using args_type = type_list<typename meta_function_helper_t<Type, decltype(value_list_element_v<Index, Setter>)>::args_type...>;
158 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
159
160 base_type::data(
161 internal::meta_data_node{
162 id,
163 /* this is never static */
164 (std::is_member_object_pointer_v<decltype(value_list_element_v<Index, Setter>)> && ... && std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
165 Setter::size,
166 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
167 &meta_arg<type_list<type_list_element_t<static_cast<std::size_t>(type_list_element_t<Index, args_type>::size != 1u), type_list_element_t<Index, args_type>>...>>,
168 +[](meta_handle instance, meta_any value) { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
170 }
171
172public:
176
181 meta_factory(meta_ctx &area) noexcept
182 : internal::basic_meta_factory{area, internal::resolve<Type>(internal::meta_context::from(area))} {}
183
189 meta_factory type(const id_type id) noexcept {
190 base_type::type(id);
191 return *this;
192 }
193
202 template<typename Base>
203 meta_factory base() noexcept {
204 static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>, "Invalid base type");
205 auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
206 base_type::insert_or_assign(internal::meta_base_node{type_id<Base>().hash(), &internal::resolve<Base>, op});
207 return *this;
208 }
209
222 template<auto Candidate>
223 auto conv() noexcept {
224 using conv_type = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
225 auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, std::invoke(Candidate, *static_cast<const Type *>(instance))); };
226 base_type::insert_or_assign(internal::meta_conv_node{type_id<conv_type>().hash(), op});
227 return *this;
228 }
229
239 template<typename To>
240 meta_factory conv() noexcept {
241 using conv_type = std::remove_cv_t<std::remove_reference_t<To>>;
242 auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast<To>(*static_cast<const Type *>(instance))); };
243 base_type::insert_or_assign(internal::meta_conv_node{type_id<conv_type>().hash(), op});
244 return *this;
245 }
246
260 template<auto Candidate, typename Policy = as_is_t>
261 meta_factory ctor() noexcept {
262 using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
263 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
264 static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>, Type>, "The function doesn't return an object of the required type");
265 base_type::insert_or_assign(internal::meta_ctor_node{type_id<typename descriptor::args_type>().hash(), descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Candidate, Policy>});
266 return *this;
267 }
268
279 template<typename... Args>
280 meta_factory ctor() noexcept {
281 // default constructor is already implicitly generated, no need for redundancy
282 if constexpr(sizeof...(Args) != 0u) {
283 using descriptor = meta_function_helper_t<Type, Type (*)(Args...)>;
284 base_type::insert_or_assign(internal::meta_ctor_node{type_id<typename descriptor::args_type>().hash(), descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Args...>});
285 }
286
287 return *this;
288 }
289
308 template<auto Func>
309 meta_factory dtor() noexcept {
310 static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
311 auto *const op = +[](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
312 base_type::dtor(internal::meta_dtor_node{op});
313 return *this;
314 }
315
329 template<auto Data, typename Policy = as_is_t>
330 meta_factory data(const id_type id) noexcept {
331 if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
332 using data_type = std::invoke_result_t<decltype(Data), Type &>;
333 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
334
335 base_type::data(
336 internal::meta_data_node{
337 id,
338 /* this is never static */
339 std::is_const_v<std::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
340 1u,
341 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
342 &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
345 } else {
346 using data_type = std::remove_pointer_t<decltype(Data)>;
347
348 if constexpr(std::is_pointer_v<decltype(Data)>) {
349 static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
350 } else {
351 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
352 }
353
354 base_type::data(
355 internal::meta_data_node{
356 id,
357 ((!std::is_pointer_v<decltype(Data)> || std::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
358 1u,
359 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
360 &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
363 }
364
365 return *this;
366 }
367
388 template<auto Setter, auto Getter, typename Policy = as_is_t>
389 meta_factory data(const id_type id) noexcept {
390 using descriptor = meta_function_helper_t<Type, decltype(Getter)>;
391 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
392
393 if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
394 base_type::data(
395 internal::meta_data_node{
396 id,
397 /* this is never static */
398 internal::meta_traits::is_const,
399 0u,
400 &internal::resolve<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>,
401 &meta_arg<type_list<>>,
404 } else {
405 using args_type = typename meta_function_helper_t<Type, decltype(Setter)>::args_type;
406
407 base_type::data(
408 internal::meta_data_node{
409 id,
410 /* this is never static nor const */
411 internal::meta_traits::is_none,
412 1u,
413 &internal::resolve<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>,
414 &meta_arg<type_list<type_list_element_t<static_cast<std::size_t>(args_type::size != 1u), args_type>>>,
417 }
418
419 return *this;
420 }
421
439 template<typename Setter, auto Getter, typename Policy = as_is_t>
440 [[deprecated("use variant types or conversion support")]]
441 meta_factory data(const id_type id) noexcept {
442 data<Setter, Getter, Policy>(id, std::make_index_sequence<Setter::size>{});
443 return *this;
444 }
445
459 template<auto Candidate, typename Policy = as_is_t>
460 meta_factory func(const id_type id) noexcept {
461 using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
462 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
463
464 base_type::func(
465 internal::meta_func_node{
466 id,
467 (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
468 descriptor::args_type::size,
469 &internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>,
470 &meta_arg<typename descriptor::args_type>,
472
473 return *this;
474 }
475
485 template<typename Value>
486 meta_factory traits(const Value value) {
487 static_assert(std::is_enum_v<Value>, "Invalid enum type");
488 base_type::traits(internal::user_to_meta_traits(value));
489 return *this;
490 }
491
499 template<typename Value, typename... Args>
500 meta_factory custom(Args &&...args) {
501 base_type::custom(internal::meta_custom_node{type_id<Value>().hash(), std::make_shared<Value>(std::forward<Args>(args)...)});
502 return *this;
503 }
504};
505
518template<typename Type>
519[[nodiscard]] [[deprecated("use meta_factory directly instead")]] auto meta(meta_ctx &ctx) noexcept {
520 return meta_factory<Type>{ctx};
521}
522
534template<typename Type>
535[[nodiscard]] [[deprecated("use meta_factory directly instead")]] auto meta() noexcept {
537}
538
551inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept {
552 auto &&context = internal::meta_context::from(ctx);
553
554 for(auto it = context.value.begin(); it != context.value.end();) {
555 if(it->second.id == id) {
556 it = context.value.erase(it);
557 } else {
558 ++it;
559 }
560 }
561}
562
574inline void meta_reset(const id_type id) noexcept {
576}
577
586template<typename Type>
587void meta_reset(meta_ctx &ctx) noexcept {
588 internal::meta_context::from(ctx).value.erase(type_id<Type>().hash());
589}
590
598template<typename Type>
602
610inline void meta_reset(meta_ctx &ctx) noexcept {
611 internal::meta_context::from(ctx).value.clear();
612}
613
619inline void meta_reset() noexcept {
621}
622
623} // namespace entt
624
625#endif
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
Definition locator.hpp:88
Opaque wrapper for values of any type.
Definition meta.hpp:166
meta_any as_ref() noexcept
Aliasing constructor.
Definition meta.hpp:624
Opaque meta context type.
Definition context.hpp:34
Meta factory to be used for reflection purposes.
Definition factory.hpp:150
meta_factory base() noexcept
Assigns a meta base to a meta type.
Definition factory.hpp:203
meta_factory custom(Args &&...args)
Sets user defined data that will never be used by the library.
Definition factory.hpp:500
meta_factory ctor() noexcept
Assigns a meta constructor to a meta type.
Definition factory.hpp:280
auto conv() noexcept
Assigns a meta conversion function to a meta type.
Definition factory.hpp:223
meta_factory ctor() noexcept
Assigns a meta constructor to a meta type.
Definition factory.hpp:261
meta_factory() noexcept
Default constructor.
Definition factory.hpp:174
meta_factory dtor() noexcept
Assigns a meta destructor to a meta type.
Definition factory.hpp:309
meta_factory data(const id_type id) noexcept
Assigns a meta data to a meta type.
Definition factory.hpp:330
meta_factory(meta_ctx &area) noexcept
Context aware constructor.
Definition factory.hpp:181
meta_factory conv() noexcept
Assigns a meta conversion function to a meta type.
Definition factory.hpp:240
meta_factory data(const id_type id) noexcept
Assigns a meta data to a meta type by means of its setter and getter.
Definition factory.hpp:389
meta_factory func(const id_type id) noexcept
Assigns a meta function to a meta type.
Definition factory.hpp:460
meta_factory type(const id_type id) noexcept
Assigns a custom unique identifier to a meta type.
Definition factory.hpp:189
meta_factory traits(const Value value)
Sets traits on the last created meta object.
Definition factory.hpp:486
EnTT default namespace.
Definition dense_map.hpp:22
typename meta_function_helper< Type, Candidate >::type meta_function_helper_t
Helper type.
Definition utility.hpp:152
std::enable_if_t< is_meta_policy_v< Policy >, meta_any > meta_getter(meta_handle instance)
Gets the value of a given variable.
Definition utility.hpp:317
constexpr auto value_list_element_v
Helper type.
meta_any meta_construct(const meta_ctx &ctx, meta_any *const args)
Tries to construct an instance given a list of erased parameters.
Definition utility.hpp:433
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
auto meta() noexcept
Utility function to use for reflection.
Definition factory.hpp:535
std::enable_if_t< is_meta_policy_v< Policy >, meta_any > meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args)
Tries to invoke an object given a list of erased parameters.
Definition utility.hpp:370
constexpr get_t< Type... > get
Variable template for lists of observed elements.
Definition fwd.hpp:167
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
void meta_reset() noexcept
Resets a type and all its parts.
Definition factory.hpp:599
meta_any forward_as_meta(const meta_ctx &ctx, Type &&value)
Forwards its argument and avoids copies for lvalue references.
Definition meta.hpp:672
bool meta_setter(meta_handle instance, meta_any value)
Sets the value of a given variable.
Definition utility.hpp:276
void invoke(Registry &reg, const typename Registry::entity_type entt)
Helper to create a listener that directly invokes a member function.
Definition helper.hpp:108
constexpr auto overload(Type Class::*member) noexcept
Constant utility to disambiguate overloaded members of a class.
Definition utility.hpp:34
meta_type resolve(const meta_ctx &ctx) noexcept
Returns the meta type associated with a given type.
Definition resolve.hpp:21
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
@ ref
Aliasing mode, the object points to a non-const element.
Definition fwd.hpp:19
Opaque pointers to instances of any type.
Definition meta.hpp:688
constexpr id_type hash() const noexcept
Type hash.
A class to use to push around lists of types, nothing more.