1 #ifndef ENTT_META_META_HPP
2 #define ENTT_META_META_HPP
3
4
5 #include <cstddef>
6 #include <functional>
7 #include <iterator>
8 #include <memory>
9 #include <type_traits>
10 #include <utility>
11 #include "../config/config.h"
12 #include "../core/any.hpp"
13 #include "../core/fwd.hpp"
14 #include "../core/utility.hpp"
15 #include "../core/type_info.hpp"
16 #include "../core/type_traits.hpp"
17 #include "adl_pointer.hpp"
18 #include "ctx.hpp"
19 #include "node.hpp"
20 #include "range.hpp"
21 #include "type_traits.hpp"
22
23
24 namespace entt {
25
26
27 class meta_any;
28 class meta_type;
29
30
31 /*! @brief Proxy object for sequence containers. */
32 class meta_sequence_container {
33 template<typename>
34 struct meta_sequence_container_proxy;
35
36 class meta_iterator;
37
38 public:
39 /*! @brief Unsigned integer type. */
40 using size_type = std::size_t;
41 /*! @brief Meta iterator type. */
42 using iterator = meta_iterator;
43
44 /*! @brief Default constructor. */
45 meta_sequence_container() ENTT_NOEXCEPT = default;
46
47 /**
48 * @brief Construct a proxy object for sequence containers.
49 * @tparam Type Type of container to wrap.
50 * @param instance The container to wrap.
51 */
52 template<typename Type>
meta_sequence_container(std::in_place_type_t<Type>,any instance)53 meta_sequence_container(std::in_place_type_t<Type>, any instance) ENTT_NOEXCEPT
54 : value_type_fn{&meta_sequence_container_proxy<Type>::value_type},
55 size_fn{&meta_sequence_container_proxy<Type>::size},
56 resize_fn{&meta_sequence_container_proxy<Type>::resize},
57 clear_fn{&meta_sequence_container_proxy<Type>::clear},
58 begin_fn{&meta_sequence_container_proxy<Type>::begin},
59 end_fn{&meta_sequence_container_proxy<Type>::end},
60 insert_fn{&meta_sequence_container_proxy<Type>::insert},
61 erase_fn{&meta_sequence_container_proxy<Type>::erase},
62 get_fn{&meta_sequence_container_proxy<Type>::get},
63 storage{std::move(instance)}
64 {}
65
66 [[nodiscard]] inline meta_type value_type() const ENTT_NOEXCEPT;
67 [[nodiscard]] inline size_type size() const ENTT_NOEXCEPT;
68 inline bool resize(size_type);
69 inline bool clear();
70 [[nodiscard]] inline iterator begin();
71 [[nodiscard]] inline iterator end();
72 inline std::pair<iterator, bool> insert(iterator, meta_any);
73 inline std::pair<iterator, bool> erase(iterator);
74 [[nodiscard]] inline meta_any operator[](size_type);
75 [[nodiscard]] inline explicit operator bool() const ENTT_NOEXCEPT;
76
77 private:
78 meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr;
79 size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr;
80 bool(* resize_fn)(any &, size_type) = nullptr;
81 bool(* clear_fn)(any &) = nullptr;
82 iterator(* begin_fn)(any &) = nullptr;
83 iterator(* end_fn)(any &) = nullptr;
84 std::pair<iterator, bool>(* insert_fn)(any &, iterator, meta_any &) = nullptr;
85 std::pair<iterator, bool>(* erase_fn)(any &, iterator) = nullptr;
86 meta_any(* get_fn)(any &, size_type) = nullptr;
87 any storage{};
88 };
89
90
91 /*! @brief Proxy object for associative containers. */
92 class meta_associative_container {
93 template<typename>
94 struct meta_associative_container_proxy;
95
96 class meta_iterator;
97
98 public:
99 /*! @brief Unsigned integer type. */
100 using size_type = std::size_t;
101 /*! @brief Meta iterator type. */
102 using iterator = meta_iterator;
103
104 /*! @brief Default constructor. */
105 meta_associative_container() ENTT_NOEXCEPT = default;
106
107 /**
108 * @brief Construct a proxy object for associative containers.
109 * @tparam Type Type of container to wrap.
110 * @param instance The container to wrap.
111 */
112 template<typename Type>
meta_associative_container(std::in_place_type_t<Type>,any instance)113 meta_associative_container(std::in_place_type_t<Type>, any instance) ENTT_NOEXCEPT
114 : key_only_container{is_key_only_meta_associative_container_v<Type>},
115 key_type_fn{&meta_associative_container_proxy<Type>::key_type},
116 mapped_type_fn{&meta_associative_container_proxy<Type>::mapped_type},
117 value_type_fn{&meta_associative_container_proxy<Type>::value_type},
118 size_fn{&meta_associative_container_proxy<Type>::size},
119 clear_fn{&meta_associative_container_proxy<Type>::clear},
120 begin_fn{&meta_associative_container_proxy<Type>::begin},
121 end_fn{&meta_associative_container_proxy<Type>::end},
122 insert_fn{&meta_associative_container_proxy<Type>::insert},
123 erase_fn{&meta_associative_container_proxy<Type>::erase},
124 find_fn{&meta_associative_container_proxy<Type>::find},
125 storage{std::move(instance)}
126 {}
127
128 [[nodiscard]] inline bool key_only() const ENTT_NOEXCEPT;
129 [[nodiscard]] inline meta_type key_type() const ENTT_NOEXCEPT;
130 [[nodiscard]] inline meta_type mapped_type() const ENTT_NOEXCEPT;
131 [[nodiscard]] inline meta_type value_type() const ENTT_NOEXCEPT;
132 [[nodiscard]] inline size_type size() const ENTT_NOEXCEPT;
133 inline bool clear();
134 [[nodiscard]] inline iterator begin();
135 [[nodiscard]] inline iterator end();
136 inline bool insert(meta_any, meta_any);
137 inline bool erase(meta_any);
138 [[nodiscard]] inline iterator find(meta_any);
139 [[nodiscard]] inline explicit operator bool() const ENTT_NOEXCEPT;
140
141 private:
142 bool key_only_container{};
143 meta_type(* key_type_fn)() ENTT_NOEXCEPT = nullptr;
144 meta_type(* mapped_type_fn)() ENTT_NOEXCEPT = nullptr;
145 meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr;
146 size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr;
147 bool(* clear_fn)(any &) = nullptr;
148 iterator(* begin_fn)(any &) = nullptr;
149 iterator(* end_fn)(any &) = nullptr;
150 bool(* insert_fn)(any &, meta_any &, meta_any &) = nullptr;
151 bool(* erase_fn)(any &, meta_any &) = nullptr;
152 iterator(* find_fn)(any &, meta_any &) = nullptr;
153 any storage{};
154 };
155
156
157 /*! @brief Opaque wrapper for values of any type. */
158 class meta_any {
159 enum class operation { DTOR, DEREF, SEQ, ASSOC };
160
161 using vtable_type = void(const operation, const any &, void *);
162
163 template<typename Type>
basic_vtable(const operation op,const any & from,void * to)164 static void basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) {
165 static_assert(std::is_same_v<std::remove_reference_t<std::remove_const_t<Type>>, Type>, "Invalid type");
166
167 if constexpr(!std::is_void_v<Type>) {
168 switch(op) {
169 case operation::DTOR:
170 if(auto *curr = static_cast<internal::meta_type_node *>(to); curr->dtor && from.owner()) {
171 curr->dtor(const_cast<any &>(from).data());
172 }
173 break;
174 case operation::DEREF:
175 if constexpr(is_meta_pointer_like_v<Type>) {
176 using element_type = std::remove_const_t<typename std::pointer_traits<Type>::element_type>;
177
178 if constexpr(std::is_function_v<element_type>) {
179 *static_cast<meta_any *>(to) = any_cast<Type>(from);
180 } else if constexpr(!std::is_same_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>, void>) {
181 using in_place_type = decltype(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(from)));
182 static_cast<meta_any *>(to)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(from)));
183 }
184 }
185 break;
186 case operation::SEQ:
187 if constexpr(is_complete_v<meta_sequence_container_traits<Type>>) {
188 *static_cast<meta_sequence_container *>(to) = { std::in_place_type<Type>, std::move(const_cast<any &>(from)) };
189 }
190 break;
191 case operation::ASSOC:
192 if constexpr(is_complete_v<meta_associative_container_traits<Type>>) {
193 *static_cast<meta_associative_container *>(to) = { std::in_place_type<Type>, std::move(const_cast<any &>(from)) };
194 }
195 break;
196 }
197 }
198 }
199
meta_any(const meta_any & other,any ref)200 meta_any(const meta_any &other, any ref) ENTT_NOEXCEPT
201 : storage{std::move(ref)},
202 node{storage ? other.node : nullptr},
203 vtable{storage ? other.vtable : &basic_vtable<void>}
204 {}
205
206 public:
207 /*! @brief Default constructor. */
meta_any()208 meta_any() ENTT_NOEXCEPT
209 : storage{},
210 node{},
211 vtable{&basic_vtable<void>}
212 {}
213
214 /**
215 * @brief Constructs a wrapper by directly initializing the new object.
216 * @tparam Type Type of object to use to initialize the wrapper.
217 * @tparam Args Types of arguments to use to construct the new instance.
218 * @param args Parameters to use to construct the instance.
219 */
220 template<typename Type, typename... Args>
meta_any(std::in_place_type_t<Type>,Args &&...args)221 explicit meta_any(std::in_place_type_t<Type>, Args &&... args)
222 : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
223 node{internal::meta_info<Type>::resolve()},
224 vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>}
225 {}
226
227 /**
228 * @brief Constructs a wrapper that holds an unmanaged object.
229 * @tparam Type Type of object to use to initialize the wrapper.
230 * @param value An instance of an object to use to initialize the wrapper.
231 */
232 template<typename Type>
meta_any(std::reference_wrapper<Type> value)233 meta_any(std::reference_wrapper<Type> value)
234 : meta_any{}
235 {
236 // invokes deprecated assignment operator (and avoids issues with vs2017)
237 *this = value;
238 }
239
240 /**
241 * @brief Constructs a wrapper from a given value.
242 * @tparam Type Type of object to use to initialize the wrapper.
243 * @param value An instance of an object to use to initialize the wrapper.
244 */
245 template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
meta_any(Type && value)246 meta_any(Type &&value)
247 : storage{std::forward<Type>(value)},
248 node{internal::meta_info<std::decay_t<Type>>::resolve()},
249 vtable{&basic_vtable<std::decay_t<Type>>}
250 {}
251
252 /**
253 * @brief Copy constructor.
254 * @param other The instance to copy from.
255 */
256 meta_any(const meta_any &other) = default;
257
258 /**
259 * @brief Move constructor.
260 * @param other The instance to move from.
261 */
meta_any(meta_any && other)262 meta_any(meta_any &&other) ENTT_NOEXCEPT
263 : storage{std::move(other.storage)},
264 node{std::exchange(other.node, nullptr)},
265 vtable{std::exchange(other.vtable, &basic_vtable<void>)}
266 {}
267
268 /*! @brief Frees the internal storage, whatever it means. */
~meta_any()269 ~meta_any() {
270 vtable(operation::DTOR, storage, node);
271 }
272
273 /**
274 * @brief Copy assignment operator.
275 * @param other The instance to copy from.
276 * @return This meta any object.
277 */
operator =(const meta_any & other)278 meta_any & operator=(const meta_any &other) {
279 std::exchange(vtable, other.vtable)(operation::DTOR, storage, node);
280 storage = other.storage;
281 node = other.node;
282 return *this;
283 }
284
285 /**
286 * @brief Move assignment operator.
287 * @param other The instance to move from.
288 * @return This meta any object.
289 */
operator =(meta_any && other)290 meta_any & operator=(meta_any &&other) ENTT_NOEXCEPT {
291 std::exchange(vtable, std::exchange(other.vtable, &basic_vtable<void>))(operation::DTOR, storage, node);
292 storage = std::move(other.storage);
293 node = std::exchange(other.node, nullptr);
294 return *this;
295 }
296
297 /**
298 * @brief Value assignment operator.
299 * @tparam Type Type of object to use to initialize the wrapper.
300 * @param value An instance of an object to use to initialize the wrapper.
301 * @return This meta any object.
302 */
303 template<typename Type>
304 [[deprecated("Use std::in_place_type<T &>, entt::make_meta<T &>, emplace<Type &> or forward_as_meta instead")]]
operator =(std::reference_wrapper<Type> value)305 meta_any & operator=(std::reference_wrapper<Type> value) {
306 emplace<Type &>(value.get());
307 return *this;
308 }
309
310 /**
311 * @brief Value assignment operator.
312 * @tparam Type Type of object to use to initialize the wrapper.
313 * @param value An instance of an object to use to initialize the wrapper.
314 * @return This meta any object.
315 */
316 template<typename Type>
317 std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>, meta_any &>
operator =(Type && value)318 operator=(Type &&value) {
319 emplace<std::decay_t<Type>>(std::forward<Type>(value));
320 return *this;
321 }
322
323 /**
324 * @brief Returns the type of the underlying object.
325 * @return The type of the underlying object, if any.
326 */
327 [[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT;
328
329 /**
330 * @brief Returns an opaque pointer to the contained instance.
331 * @return An opaque pointer the contained instance, if any.
332 */
data() const333 [[nodiscard]] const void * data() const ENTT_NOEXCEPT {
334 return storage.data();
335 }
336
337 /*! @copydoc data */
data()338 [[nodiscard]] void * data() ENTT_NOEXCEPT {
339 return storage.data();
340 }
341
342 /**
343 * @brief Invokes the underlying function, if possible.
344 *
345 * @sa meta_func::invoke
346 *
347 * @tparam Args Types of arguments to use to invoke the function.
348 * @param id Unique identifier.
349 * @param args Parameters to use to invoke the function.
350 * @return A wrapper containing the returned value, if any.
351 */
352 template<typename... Args>
353 meta_any invoke(const id_type id, Args &&... args) const;
354
355 /*! @copydoc invoke */
356 template<typename... Args>
357 meta_any invoke(const id_type id, Args &&... args);
358
359 /**
360 * @brief Sets the value of a given variable.
361 *
362 * The type of the value must be such that a cast or conversion to the type
363 * of the variable is possible. Otherwise, invoking the setter does nothing.
364 *
365 * @tparam Type Type of value to assign.
366 * @param id Unique identifier.
367 * @param value Parameter to use to set the underlying variable.
368 * @return True in case of success, false otherwise.
369 */
370 template<typename Type>
371 bool set(const id_type id, Type &&value);
372
373 /**
374 * @brief Gets the value of a given variable.
375 * @param id Unique identifier.
376 * @return A wrapper containing the value of the underlying variable.
377 */
378 [[nodiscard]] meta_any get(const id_type id) const;
379
380 /*! @copydoc get */
381 [[nodiscard]] meta_any get(const id_type id);
382
383 /**
384 * @brief Tries to cast an instance to a given type.
385 * @tparam Type Type to which to cast the instance.
386 * @return A (possibly null) pointer to the contained instance.
387 */
388 template<typename Type>
try_cast() const389 [[nodiscard]] const Type * try_cast() const {
390 if(node) {
391 if(const auto info = type_id<Type>(); node->info == info) {
392 return any_cast<Type>(&storage);
393 } else if(const auto *base = internal::meta_visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
394 return static_cast<const Type *>(base->cast(storage.data()));
395 }
396 }
397
398 return nullptr;
399 }
400
401 /*! @copydoc try_cast */
402 template<typename Type>
try_cast()403 [[nodiscard]] Type * try_cast() {
404 if(node) {
405 if(const auto info = type_id<Type>(); node->info == info) {
406 return any_cast<Type>(&storage);
407 } else if(const auto *base = internal::meta_visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
408 return static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(base->cast(static_cast<constness_as_t<any, Type> &>(storage).data())));
409 }
410 }
411
412 return nullptr;
413 }
414
415 /**
416 * @brief Tries to cast an instance to a given type.
417 *
418 * The type of the instance must be such that the cast is possible.
419 *
420 * @warning
421 * Attempting to perform an invalid cast results in undefined behavior.
422 *
423 * @tparam Type Type to which to cast the instance.
424 * @return A reference to the contained instance.
425 */
426 template<typename Type>
cast() const427 [[nodiscard]] Type cast() const {
428 auto * const instance = try_cast<std::remove_reference_t<Type>>();
429 ENTT_ASSERT(instance, "Invalid instance");
430 return static_cast<Type>(*instance);
431 }
432
433 /*! @copydoc cast */
434 template<typename Type>
cast()435 [[nodiscard]] Type cast() {
436 // forces const on non-reference types to make them work also with wrappers for const references
437 auto * const instance = try_cast<std::remove_reference_t<const Type>>();
438 ENTT_ASSERT(instance, "Invalid instance");
439 return static_cast<Type>(*instance);
440 }
441
442 /**
443 * @brief Converts an object in such a way that a given cast becomes viable.
444 * @tparam Type Type to which the cast is requested.
445 * @return A valid meta any object if there exists a viable conversion, an
446 * invalid one otherwise.
447 */
448 template<typename Type>
allow_cast() const449 [[nodiscard]] meta_any allow_cast() const {
450 if(try_cast<std::remove_reference_t<Type>>() != nullptr) {
451 return as_ref();
452 } else if(node) {
453 if(const auto * const conv = internal::meta_visit<&internal::meta_type_node::conv>([info = type_id<Type>()](const auto *curr) { return curr->type()->info == info; }, node); conv) {
454 return conv->conv(storage.data());
455 }
456 }
457
458 return {};
459 }
460
461 /**
462 * @brief Converts an object in such a way that a given cast becomes viable.
463 * @tparam Type Type to which the cast is requested.
464 * @return True if there exists a viable conversion, false otherwise.
465 */
466 template<typename Type>
allow_cast()467 bool allow_cast() {
468 // forces const on non-reference types to make them work also with wrappers for const references
469 if(try_cast<std::remove_reference_t<const Type>>() != nullptr) {
470 return true;
471 } else if(node) {
472 if(const auto * const conv = internal::meta_visit<&internal::meta_type_node::conv>([info = type_id<Type>()](const auto *curr) { return curr->type()->info == info; }, node); conv) {
473 *this = conv->conv(std::as_const(storage).data());
474 return true;
475 }
476 }
477
478 return false;
479 }
480
481 /**
482 * @brief Replaces the contained object by creating a new instance directly.
483 * @tparam Type Type of object to use to initialize the wrapper.
484 * @tparam Args Types of arguments to use to construct the new instance.
485 * @param args Parameters to use to construct the instance.
486 */
487 template<typename Type, typename... Args>
emplace(Args &&...args)488 void emplace(Args &&... args) {
489 std::exchange(vtable, &basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>)(operation::DTOR, storage, node);
490 storage.emplace<Type>(std::forward<Args>(args)...);
491 node = internal::meta_info<Type>::resolve();
492 }
493
494 /*! @brief Destroys contained object */
reset()495 void reset() {
496 std::exchange(vtable, &basic_vtable<void>)(operation::DTOR, storage, node);
497 storage.reset();
498 node = nullptr;
499 }
500
501 /**
502 * @brief Returns a sequence container proxy.
503 * @return A sequence container proxy for the underlying object.
504 */
as_sequence_container()505 [[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT {
506 meta_sequence_container proxy;
507 vtable(operation::SEQ, storage.as_ref(), &proxy);
508 return proxy;
509 }
510
511 /*! @copydoc as_sequence_container */
as_sequence_container() const512 [[nodiscard]] meta_sequence_container as_sequence_container() const ENTT_NOEXCEPT {
513 meta_sequence_container proxy;
514 vtable(operation::SEQ, storage.as_ref(), &proxy);
515 return proxy;
516 }
517
518 /**
519 * @brief Returns an associative container proxy.
520 * @return An associative container proxy for the underlying object.
521 */
as_associative_container()522 [[nodiscard]] meta_associative_container as_associative_container() ENTT_NOEXCEPT {
523 meta_associative_container proxy;
524 vtable(operation::ASSOC, storage.as_ref(), &proxy);
525 return proxy;
526 }
527
528 /*! @copydoc as_associative_container */
as_associative_container() const529 [[nodiscard]] meta_associative_container as_associative_container() const ENTT_NOEXCEPT {
530 meta_associative_container proxy;
531 vtable(operation::ASSOC, storage.as_ref(), &proxy);
532 return proxy;
533 }
534
535 /**
536 * @brief Indirection operator for dereferencing opaque objects.
537 * @return A wrapper that shares a reference to an unmanaged object if the
538 * wrapped element is dereferenceable, an invalid meta any otherwise.
539 */
operator *() const540 [[nodiscard]] meta_any operator*() const ENTT_NOEXCEPT {
541 meta_any ret{};
542 vtable(operation::DEREF, storage, &ret);
543 return ret;
544 }
545
546 /**
547 * @brief Returns false if a wrapper is invalid, true otherwise.
548 * @return False if the wrapper is invalid, true otherwise.
549 */
operator bool() const550 [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
551 return !(node == nullptr);
552 }
553
554 /**
555 * @brief Checks if two wrappers differ in their content.
556 * @param other Wrapper with which to compare.
557 * @return False if the two objects differ in their content, true otherwise.
558 */
operator ==(const meta_any & other) const559 [[nodiscard]] bool operator==(const meta_any &other) const {
560 return (!node && !other.node) || (node && other.node && node->info == other.node->info && storage == other.storage);
561 }
562
563 /**
564 * @brief Aliasing constructor.
565 * @return A wrapper that shares a reference to an unmanaged object.
566 */
as_ref()567 [[nodiscard]] meta_any as_ref() ENTT_NOEXCEPT {
568 return meta_any{*this, storage.as_ref()};
569 }
570
571 /*! @copydoc as_ref */
as_ref() const572 [[nodiscard]] meta_any as_ref() const ENTT_NOEXCEPT {
573 return meta_any{*this, storage.as_ref()};
574 }
575
576 private:
577 any storage;
578 internal::meta_type_node *node;
579 vtable_type *vtable;
580 };
581
582
583 /**
584 * @brief Checks if two wrappers differ in their content.
585 * @param lhs A wrapper, either empty or not.
586 * @param rhs A wrapper, either empty or not.
587 * @return True if the two wrappers differ in their content, false otherwise.
588 */
operator !=(const meta_any & lhs,const meta_any & rhs)589 [[nodiscard]] inline bool operator!=(const meta_any &lhs, const meta_any &rhs) ENTT_NOEXCEPT {
590 return !(lhs == rhs);
591 }
592
593
594 /**
595 * @brief Constructs a wrapper from a given type, passing it all arguments.
596 * @tparam Type Type of object to use to initialize the wrapper.
597 * @tparam Args Types of arguments to use to construct the new instance.
598 * @param args Parameters to use to construct the instance.
599 * @return A properly initialized wrapper for an object of the given type.
600 */
601 template<typename Type, typename... Args>
make_meta(Args &&...args)602 meta_any make_meta(Args &&... args) {
603 return meta_any{std::in_place_type<Type>, std::forward<Args>(args)...};
604 }
605
606
607 /**
608 * @brief Forwards its argument and avoids copies for lvalue references.
609 * @tparam Type Type of argument to use to construct the new instance.
610 * @param value Parameter to use to construct the instance.
611 * @return A properly initialized and not necessarily owning wrapper.
612 */
613 template<typename Type>
forward_as_meta(Type && value)614 meta_any forward_as_meta(Type &&value) {
615 return meta_any{std::in_place_type<std::conditional_t<std::is_rvalue_reference_v<Type>, std::decay_t<Type>, Type>>, std::forward<Type>(value)};
616 }
617
618
619 /**
620 * @brief Opaque pointers to instances of any type.
621 *
622 * A handle doesn't perform copies and isn't responsible for the contained
623 * object. It doesn't prolong the lifetime of the pointed instance.<br/>
624 * Handles are used to generate references to actual objects when needed.
625 */
626 struct meta_handle {
627 /*! @brief Default constructor. */
628 meta_handle() = default;
629
630
631 /*! @brief Default copy constructor, deleted on purpose. */
632 meta_handle(const meta_handle &) = delete;
633
634 /*! @brief Default move constructor. */
635 meta_handle(meta_handle &&) = default;
636
637 /**
638 * @brief Default copy assignment operator, deleted on purpose.
639 * @return This meta handle.
640 */
641 meta_handle & operator=(const meta_handle &) = delete;
642
643 /**
644 * @brief Default move assignment operator.
645 * @return This meta handle.
646 */
647 meta_handle & operator=(meta_handle &&) = default;
648
649 /**
650 * @brief Creates a handle that points to an unmanaged object.
651 * @tparam Type Type of object to use to initialize the handle.
652 * @param value An instance of an object to use to initialize the handle.
653 */
654 template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
meta_handleentt::meta_handle655 meta_handle(Type &value) ENTT_NOEXCEPT
656 : meta_handle{}
657 {
658 if constexpr(std::is_same_v<std::decay_t<Type>, meta_any>) {
659 any = value.as_ref();
660 } else {
661 any.emplace<Type &>(value);
662 }
663 }
664
665 /**
666 * @brief Returns false if a handle is invalid, true otherwise.
667 * @return False if the handle is invalid, true otherwise.
668 */
operator boolentt::meta_handle669 [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
670 return static_cast<bool>(any);
671 }
672
673 /**
674 * @brief Access operator for accessing the contained opaque object.
675 * @return A wrapper that shares a reference to an unmanaged object.
676 */
operator ->entt::meta_handle677 [[nodiscard]] meta_any * operator->() {
678 return &any;
679 }
680
681 /*! @copydoc operator-> */
operator ->entt::meta_handle682 [[nodiscard]] const meta_any * operator->() const {
683 return &any;
684 }
685
686 private:
687 meta_any any;
688 };
689
690
691 /*! @brief Opaque wrapper for properties of any type. */
692 struct meta_prop {
693 /*! @brief Node type. */
694 using node_type = internal::meta_prop_node;
695
696 /**
697 * @brief Constructs an instance from a given node.
698 * @param curr The underlying node with which to construct the instance.
699 */
meta_propentt::meta_prop700 meta_prop(const node_type *curr = nullptr) ENTT_NOEXCEPT
701 : node{curr}
702 {}
703
704 /**
705 * @brief Returns the stored key as a const reference.
706 * @return A wrapper containing the key stored with the property.
707 */
keyentt::meta_prop708 [[nodiscard]] meta_any key() const {
709 return node->id.as_ref();
710 }
711
712 /**
713 * @brief Returns the stored value by copy.
714 * @return A wrapper containing the value stored with the property.
715 */
valueentt::meta_prop716 [[nodiscard]] meta_any value() const {
717 return node->value;
718 }
719
720 /**
721 * @brief Returns true if an object is valid, false otherwise.
722 * @return True if the object is valid, false otherwise.
723 */
operator boolentt::meta_prop724 [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
725 return !(node == nullptr);
726 }
727
728 private:
729 const node_type *node;
730 };
731
732
733 /*! @brief Opaque wrapper for constructors. */
734 struct meta_ctor {
735 /*! @brief Node type. */
736 using node_type = internal::meta_ctor_node;
737 /*! @brief Unsigned integer type. */
738 using size_type = typename node_type::size_type;
739
740 /*! @copydoc meta_prop::meta_prop */
meta_ctorentt::meta_ctor741 meta_ctor(const node_type *curr = nullptr) ENTT_NOEXCEPT
742 : node{curr}
743 {}
744
745 /**
746 * @brief Returns the type to which an object belongs.
747 * @return The type to which the object belongs.
748 */
749 [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT;
750
751 /**
752 * @brief Returns the number of arguments accepted by a constructor.
753 * @return The number of arguments accepted by the constructor.
754 */
arityentt::meta_ctor755 [[nodiscard]] size_type arity() const ENTT_NOEXCEPT {
756 return node->arity;
757 }
758
759 /**
760 * @brief Returns the type of the i-th argument of a constructor.
761 * @param index Index of the argument of which to return the type.
762 * @return The type of the i-th argument of a constructor.
763 */
764 [[nodiscard]] meta_type arg(size_type index) const ENTT_NOEXCEPT;
765
766 /**
767 * @brief Creates an instance of the underlying type, if possible.
768 *
769 * Parameters must be such that a cast or conversion to the required types
770 * is possible. Otherwise, an empty and thus invalid wrapper is returned.
771 *
772 * @param args Parameters to use to construct the instance.
773 * @param sz Number of parameters to use to construct the instance.
774 * @return A wrapper containing the new instance, if any.
775 */
invokeentt::meta_ctor776 [[nodiscard]] meta_any invoke(meta_any * const args, const size_type sz) const {
777 return sz == arity() ? node->invoke(args) : meta_any{};
778 }
779
780 /**
781 * @copybrief invoke
782 *
783 * @sa invoke
784 *
785 * @tparam Args Types of arguments to use to construct the instance.
786 * @param args Parameters to use to construct the instance.
787 * @return A wrapper containing the new instance, if any.
788 */
789 template<typename... Args>
invokeentt::meta_ctor790 [[nodiscard]] meta_any invoke([[maybe_unused]] Args &&... args) const {
791 meta_any arguments[sizeof...(Args) + 1u]{std::forward<Args>(args)...};
792 return invoke(arguments, sizeof...(Args));
793 }
794
795 /**
796 * @brief Returns a range to use to visit all properties.
797 * @return An iterable range to use to visit all properties.
798 */
propentt::meta_ctor799 [[nodiscard]] meta_range<meta_prop> prop() const ENTT_NOEXCEPT {
800 return node->prop;
801 }
802
803 /**
804 * @brief Returns the property associated with a given key.
805 * @param key The key to use to search for a property.
806 * @return The property associated with the given key, if any.
807 */
propentt::meta_ctor808 [[nodiscard]] meta_prop prop(meta_any key) const {
809 return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node);
810 }
811
812 /**
813 * @brief Returns true if an object is valid, false otherwise.
814 * @return True if the object is valid, false otherwise.
815 */
operator boolentt::meta_ctor816 [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
817 return !(node == nullptr);
818 }
819
820 private:
821 const node_type *node;
822 };
823
824
825 /*! @brief Opaque wrapper for data members. */
826 struct meta_data {
827 /*! @brief Node type. */
828 using node_type = internal::meta_data_node;
829
830 /*! @copydoc meta_prop::meta_prop */
meta_dataentt::meta_data831 meta_data(const node_type *curr = nullptr) ENTT_NOEXCEPT
832 : node{curr}
833 {}
834
835 /*! @copydoc meta_type::id */
identt::meta_data836 [[nodiscard]] id_type id() const ENTT_NOEXCEPT {
837 return node->id;
838 }
839
840 /*! @copydoc meta_ctor::parent */
841 [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT;
842
843 /**
844 * @brief Indicates whether a data member is constant or not.
845 * @return True if the data member is constant, false otherwise.
846 */
is_constentt::meta_data847 [[nodiscard]] bool is_const() const ENTT_NOEXCEPT {
848 return node->is_const;
849 }
850
851 /**
852 * @brief Indicates whether a data member is static or not.
853 * @return True if the data member is static, false otherwise.
854 */
is_staticentt::meta_data855 [[nodiscard]] bool is_static() const ENTT_NOEXCEPT {
856 return node->is_static;
857 }
858
859 /*! @copydoc meta_any::type */
860 [[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT;
861
862 /**
863 * @brief Sets the value of a given variable.
864 *
865 * It must be possible to cast the instance to the parent type of the data
866 * member. Otherwise, invoking the setter results in an undefined
867 * behavior.<br/>
868 * The type of the value must be such that a cast or conversion to the type
869 * of the variable is possible. Otherwise, invoking the setter does nothing.
870 *
871 * @tparam Type Type of value to assign.
872 * @param instance An opaque instance of the underlying type.
873 * @param value Parameter to use to set the underlying variable.
874 * @return True in case of success, false otherwise.
875 */
876 template<typename Type>
setentt::meta_data877 bool set(meta_handle instance, Type &&value) const {
878 return node->set && node->set(std::move(instance), std::forward<Type>(value));
879 }
880
881 /**
882 * @brief Gets the value of a given variable.
883 *
884 * It must be possible to cast the instance to the parent type of the data
885 * member. Otherwise, invoking the getter results in an undefined behavior.
886 *
887 * @param instance An opaque instance of the underlying type.
888 * @return A wrapper containing the value of the underlying variable.
889 */
getentt::meta_data890 [[nodiscard]] meta_any get(meta_handle instance) const {
891 return node->get(std::move(instance));
892 }
893
894 /*! @copydoc meta_ctor::prop */
propentt::meta_data895 [[nodiscard]] meta_range<meta_prop> prop() const ENTT_NOEXCEPT {
896 return node->prop;
897 }
898
899 /**
900 * @brief Returns the property associated with a given key.
901 * @param key The key to use to search for a property.
902 * @return The property associated with the given key, if any.
903 */
propentt::meta_data904 [[nodiscard]] meta_prop prop(meta_any key) const {
905 return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node);
906 }
907
908 /**
909 * @brief Returns true if an object is valid, false otherwise.
910 * @return True if the object is valid, false otherwise.
911 */
operator boolentt::meta_data912 [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
913 return !(node == nullptr);
914 }
915
916 private:
917 const node_type *node;
918 };
919
920
921 /*! @brief Opaque wrapper for member functions. */
922 struct meta_func {
923 /*! @brief Node type. */
924 using node_type = internal::meta_func_node;
925 /*! @brief Unsigned integer type. */
926 using size_type = typename node_type::size_type;
927
928 /*! @copydoc meta_prop::meta_prop */
meta_funcentt::meta_func929 meta_func(const node_type *curr = nullptr) ENTT_NOEXCEPT
930 : node{curr}
931 {}
932
933 /*! @copydoc meta_type::id */
identt::meta_func934 [[nodiscard]] id_type id() const ENTT_NOEXCEPT {
935 return node->id;
936 }
937
938 /*! @copydoc meta_ctor::parent */
939 [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT;
940
941 /**
942 * @brief Returns the number of arguments accepted by a member function.
943 * @return The number of arguments accepted by the member function.
944 */
arityentt::meta_func945 [[nodiscard]] size_type arity() const ENTT_NOEXCEPT {
946 return node->arity;
947 }
948
949 /**
950 * @brief Indicates whether a member function is constant or not.
951 * @return True if the member function is constant, false otherwise.
952 */
is_constentt::meta_func953 [[nodiscard]] bool is_const() const ENTT_NOEXCEPT {
954 return node->is_const;
955 }
956
957 /**
958 * @brief Indicates whether a member function is static or not.
959 * @return True if the member function is static, false otherwise.
960 */
is_staticentt::meta_func961 [[nodiscard]] bool is_static() const ENTT_NOEXCEPT {
962 return node->is_static;
963 }
964
965 /**
966 * @brief Returns the return type of a member function.
967 * @return The return type of the member function.
968 */
969 [[nodiscard]] inline meta_type ret() const ENTT_NOEXCEPT;
970
971 /**
972 * @brief Returns the type of the i-th argument of a member function.
973 * @param index Index of the argument of which to return the type.
974 * @return The type of the i-th argument of a member function.
975 */
976 [[nodiscard]] inline meta_type arg(size_type index) const ENTT_NOEXCEPT;
977
978 /**
979 * @brief Invokes the underlying function, if possible.
980 *
981 * To invoke a member function, the parameters must be such that a cast or
982 * conversion to the required types is possible. Otherwise, an empty and
983 * thus invalid wrapper is returned.<br/>
984 * It must be possible to cast the instance to the parent type of the member
985 * function. Otherwise, invoking the underlying function results in an
986 * undefined behavior.
987 *
988 * @param instance An opaque instance of the underlying type.
989 * @param args Parameters to use to invoke the function.
990 * @param sz Number of parameters to use to invoke the function.
991 * @return A wrapper containing the returned value, if any.
992 */
invokeentt::meta_func993 meta_any invoke(meta_handle instance, meta_any * const args, const size_type sz) const {
994 return sz == arity() ? node->invoke(std::move(instance), args) : meta_any{};
995 }
996
997 /**
998 * @copybrief invoke
999 *
1000 * @sa invoke
1001 *
1002 * @tparam Args Types of arguments to use to invoke the function.
1003 * @param instance An opaque instance of the underlying type.
1004 * @param args Parameters to use to invoke the function.
1005 * @return A wrapper containing the new instance, if any.
1006 */
1007 template<typename... Args>
invokeentt::meta_func1008 meta_any invoke(meta_handle instance, Args &&... args) const {
1009 meta_any arguments[sizeof...(Args) + 1u]{std::forward<Args>(args)...};
1010 return invoke(std::move(instance), arguments, sizeof...(Args));
1011 }
1012
1013 /*! @copydoc meta_ctor::prop */
propentt::meta_func1014 [[nodiscard]] meta_range<meta_prop> prop() const ENTT_NOEXCEPT {
1015 return node->prop;
1016 }
1017
1018 /**
1019 * @brief Returns the property associated with a given key.
1020 * @param key The key to use to search for a property.
1021 * @return The property associated with the given key, if any.
1022 */
propentt::meta_func1023 [[nodiscard]] meta_prop prop(meta_any key) const {
1024 return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node);
1025 }
1026
1027 /**
1028 * @brief Returns true if an object is valid, false otherwise.
1029 * @return True if the object is valid, false otherwise.
1030 */
operator boolentt::meta_func1031 [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
1032 return !(node == nullptr);
1033 }
1034
1035 private:
1036 const node_type *node;
1037 };
1038
1039
1040 /*! @brief Opaque wrapper for types. */
1041 class meta_type {
can_cast_or_convert(const internal::meta_type_node * type,const type_info info)1042 static bool can_cast_or_convert(const internal::meta_type_node *type, const type_info info) ENTT_NOEXCEPT {
1043 if(type->info == info) {
1044 return true;
1045 }
1046
1047 for(const auto *curr = type->conv; curr; curr = curr->next) {
1048 if(curr->type()->info == info) {
1049 return true;
1050 }
1051 }
1052
1053 for(const auto *curr = type->base; curr; curr = curr->next) {
1054 if(auto *target = curr->type(); can_cast_or_convert(target, info)) {
1055 return true;
1056 }
1057 }
1058
1059 return false;
1060 }
1061
1062 template<typename... Args, auto... Index>
ctor(const internal::meta_ctor_node * curr,std::index_sequence<Index...>)1063 [[nodiscard]] static const internal::meta_ctor_node * ctor(const internal::meta_ctor_node *curr, std::index_sequence<Index...>) {
1064 for(; curr; curr = curr->next) {
1065 if(curr->arity == sizeof...(Args) && (can_cast_or_convert(internal::meta_info<Args>::resolve(), curr->arg(Index).info()) && ...)) {
1066 return curr;
1067 }
1068 }
1069
1070 return nullptr;
1071 }
1072
1073 template<auto... Member, typename Node>
unregister_all(Node ** curr)1074 void unregister_all(Node **curr) {
1075 while(*curr) {
1076 (unregister_all(&((*curr)->*Member)), ...);
1077 *curr = std::exchange((*curr)->next, nullptr);
1078 }
1079 }
1080
1081 public:
1082 /*! @brief Node type. */
1083 using node_type = internal::meta_type_node;
1084 /*! @brief Node type. */
1085 using base_node_type = internal::meta_base_node;
1086 /*! @brief Unsigned integer type. */
1087 using size_type = typename node_type::size_type;
1088
1089 /*! @copydoc meta_prop::meta_prop */
meta_type(node_type * curr=nullptr)1090 meta_type(node_type *curr = nullptr) ENTT_NOEXCEPT
1091 : node{curr}
1092 {}
1093
1094 /**
1095 * @brief Constructs an instance from a given base node.
1096 * @param curr The base node with which to construct the instance.
1097 */
meta_type(base_node_type * curr)1098 meta_type(base_node_type *curr) ENTT_NOEXCEPT
1099 : node{curr ? curr->type() : nullptr}
1100 {}
1101
1102 /**
1103 * @brief Returns the type info object of the underlying type.
1104 * @return The type info object of the underlying type.
1105 */
info() const1106 [[nodiscard]] type_info info() const ENTT_NOEXCEPT {
1107 return node->info;
1108 }
1109
1110 /**
1111 * @brief Returns the identifier assigned to a type.
1112 * @return The identifier assigned to the type.
1113 */
id() const1114 [[nodiscard]] id_type id() const ENTT_NOEXCEPT {
1115 return node->id;
1116 }
1117
1118 /**
1119 * @brief Returns the size of the underlying type if known.
1120 * @return The size of the underlying type if known, 0 otherwise.
1121 */
size_of() const1122 [[nodiscard]] size_type size_of() const ENTT_NOEXCEPT {
1123 return node->size_of;
1124 }
1125
1126 /**
1127 * @brief Checks whether a type refers to void or not.
1128 * @return True if the underlying type is void, false otherwise.
1129 */
is_void() const1130 [[nodiscard]] bool is_void() const ENTT_NOEXCEPT {
1131 return node->is_void;
1132 }
1133
1134 /**
1135 * @brief Checks whether a type refers to an integral type or not.
1136 * @return True if the underlying type is an integral type, false otherwise.
1137 */
is_integral() const1138 [[nodiscard]] bool is_integral() const ENTT_NOEXCEPT {
1139 return node->is_integral;
1140 }
1141
1142 /**
1143 * @brief Checks whether a type refers to a floating-point type or not.
1144 * @return True if the underlying type is a floating-point type, false
1145 * otherwise.
1146 */
is_floating_point() const1147 [[nodiscard]] bool is_floating_point() const ENTT_NOEXCEPT {
1148 return node->is_floating_point;
1149 }
1150
1151 /**
1152 * @brief Checks whether a type refers to an array type or not.
1153 * @return True if the underlying type is an array type, false otherwise.
1154 */
is_array() const1155 [[nodiscard]] bool is_array() const ENTT_NOEXCEPT {
1156 return node->is_array;
1157 }
1158
1159 /**
1160 * @brief Checks whether a type refers to an enum or not.
1161 * @return True if the underlying type is an enum, false otherwise.
1162 */
is_enum() const1163 [[nodiscard]] bool is_enum() const ENTT_NOEXCEPT {
1164 return node->is_enum;
1165 }
1166
1167 /**
1168 * @brief Checks whether a type refers to an union or not.
1169 * @return True if the underlying type is an union, false otherwise.
1170 */
is_union() const1171 [[nodiscard]] bool is_union() const ENTT_NOEXCEPT {
1172 return node->is_union;
1173 }
1174
1175 /**
1176 * @brief Checks whether a type refers to a class or not.
1177 * @return True if the underlying type is a class, false otherwise.
1178 */
is_class() const1179 [[nodiscard]] bool is_class() const ENTT_NOEXCEPT {
1180 return node->is_class;
1181 }
1182
1183 /**
1184 * @brief Checks whether a type refers to a pointer or not.
1185 * @return True if the underlying type is a pointer, false otherwise.
1186 */
is_pointer() const1187 [[nodiscard]] bool is_pointer() const ENTT_NOEXCEPT {
1188 return node->is_pointer;
1189 }
1190
1191 /**
1192 * @brief Checks whether a type refers to a function pointer or not.
1193 * @return True if the underlying type is a function pointer, false
1194 * otherwise.
1195 */
is_function_pointer() const1196 [[nodiscard]] bool is_function_pointer() const ENTT_NOEXCEPT {
1197 return node->is_function_pointer;
1198 }
1199
1200 /**
1201 * @brief Checks whether a type refers to a pointer to data member or not.
1202 * @return True if the underlying type is a pointer to data member, false
1203 * otherwise.
1204 */
is_member_object_pointer() const1205 [[nodiscard]] bool is_member_object_pointer() const ENTT_NOEXCEPT {
1206 return node->is_member_object_pointer;
1207 }
1208
1209 /**
1210 * @brief Checks whether a type refers to a pointer to member function or
1211 * not.
1212 * @return True if the underlying type is a pointer to member function,
1213 * false otherwise.
1214 */
is_member_function_pointer() const1215 [[nodiscard]] bool is_member_function_pointer() const ENTT_NOEXCEPT {
1216 return node->is_member_function_pointer;
1217 }
1218
1219 /**
1220 * @brief Checks whether a type is a pointer-like type or not.
1221 * @return True if the underlying type is a pointer-like one, false
1222 * otherwise.
1223 */
is_pointer_like() const1224 [[nodiscard]] bool is_pointer_like() const ENTT_NOEXCEPT {
1225 return node->is_pointer_like;
1226 }
1227
1228 /**
1229 * @brief Checks whether a type refers to a sequence container or not.
1230 * @return True if the type is a sequence container, false otherwise.
1231 */
is_sequence_container() const1232 [[nodiscard]] bool is_sequence_container() const ENTT_NOEXCEPT {
1233 return node->is_sequence_container;
1234 }
1235
1236 /**
1237 * @brief Checks whether a type refers to an associative container or not.
1238 * @return True if the type is an associative container, false otherwise.
1239 */
is_associative_container() const1240 [[nodiscard]] bool is_associative_container() const ENTT_NOEXCEPT {
1241 return node->is_associative_container;
1242 }
1243
1244 /**
1245 * @brief Checks whether a type refers to a recognized class template
1246 * specialization or not.
1247 * @return True if the type is a recognized class template specialization,
1248 * false otherwise.
1249 */
is_template_specialization() const1250 [[nodiscard]] bool is_template_specialization() const ENTT_NOEXCEPT {
1251 return node->template_info.is_template_specialization;
1252 }
1253
1254 /**
1255 * @brief Returns the number of template arguments, if any.
1256 * @return The number of template arguments, if any.
1257 */
template_arity() const1258 [[nodiscard]] size_type template_arity() const ENTT_NOEXCEPT {
1259 return node->template_info.arity;
1260 }
1261
1262 /**
1263 * @brief Returns a tag for the class template of the underlying type.
1264 *
1265 * @sa meta_class_template_tag
1266 *
1267 * @return The tag for the class template of the underlying type.
1268 */
template_type() const1269 [[nodiscard]] inline meta_type template_type() const ENTT_NOEXCEPT {
1270 return is_template_specialization() ? node->template_info.type() : meta_type{};
1271 }
1272
1273 /**
1274 * @brief Returns the type of the i-th template argument of a type.
1275 * @param index Index of the template argument of which to return the type.
1276 * @return The type of the i-th template argument of a type.
1277 */
template_arg(size_type index) const1278 [[nodiscard]] inline meta_type template_arg(size_type index) const ENTT_NOEXCEPT {
1279 return index < template_arity() ? node->template_info.arg(index) : meta_type{};
1280 }
1281
1282 /**
1283 * @brief Provides the number of dimensions of an array type.
1284 * @return The number of dimensions in case of array types, 0 otherwise.
1285 */
rank() const1286 [[nodiscard]] size_type rank() const ENTT_NOEXCEPT {
1287 return node->rank;
1288 }
1289
1290 /**
1291 * @brief The number of elements along the given dimension of an array type.
1292 * @param dim The dimension of which to return the number of elements.
1293 * @return The number of elements along the given dimension in case of array
1294 * types, 0 otherwise.
1295 */
extent(size_type dim={}) const1296 [[nodiscard]] size_type extent(size_type dim = {}) const ENTT_NOEXCEPT {
1297 return node->extent(dim);
1298 }
1299
1300 /**
1301 * @brief Provides the type for which the pointer is defined.
1302 * @return The type for which the pointer is defined or this type if it
1303 * doesn't refer to a pointer type.
1304 */
remove_pointer() const1305 [[nodiscard]] meta_type remove_pointer() const ENTT_NOEXCEPT {
1306 return node->remove_pointer();
1307 }
1308
1309 /**
1310 * @brief Provides the type for which the array is defined.
1311 * @return The type for which the array is defined or this type if it
1312 * doesn't refer to an array type.
1313 */
remove_extent() const1314 [[nodiscard]] meta_type remove_extent() const ENTT_NOEXCEPT {
1315 return node->remove_extent();
1316 }
1317
1318 /**
1319 * @brief Returns a range to use to visit top-level base meta types.
1320 * @return An iterable range to use to visit top-level base meta types.
1321 */
base() const1322 [[nodiscard]] meta_range<meta_type, internal::meta_base_node> base() const ENTT_NOEXCEPT {
1323 return node->base;
1324 }
1325
1326 /**
1327 * @brief Returns the base meta type associated with a given identifier.
1328 * @param id Unique identifier.
1329 * @return The base meta type associated with the given identifier, if any.
1330 */
base(const id_type id) const1331 [[nodiscard]] meta_type base(const id_type id) const {
1332 return internal::meta_visit<&node_type::base>([id](const auto *curr) { return curr->type()->id == id; }, node);
1333 }
1334
1335 /**
1336 * @brief Returns a range to use to visit top-level constructors.
1337 * @return An iterable range to use to visit top-level constructors.
1338 */
ctor() const1339 [[nodiscard]] meta_range<meta_ctor> ctor() const ENTT_NOEXCEPT {
1340 return node->ctor;
1341 }
1342
1343 /**
1344 * @brief Returns a constructor for a given list of types of arguments.
1345 * @tparam Args Constructor arguments.
1346 * @return The requested constructor, if any.
1347 */
1348 template<typename... Args>
ctor() const1349 [[nodiscard]] meta_ctor ctor() const {
1350 return ctor<Args...>(node->ctor, std::make_index_sequence<sizeof...(Args)>{});
1351 }
1352
1353 /**
1354 * @brief Returns a range to use to visit top-level data.
1355 * @return An iterable range to use to visit top-level data.
1356 */
data() const1357 [[nodiscard]] meta_range<meta_data> data() const ENTT_NOEXCEPT {
1358 return node->data;
1359 }
1360
1361 /**
1362 * @brief Returns the data associated with a given identifier.
1363 *
1364 * The data of the base classes will also be visited, if any.
1365 *
1366 * @param id Unique identifier.
1367 * @return The data associated with the given identifier, if any.
1368 */
data(const id_type id) const1369 [[nodiscard]] meta_data data(const id_type id) const {
1370 return internal::meta_visit<&node_type::data>([id](const auto *curr) { return curr->id == id; }, node);
1371 }
1372
1373 /**
1374 * @brief Returns a range to use to visit top-level functions.
1375 * @return An iterable range to use to visit top-level functions.
1376 */
func() const1377 [[nodiscard]] meta_range<meta_func> func() const ENTT_NOEXCEPT {
1378 return node->func;
1379 }
1380
1381 /**
1382 * @brief Returns the function associated with a given identifier.
1383 *
1384 * The functions of the base classes will also be visited, if any.<br/>
1385 * In the case of overloaded functions, the first one with the required
1386 * identifier will be returned.
1387 *
1388 * @param id Unique identifier.
1389 * @return The function associated with the given identifier, if any.
1390 */
func(const id_type id) const1391 [[nodiscard]] meta_func func(const id_type id) const {
1392 return internal::meta_visit<&node_type::func>([id](const auto *curr) { return curr->id == id; }, node);
1393 }
1394
1395 /**
1396 * @brief Creates an instance of the underlying type, if possible.
1397 *
1398 * Parameters must be such that a cast or conversion to the required types
1399 * is possible. Otherwise, an empty and thus invalid wrapper is returned.
1400 *
1401 * @param args Parameters to use to construct the instance.
1402 * @param sz Number of parameters to use to construct the instance.
1403 * @return A wrapper containing the new instance, if any.
1404 */
construct(meta_any * const args,const size_type sz) const1405 [[nodiscard]] meta_any construct(meta_any * const args, const size_type sz) const {
1406 meta_any ret{};
1407 internal::meta_visit<&node_type::ctor>([args, sz, &ret](const auto *curr) { return (curr->arity == sz) && (ret = curr->invoke(args)); }, node);
1408 return ret;
1409 }
1410
1411 /**
1412 * @copybrief construct
1413 *
1414 * @sa construct
1415 *
1416 * @tparam Args Types of arguments to use to construct the instance.
1417 * @param args Parameters to use to construct the instance.
1418 * @return A wrapper containing the new instance, if any.
1419 */
1420 template<typename... Args>
construct(Args &&...args) const1421 [[nodiscard]] meta_any construct(Args &&... args) const {
1422 meta_any arguments[sizeof...(Args) + 1u]{std::forward<Args>(args)...};
1423 return construct(arguments, sizeof...(Args));
1424 }
1425
1426 /**
1427 * @brief Invokes a function given an identifier, if possible.
1428 *
1429 * It must be possible to cast the instance to the parent type of the member
1430 * function. Otherwise, invoking the underlying function results in an
1431 * undefined behavior.
1432 *
1433 * @sa meta_func::invoke
1434 *
1435 * @param id Unique identifier.
1436 * @param instance An opaque instance of the underlying type.
1437 * @param args Parameters to use to invoke the function.
1438 * @param sz Number of parameters to use to invoke the function.
1439 * @return A wrapper containing the returned value, if any.
1440 */
invoke(const id_type id,meta_handle instance,meta_any * const args,const size_type sz) const1441 meta_any invoke(const id_type id, meta_handle instance, meta_any * const args, const size_type sz) const {
1442 const internal::meta_func_node* candidate{};
1443 size_type extent{sz + 1u};
1444 bool ambiguous{};
1445
1446 for(auto *it = internal::meta_visit<&node_type::func>([id, sz](const auto *curr) { return curr->id == id && curr->arity == sz; }, node); it && it->id == id && it->arity == sz; it = it->next) {
1447 size_type direct{};
1448 size_type ext{};
1449
1450 for(size_type next{}; next < sz && next == (direct + ext); ++next) {
1451 const auto type = args[next].type();
1452 const auto req = it->arg(next).info();
1453 type.info() == req ? ++direct : (ext += can_cast_or_convert(type.node, req));
1454 }
1455
1456 if((direct + ext) == sz) {
1457 if(ext < extent) {
1458 candidate = it;
1459 extent = ext;
1460 ambiguous = false;
1461 } else if(ext == extent) {
1462 ambiguous = true;
1463 }
1464 }
1465 }
1466
1467 return (candidate && !ambiguous) ? candidate->invoke(std::move(instance), args) : meta_any{};
1468 }
1469
1470 /**
1471 * @copybrief invoke
1472 *
1473 * @sa invoke
1474 *
1475 * @param id Unique identifier.
1476 * @tparam Args Types of arguments to use to invoke the function.
1477 * @param instance An opaque instance of the underlying type.
1478 * @param args Parameters to use to invoke the function.
1479 * @return A wrapper containing the new instance, if any.
1480 */
1481 template<typename... Args>
invoke(const id_type id,meta_handle instance,Args &&...args) const1482 meta_any invoke(const id_type id, meta_handle instance, Args &&... args) const {
1483 meta_any arguments[sizeof...(Args) + 1u]{std::forward<Args>(args)...};
1484 return invoke(id, std::move(instance), arguments, sizeof...(Args));
1485 }
1486
1487 /**
1488 * @brief Sets the value of a given variable.
1489 *
1490 * It must be possible to cast the instance to the parent type of the data
1491 * member. Otherwise, invoking the setter results in an undefined
1492 * behavior.<br/>
1493 * The type of the value must be such that a cast or conversion to the type
1494 * of the variable is possible. Otherwise, invoking the setter does nothing.
1495 *
1496 * @tparam Type Type of value to assign.
1497 * @param id Unique identifier.
1498 * @param instance An opaque instance of the underlying type.
1499 * @param value Parameter to use to set the underlying variable.
1500 * @return True in case of success, false otherwise.
1501 */
1502 template<typename Type>
set(const id_type id,meta_handle instance,Type && value) const1503 bool set(const id_type id, meta_handle instance, Type &&value) const {
1504 const auto candidate = data(id);
1505 return candidate && candidate.set(std::move(instance), std::forward<Type>(value));
1506 }
1507
1508 /**
1509 * @brief Gets the value of a given variable.
1510 *
1511 * It must be possible to cast the instance to the parent type of the data
1512 * member. Otherwise, invoking the getter results in an undefined behavior.
1513 *
1514 * @param id Unique identifier.
1515 * @param instance An opaque instance of the underlying type.
1516 * @return A wrapper containing the value of the underlying variable.
1517 */
get(const id_type id,meta_handle instance) const1518 [[nodiscard]] meta_any get(const id_type id, meta_handle instance) const {
1519 const auto candidate = data(id);
1520 return candidate ? candidate.get(std::move(instance)) : meta_any{};
1521 }
1522
1523 /**
1524 * @brief Returns a range to use to visit top-level properties.
1525 * @return An iterable range to use to visit top-level properties.
1526 */
prop() const1527 [[nodiscard]] meta_range<meta_prop> prop() const ENTT_NOEXCEPT {
1528 return node->prop;
1529 }
1530
1531 /**
1532 * @brief Returns the property associated with a given key.
1533 *
1534 * Properties of the base classes will also be visited, if any.
1535 *
1536 * @param key The key to use to search for a property.
1537 * @return The property associated with the given key, if any.
1538 */
prop(meta_any key) const1539 [[nodiscard]] meta_prop prop(meta_any key) const {
1540 return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node);
1541 }
1542
1543 /**
1544 * @brief Returns true if an object is valid, false otherwise.
1545 * @return True if the object is valid, false otherwise.
1546 */
operator bool() const1547 [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
1548 return !(node == nullptr);
1549 }
1550
1551 /**
1552 * @brief Checks if two objects refer to the same type.
1553 * @param other The object with which to compare.
1554 * @return True if the objects refer to the same type, false otherwise.
1555 */
operator ==(const meta_type & other) const1556 [[nodiscard]] bool operator==(const meta_type &other) const ENTT_NOEXCEPT {
1557 return (!node && !other.node) || (node && other.node && node->info == other.node->info);
1558 }
1559
1560 /**
1561 * @brief Resets a type and all its parts.
1562 *
1563 * This function resets a type and all its data members, member functions
1564 * and properties, as well as its constructors, destructors and conversion
1565 * functions if any.<br/>
1566 * Base classes aren't reset but the link between the two types is removed.
1567 *
1568 * The type is also removed from the list of searchable types.
1569 */
reset()1570 void reset() ENTT_NOEXCEPT {
1571 for(auto** it = internal::meta_context::global(); *it; it = &(*it)->next) {
1572 if(*it == node) {
1573 *it = (*it)->next;
1574 break;
1575 }
1576 }
1577
1578 unregister_all(&node->prop);
1579 unregister_all(&node->base);
1580 unregister_all(&node->conv);
1581 unregister_all<&internal::meta_ctor_node::prop>(&node->ctor);
1582 unregister_all<&internal::meta_data_node::prop>(&node->data);
1583 unregister_all<&internal::meta_func_node::prop>(&node->func);
1584
1585 node->id = {};
1586 node->ctor = node->def_ctor;
1587 node->dtor = nullptr;
1588 }
1589
1590 private:
1591 node_type *node;
1592 };
1593
1594
1595 /**
1596 * @brief Checks if two objects refer to the same type.
1597 * @param lhs An object, either valid or not.
1598 * @param rhs An object, either valid or not.
1599 * @return False if the objects refer to the same node, true otherwise.
1600 */
operator !=(const meta_type & lhs,const meta_type & rhs)1601 [[nodiscard]] inline bool operator!=(const meta_type &lhs, const meta_type &rhs) ENTT_NOEXCEPT {
1602 return !(lhs == rhs);
1603 }
1604
1605
type() const1606 [[nodiscard]] inline meta_type meta_any::type() const ENTT_NOEXCEPT {
1607 return node;
1608 }
1609
1610
1611 template<typename... Args>
invoke(const id_type id,Args &&...args) const1612 meta_any meta_any::invoke(const id_type id, Args &&... args) const {
1613 return type().invoke(id, *this, std::forward<Args>(args)...);
1614 }
1615
1616
1617 template<typename... Args>
invoke(const id_type id,Args &&...args)1618 meta_any meta_any::invoke(const id_type id, Args &&... args) {
1619 return type().invoke(id, *this, std::forward<Args>(args)...);
1620 }
1621
1622
1623 template<typename Type>
set(const id_type id,Type && value)1624 bool meta_any::set(const id_type id, Type &&value) {
1625 return type().set(id, *this, std::forward<Type>(value));
1626 }
1627
1628
get(const id_type id) const1629 [[nodiscard]] inline meta_any meta_any::get(const id_type id) const {
1630 return type().get(id, *this);
1631 }
1632
1633
get(const id_type id)1634 [[nodiscard]] inline meta_any meta_any::get(const id_type id) {
1635 return type().get(id, *this);
1636 }
1637
1638
parent() const1639 [[nodiscard]] inline meta_type meta_ctor::parent() const ENTT_NOEXCEPT {
1640 return node->parent;
1641 }
1642
1643
arg(size_type index) const1644 [[nodiscard]] inline meta_type meta_ctor::arg(size_type index) const ENTT_NOEXCEPT {
1645 return index < arity() ? node->arg(index) : meta_type{};
1646 }
1647
1648
parent() const1649 [[nodiscard]] inline meta_type meta_data::parent() const ENTT_NOEXCEPT {
1650 return node->parent;
1651 }
1652
1653
type() const1654 [[nodiscard]] inline meta_type meta_data::type() const ENTT_NOEXCEPT {
1655 return node->type();
1656 }
1657
1658
parent() const1659 [[nodiscard]] inline meta_type meta_func::parent() const ENTT_NOEXCEPT {
1660 return node->parent;
1661 }
1662
1663
ret() const1664 [[nodiscard]] inline meta_type meta_func::ret() const ENTT_NOEXCEPT {
1665 return node->ret();
1666 }
1667
1668
arg(size_type index) const1669 [[nodiscard]] inline meta_type meta_func::arg(size_type index) const ENTT_NOEXCEPT {
1670 return index < arity() ? node->arg(index) : meta_type{};
1671 }
1672
1673
1674 /*! @brief Opaque iterator for sequence containers. */
1675 class meta_sequence_container::meta_iterator {
1676 /*! @brief A sequence container can access the underlying iterator. */
1677 friend class meta_sequence_container;
1678
1679 enum class operation { INCR, DEREF };
1680
1681 using vtable_type = void(const operation, const any &, void *);
1682
1683 template<typename It>
basic_vtable(const operation op,const any & from,void * to)1684 static void basic_vtable(const operation op, const any &from, void *to) {
1685 switch(op) {
1686 case operation::INCR:
1687 ++any_cast<It &>(const_cast<any &>(from));
1688 break;
1689 case operation::DEREF:
1690 static_cast<meta_any *>(to)->emplace<typename std::iterator_traits<It>::reference>(*any_cast<const It &>(from));
1691 break;
1692 }
1693 }
1694
1695 public:
1696 /*! @brief Signed integer type. */
1697 using difference_type = std::ptrdiff_t;
1698 /*! @brief Type of elements returned by the iterator. */
1699 using value_type = meta_any;
1700 /*! @brief Pointer type, `void` on purpose. */
1701 using pointer = void;
1702 /*! @brief Reference type, it is **not** an actual reference. */
1703 using reference = value_type;
1704 /*! @brief Iterator category. */
1705 using iterator_category = std::input_iterator_tag;
1706
1707 /*! @brief Default constructor. */
1708 meta_iterator() ENTT_NOEXCEPT = default;
1709
1710 /**
1711 * @brief Constructs a meta iterator from a given iterator.
1712 * @tparam It Type of actual iterator with which to build the meta iterator.
1713 * @param iter The actual iterator with which to build the meta iterator.
1714 */
1715 template<typename It>
meta_iterator(It iter)1716 meta_iterator(It iter)
1717 : vtable{&basic_vtable<It>},
1718 handle{std::move(iter)}
1719 {}
1720
1721 /*! @brief Pre-increment operator. @return This iterator. */
operator ++()1722 meta_iterator & operator++() ENTT_NOEXCEPT {
1723 return vtable(operation::INCR, handle, nullptr), *this;
1724 }
1725
1726 /*! @brief Post-increment operator. @return This iterator. */
operator ++(int)1727 meta_iterator operator++(int) ENTT_NOEXCEPT {
1728 meta_iterator orig = *this;
1729 return ++(*this), orig;
1730 }
1731
1732 /**
1733 * @brief Checks if two iterators refer to the same element.
1734 * @param other The iterator with which to compare.
1735 * @return True if the iterators refer to the same element, false otherwise.
1736 */
operator ==(const meta_iterator & other) const1737 [[nodiscard]] bool operator==(const meta_iterator &other) const ENTT_NOEXCEPT {
1738 return handle == other.handle;
1739 }
1740
1741 /**
1742 * @brief Checks if two iterators refer to the same element.
1743 * @param other The iterator with which to compare.
1744 * @return False if the iterators refer to the same element, true otherwise.
1745 */
operator !=(const meta_iterator & other) const1746 [[nodiscard]] bool operator!=(const meta_iterator &other) const ENTT_NOEXCEPT {
1747 return !(*this == other);
1748 }
1749
1750 /**
1751 * @brief Indirection operator.
1752 * @return The element to which the iterator points.
1753 */
operator *() const1754 [[nodiscard]] reference operator*() const {
1755 meta_any other;
1756 vtable(operation::DEREF, handle, &other);
1757 return other;
1758 }
1759
1760 /**
1761 * @brief Returns false if an iterator is invalid, true otherwise.
1762 * @return False if the iterator is invalid, true otherwise.
1763 */
operator bool() const1764 [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
1765 return static_cast<bool>(handle);
1766 }
1767
1768 private:
1769 vtable_type *vtable{};
1770 any handle{};
1771 };
1772
1773
1774 template<typename Type>
1775 struct meta_sequence_container::meta_sequence_container_proxy {
1776 using traits_type = meta_sequence_container_traits<Type>;
1777
value_typeentt::meta_sequence_container::meta_sequence_container_proxy1778 [[nodiscard]] static meta_type value_type() ENTT_NOEXCEPT {
1779 return internal::meta_info<typename Type::value_type>::resolve();
1780 }
1781
sizeentt::meta_sequence_container::meta_sequence_container_proxy1782 [[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT {
1783 return traits_type::size(any_cast<const Type &>(container));
1784 }
1785
resizeentt::meta_sequence_container::meta_sequence_container_proxy1786 [[nodiscard]] static bool resize(any &container, size_type sz) {
1787 auto * const cont = any_cast<Type>(&container);
1788 return cont && traits_type::resize(*cont, sz);
1789 }
1790
clearentt::meta_sequence_container::meta_sequence_container_proxy1791 [[nodiscard]] static bool clear(any &container) {
1792 auto * const cont = any_cast<Type>(&container);
1793 return cont && traits_type::clear(*cont);
1794 }
1795
beginentt::meta_sequence_container::meta_sequence_container_proxy1796 [[nodiscard]] static iterator begin(any &container) {
1797 if(auto * const cont = any_cast<Type>(&container); cont) {
1798 return iterator{traits_type::begin(*cont)};
1799 }
1800
1801 return iterator{traits_type::cbegin(any_cast<const Type &>(container))};
1802 }
1803
endentt::meta_sequence_container::meta_sequence_container_proxy1804 [[nodiscard]] static iterator end(any &container) {
1805 if(auto * const cont = any_cast<Type>(&container); cont) {
1806 return iterator{traits_type::end(*cont)};
1807 }
1808
1809 return iterator{traits_type::cend(any_cast<const Type &>(container))};
1810 }
1811
insertentt::meta_sequence_container::meta_sequence_container_proxy1812 [[nodiscard]] static std::pair<iterator, bool> insert(any &container, iterator it, meta_any &value) {
1813 if(auto * const cont = any_cast<Type>(&container); cont) {
1814 // this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
1815 if(value.allow_cast<typename Type::const_reference>() || value.allow_cast<typename Type::value_type>()) {
1816 const auto *element = value.try_cast<std::remove_reference_t<typename Type::const_reference>>();
1817 auto ret = traits_type::insert(*cont, any_cast<const typename Type::iterator &>(it.handle), element ? *element : value.cast<typename Type::value_type>());
1818 return { iterator{std::move(ret.first)}, ret.second };
1819 }
1820 }
1821
1822 return {};
1823 }
1824
eraseentt::meta_sequence_container::meta_sequence_container_proxy1825 [[nodiscard]] static std::pair<iterator, bool> erase(any &container, iterator it) {
1826 if(auto * const cont = any_cast<Type>(&container); cont) {
1827 auto ret = traits_type::erase(*cont, any_cast<const typename Type::iterator &>(it.handle));
1828 return { iterator{std::move(ret.first)}, ret.second };
1829 }
1830
1831 return {};
1832 }
1833
getentt::meta_sequence_container::meta_sequence_container_proxy1834 [[nodiscard]] static meta_any get(any &container, size_type pos) {
1835 if(auto * const cont = any_cast<Type>(&container); cont) {
1836 return meta_any{std::in_place_type<typename Type::reference>, traits_type::get(*cont, pos)};
1837 }
1838
1839 return meta_any{std::in_place_type<typename Type::const_reference>, traits_type::cget(any_cast<const Type &>(container), pos)};
1840 }
1841 };
1842
1843
1844 /**
1845 * @brief Returns the meta value type of a container.
1846 * @return The meta value type of the container.
1847 */
value_type() const1848 [[nodiscard]] inline meta_type meta_sequence_container::value_type() const ENTT_NOEXCEPT {
1849 return value_type_fn();
1850 }
1851
1852
1853 /**
1854 * @brief Returns the size of a container.
1855 * @return The size of the container.
1856 */
size() const1857 [[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const ENTT_NOEXCEPT {
1858 return size_fn(storage);
1859 }
1860
1861
1862 /**
1863 * @brief Resizes a container to contain a given number of elements.
1864 * @param sz The new size of the container.
1865 * @return True in case of success, false otherwise.
1866 */
resize(size_type sz)1867 inline bool meta_sequence_container::resize(size_type sz) {
1868 return resize_fn(storage, sz);
1869 }
1870
1871
1872 /**
1873 * @brief Clears the content of a container.
1874 * @return True in case of success, false otherwise.
1875 */
clear()1876 inline bool meta_sequence_container::clear() {
1877 return clear_fn(storage);
1878 }
1879
1880
1881 /**
1882 * @brief Returns an iterator to the first element of a container.
1883 * @return An iterator to the first element of the container.
1884 */
begin()1885 [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() {
1886 return begin_fn(storage);
1887 }
1888
1889
1890 /**
1891 * @brief Returns an iterator that is past the last element of a container.
1892 * @return An iterator that is past the last element of the container.
1893 */
end()1894 [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() {
1895 return end_fn(storage);
1896 }
1897
1898
1899 /**
1900 * @brief Inserts an element at a specified location of a container.
1901 * @param it Iterator before which the element will be inserted.
1902 * @param value Element value to insert.
1903 * @return A pair consisting of an iterator to the inserted element (in case of
1904 * success) and a bool denoting whether the insertion took place.
1905 */
insert(iterator it,meta_any value)1906 inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_container::insert(iterator it, meta_any value) {
1907 return insert_fn(storage, it, value);
1908 }
1909
1910
1911 /**
1912 * @brief Removes a given element from a container.
1913 * @param it Iterator to the element to remove.
1914 * @return A pair consisting of an iterator following the last removed element
1915 * (in case of success) and a bool denoting whether the insertion took place.
1916 */
erase(iterator it)1917 inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_container::erase(iterator it) {
1918 return erase_fn(storage, it);
1919 }
1920
1921
1922 /**
1923 * @brief Returns a reference to the element at a given location of a container
1924 * (no bounds checking is performed).
1925 * @param pos The position of the element to return.
1926 * @return A reference to the requested element properly wrapped.
1927 */
operator [](size_type pos)1928 [[nodiscard]] inline meta_any meta_sequence_container::operator[](size_type pos) {
1929 return get_fn(storage, pos);
1930 }
1931
1932
1933 /**
1934 * @brief Returns false if a proxy is invalid, true otherwise.
1935 * @return False if the proxy is invalid, true otherwise.
1936 */
operator bool() const1937 [[nodiscard]] inline meta_sequence_container::operator bool() const ENTT_NOEXCEPT {
1938 return static_cast<bool>(storage);
1939 }
1940
1941
1942 /*! @brief Opaque iterator for associative containers. */
1943 class meta_associative_container::meta_iterator {
1944 enum operation { INCR, DEREF };
1945
1946 using vtable_type = void(const operation, const any &, void *);
1947
1948 template<bool KeyOnly, typename It>
basic_vtable(const operation op,const any & from,void * to)1949 static void basic_vtable(const operation op, const any &from, void *to) {
1950 switch(op) {
1951 case operation::INCR:
1952 ++any_cast<It &>(const_cast<any &>(from));
1953 break;
1954 case operation::DEREF:
1955 const auto &it = any_cast<const It &>(from);
1956 if constexpr(KeyOnly) {
1957 static_cast<std::pair<meta_any, meta_any> *>(to)->first.emplace<decltype(*it)>(*it);
1958 } else {
1959 static_cast<std::pair<meta_any, meta_any> *>(to)->first.emplace<decltype((it->first))>(it->first);
1960 static_cast<std::pair<meta_any, meta_any> *>(to)->second.emplace<decltype((it->second))>(it->second);
1961 }
1962 break;
1963 }
1964 }
1965
1966 public:
1967 /*! @brief Signed integer type. */
1968 using difference_type = std::ptrdiff_t;
1969 /*! @brief Type of elements returned by the iterator. */
1970 using value_type = std::pair<meta_any, meta_any>;
1971 /*! @brief Pointer type, `void` on purpose. */
1972 using pointer = void;
1973 /*! @brief Reference type, it is **not** an actual reference. */
1974 using reference = value_type;
1975 /*! @brief Iterator category. */
1976 using iterator_category = std::input_iterator_tag;
1977
1978 /*! @brief Default constructor. */
1979 meta_iterator() ENTT_NOEXCEPT = default;
1980
1981 /**
1982 * @brief Constructs an meta iterator from a given iterator.
1983 * @tparam KeyOnly True if the container is also key-only, false otherwise.
1984 * @tparam It Type of actual iterator with which to build the meta iterator.
1985 * @param iter The actual iterator with which to build the meta iterator.
1986 */
1987 template<bool KeyOnly, typename It>
meta_iterator(std::integral_constant<bool,KeyOnly>,It iter)1988 meta_iterator(std::integral_constant<bool, KeyOnly>, It iter)
1989 : vtable{&basic_vtable<KeyOnly, It>},
1990 handle{std::move(iter)}
1991 {}
1992
1993 /*! @brief Pre-increment operator. @return This iterator. */
operator ++()1994 meta_iterator & operator++() ENTT_NOEXCEPT {
1995 return vtable(operation::INCR, handle, nullptr), *this;
1996 }
1997
1998 /*! @brief Post-increment operator. @return This iterator. */
operator ++(int)1999 meta_iterator operator++(int) ENTT_NOEXCEPT {
2000 meta_iterator orig = *this;
2001 return ++(*this), orig;
2002 }
2003
2004 /**
2005 * @brief Checks if two iterators refer to the same element.
2006 * @param other The iterator with which to compare.
2007 * @return True if the iterators refer to the same element, false otherwise.
2008 */
operator ==(const meta_iterator & other) const2009 [[nodiscard]] bool operator==(const meta_iterator &other) const ENTT_NOEXCEPT {
2010 return handle == other.handle;
2011 }
2012
2013 /**
2014 * @brief Checks if two iterators refer to the same element.
2015 * @param other The iterator with which to compare.
2016 * @return False if the iterators refer to the same element, true otherwise.
2017 */
operator !=(const meta_iterator & other) const2018 [[nodiscard]] bool operator!=(const meta_iterator &other) const ENTT_NOEXCEPT {
2019 return !(*this == other);
2020 }
2021
2022 /**
2023 * @brief Indirection operator.
2024 * @return The element to which the iterator points.
2025 */
operator *() const2026 [[nodiscard]] reference operator*() const {
2027 reference other;
2028 vtable(operation::DEREF, handle, &other);
2029 return other;
2030 }
2031
2032 /**
2033 * @brief Returns false if an iterator is invalid, true otherwise.
2034 * @return False if the iterator is invalid, true otherwise.
2035 */
operator bool() const2036 [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
2037 return static_cast<bool>(handle);
2038 }
2039
2040 private:
2041 vtable_type *vtable{};
2042 any handle{};
2043 };
2044
2045
2046 template<typename Type>
2047 struct meta_associative_container::meta_associative_container_proxy {
2048 using traits_type = meta_associative_container_traits<Type>;
2049
key_typeentt::meta_associative_container::meta_associative_container_proxy2050 [[nodiscard]] static meta_type key_type() ENTT_NOEXCEPT {
2051 return internal::meta_info<typename Type::key_type>::resolve();
2052 }
2053
mapped_typeentt::meta_associative_container::meta_associative_container_proxy2054 [[nodiscard]] static meta_type mapped_type() ENTT_NOEXCEPT {
2055 if constexpr(is_key_only_meta_associative_container_v<Type>) {
2056 return meta_type{};
2057 } else {
2058 return internal::meta_info<typename Type::mapped_type>::resolve();
2059 }
2060 }
2061
value_typeentt::meta_associative_container::meta_associative_container_proxy2062 [[nodiscard]] static meta_type value_type() ENTT_NOEXCEPT {
2063 return internal::meta_info<typename Type::value_type>::resolve();
2064 }
2065
sizeentt::meta_associative_container::meta_associative_container_proxy2066 [[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT {
2067 return traits_type::size(any_cast<const Type &>(container));
2068 }
2069
clearentt::meta_associative_container::meta_associative_container_proxy2070 [[nodiscard]] static bool clear(any &container) {
2071 auto * const cont = any_cast<Type>(&container);
2072 return cont && traits_type::clear(*cont);
2073 }
2074
beginentt::meta_associative_container::meta_associative_container_proxy2075 [[nodiscard]] static iterator begin(any &container) {
2076 if(auto * const cont = any_cast<Type>(&container); cont) {
2077 return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::begin(*cont)};
2078 }
2079
2080 return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::cbegin(any_cast<const Type &>(container))};
2081 }
2082
endentt::meta_associative_container::meta_associative_container_proxy2083 [[nodiscard]] static iterator end(any &container) {
2084 if(auto * const cont = any_cast<Type>(&container); cont) {
2085 return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::end(*cont)};
2086 }
2087
2088 return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::cend(any_cast<const Type &>(container))};
2089 }
2090
insertentt::meta_associative_container::meta_associative_container_proxy2091 [[nodiscard]] static bool insert(any &container, meta_any &key, meta_any &value) {
2092 if(auto * const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
2093 if constexpr(is_key_only_meta_associative_container_v<Type>) {
2094 return traits_type::insert(*cont, key.cast<const typename Type::key_type &>());
2095 } else {
2096 return value.allow_cast<const typename Type::mapped_type &>()
2097 && traits_type::insert(*cont, key.cast<const typename Type::key_type &>(), value.cast<const typename Type::mapped_type &>());
2098 }
2099 }
2100
2101 return false;
2102 }
2103
eraseentt::meta_associative_container::meta_associative_container_proxy2104 [[nodiscard]] static bool erase(any &container, meta_any &key) {
2105 if(auto * const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
2106 return traits_type::erase(*cont, key.cast<const typename Type::key_type &>());
2107 }
2108
2109 return false;
2110 }
2111
findentt::meta_associative_container::meta_associative_container_proxy2112 [[nodiscard]] static iterator find(any &container, meta_any &key) {
2113 if(key.allow_cast<const typename Type::key_type &>()) {
2114 if(auto * const cont = any_cast<Type>(&container); cont) {
2115 return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*cont, key.cast<const typename Type::key_type &>())};
2116 }
2117
2118 return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::cfind(any_cast<const Type &>(container), key.cast<const typename Type::key_type &>())};
2119 }
2120
2121 return {};
2122 }
2123 };
2124
2125
2126 /**
2127 * @brief Returns true if a container is also key-only, false otherwise.
2128 * @return True if the associative container is also key-only, false otherwise.
2129 */
key_only() const2130 [[nodiscard]] inline bool meta_associative_container::key_only() const ENTT_NOEXCEPT {
2131 return key_only_container;
2132 }
2133
2134
2135 /**
2136 * @brief Returns the meta key type of a container.
2137 * @return The meta key type of the a container.
2138 */
key_type() const2139 [[nodiscard]] inline meta_type meta_associative_container::key_type() const ENTT_NOEXCEPT {
2140 return key_type_fn();
2141 }
2142
2143
2144 /**
2145 * @brief Returns the meta mapped type of a container.
2146 * @return The meta mapped type of the a container.
2147 */
mapped_type() const2148 [[nodiscard]] inline meta_type meta_associative_container::mapped_type() const ENTT_NOEXCEPT {
2149 return mapped_type_fn();
2150 }
2151
2152
2153 /*! @copydoc meta_sequence_container::value_type */
value_type() const2154 [[nodiscard]] inline meta_type meta_associative_container::value_type() const ENTT_NOEXCEPT {
2155 return value_type_fn();
2156 }
2157
2158
2159 /*! @copydoc meta_sequence_container::size */
size() const2160 [[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const ENTT_NOEXCEPT {
2161 return size_fn(storage);
2162 }
2163
2164
2165 /*! @copydoc meta_sequence_container::clear */
clear()2166 inline bool meta_associative_container::clear() {
2167 return clear_fn(storage);
2168 }
2169
2170
2171 /*! @copydoc meta_sequence_container::begin */
begin()2172 [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() {
2173 return begin_fn(storage);
2174 }
2175
2176
2177 /*! @copydoc meta_sequence_container::end */
end()2178 [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() {
2179 return end_fn(storage);
2180 }
2181
2182
2183 /**
2184 * @brief Inserts an element (a key/value pair) into a container.
2185 * @param key The key of the element to insert.
2186 * @param value The value of the element to insert.
2187 * @return A bool denoting whether the insertion took place.
2188 */
insert(meta_any key,meta_any value={})2189 inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) {
2190 return insert_fn(storage, key, value);
2191 }
2192
2193
2194 /**
2195 * @brief Removes the specified element from a container.
2196 * @param key The key of the element to remove.
2197 * @return A bool denoting whether the removal took place.
2198 */
erase(meta_any key)2199 inline bool meta_associative_container::erase(meta_any key) {
2200 return erase_fn(storage, key);
2201 }
2202
2203
2204 /**
2205 * @brief Returns an iterator to the element with a given key, if any.
2206 * @param key The key of the element to search.
2207 * @return An iterator to the element with the given key, if any.
2208 */
find(meta_any key)2209 [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) {
2210 return find_fn(storage, key);
2211 }
2212
2213
2214 /**
2215 * @brief Returns false if a proxy is invalid, true otherwise.
2216 * @return False if the proxy is invalid, true otherwise.
2217 */
operator bool() const2218 [[nodiscard]] inline meta_associative_container::operator bool() const ENTT_NOEXCEPT {
2219 return static_cast<bool>(storage);
2220 }
2221
2222
2223 }
2224
2225
2226 #endif
2227