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