EnTT 3.16.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/hashed_string.hpp"
15#include "../core/type_info.hpp"
16#include "../core/type_traits.hpp"
17#include "../locator/locator.hpp"
18#include "context.hpp"
19#include "fwd.hpp"
20#include "meta.hpp"
21#include "node.hpp"
22#include "policy.hpp"
23#include "range.hpp"
24#include "resolve.hpp"
25#include "utility.hpp"
26
27namespace entt {
28
30namespace internal {
31
32class basic_meta_factory {
33 using invoke_type = std::remove_pointer_t<decltype(meta_func_node::invoke)>;
34
35 [[nodiscard]] auto &fetch_node() noexcept {
36 return *meta_context::from(*ctx).value[parent];
37 }
38
39 [[nodiscard]] auto *find_member_or_assert() {
40 auto *member = find_member<&meta_data_node::id>(fetch_node().details->data, bucket);
41 ENTT_ASSERT(member != nullptr, "Cannot find member");
42 return member;
43 }
44
45 [[nodiscard]] auto *find_overload_or_assert() {
46 auto *overload = find_overload(find_member<&meta_func_node::id>(fetch_node().details->func, bucket), invoke);
47 ENTT_ASSERT(overload != nullptr, "Cannot find overload");
48 return overload;
49 }
50
51 void reset_bucket(const id_type id, invoke_type *const ref = nullptr) {
52 invoke = ref;
53 bucket = id;
54 }
55
56protected:
57 void type(const id_type id, const char *name) noexcept {
58 reset_bucket(parent);
59 auto &elem = fetch_node();
60 ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier");
61 elem.name = name;
62 elem.id = id;
63 }
64
65 template<typename Type>
66 void insert_or_assign(Type node) {
67 auto &elem = fetch_node();
68
69 reset_bucket(parent);
70
71 if constexpr(std::is_same_v<Type, meta_base_node>) {
72 auto *member = find_member<&meta_base_node::type>(elem.details->base, node.type);
73 member ? (*member = node) : elem.details->base.emplace_back(node);
74 } else if constexpr(std::is_same_v<Type, meta_conv_node>) {
75 auto *member = find_member<&meta_conv_node::type>(elem.details->conv, node.type);
76 member ? (*member = node) : elem.details->conv.emplace_back(node);
77 } else {
78 static_assert(std::is_same_v<Type, meta_ctor_node>, "Unexpected type");
79 auto *member = find_member<&meta_ctor_node::id>(elem.details->ctor, node.id);
80 member ? (*member = node) : elem.details->ctor.emplace_back(node);
81 }
82 }
83
84 void data(meta_data_node node) {
85 auto &elem = fetch_node();
86
87 reset_bucket(node.id);
88
89 if(auto *member = find_member<&meta_data_node::id>(elem.details->data, node.id); member == nullptr) {
90 elem.details->data.emplace_back(std::move(node));
91 } else if(member->set != node.set || member->get != node.get) {
92 *member = std::move(node);
93 }
94 }
95
96 void func(meta_func_node node) {
97 auto &elem = fetch_node();
98
99 reset_bucket(node.id, node.invoke);
100
101 if(auto *member = find_member<&meta_func_node::id>(elem.details->func, node.id); member == nullptr) {
102 elem.details->func.emplace_back(std::move(node));
103 } else if(auto *overload = find_overload(member, node.invoke); overload == nullptr) {
104 while(member->next != nullptr) { member = member->next.get(); }
105 member->next = std::make_unique<meta_func_node>(std::move(node));
106 }
107 }
108
109 void traits(const meta_traits value, const bool unset) {
110 auto set_or_unset_on = [=](auto &node) {
111 node.traits = (unset ? (node.traits & ~value) : (node.traits | value));
112 };
113
114 if(bucket == parent) {
115 set_or_unset_on(fetch_node());
116 } else if(invoke == nullptr) {
117 set_or_unset_on(*find_member_or_assert());
118 } else {
119 set_or_unset_on(*find_overload_or_assert());
120 }
121 }
122
123 void custom(meta_custom_node node) {
124 if(bucket == parent) {
125 fetch_node().custom = std::move(node);
126 } else if(invoke == nullptr) {
127 find_member_or_assert()->custom = std::move(node);
128 } else {
129 find_overload_or_assert()->custom = std::move(node);
130 }
131 }
132
133public:
134 basic_meta_factory(meta_ctx &area, meta_type_node node)
135 : ctx{&area},
136 parent{node.info->hash()},
137 bucket{parent} {
138 if(auto *curr = meta_context::from(*ctx).value.try_emplace(parent, std::make_unique<meta_type_node>(std::move(node))).first->second.get(); curr->details == nullptr) {
139 curr->details = std::make_unique<meta_type_descriptor>();
140 }
141 }
142
143private:
144 meta_ctx *ctx{};
145 id_type parent{};
146 id_type bucket{};
147 invoke_type *invoke{};
148};
149
150} // namespace internal
152
157template<typename Type>
158class meta_factory: private internal::basic_meta_factory {
159 using base_type = internal::basic_meta_factory;
160
161public:
163 using element_type = Type;
164
168
173 meta_factory(meta_ctx &area) noexcept
174 : internal::basic_meta_factory{area, internal::setup_node_for<Type>()} {}
175
181 meta_factory type(const char *name) noexcept {
182 return type(hashed_string::value(name), name);
183 }
184
191 meta_factory type(const id_type id, const char *name = nullptr) noexcept {
192 base_type::type(id, name);
193 return *this;
194 }
195
204 template<typename Base>
205 meta_factory base() noexcept {
206 static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>, "Invalid base type");
207 auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
208 base_type::insert_or_assign(internal::meta_base_node{type_id<Base>().hash(), &internal::resolve<Base>, op});
209 return *this;
210 }
211
224 template<auto Candidate>
225 auto conv() noexcept {
226 using conv_type = std::remove_const_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
227 auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, std::invoke(Candidate, *static_cast<const Type *>(instance))); };
228 base_type::insert_or_assign(internal::meta_conv_node{type_id<conv_type>().hash(), op});
229 return *this;
230 }
231
241 template<typename To>
242 meta_factory conv() noexcept {
243 using conv_type = std::remove_const_t<std::remove_reference_t<To>>;
244 auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast<To>(*static_cast<const Type *>(instance))); };
245 base_type::insert_or_assign(internal::meta_conv_node{type_id<conv_type>().hash(), op});
246 return *this;
247 }
248
262 template<auto Candidate, typename Policy = as_value_t>
263 meta_factory ctor() noexcept {
264 using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
265 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
266 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>, Type>, "The function doesn't return an object of the required type");
267 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>});
268 return *this;
269 }
270
281 template<typename... Args>
282 meta_factory ctor() noexcept {
283 // default constructor is already implicitly generated, no need for redundancy
284 if constexpr(sizeof...(Args) != 0u) {
285 using descriptor = meta_function_helper_t<Type, Type (*)(Args...)>;
286 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...>});
287 }
288
289 return *this;
290 }
291
299 template<auto Data, typename Policy = as_value_t>
300 meta_factory data(const char *name) noexcept {
301 return data<Data, Policy>(hashed_string::value(name), name);
302 }
303
318 template<auto Data, typename Policy = as_value_t>
319 meta_factory data(const id_type id, const char *name = nullptr) noexcept {
320 if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
321 using data_type = std::invoke_result_t<decltype(Data), Type &>;
322 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
323
324 base_type::data(
325 internal::meta_data_node{
326 id,
327 name,
328 /* this is never static */
329 std::is_const_v<std::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
330 1u,
331 &internal::resolve<std::remove_const_t<std::remove_reference_t<data_type>>>,
335 } else {
336 using data_type = std::remove_pointer_t<decltype(Data)>;
337
338 if constexpr(std::is_pointer_v<decltype(Data)>) {
339 static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
340 } else {
341 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
342 }
343
344 base_type::data(
345 internal::meta_data_node{
346 id,
347 name,
348 ((!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,
349 1u,
350 &internal::resolve<std::remove_const_t<std::remove_reference_t<data_type>>>,
351 &meta_arg<type_list<std::remove_const_t<std::remove_reference_t<data_type>>>>,
354 }
355
356 return *this;
357 }
358
368 template<auto Setter, auto Getter, typename Policy = as_value_t>
369 meta_factory data(const char *name) noexcept {
371 }
372
394 template<auto Setter, auto Getter, typename Policy = as_value_t>
395 meta_factory data(const id_type id, const char *name = nullptr) noexcept {
396 using descriptor = meta_function_helper_t<Type, decltype(Getter)>;
397 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
398
399 if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
400 base_type::data(
401 internal::meta_data_node{
402 id,
403 name,
404 /* this is never static */
405 internal::meta_traits::is_const,
406 0u,
407 &internal::resolve<std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>>,
411 } else {
412 using args_type = typename meta_function_helper_t<Type, decltype(Setter)>::args_type;
413
414 base_type::data(
415 internal::meta_data_node{
416 id,
417 name,
418 /* this is never static nor const */
419 internal::meta_traits::is_none,
420 1u,
421 &internal::resolve<std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>>,
422 &meta_arg<type_list<type_list_element_t<static_cast<std::size_t>(args_type::size != 1u), args_type>>>,
425 }
426
427 return *this;
428 }
429
437 template<auto Candidate, typename Policy = as_value_t>
438 meta_factory func(const char *name) noexcept {
440 }
441
456 template<auto Candidate, typename Policy = as_value_t>
457 meta_factory func(const id_type id, const char *name = nullptr) noexcept {
458 using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
459 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
460
461 base_type::func(
462 internal::meta_func_node{
463 id,
464 name,
465 (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),
466 descriptor::args_type::size,
467 &internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>>>,
470
471 return *this;
472 }
473
484 template<typename Value>
485 meta_factory traits(const Value value, const bool unset = false) {
486 static_assert(std::is_enum_v<Value>, "Invalid enum type");
487 base_type::traits(internal::user_to_meta_traits(value), unset);
488 return *this;
489 }
490
498 template<typename Value, typename... Args>
499 meta_factory custom(Args &&...args) {
500 base_type::custom(internal::meta_custom_node{type_id<Value>().hash(), std::make_shared<Value>(std::forward<Args>(args)...)});
501 return *this;
502 }
503};
504
517inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept {
518 auto &context = internal::meta_context::from(ctx);
519
520 for(auto it = context.value.begin(); it != context.value.end();) {
521 if(it->second->id == id) {
522 it = context.value.erase(it);
523 } else {
524 ++it;
525 }
526 }
527}
528
540inline void meta_reset(const id_type id) noexcept {
542}
543
552template<typename Type>
553void meta_reset(meta_ctx &ctx) noexcept {
554 internal::meta_context::from(ctx).value.erase(type_id<Type>().hash());
555}
556
564template<typename Type>
568
576inline void meta_reset(meta_ctx &ctx) noexcept {
577 internal::meta_context::from(ctx).value.clear();
578}
579
585inline void meta_reset() noexcept {
587}
588
589} // namespace entt
590
591#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:88
Opaque meta context type.
Definition context.hpp:34
meta_factory base() noexcept
Assigns a meta base to a meta type.
Definition factory.hpp:205
meta_factory custom(Args &&...args)
Sets user defined data that will never be used by the library.
Definition factory.hpp:499
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:395
meta_factory ctor() noexcept
Assigns a meta constructor to a meta type.
Definition factory.hpp:282
meta_factory type(const id_type id, const char *name=nullptr) noexcept
Assigns a custom unique identifier to a meta type.
Definition factory.hpp:191
auto conv() noexcept
Assigns a meta conversion function to a meta type.
Definition factory.hpp:225
meta_factory func(const id_type id, const char *name=nullptr) noexcept
Assigns a meta function to a meta type.
Definition factory.hpp:457
meta_factory data(const id_type id, const char *name=nullptr) noexcept
Assigns a meta data to a meta type.
Definition factory.hpp:319
meta_factory ctor() noexcept
Assigns a meta constructor to a meta type.
Definition factory.hpp:263
meta_factory() noexcept
Default constructor.
Definition factory.hpp:166
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:369
meta_factory func(const char *name) noexcept
Assigns a meta function to a meta type.
Definition factory.hpp:438
meta_factory data(const char *name) noexcept
Assigns a meta data to a meta type.
Definition factory.hpp:300
meta_factory(meta_ctx &area) noexcept
Context aware constructor.
Definition factory.hpp:173
meta_factory conv() noexcept
Assigns a meta conversion function to a meta type.
Definition factory.hpp:242
meta_factory traits(const Value value, const bool unset=false)
Sets traits on the last created meta object.
Definition factory.hpp:485
meta_factory type(const char *name) noexcept
Assigns a custom unique identifier to a meta type.
Definition factory.hpp:181
Type element_type
Type of object for which this factory builds a meta type.
Definition factory.hpp:163
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
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:388
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
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:356
void meta_reset() noexcept
Resets a type and all its parts.
Definition factory.hpp:565
meta_any forward_as_meta(const meta_ctx &ctx, Type &&value)
Forwards its argument and avoids copies for lvalue references.
Definition meta.hpp:647
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 meta_arg(const meta_ctx &ctx, const std::size_t index) noexcept
Returns the meta type of the i-th element of a list of arguments.
Definition utility.hpp:251
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, non-const reference.
Definition fwd.hpp:19
constexpr id_type hash() const noexcept
Type hash.
A class to use to push around lists of types, nothing more.