EnTT 3.13.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 <functional>
6#include <memory>
7#include <tuple>
8#include <type_traits>
9#include <utility>
10#include "../config/config.h"
11#include "../core/fwd.hpp"
12#include "../core/type_info.hpp"
13#include "../core/type_traits.hpp"
14#include "../locator/locator.hpp"
15#include "context.hpp"
16#include "meta.hpp"
17#include "node.hpp"
18#include "policy.hpp"
19#include "range.hpp"
20#include "resolve.hpp"
21#include "utility.hpp"
22
23namespace entt {
24
26namespace internal {
27
28[[nodiscard]] inline decltype(auto) owner(meta_ctx &ctx, const type_info &info) {
29 auto &&context = internal::meta_context::from(ctx);
30 ENTT_ASSERT(context.value.contains(info.hash()), "Type not available");
31 return context.value[info.hash()];
32}
33
34inline meta_data_node &meta_extend(internal::meta_type_node &parent, const id_type id, meta_data_node node) {
35 return parent.details->data.insert_or_assign(id, std::move(node)).first->second;
36}
37
38inline meta_func_node &meta_extend(internal::meta_type_node &parent, const id_type id, meta_func_node node) {
39 if(auto it = parent.details->func.find(id); it != parent.details->func.end()) {
40 for(auto *curr = &it->second; curr; curr = curr->next.get()) {
41 if(curr->invoke == node.invoke) {
42 node.next = std::move(curr->next);
43 *curr = std::move(node);
44 return *curr;
45 }
46 }
47
48 // locally overloaded function
49 node.next = std::make_shared<meta_func_node>(std::move(parent.details->func[id]));
50 }
51
52 return parent.details->func.insert_or_assign(id, std::move(node)).first->second;
53}
54
55} // namespace internal
62template<typename Type>
64 template<typename Setter, auto Getter, typename Policy, std::size_t... Index>
65 void data(const id_type id, std::index_sequence<Index...>) noexcept {
66 using data_type = std::invoke_result_t<decltype(Getter), Type &>;
67 using args_type = type_list<typename meta_function_helper_t<Type, decltype(value_list_element_v<Index, Setter>)>::args_type...>;
68 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
69
70 auto &&elem = internal::meta_extend(
71 internal::owner(*ctx, *info),
72 id,
73 internal::meta_data_node{
74 /* this is never static */
75 (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,
76 Setter::size,
77 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
78 &meta_arg<type_list<type_list_element_t<type_list_element_t<Index, args_type>::size != 1u, type_list_element_t<Index, args_type>>...>>,
79 +[](meta_handle instance, meta_any value) { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
80 &meta_getter<Type, Getter, Policy>});
81
82 bucket = &elem.prop;
83 }
84
85public:
87 meta_factory() noexcept
89
94 meta_factory(meta_ctx &area) noexcept
95 : ctx{&area},
96 bucket{},
97 info{&type_id<Type>()} {
98 auto &&elem = internal::owner(*ctx, *info);
99
100 if(!elem.details) {
101 elem.details = std::make_shared<internal::meta_type_descriptor>();
102 }
103
104 bucket = &elem.details->prop;
105 }
106
112 auto type(const id_type id) noexcept {
113 auto &&elem = internal::owner(*ctx, *info);
114 ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier");
115 bucket = &elem.details->prop;
116 elem.id = id;
117 return *this;
118 }
119
128 template<typename Base>
129 auto base() noexcept {
130 static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>, "Invalid base type");
131 auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
132 internal::owner(*ctx, *info).details->base.insert_or_assign(type_id<Base>().hash(), internal::meta_base_node{&internal::resolve<Base>, op});
133 bucket = nullptr;
134 return *this;
135 }
136
149 template<auto Candidate>
150 auto conv() noexcept {
151 using conv_type = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
152 auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, std::invoke(Candidate, *static_cast<const Type *>(instance))); };
153 internal::owner(*ctx, *info).details->conv.insert_or_assign(type_id<conv_type>().hash(), internal::meta_conv_node{op});
154 bucket = nullptr;
155 return *this;
156 }
157
167 template<typename To>
168 auto conv() noexcept {
169 using conv_type = std::remove_cv_t<std::remove_reference_t<To>>;
170 auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast<To>(*static_cast<const Type *>(instance))); };
171 internal::owner(*ctx, *info).details->conv.insert_or_assign(type_id<conv_type>().hash(), internal::meta_conv_node{op});
172 bucket = nullptr;
173 return *this;
174 }
175
189 template<auto Candidate, typename Policy = as_is_t>
190 auto ctor() noexcept {
191 using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
192 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
193 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");
194 internal::owner(*ctx, *info).details->ctor.insert_or_assign(type_id<typename descriptor::args_type>().hash(), internal::meta_ctor_node{descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Candidate, Policy>});
195 bucket = nullptr;
196 return *this;
197 }
198
209 template<typename... Args>
210 auto ctor() noexcept {
211 // default constructor is already implicitly generated, no need for redundancy
212 if constexpr(sizeof...(Args) != 0u) {
213 using descriptor = meta_function_helper_t<Type, Type (*)(Args...)>;
214 internal::owner(*ctx, *info).details->ctor.insert_or_assign(type_id<typename descriptor::args_type>().hash(), internal::meta_ctor_node{descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Args...>});
215 }
216
217 bucket = nullptr;
218 return *this;
219 }
220
239 template<auto Func>
240 auto dtor() noexcept {
241 static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
242 auto *const op = +[](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
243 internal::owner(*ctx, *info).dtor = internal::meta_dtor_node{op};
244 bucket = nullptr;
245 return *this;
246 }
247
261 template<auto Data, typename Policy = as_is_t>
262 auto data(const id_type id) noexcept {
263 if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
264 using data_type = std::invoke_result_t<decltype(Data), Type &>;
265 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
266
267 auto &&elem = internal::meta_extend(
268 internal::owner(*ctx, *info),
269 id,
270 internal::meta_data_node{
271 /* this is never static */
272 std::is_const_v<std::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
273 1u,
274 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
275 &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
276 &meta_setter<Type, Data>,
277 &meta_getter<Type, Data, Policy>});
278
279 bucket = &elem.prop;
280 } else {
281 using data_type = std::remove_pointer_t<decltype(Data)>;
282
283 if constexpr(std::is_pointer_v<decltype(Data)>) {
284 static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
285 } else {
286 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
287 }
288
289 auto &&elem = internal::meta_extend(
290 internal::owner(*ctx, *info),
291 id,
292 internal::meta_data_node{
293 ((std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<data_type>>> || std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
294 1u,
295 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
296 &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
297 &meta_setter<Type, Data>,
298 &meta_getter<Type, Data, Policy>});
299
300 bucket = &elem.prop;
301 }
302
303 return *this;
304 }
305
326 template<auto Setter, auto Getter, typename Policy = as_is_t>
327 auto data(const id_type id) noexcept {
328 using data_type = std::invoke_result_t<decltype(Getter), Type &>;
329 static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
330
331 if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
332 auto &&elem = internal::meta_extend(
333 internal::owner(*ctx, *info),
334 id,
335 internal::meta_data_node{
336 /* this is never static */
337 internal::meta_traits::is_const,
338 0u,
339 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
340 &meta_arg<type_list<>>,
341 &meta_setter<Type, Setter>,
342 &meta_getter<Type, Getter, Policy>});
343
344 bucket = &elem.prop;
345 } else {
346 using args_type = typename meta_function_helper_t<Type, decltype(Setter)>::args_type;
347
348 auto &&elem = internal::meta_extend(
349 internal::owner(*ctx, *info),
350 id,
351 internal::meta_data_node{
352 /* this is never static nor const */
353 internal::meta_traits::is_none,
354 1u,
355 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
356 &meta_arg<type_list<type_list_element_t<args_type::size != 1u, args_type>>>,
357 &meta_setter<Type, Setter>,
358 &meta_getter<Type, Getter, Policy>});
359
360 bucket = &elem.prop;
361 }
362
363 return *this;
364 }
365
383 template<typename Setter, auto Getter, typename Policy = as_is_t>
384 auto data(const id_type id) noexcept {
385 data<Setter, Getter, Policy>(id, std::make_index_sequence<Setter::size>{});
386 return *this;
387 }
388
402 template<auto Candidate, typename Policy = as_is_t>
403 auto func(const id_type id) noexcept {
404 using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
405 static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
406
407 auto &&elem = internal::meta_extend(
408 internal::owner(*ctx, *info),
409 id,
410 internal::meta_func_node{
411 (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),
412 descriptor::args_type::size,
413 &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>>>>,
414 &meta_arg<typename descriptor::args_type>,
415 &meta_invoke<Type, Candidate, Policy>});
416
417 bucket = &elem.prop;
418 return *this;
419 }
420
431 template<typename... Value>
432 meta_factory prop(id_type id, [[maybe_unused]] Value &&...value) {
433 ENTT_ASSERT(bucket != nullptr, "Meta object does not support properties");
434
435 if constexpr(sizeof...(Value) == 0u) {
436 (*bucket)[id] = internal::meta_prop_node{&internal::resolve<void>};
437 } else {
438 (*bucket)[id] = internal::meta_prop_node{
439 &internal::resolve<std::decay_t<Value>>...,
440 std::make_shared<std::decay_t<Value>>(std::forward<Value>(value))...};
441 }
442
443 return *this;
444 }
445
446private:
447 meta_ctx *ctx;
449 const type_info *info;
450};
451
464template<typename Type>
465[[nodiscard]] auto meta(meta_ctx &ctx) noexcept {
466 auto &&context = internal::meta_context::from(ctx);
467 // make sure the type exists in the context before returning a factory
468 context.value.try_emplace(type_id<Type>().hash(), internal::resolve<Type>(context));
469 return meta_factory<Type>{ctx};
470}
471
483template<typename Type>
484[[nodiscard]] auto meta() noexcept {
485 return meta<Type>(locator<meta_ctx>::value_or());
486}
487
500inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept {
501 auto &&context = internal::meta_context::from(ctx);
502
503 for(auto it = context.value.begin(); it != context.value.end();) {
504 if(it->second.id == id) {
505 it = context.value.erase(it);
506 } else {
507 ++it;
508 }
509 }
510}
511
523inline void meta_reset(const id_type id) noexcept {
525}
526
535template<typename Type>
536void meta_reset(meta_ctx &ctx) noexcept {
537 internal::meta_context::from(ctx).value.erase(type_id<Type>().hash());
538}
539
547template<typename Type>
548void meta_reset() noexcept {
549 meta_reset<Type>(locator<meta_ctx>::value_or());
550}
551
559inline void meta_reset(meta_ctx &ctx) noexcept {
560 internal::meta_context::from(ctx).value.clear();
561}
562
568inline void meta_reset() noexcept {
570}
571
572} // namespace entt
573
574#endif
Associative container for key-value pairs with unique keys.
Service locator, nothing more.
Definition locator.hpp:27
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
Definition locator.hpp:78
Opaque wrapper for values of any type.
Definition meta.hpp:181
meta_any as_ref() noexcept
Aliasing constructor.
Definition meta.hpp:600
Opaque meta context type.
Definition context.hpp:34
Basic meta factory to be used for reflection purposes.
Definition factory.hpp:63
auto base() noexcept
Assigns a meta base to a meta type.
Definition factory.hpp:129
auto conv() noexcept
Assigns a meta conversion function to a meta type.
Definition factory.hpp:150
meta_factory prop(id_type id, Value &&...value)
Assigns a property to the last meta object created.
Definition factory.hpp:432
meta_factory() noexcept
Default constructor.
Definition factory.hpp:87
auto data(const id_type id) noexcept
Assigns a meta data to a meta type.
Definition factory.hpp:262
meta_factory(meta_ctx &area) noexcept
Context aware constructor.
Definition factory.hpp:94
auto data(const id_type id) noexcept
Assigns a meta data to a meta type by means of its setter and getter.
Definition factory.hpp:327
auto dtor() noexcept
Assigns a meta destructor to a meta type.
Definition factory.hpp:240
auto ctor() noexcept
Assigns a meta constructor to a meta type.
Definition factory.hpp:190
auto ctor() noexcept
Assigns a meta constructor to a meta type.
Definition factory.hpp:210
auto type(const id_type id) noexcept
Assigns a custom unique identifier to a meta type.
Definition factory.hpp:112
auto func(const id_type id) noexcept
Assigns a meta function to a meta type.
Definition factory.hpp:403
EnTT default namespace.
Definition dense_map.hpp:21
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:13
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:446
typename meta_function_helper< Type, Candidate >::type meta_function_helper_t
Helper type.
Definition utility.hpp:152
auto meta() noexcept
Utility function to use for reflection.
Definition factory.hpp:484
meta_type resolve() noexcept
Returns the meta type associated with a given type.
Definition resolve.hpp:32
void meta_reset() noexcept
Resets a type and all its parts.
Definition factory.hpp:548
meta_any forward_as_meta(const meta_ctx &ctx, Type &&value)
Forwards its argument and avoids copies for lvalue references.
Definition meta.hpp:637
bool meta_setter(meta_handle instance, meta_any value)
Sets the value of a given variable.
Definition utility.hpp:226
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
@ owner
Default mode, the object owns the contained element.
Opaque pointers to instances of any type.
Definition meta.hpp:658
Implementation specific information about a type.
A class to use to push around lists of types, nothing more.