EnTT 4.0.0
Loading...
Searching...
No Matches
factory.hpp
1#ifndef ENTT_META_FACTORY_HPP
2#define ENTT_META_FACTORY_HPP
3
4#include "../config/config.h"
5#include "../core/bit.hpp"
6#include "../core/fwd.hpp"
7#include "../core/hashed_string.hpp"
8#include "../core/type_info.hpp"
9#include "../core/type_traits.hpp"
10#include "../locator/locator.hpp"
11#include "../stl/algorithm.hpp"
12#include "../stl/concepts.hpp"
13#include "../stl/cstddef.hpp"
14#include "../stl/cstdint.hpp"
15#include "../stl/functional.hpp"
16#include "../stl/memory.hpp"
17#include "../stl/type_traits.hpp"
18#include "../stl/utility.hpp"
19#include "context.hpp"
20#include "fwd.hpp"
21#include "meta.hpp"
22#include "node.hpp"
23#include "policy.hpp"
24#include "range.hpp"
25#include "utility.hpp"
26
27namespace entt {
28
30namespace internal {
31
32class basic_meta_factory {
33 using invoke_type = stl::remove_pointer_t<decltype(meta_func_node::invoke)>;
34
35 enum class mode {
36 type,
37 data,
38 func
39 };
40
41 [[nodiscard]] auto *find_member_or_assert() {
42 auto *member = find_member(parent->details->data, bucket);
43 ENTT_ASSERT(member != nullptr, "Cannot find member");
44 return member;
45 }
46
47 [[nodiscard]] auto *find_overload_or_assert() {
48 ENTT_ASSERT(invoke != nullptr, "Invoke function not available");
49 auto *overload = find_overload(find_member(parent->details->func, bucket), invoke);
50 ENTT_ASSERT(overload != nullptr, "Cannot find overload");
51 return overload;
52 }
53
54 bool unique_alias(const id_type alias) const noexcept {
55 return (ctx->bucket.find(alias) == ctx->bucket.cend()) && (stl::find_if(ctx->bucket.cbegin(), ctx->bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }) == ctx->bucket.cend());
56 }
57
58protected:
59 void type(const id_type alias, const char *name) noexcept {
60 state = mode::type;
61 ENTT_ASSERT((parent->alias == alias) || unique_alias(alias), "Duplicate identifier");
62 parent->alias = alias;
63 parent->name = name;
64 }
65
66 template<typename Type>
67 void insert_or_assign(Type node) {
68 state = mode::type;
69
70 if constexpr(stl::is_same_v<Type, meta_base_node>) {
71 auto *member = find_member(parent->details->base, node.id);
72 member ? (*member = node) : parent->details->base.emplace_back(node);
73 } else if constexpr(stl::is_same_v<Type, meta_conv_node>) {
74 auto *member = find_member(parent->details->conv, node.id);
75 member ? (*member = node) : parent->details->conv.emplace_back(node);
76 } else {
77 static_assert(stl::is_same_v<Type, meta_ctor_node>, "Unexpected type");
78 auto *member = find_member(parent->details->ctor, node.id);
79 member ? (*member = node) : parent->details->ctor.emplace_back(node);
80 }
81 }
82
83 void data(meta_data_node node) {
84 state = mode::data;
85 bucket = node.id;
86
87 if(auto *member = find_member(parent->details->data, node.id); member == nullptr) {
88 parent->details->data.emplace_back(stl::move(node));
89 } else if(member->set != node.set || member->get != node.get) {
90 *member = stl::move(node);
91 }
92 }
93
94 void func(meta_func_node node) {
95 state = mode::func;
96 bucket = node.id;
97 invoke = node.invoke;
98
99 if(auto *member = find_member(parent->details->func, node.id); member == nullptr) {
100 parent->details->func.emplace_back(stl::move(node));
101 } else if(auto *overload = find_overload(member, node.invoke); overload == nullptr) {
102 while(member->next != nullptr) { member = member->next.get(); }
103 member->next = stl::make_unique<meta_func_node>(stl::move(node));
104 }
105 }
106
107 void traits(const meta_traits value, const bool unset) {
108 const auto set_or_unset_on = [=](auto &node) {
109 node.traits = (unset ? (node.traits & ~value) : (node.traits | value));
110 };
111
112 switch(state) {
113 case mode::type:
114 set_or_unset_on(*parent);
115 break;
116 case mode::data:
117 set_or_unset_on(*find_member_or_assert());
118 break;
119 case mode::func:
120 set_or_unset_on(*find_overload_or_assert());
121 break;
122 }
123 }
124
125 void custom(meta_custom_node node) {
126 switch(state) {
127 case mode::type:
128 parent->custom = stl::move(node);
129 break;
130 case mode::data:
131 find_member_or_assert()->custom = stl::move(node);
132 break;
133 case mode::func:
134 find_overload_or_assert()->custom = stl::move(node);
135 break;
136 }
137 }
138
139public:
140 basic_meta_factory(meta_ctx &area, meta_type_node node, const id_type id)
141 : ctx{&meta_context::from(area)},
142 bucket{},
143 state{mode::type} {
144 if(const auto it = ctx->bucket.find(id); it == ctx->bucket.cend()) {
145 ENTT_ASSERT(unique_alias(id), "Duplicate identifier");
146 parent = ctx->bucket.emplace(id, stl::make_unique<meta_type_node>(stl::move(node))).first->second.get();
147 parent->details = stl::make_unique<meta_type_descriptor>();
148 parent->alias = id;
149 } else {
150 parent = it->second.get();
151 }
152 }
153
154private:
155 meta_context *ctx{};
156 invoke_type *invoke{};
157 meta_type_node *parent{};
158 id_type bucket{};
159 mode state{};
160};
161
162} // namespace internal
164
169template<typename Type>
170class meta_factory: private internal::basic_meta_factory {
171 using base_type = internal::basic_meta_factory;
172
173public:
175 using element_type = Type;
176
180
185 meta_factory(meta_ctx &area) noexcept
186 : base_type{area, internal::setup_node_for<element_type>(), type_hash<Type>::value()} {}
187
194
200 meta_factory(meta_ctx &area, const id_type id) noexcept
201 : base_type{area, internal::setup_node_for<element_type>(), id} {}
202
208 meta_factory type(const char *name) noexcept {
209 return type(hashed_string::value(name), name);
210 }
211
218 meta_factory type(const id_type alias, const char *name = nullptr) noexcept {
219 base_type::type(alias, name);
220 return *this;
221 }
222
231 template<typename Base>
232 requires stl::derived_from<element_type, Base>
233 meta_factory base() noexcept {
234 if constexpr(!stl::same_as<element_type, Base>) {
235 auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const element_type *>(instance))); };
236
237 base_type::insert_or_assign(
238 internal::meta_base_node{
240 &internal::resolve<Base>,
241 op});
242 }
243
244 return *this;
245 }
246
259 template<auto Candidate>
260 auto conv() noexcept {
261 using conv_type = stl::remove_cvref_t<stl::invoke_result_t<decltype(Candidate), element_type &>>;
262 auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, stl::invoke(Candidate, *static_cast<const element_type *>(instance))); };
263
264 base_type::insert_or_assign(
265 internal::meta_conv_node{
267 op});
268
269 return *this;
270 }
271
281 template<typename To>
282 meta_factory conv() noexcept {
283 using conv_type = stl::remove_cvref_t<To>;
284 auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast<To>(*static_cast<const element_type *>(instance))); };
285
286 base_type::insert_or_assign(
287 internal::meta_conv_node{
289 op});
290
291 return *this;
292 }
293
307 template<auto Candidate, typename Policy = as_value_t>
308 meta_factory ctor() noexcept {
309 using descriptor = meta_function_helper_t<element_type, decltype(Candidate)>;
310 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
311 static_assert(stl::is_same_v<stl::remove_cvref_t<typename descriptor::return_type>, element_type>, "The function doesn't return an object of the required type");
312
313 base_type::insert_or_assign(
314 internal::meta_ctor_node{
316 descriptor::args_type::size,
319
320 return *this;
321 }
322
333 template<typename... Args>
334 meta_factory ctor() noexcept {
335 // default constructor is already implicitly generated, no need for redundancy
336 if constexpr(sizeof...(Args) != 0u) {
337 using descriptor = meta_function_helper_t<element_type, element_type (*)(Args...)>;
338
339 base_type::insert_or_assign(
340 internal::meta_ctor_node{
342 descriptor::args_type::size,
344 &meta_construct<element_type, Args...>});
345 }
346
347 return *this;
348 }
349
357 template<auto Data, typename Policy = as_value_t>
358 meta_factory data(const char *name) noexcept {
359 return data<Data, Policy>(hashed_string::value(name), name);
360 }
361
376 template<auto Data, typename Policy = as_value_t>
377 meta_factory data(const id_type id, const char *name = nullptr) noexcept {
378 if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
379 using data_type = stl::invoke_result_t<decltype(Data), element_type &>;
380 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
381
382 base_type::data(
383 internal::meta_data_node{
384 id,
385 name,
386 /* this is never static */
387 stl::is_const_v<stl::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
388 1u,
389 0u,
392 &internal::resolve<stl::remove_cvref_t<data_type>>,
395 } else {
396 using data_type = stl::remove_pointer_t<decltype(Data)>;
397
398 if constexpr(stl::is_pointer_v<decltype(Data)>) {
399 static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
400 } else {
401 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
402 }
403
404 base_type::data(
405 internal::meta_data_node{
406 id,
407 name,
408 ((!stl::is_pointer_v<decltype(Data)> || stl::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
409 1u,
410 0u,
411 &meta_arg<type_list<stl::remove_cvref_t<data_type>>>,
413 &internal::resolve<stl::remove_cvref_t<data_type>>,
416 }
417
418 return *this;
419 }
420
430 template<auto Setter, auto Getter, typename Policy = as_value_t>
431 meta_factory data(const char *name) noexcept {
433 }
434
456 template<auto Setter, auto Getter, typename Policy = as_value_t>
457 meta_factory data(const id_type id, const char *name = nullptr) noexcept {
458 using getter = meta_function_helper_t<element_type, decltype(Getter)>;
459 static_assert(Policy::template value<typename getter::return_type>, "Invalid return type for the given policy");
460
461 if constexpr(stl::is_same_v<decltype(Setter), stl::nullptr_t>) {
462 base_type::data(
463 internal::meta_data_node{
464 id,
465 name,
466 /* this is never static */
467 internal::meta_traits::is_const,
468 0u,
469 getter::args_type::size,
472 &internal::resolve<stl::remove_cvref_t<typename getter::return_type>>,
475 } else {
476 using setter = meta_function_helper_t<element_type, decltype(Setter)>;
477
478 base_type::data(
479 internal::meta_data_node{
480 id,
481 name,
482 /* this is never static nor const */
483 internal::meta_traits::is_none,
484 setter::args_type::size,
485 getter::args_type::size,
488 &internal::resolve<stl::remove_cvref_t<typename getter::return_type>>,
491 }
492
493 return *this;
494 }
495
503 template<auto Candidate, typename Policy = as_value_t>
504 meta_factory func(const char *name) noexcept {
506 }
507
522 template<auto Candidate, typename Policy = as_value_t>
523 meta_factory func(const id_type id, const char *name = nullptr) noexcept {
524 using descriptor = meta_function_helper_t<element_type, decltype(Candidate)>;
525 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
526
527 base_type::func(
528 internal::meta_func_node{
529 id,
530 name,
531 (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),
532 descriptor::args_type::size,
533 &internal::resolve<stl::conditional_t<stl::is_same_v<Policy, as_void_t>, void, stl::remove_cvref_t<typename descriptor::return_type>>>,
536
537 return *this;
538 }
539
550 template<typename Value>
551 meta_factory traits(const Value value, const bool unset = false) {
552 static_assert(stl::is_enum_v<Value>, "Invalid enum type");
553 base_type::traits(internal::user_to_meta_traits(value), unset);
554 return *this;
555 }
556
564 template<typename Value, typename... Args>
565 meta_factory custom(Args &&...args) {
566 base_type::custom(internal::meta_custom_node{type_id<Value>().hash(), stl::make_shared<Value>(stl::forward<Args>(args)...)});
567 return *this;
568 }
569};
570
583inline void meta_reset(meta_ctx &ctx, const id_type alias) noexcept {
584 auto &bucket = internal::meta_context::from(ctx).bucket;
585
586 // fast path for unsearchable and overloaded types
587 if(bucket.erase(alias) == 0u) {
588 if(const auto it = stl::find_if(bucket.cbegin(), bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }); it != bucket.cend()) {
589 bucket.erase(it);
590 }
591 }
592}
593
605inline void meta_reset(const id_type alias) noexcept {
607}
608
617template<typename Type>
618void meta_reset(meta_ctx &ctx) noexcept {
619 internal::meta_context::from(ctx).bucket.erase(type_id<Type>().hash());
620}
621
629template<typename Type>
633
641inline void meta_reset(meta_ctx &ctx) noexcept {
642 internal::meta_context::from(ctx).bucket.clear();
643}
644
650inline void meta_reset() noexcept {
652}
653
654} // namespace entt
655
656#endif
static constexpr hash_type value(const value_type *str, const size_type len) noexcept
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
Definition locator.hpp:90
meta_factory custom(Args &&...args)
Sets user defined data that will never be used by the library.
Definition factory.hpp:565
meta_factory data(const id_type id, const char *name=nullptr) noexcept
Assigns a meta data to a meta type by means of its setter and getter.
Definition factory.hpp:457
meta_factory ctor() noexcept
Assigns a meta constructor to a meta type.
Definition factory.hpp:334
auto conv() noexcept
Assigns a meta conversion function to a meta type.
Definition factory.hpp:260
meta_factory func(const id_type id, const char *name=nullptr) noexcept
Assigns a meta function to a meta type.
Definition factory.hpp:523
meta_factory data(const id_type id, const char *name=nullptr) noexcept
Assigns a meta data to a meta type.
Definition factory.hpp:377
meta_factory ctor() noexcept
Assigns a meta constructor to a meta type.
Definition factory.hpp:308
meta_factory() noexcept
Default constructor.
Definition factory.hpp:178
meta_factory data(const char *name) noexcept
Assigns a meta data to a meta type by means of its setter and getter.
Definition factory.hpp:431
meta_factory func(const char *name) noexcept
Assigns a meta function to a meta type.
Definition factory.hpp:504
meta_factory data(const char *name) noexcept
Assigns a meta data to a meta type.
Definition factory.hpp:358
meta_factory type(const id_type alias, const char *name=nullptr) noexcept
Assigns a custom unique identifier to a meta type.
Definition factory.hpp:218
meta_factory(meta_ctx &area) noexcept
Context aware constructor.
Definition factory.hpp:185
meta_factory(meta_ctx &area, const id_type id) noexcept
Context aware constructor.
Definition factory.hpp:200
meta_factory conv() noexcept
Assigns a meta conversion function to a meta type.
Definition factory.hpp:282
meta_factory base() noexcept
Assigns a meta base to a meta type.
Definition factory.hpp:233
meta_factory traits(const Value value, const bool unset=false)
Sets traits on the last created meta object.
Definition factory.hpp:551
meta_factory type(const char *name) noexcept
Assigns a custom unique identifier to a meta type.
Definition factory.hpp:208
meta_factory(const id_type id) noexcept
Constructs an unconstrained type assigned to a given identifier.
Definition factory.hpp:192
Type element_type
Type of object for which this factory builds a meta type.
Definition factory.hpp:175
EnTT default namespace.
Definition dense_map.hpp:25
meta_function_helper< Type, Candidate >::type meta_function_helper_t
Helper type.
Definition utility.hpp:153
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:410
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:378
meta_any forward_as_meta(const meta_ctx &ctx, auto &&value)
Forwards its argument and avoids copies for lvalue references.
Definition meta.hpp:662
void meta_reset() noexcept
Resets a type and all its parts.
Definition factory.hpp:630
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:17
meta_type meta_arg(const meta_ctx &ctx, const stl::size_t index) noexcept
Returns the meta type of the i-th element of a list of arguments.
Definition utility.hpp:252
meta_any meta_getter(meta_handle instance, meta_any *const args)
Gets the value of a given variable.
Definition utility.hpp:330
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
stl::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
bool meta_setter(meta_handle instance, meta_any *const args)
Sets the value of a given variable.
Definition utility.hpp:277
Opaque meta context type.
Definition context.hpp:30
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.
constexpr id_type hash() const noexcept
Type hash.
A class to use to push around lists of types, nothing more.