diff options
Diffstat (limited to 'deps/include/entt/meta')
| -rw-r--r-- | deps/include/entt/meta/adl_pointer.hpp | 35 | ||||
| -rw-r--r-- | deps/include/entt/meta/container.hpp | 388 | ||||
| -rw-r--r-- | deps/include/entt/meta/context.hpp | 51 | ||||
| -rw-r--r-- | deps/include/entt/meta/factory.hpp | 668 | ||||
| -rw-r--r-- | deps/include/entt/meta/fwd.hpp | 26 | ||||
| -rw-r--r-- | deps/include/entt/meta/meta.hpp | 2026 | ||||
| -rw-r--r-- | deps/include/entt/meta/node.hpp | 298 | ||||
| -rw-r--r-- | deps/include/entt/meta/pointer.hpp | 51 | ||||
| -rw-r--r-- | deps/include/entt/meta/policy.hpp | 58 | ||||
| -rw-r--r-- | deps/include/entt/meta/range.hpp | 143 | ||||
| -rw-r--r-- | deps/include/entt/meta/resolve.hpp | 102 | ||||
| -rw-r--r-- | deps/include/entt/meta/template.hpp | 29 | ||||
| -rw-r--r-- | deps/include/entt/meta/type_traits.hpp | 54 | ||||
| -rw-r--r-- | deps/include/entt/meta/utility.hpp | 539 |
14 files changed, 4468 insertions, 0 deletions
diff --git a/deps/include/entt/meta/adl_pointer.hpp b/deps/include/entt/meta/adl_pointer.hpp new file mode 100644 index 0000000..2623d0e --- /dev/null +++ b/deps/include/entt/meta/adl_pointer.hpp @@ -0,0 +1,35 @@ +#ifndef ENTT_META_ADL_POINTER_HPP
+#define ENTT_META_ADL_POINTER_HPP
+
+namespace entt {
+
+/**
+ * @brief ADL based lookup function for dereferencing meta pointer-like types.
+ * @tparam Type Element type.
+ * @param value A pointer-like object.
+ * @return The value returned from the dereferenced pointer.
+ */
+template<typename Type>
+decltype(auto) dereference_meta_pointer_like(const Type &value) {
+ return *value;
+}
+
+/**
+ * @brief Fake ADL based lookup function for meta pointer-like types.
+ * @tparam Type Element type.
+ */
+template<typename Type>
+struct adl_meta_pointer_like {
+ /**
+ * @brief Uses the default ADL based lookup method to resolve the call.
+ * @param value A pointer-like object.
+ * @return The value returned from the dereferenced pointer.
+ */
+ static decltype(auto) dereference(const Type &value) {
+ return dereference_meta_pointer_like(value);
+ }
+};
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/container.hpp b/deps/include/entt/meta/container.hpp new file mode 100644 index 0000000..ee90c7d --- /dev/null +++ b/deps/include/entt/meta/container.hpp @@ -0,0 +1,388 @@ +// IWYU pragma: always_keep
+
+#ifndef ENTT_META_CONTAINER_HPP
+#define ENTT_META_CONTAINER_HPP
+
+#include <array>
+#include <deque>
+#include <iterator>
+#include <list>
+#include <map>
+#include <set>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+#include "../container/dense_map.hpp"
+#include "../container/dense_set.hpp"
+#include "context.hpp"
+#include "meta.hpp"
+#include "type_traits.hpp"
+
+namespace entt {
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename, typename = void>
+struct fixed_size_sequence_container: std::true_type {};
+
+template<typename Type>
+struct fixed_size_sequence_container<Type, std::void_t<decltype(&Type::clear)>>: std::false_type {};
+
+template<typename Type>
+inline constexpr bool fixed_size_sequence_container_v = fixed_size_sequence_container<Type>::value;
+
+template<typename, typename = void>
+struct key_only_associative_container: std::true_type {};
+
+template<typename Type>
+struct key_only_associative_container<Type, std::void_t<typename Type::mapped_type>>: std::false_type {};
+
+template<typename Type>
+inline constexpr bool key_only_associative_container_v = key_only_associative_container<Type>::value;
+
+template<typename, typename = void>
+struct reserve_aware_container: std::false_type {};
+
+template<typename Type>
+struct reserve_aware_container<Type, std::void_t<decltype(&Type::reserve)>>: std::true_type {};
+
+template<typename Type>
+inline constexpr bool reserve_aware_container_v = reserve_aware_container<Type>::value;
+
+} // namespace internal
+/*! @endcond */
+
+/**
+ * @brief General purpose implementation of meta sequence container traits.
+ * @tparam Type Type of underlying sequence container.
+ */
+template<typename Type>
+struct basic_meta_sequence_container_traits {
+ static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
+
+ /*! @brief Unsigned integer type. */
+ using size_type = typename meta_sequence_container::size_type;
+ /*! @brief Meta iterator type. */
+ using iterator = typename meta_sequence_container::iterator;
+
+ /*! @brief True in case of key-only containers, false otherwise. */
+ static constexpr bool fixed_size = internal::fixed_size_sequence_container_v<Type>;
+
+ /**
+ * @brief Returns the number of elements in a container.
+ * @param container Opaque pointer to a container of the given type.
+ * @return Number of elements.
+ */
+ [[nodiscard]] static size_type size(const void *container) {
+ return static_cast<const Type *>(container)->size();
+ }
+
+ /**
+ * @brief Clears a container.
+ * @param container Opaque pointer to a container of the given type.
+ * @return True in case of success, false otherwise.
+ */
+ [[nodiscard]] static bool clear([[maybe_unused]] void *container) {
+ if constexpr(fixed_size) {
+ return false;
+ } else {
+ static_cast<Type *>(container)->clear();
+ return true;
+ }
+ }
+
+ /**
+ * @brief Increases the capacity of a container.
+ * @param container Opaque pointer to a container of the given type.
+ * @param sz Desired capacity.
+ * @return True in case of success, false otherwise.
+ */
+ [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
+ if constexpr(internal::reserve_aware_container_v<Type>) {
+ static_cast<Type *>(container)->reserve(sz);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @brief Resizes a container.
+ * @param container Opaque pointer to a container of the given type.
+ * @param sz The new number of elements.
+ * @return True in case of success, false otherwise.
+ */
+ [[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
+ if constexpr(fixed_size || !std::is_default_constructible_v<typename Type::value_type>) {
+ return false;
+ } else {
+ static_cast<Type *>(container)->resize(sz);
+ return true;
+ }
+ }
+
+ /**
+ * @brief Returns a possibly const iterator to the beginning.
+ * @param area The context to pass to the newly created iterator.
+ * @param container Opaque pointer to a container of the given type.
+ * @param as_const Const opaque pointer fallback.
+ * @return An iterator to the first element of the container.
+ */
+ static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
+ return container ? iterator{area, static_cast<Type *>(container)->begin()}
+ : iterator{area, static_cast<const Type *>(as_const)->begin()};
+ }
+
+ /**
+ * @brief Returns a possibly const iterator to the end.
+ * @param area The context to pass to the newly created iterator.
+ * @param container Opaque pointer to a container of the given type.
+ * @param as_const Const opaque pointer fallback.
+ * @return An iterator that is past the last element of the container.
+ */
+ static iterator end(const meta_ctx &area, void *container, const void *as_const) {
+ return container ? iterator{area, static_cast<Type *>(container)->end()}
+ : iterator{area, static_cast<const Type *>(as_const)->end()};
+ }
+
+ /**
+ * @brief Assigns one element to a container and constructs its object from
+ * a given opaque instance.
+ * @param area The context to pass to the newly created iterator.
+ * @param container Opaque pointer to a container of the given type.
+ * @param value Optional opaque instance of the object to construct (as
+ * value type).
+ * @param cref Optional opaque instance of the object to construct (as
+ * decayed const reference type).
+ * @param it Iterator before which the element will be inserted.
+ * @return A possibly invalid iterator to the inserted element.
+ */
+ [[nodiscard]] static iterator insert([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const void *value, [[maybe_unused]] const void *cref, [[maybe_unused]] const iterator &it) {
+ if constexpr(fixed_size) {
+ return iterator{};
+ } else {
+ auto *const non_const = any_cast<typename Type::iterator>(&it.base());
+ return {area, static_cast<Type *>(container)->insert(
+ non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()),
+ value ? *static_cast<const typename Type::value_type *>(value) : *static_cast<const std::remove_reference_t<typename Type::const_reference> *>(cref))};
+ }
+ }
+
+ /**
+ * @brief Erases an element from a container.
+ * @param area The context to pass to the newly created iterator.
+ * @param container Opaque pointer to a container of the given type.
+ * @param it An opaque iterator to the element to erase.
+ * @return A possibly invalid iterator following the last removed element.
+ */
+ [[nodiscard]] static iterator erase([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) {
+ if constexpr(fixed_size) {
+ return iterator{};
+ } else {
+ auto *const non_const = any_cast<typename Type::iterator>(&it.base());
+ return {area, static_cast<Type *>(container)->erase(non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()))};
+ }
+ }
+};
+
+/**
+ * @brief General purpose implementation of meta associative container traits.
+ * @tparam Type Type of underlying associative container.
+ */
+template<typename Type>
+struct basic_meta_associative_container_traits {
+ static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
+
+ /*! @brief Unsigned integer type. */
+ using size_type = typename meta_associative_container::size_type;
+ /*! @brief Meta iterator type. */
+ using iterator = typename meta_associative_container::iterator;
+
+ /*! @brief True in case of key-only containers, false otherwise. */
+ static constexpr bool key_only = internal::key_only_associative_container_v<Type>;
+
+ /**
+ * @brief Returns the number of elements in a container.
+ * @param container Opaque pointer to a container of the given type.
+ * @return Number of elements.
+ */
+ [[nodiscard]] static size_type size(const void *container) {
+ return static_cast<const Type *>(container)->size();
+ }
+
+ /**
+ * @brief Clears a container.
+ * @param container Opaque pointer to a container of the given type.
+ * @return True in case of success, false otherwise.
+ */
+ [[nodiscard]] static bool clear(void *container) {
+ static_cast<Type *>(container)->clear();
+ return true;
+ }
+
+ /**
+ * @brief Increases the capacity of a container.
+ * @param container Opaque pointer to a container of the given type.
+ * @param sz Desired capacity.
+ * @return True in case of success, false otherwise.
+ */
+ [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
+ if constexpr(internal::reserve_aware_container_v<Type>) {
+ static_cast<Type *>(container)->reserve(sz);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @brief Returns a possibly const iterator to the beginning.
+ * @param area The context to pass to the newly created iterator.
+ * @param container Opaque pointer to a container of the given type.
+ * @param as_const Const opaque pointer fallback.
+ * @return An iterator to the first element of the container.
+ */
+ static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
+ return container ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->begin()}
+ : iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->begin()};
+ }
+
+ /**
+ * @brief Returns a possibly const iterator to the end.
+ * @param area The context to pass to the newly created iterator.
+ * @param container Opaque pointer to a container of the given type.
+ * @param as_const Const opaque pointer fallback.
+ * @return An iterator that is past the last element of the container.
+ */
+ static iterator end(const meta_ctx &area, void *container, const void *as_const) {
+ return container ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->end()}
+ : iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->end()};
+ }
+
+ /**
+ * @brief Inserts an element into a container, if the key does not exist.
+ * @param container Opaque pointer to a container of the given type.
+ * @param key An opaque key value of an element to insert.
+ * @param value Optional opaque value to insert (key-value containers).
+ * @return True if the insertion took place, false otherwise.
+ */
+ [[nodiscard]] static bool insert(void *container, const void *key, [[maybe_unused]] const void *value) {
+ if constexpr(key_only) {
+ return static_cast<Type *>(container)->insert(*static_cast<const typename Type::key_type *>(key)).second;
+ } else {
+ return static_cast<Type *>(container)->emplace(*static_cast<const typename Type::key_type *>(key), *static_cast<const typename Type::mapped_type *>(value)).second;
+ }
+ }
+
+ /**
+ * @brief Removes an element from a container.
+ * @param container Opaque pointer to a container of the given type.
+ * @param key An opaque key value of an element to remove.
+ * @return Number of elements removed (either 0 or 1).
+ */
+ [[nodiscard]] static size_type erase(void *container, const void *key) {
+ return static_cast<Type *>(container)->erase(*static_cast<const typename Type::key_type *>(key));
+ }
+
+ /**
+ * @brief Finds an element with a given key.
+ * @param area The context to pass to the newly created iterator.
+ * @param container Opaque pointer to a container of the given type.
+ * @param as_const Const opaque pointer fallback.
+ * @param key Opaque key value of an element to search for.
+ * @return An iterator to the element with the given key, if any.
+ */
+ static iterator find(const meta_ctx &area, void *container, const void *as_const, const void *key) {
+ return container ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->find(*static_cast<const typename Type::key_type *>(key))}
+ : iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->find(*static_cast<const typename Type::key_type *>(key))};
+ }
+};
+
+/**
+ * @brief Meta sequence container traits for `std::vector`s of any type.
+ * @tparam Args Template arguments for the container.
+ */
+template<typename... Args>
+struct meta_sequence_container_traits<std::vector<Args...>>
+ : basic_meta_sequence_container_traits<std::vector<Args...>> {};
+
+/**
+ * @brief Meta sequence container traits for `std::array`s of any type.
+ * @tparam Type Template arguments for the container.
+ * @tparam N Template arguments for the container.
+ */
+template<typename Type, auto N>
+struct meta_sequence_container_traits<std::array<Type, N>>
+ : basic_meta_sequence_container_traits<std::array<Type, N>> {};
+
+/**
+ * @brief Meta sequence container traits for `std::list`s of any type.
+ * @tparam Args Template arguments for the container.
+ */
+template<typename... Args>
+struct meta_sequence_container_traits<std::list<Args...>>
+ : basic_meta_sequence_container_traits<std::list<Args...>> {};
+
+/**
+ * @brief Meta sequence container traits for `std::deque`s of any type.
+ * @tparam Args Template arguments for the container.
+ */
+template<typename... Args>
+struct meta_sequence_container_traits<std::deque<Args...>>
+ : basic_meta_sequence_container_traits<std::deque<Args...>> {};
+
+/**
+ * @brief Meta associative container traits for `std::map`s of any type.
+ * @tparam Args Template arguments for the container.
+ */
+template<typename... Args>
+struct meta_associative_container_traits<std::map<Args...>>
+ : basic_meta_associative_container_traits<std::map<Args...>> {};
+
+/**
+ * @brief Meta associative container traits for `std::unordered_map`s of any
+ * type.
+ * @tparam Args Template arguments for the container.
+ */
+template<typename... Args>
+struct meta_associative_container_traits<std::unordered_map<Args...>>
+ : basic_meta_associative_container_traits<std::unordered_map<Args...>> {};
+
+/**
+ * @brief Meta associative container traits for `std::set`s of any type.
+ * @tparam Args Template arguments for the container.
+ */
+template<typename... Args>
+struct meta_associative_container_traits<std::set<Args...>>
+ : basic_meta_associative_container_traits<std::set<Args...>> {};
+
+/**
+ * @brief Meta associative container traits for `std::unordered_set`s of any
+ * type.
+ * @tparam Args Template arguments for the container.
+ */
+template<typename... Args>
+struct meta_associative_container_traits<std::unordered_set<Args...>>
+ : basic_meta_associative_container_traits<std::unordered_set<Args...>> {};
+
+/**
+ * @brief Meta associative container traits for `dense_map`s of any type.
+ * @tparam Args Template arguments for the container.
+ */
+template<typename... Args>
+struct meta_associative_container_traits<dense_map<Args...>>
+ : basic_meta_associative_container_traits<dense_map<Args...>> {};
+
+/**
+ * @brief Meta associative container traits for `dense_set`s of any type.
+ * @tparam Args Template arguments for the container.
+ */
+template<typename... Args>
+struct meta_associative_container_traits<dense_set<Args...>>
+ : basic_meta_associative_container_traits<dense_set<Args...>> {};
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/context.hpp b/deps/include/entt/meta/context.hpp new file mode 100644 index 0000000..920a6f1 --- /dev/null +++ b/deps/include/entt/meta/context.hpp @@ -0,0 +1,51 @@ +#ifndef ENTT_META_CTX_HPP
+#define ENTT_META_CTX_HPP
+
+#include "../container/dense_map.hpp"
+#include "../core/fwd.hpp"
+#include "../core/utility.hpp"
+
+namespace entt {
+
+class meta_ctx;
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+struct meta_type_node;
+
+struct meta_context {
+ dense_map<id_type, meta_type_node, identity> value{};
+
+ [[nodiscard]] inline static meta_context &from(meta_ctx &ctx);
+ [[nodiscard]] inline static const meta_context &from(const meta_ctx &ctx);
+};
+
+} // namespace internal
+/*! @endcond */
+
+/*! @brief Disambiguation tag for constructors and the like. */
+class meta_ctx_arg_t final {};
+
+/*! @brief Constant of type meta_context_arg_t used to disambiguate calls. */
+inline constexpr meta_ctx_arg_t meta_ctx_arg{};
+
+/*! @brief Opaque meta context type. */
+class meta_ctx: private internal::meta_context {
+ // attorney idiom like model to access the base class
+ friend struct internal::meta_context;
+};
+
+/*! @cond TURN_OFF_DOXYGEN */
+[[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) {
+ return ctx;
+}
+
+[[nodiscard]] inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) {
+ return ctx;
+}
+/*! @endcond */
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/factory.hpp b/deps/include/entt/meta/factory.hpp new file mode 100644 index 0000000..3f61d69 --- /dev/null +++ b/deps/include/entt/meta/factory.hpp @@ -0,0 +1,668 @@ +#ifndef ENTT_META_FACTORY_HPP
+#define ENTT_META_FACTORY_HPP
+
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include "../config/config.h"
+#include "../core/bit.hpp"
+#include "../core/fwd.hpp"
+#include "../core/type_info.hpp"
+#include "../core/type_traits.hpp"
+#include "../locator/locator.hpp"
+#include "context.hpp"
+#include "meta.hpp"
+#include "node.hpp"
+#include "policy.hpp"
+#include "range.hpp"
+#include "resolve.hpp"
+#include "utility.hpp"
+
+namespace entt {
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+class basic_meta_factory {
+ using invoke_type = std::remove_pointer_t<decltype(meta_func_node::invoke)>;
+
+ auto *find_overload() {
+ auto *curr = &details->func[bucket];
+
+ while(curr->invoke != invoke) {
+ curr = curr->next.get();
+ }
+
+ return curr;
+ }
+
+protected:
+ void type(const id_type id) noexcept {
+ auto &&elem = meta_context::from(*ctx).value[parent];
+ ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier");
+ invoke = nullptr;
+ bucket = parent;
+ elem.id = id;
+ }
+
+ void base(const id_type id, meta_base_node node) {
+ details->base.insert_or_assign(id, node);
+ invoke = nullptr;
+ bucket = parent;
+ }
+
+ void conv(const id_type id, meta_conv_node node) {
+ details->conv.insert_or_assign(id, node);
+ invoke = nullptr;
+ bucket = parent;
+ }
+
+ void ctor(const id_type id, meta_ctor_node node) {
+ details->ctor.insert_or_assign(id, node);
+ invoke = nullptr;
+ bucket = parent;
+ }
+
+ void dtor(meta_dtor_node node) {
+ meta_context::from(*ctx).value[parent].dtor = node;
+ invoke = nullptr;
+ bucket = parent;
+ }
+
+ void data(const id_type id, meta_data_node node) {
+ if(auto it = details->data.find(id); it == details->data.end()) {
+ details->data.insert_or_assign(id, std::move(node));
+ } else if(it->second.set != node.set || it->second.get != node.get) {
+ it->second = std::move(node);
+ }
+
+ invoke = nullptr;
+ bucket = id;
+ }
+
+ void func(const id_type id, meta_func_node node) {
+ if(auto it = details->func.find(id); it == details->func.end()) {
+ auto &&elem = details->func.insert_or_assign(id, std::move(node)).first;
+ invoke = elem->second.invoke;
+ bucket = id;
+ } else {
+ auto *curr = &it->second;
+
+ while(curr->invoke != node.invoke && curr->next) {
+ curr = curr->next.get();
+ }
+
+ if(curr->invoke == node.invoke) {
+ invoke = curr->invoke;
+ } else {
+ invoke = node.invoke;
+ curr->next = std::make_shared<meta_func_node>();
+ *curr->next = std::move(node);
+ }
+
+ bucket = id;
+ }
+ }
+
+ void prop(const id_type key, meta_prop_node value) {
+ if(bucket == parent) {
+ details->prop[key] = std::move(value);
+ } else if(invoke == nullptr) {
+ details->data[bucket].prop[key] = std::move(value);
+ } else {
+ find_overload()->prop[key] = std::move(value);
+ }
+ }
+
+ void traits(const meta_traits value) {
+ if(bucket == parent) {
+ meta_context::from(*ctx).value[bucket].traits |= value;
+ } else if(invoke == nullptr) {
+ details->data[bucket].traits |= value;
+ } else {
+ find_overload()->traits |= value;
+ }
+ }
+
+ void custom(meta_custom_node node) {
+ if(bucket == parent) {
+ meta_context::from(*ctx).value[bucket].custom = std::move(node);
+ } else if(invoke == nullptr) {
+ details->data[bucket].custom = std::move(node);
+ } else {
+ find_overload()->custom = std::move(node);
+ }
+ }
+
+public:
+ basic_meta_factory(const id_type id, meta_ctx &area)
+ : ctx{&area},
+ parent{id},
+ bucket{id} {
+ auto &&elem = meta_context::from(*ctx).value[parent];
+
+ if(!elem.details) {
+ elem.details = std::make_shared<meta_type_descriptor>();
+ }
+
+ details = elem.details.get();
+ }
+
+private:
+ meta_ctx *ctx{};
+ id_type parent{};
+ id_type bucket{};
+ invoke_type *invoke{};
+ meta_type_descriptor *details{};
+};
+
+} // namespace internal
+/*! @endcond */
+
+/**
+ * @brief Meta factory to be used for reflection purposes.
+ * @tparam Type Reflected type for which the factory was created.
+ */
+template<typename Type>
+class meta_factory: private internal::basic_meta_factory {
+ using base_type = internal::basic_meta_factory;
+
+ template<typename Setter, auto Getter, typename Policy, std::size_t... Index>
+ void data(const id_type id, std::index_sequence<Index...>) noexcept {
+ using data_type = std::invoke_result_t<decltype(Getter), Type &>;
+ using args_type = type_list<typename meta_function_helper_t<Type, decltype(value_list_element_v<Index, Setter>)>::args_type...>;
+ static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
+
+ base_type::data(
+ id,
+ internal::meta_data_node{
+ /* this is never static */
+ (std::is_member_object_pointer_v<decltype(value_list_element_v<Index, Setter>)> && ... && std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
+ Setter::size,
+ &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
+ &meta_arg<type_list<type_list_element_t<type_list_element_t<Index, args_type>::size != 1u, type_list_element_t<Index, args_type>>...>>,
+ +[](meta_handle instance, meta_any value) { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
+ &meta_getter<Type, Getter, Policy>});
+ }
+
+public:
+ /*! @brief Default constructor. */
+ meta_factory() noexcept
+ : internal::basic_meta_factory{type_id<Type>(), locator<meta_ctx>::value_or()} {}
+
+ /**
+ * @brief Context aware constructor.
+ * @param area The context into which to construct meta types.
+ */
+ meta_factory(meta_ctx &area) noexcept
+ : internal::basic_meta_factory{type_id<Type>().hash(), area} {}
+
+ /**
+ * @brief Assigns a custom unique identifier to a meta type.
+ * @param id A custom unique identifier.
+ * @return A meta factory for the given type.
+ */
+ meta_factory type(const id_type id) noexcept {
+ base_type::type(id);
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta base to a meta type.
+ *
+ * A reflected base class must be a real base class of the reflected type.
+ *
+ * @tparam Base Type of the base class to assign to the meta type.
+ * @return A meta factory for the parent type.
+ */
+ template<typename Base>
+ meta_factory base() noexcept {
+ static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>, "Invalid base type");
+ auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
+ base_type::base(type_id<Base>().hash(), internal::meta_base_node{&internal::resolve<Base>, op});
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta conversion function to a meta type.
+ *
+ * Conversion functions can be either free functions or member
+ * functions.<br/>
+ * In case of free functions, they must accept a const reference to an
+ * instance of the parent type as an argument. In case of member functions,
+ * they should have no arguments at all.
+ *
+ * @tparam Candidate The actual function to use for the conversion.
+ * @return A meta factory for the parent type.
+ */
+ template<auto Candidate>
+ auto conv() noexcept {
+ using conv_type = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
+ auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, std::invoke(Candidate, *static_cast<const Type *>(instance))); };
+ base_type::conv(type_id<conv_type>().hash(), internal::meta_conv_node{op});
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta conversion function to a meta type.
+ *
+ * The given type must be such that an instance of the reflected type can be
+ * converted to it.
+ *
+ * @tparam To Type of the conversion function to assign to the meta type.
+ * @return A meta factory for the parent type.
+ */
+ template<typename To>
+ meta_factory conv() noexcept {
+ using conv_type = std::remove_cv_t<std::remove_reference_t<To>>;
+ auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast<To>(*static_cast<const Type *>(instance))); };
+ base_type::conv(type_id<conv_type>().hash(), internal::meta_conv_node{op});
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta constructor to a meta type.
+ *
+ * Both member functions and free function can be assigned to meta types in
+ * the role of constructors. All that is required is that they return an
+ * instance of the underlying type.<br/>
+ * From a client's point of view, nothing changes if a constructor of a meta
+ * type is a built-in one or not.
+ *
+ * @tparam Candidate The actual function to use as a constructor.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @return A meta factory for the parent type.
+ */
+ template<auto Candidate, typename Policy = as_is_t>
+ meta_factory ctor() noexcept {
+ using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
+ static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
+ static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>, Type>, "The function doesn't return an object of the required type");
+ base_type::ctor(type_id<typename descriptor::args_type>().hash(), internal::meta_ctor_node{descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Candidate, Policy>});
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta constructor to a meta type.
+ *
+ * A meta constructor is uniquely identified by the types of its arguments
+ * and is such that there exists an actual constructor of the underlying
+ * type that can be invoked with parameters whose types are those given.
+ *
+ * @tparam Args Types of arguments to use to construct an instance.
+ * @return A meta factory for the parent type.
+ */
+ template<typename... Args>
+ meta_factory ctor() noexcept {
+ // default constructor is already implicitly generated, no need for redundancy
+ if constexpr(sizeof...(Args) != 0u) {
+ using descriptor = meta_function_helper_t<Type, Type (*)(Args...)>;
+ base_type::ctor(type_id<typename descriptor::args_type>().hash(), internal::meta_ctor_node{descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Args...>});
+ }
+
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta destructor to a meta type.
+ *
+ * Both free functions and member functions can be assigned to meta types in
+ * the role of destructors.<br/>
+ * The signature of a free function should be identical to the following:
+ *
+ * @code{.cpp}
+ * void(Type &);
+ * @endcode
+ *
+ * Member functions should not take arguments instead.<br/>
+ * The purpose is to give users the ability to free up resources that
+ * require special treatment before an object is actually destroyed.
+ *
+ * @tparam Func The actual function to use as a destructor.
+ * @return A meta factory for the parent type.
+ */
+ template<auto Func>
+ meta_factory dtor() noexcept {
+ static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
+ auto *const op = +[](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
+ base_type::dtor(internal::meta_dtor_node{op});
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta data to a meta type.
+ *
+ * Both data members and static and global variables, as well as constants
+ * of any kind, can be assigned to a meta type.<br/>
+ * From a client's point of view, all the variables associated with the
+ * reflected object will appear as if they were part of the type itself.
+ *
+ * @tparam Data The actual variable to attach to the meta type.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param id Unique identifier.
+ * @return A meta factory for the parent type.
+ */
+ template<auto Data, typename Policy = as_is_t>
+ meta_factory data(const id_type id) noexcept {
+ if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
+ using data_type = std::invoke_result_t<decltype(Data), Type &>;
+ static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
+
+ base_type::data(
+ id,
+ internal::meta_data_node{
+ /* this is never static */
+ std::is_const_v<std::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
+ 1u,
+ &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
+ &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
+ &meta_setter<Type, Data>,
+ &meta_getter<Type, Data, Policy>});
+ } else {
+ using data_type = std::remove_pointer_t<decltype(Data)>;
+
+ if constexpr(std::is_pointer_v<decltype(Data)>) {
+ static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
+ } else {
+ static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
+ }
+
+ base_type::data(
+ id,
+ internal::meta_data_node{
+ ((std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<data_type>>> || std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
+ 1u,
+ &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
+ &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
+ &meta_setter<Type, Data>,
+ &meta_getter<Type, Data, Policy>});
+ }
+
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta data to a meta type by means of its setter and
+ * getter.
+ *
+ * Setters and getters can be either free functions, member functions or a
+ * mix of them.<br/>
+ * In case of free functions, setters and getters must accept a reference to
+ * an instance of the parent type as their first argument. A setter has then
+ * an extra argument of a type convertible to that of the parameter to
+ * set.<br/>
+ * In case of member functions, getters have no arguments at all, while
+ * setters has an argument of a type convertible to that of the parameter to
+ * set.
+ *
+ * @tparam Setter The actual function to use as a setter.
+ * @tparam Getter The actual function to use as a getter.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param id Unique identifier.
+ * @return A meta factory for the parent type.
+ */
+ template<auto Setter, auto Getter, typename Policy = as_is_t>
+ meta_factory data(const id_type id) noexcept {
+ using data_type = std::invoke_result_t<decltype(Getter), Type &>;
+ static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
+
+ if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
+ base_type::data(
+ id,
+ internal::meta_data_node{
+ /* this is never static */
+ internal::meta_traits::is_const,
+ 0u,
+ &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
+ &meta_arg<type_list<>>,
+ &meta_setter<Type, Setter>,
+ &meta_getter<Type, Getter, Policy>});
+ } else {
+ using args_type = typename meta_function_helper_t<Type, decltype(Setter)>::args_type;
+
+ base_type::data(
+ id,
+ internal::meta_data_node{
+ /* this is never static nor const */
+ internal::meta_traits::is_none,
+ 1u,
+ &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
+ &meta_arg<type_list<type_list_element_t<args_type::size != 1u, args_type>>>,
+ &meta_setter<Type, Setter>,
+ &meta_getter<Type, Getter, Policy>});
+ }
+
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta data to a meta type by means of its setters and
+ * getter.
+ *
+ * Multi-setter support for meta data members. All setters are tried in the
+ * order of definition before returning to the caller.<br/>
+ * Setters can be either free functions, member functions or a mix of them
+ * and are provided via a `value_list` type.
+ *
+ * @sa data
+ *
+ * @tparam Setter The actual functions to use as setters.
+ * @tparam Getter The actual getter function.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param id Unique identifier.
+ * @return A meta factory for the parent type.
+ */
+ template<typename Setter, auto Getter, typename Policy = as_is_t>
+ meta_factory data(const id_type id) noexcept {
+ data<Setter, Getter, Policy>(id, std::make_index_sequence<Setter::size>{});
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a meta function to a meta type.
+ *
+ * Both member functions and free functions can be assigned to a meta
+ * type.<br/>
+ * From a client's point of view, all the functions associated with the
+ * reflected object will appear as if they were part of the type itself.
+ *
+ * @tparam Candidate The actual function to attach to the meta type.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param id Unique identifier.
+ * @return A meta factory for the parent type.
+ */
+ template<auto Candidate, typename Policy = as_is_t>
+ meta_factory func(const id_type id) noexcept {
+ using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
+ static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
+
+ base_type::func(
+ id,
+ internal::meta_func_node{
+ (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
+ descriptor::args_type::size,
+ &internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>,
+ &meta_arg<typename descriptor::args_type>,
+ &meta_invoke<Type, Candidate, Policy>});
+
+ return *this;
+ }
+
+ /**
+ * @brief Assigns a property to the last created meta object.
+ *
+ * Both the key and the value (if any) must be at least copy constructible.
+ *
+ * @tparam Value Optional type of the property value.
+ * @param id Property key.
+ * @param value Optional property value.
+ * @return A meta factory for the parent type.
+ */
+ template<typename... Value>
+ meta_factory prop(id_type id, [[maybe_unused]] Value &&...value) {
+ if constexpr(sizeof...(Value) == 0u) {
+ base_type::prop(id, internal::meta_prop_node{&internal::resolve<void>});
+ } else {
+ base_type::prop(id, internal::meta_prop_node{&internal::resolve<std::decay_t<Value>>..., std::make_shared<std::decay_t<Value>>(std::forward<Value>(value))...});
+ }
+
+ return *this;
+ }
+
+ /**
+ * @brief Sets traits on the last created meta object.
+ *
+ * The assigned value must be an enum and intended as a bitmask.
+ *
+ * @tparam Value Type of the traits value.
+ * @param value Traits value.
+ * @return A meta factory for the parent type.
+ */
+ template<typename Value>
+ meta_factory traits(const Value value) {
+ static_assert(std::is_enum_v<Value>, "Invalid enum type");
+ base_type::traits(internal::user_to_meta_traits(value));
+ return *this;
+ }
+
+ /**
+ * @brief Sets user defined data that will never be used by the library.
+ * @tparam Value Type of user defined data to store.
+ * @tparam Args Types of arguments to use to construct the user data.
+ * @param args Parameters to use to initialize the user data.
+ * @return A meta factory for the parent type.
+ */
+ template<typename Value, typename... Args>
+ meta_factory custom(Args &&...args) {
+ base_type::custom(internal::meta_custom_node{type_id<Value>().hash(), std::make_shared<Value>(std::forward<Args>(args)...)});
+ return *this;
+ }
+};
+
+/**
+ * @brief Utility function to use for reflection.
+ *
+ * This is the point from which everything starts.<br/>
+ * By invoking this function with a type that is not yet reflected, a meta type
+ * is created to which it will be possible to attach meta objects through a
+ * dedicated factory.
+ *
+ * @tparam Type Type to reflect.
+ * @param ctx The context into which to construct meta types.
+ * @return A meta factory for the given type.
+ */
+template<typename Type>
+[[nodiscard]] auto meta(meta_ctx &ctx) noexcept {
+ auto &&context = internal::meta_context::from(ctx);
+ // make sure the type exists in the context before returning a factory
+ context.value.try_emplace(type_id<Type>().hash(), internal::resolve<Type>(context));
+ return meta_factory<Type>{ctx};
+}
+
+/**
+ * @brief Utility function to use for reflection.
+ *
+ * This is the point from which everything starts.<br/>
+ * By invoking this function with a type that is not yet reflected, a meta type
+ * is created to which it will be possible to attach meta objects through a
+ * dedicated factory.
+ *
+ * @tparam Type Type to reflect.
+ * @return A meta factory for the given type.
+ */
+template<typename Type>
+[[nodiscard]] auto meta() noexcept {
+ return meta<Type>(locator<meta_ctx>::value_or());
+}
+
+/**
+ * @brief Resets a type and all its parts.
+ *
+ * Resets a type and all its data members, member functions and properties, as
+ * well as its constructors, destructors and conversion functions if any.<br/>
+ * Base classes aren't reset but the link between the two types is removed.
+ *
+ * The type is also removed from the set of searchable types.
+ *
+ * @param id Unique identifier.
+ * @param ctx The context from which to reset meta types.
+ */
+inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept {
+ auto &&context = internal::meta_context::from(ctx);
+
+ for(auto it = context.value.begin(); it != context.value.end();) {
+ if(it->second.id == id) {
+ it = context.value.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+/**
+ * @brief Resets a type and all its parts.
+ *
+ * Resets a type and all its data members, member functions and properties, as
+ * well as its constructors, destructors and conversion functions if any.<br/>
+ * Base classes aren't reset but the link between the two types is removed.
+ *
+ * The type is also removed from the set of searchable types.
+ *
+ * @param id Unique identifier.
+ */
+inline void meta_reset(const id_type id) noexcept {
+ meta_reset(locator<meta_ctx>::value_or(), id);
+}
+
+/**
+ * @brief Resets a type and all its parts.
+ *
+ * @sa meta_reset
+ *
+ * @tparam Type Type to reset.
+ * @param ctx The context from which to reset meta types.
+ */
+template<typename Type>
+void meta_reset(meta_ctx &ctx) noexcept {
+ internal::meta_context::from(ctx).value.erase(type_id<Type>().hash());
+}
+
+/**
+ * @brief Resets a type and all its parts.
+ *
+ * @sa meta_reset
+ *
+ * @tparam Type Type to reset.
+ */
+template<typename Type>
+void meta_reset() noexcept {
+ meta_reset<Type>(locator<meta_ctx>::value_or());
+}
+
+/**
+ * @brief Resets all meta types.
+ *
+ * @sa meta_reset
+ *
+ * @param ctx The context from which to reset meta types.
+ */
+inline void meta_reset(meta_ctx &ctx) noexcept {
+ internal::meta_context::from(ctx).value.clear();
+}
+
+/**
+ * @brief Resets all meta types.
+ *
+ * @sa meta_reset
+ */
+inline void meta_reset() noexcept {
+ meta_reset(locator<meta_ctx>::value_or());
+}
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/fwd.hpp b/deps/include/entt/meta/fwd.hpp new file mode 100644 index 0000000..83be362 --- /dev/null +++ b/deps/include/entt/meta/fwd.hpp @@ -0,0 +1,26 @@ +#ifndef ENTT_META_FWD_HPP
+#define ENTT_META_FWD_HPP
+
+namespace entt {
+
+class meta_sequence_container;
+
+class meta_associative_container;
+
+class meta_any;
+
+struct meta_handle;
+
+struct meta_prop;
+
+struct meta_custom;
+
+struct meta_data;
+
+struct meta_func;
+
+class meta_type;
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/meta.hpp b/deps/include/entt/meta/meta.hpp new file mode 100644 index 0000000..64419c1 --- /dev/null +++ b/deps/include/entt/meta/meta.hpp @@ -0,0 +1,2026 @@ +#ifndef ENTT_META_META_HPP
+#define ENTT_META_META_HPP
+
+#include <array>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+#include "../config/config.h"
+#include "../core/any.hpp"
+#include "../core/fwd.hpp"
+#include "../core/iterator.hpp"
+#include "../core/type_info.hpp"
+#include "../core/type_traits.hpp"
+#include "../core/utility.hpp"
+#include "../locator/locator.hpp"
+#include "adl_pointer.hpp"
+#include "context.hpp"
+#include "fwd.hpp"
+#include "node.hpp"
+#include "range.hpp"
+#include "type_traits.hpp"
+
+namespace entt {
+
+class meta_any;
+class meta_type;
+
+/*! @brief Proxy object for sequence containers. */
+class meta_sequence_container {
+ class meta_iterator;
+
+public:
+ /*! @brief Unsigned integer type. */
+ using size_type = std::size_t;
+ /*! @brief Meta iterator type. */
+ using iterator = meta_iterator;
+
+ /*! @brief Default constructor. */
+ meta_sequence_container() = default;
+
+ /**
+ * @brief Context aware constructor.
+ * @param area The context from which to search for meta types.
+ */
+ meta_sequence_container(const meta_ctx &area) noexcept
+ : ctx{&area} {}
+
+ /**
+ * @brief Rebinds a proxy object to a sequence container type.
+ * @tparam Type Type of container to wrap.
+ * @param instance The container to wrap.
+ */
+ template<typename Type>
+ void rebind(Type &instance) noexcept {
+ value_type_node = &internal::resolve<typename Type::value_type>;
+ const_reference_node = &internal::resolve<std::remove_const_t<std::remove_reference_t<typename Type::const_reference>>>;
+ size_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::size;
+ clear_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::clear;
+ reserve_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::reserve;
+ resize_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::resize;
+ begin_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::begin;
+ end_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::end;
+ insert_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::insert;
+ erase_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::erase;
+ const_only = std::is_const_v<Type>;
+ data = &instance;
+ }
+
+ [[nodiscard]] inline meta_type value_type() const noexcept;
+ [[nodiscard]] inline size_type size() const noexcept;
+ inline bool resize(const size_type);
+ inline bool clear();
+ inline bool reserve(const size_type);
+ [[nodiscard]] inline iterator begin();
+ [[nodiscard]] inline iterator end();
+ inline iterator insert(const iterator &, meta_any);
+ inline iterator erase(const iterator &);
+ [[nodiscard]] inline meta_any operator[](const size_type);
+ [[nodiscard]] inline explicit operator bool() const noexcept;
+
+private:
+ const meta_ctx *ctx{&locator<meta_ctx>::value_or()};
+ internal::meta_type_node (*value_type_node)(const internal::meta_context &){};
+ internal::meta_type_node (*const_reference_node)(const internal::meta_context &){};
+ size_type (*size_fn)(const void *){};
+ bool (*clear_fn)(void *){};
+ bool (*reserve_fn)(void *, const size_type){};
+ bool (*resize_fn)(void *, const size_type){};
+ iterator (*begin_fn)(const meta_ctx &, void *, const void *){};
+ iterator (*end_fn)(const meta_ctx &, void *, const void *){};
+ iterator (*insert_fn)(const meta_ctx &, void *, const void *, const void *, const iterator &){};
+ iterator (*erase_fn)(const meta_ctx &, void *, const iterator &){};
+ const void *data{};
+ bool const_only{};
+};
+
+/*! @brief Proxy object for associative containers. */
+class meta_associative_container {
+ class meta_iterator;
+
+public:
+ /*! @brief Unsigned integer type. */
+ using size_type = std::size_t;
+ /*! @brief Meta iterator type. */
+ using iterator = meta_iterator;
+
+ /*! @brief Default constructor. */
+ meta_associative_container() = default;
+
+ /**
+ * @brief Context aware constructor.
+ * @param area The context from which to search for meta types.
+ */
+ meta_associative_container(const meta_ctx &area) noexcept
+ : ctx{&area} {}
+
+ /**
+ * @brief Rebinds a proxy object to an associative container type.
+ * @tparam Type Type of container to wrap.
+ * @param instance The container to wrap.
+ */
+ template<typename Type>
+ void rebind(Type &instance) noexcept {
+ key_type_node = &internal::resolve<typename Type::key_type>;
+ value_type_node = &internal::resolve<typename Type::value_type>;
+
+ if constexpr(!meta_associative_container_traits<std::remove_const_t<Type>>::key_only) {
+ mapped_type_node = &internal::resolve<typename Type::mapped_type>;
+ }
+
+ size_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::size;
+ clear_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::clear;
+ reserve_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::reserve;
+ begin_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::begin;
+ end_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::end;
+ insert_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::insert;
+ erase_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::erase;
+ find_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::find;
+ const_only = std::is_const_v<Type>;
+ data = &instance;
+ }
+
+ [[nodiscard]] inline meta_type key_type() const noexcept;
+ [[nodiscard]] inline meta_type mapped_type() const noexcept;
+ [[nodiscard]] inline meta_type value_type() const noexcept;
+ [[nodiscard]] inline size_type size() const noexcept;
+ inline bool clear();
+ inline bool reserve(const size_type);
+ [[nodiscard]] inline iterator begin();
+ [[nodiscard]] inline iterator end();
+ inline bool insert(meta_any, meta_any);
+ inline size_type erase(meta_any);
+ [[nodiscard]] inline iterator find(meta_any);
+ [[nodiscard]] inline explicit operator bool() const noexcept;
+
+private:
+ const meta_ctx *ctx{&locator<meta_ctx>::value_or()};
+ internal::meta_type_node (*key_type_node)(const internal::meta_context &){};
+ internal::meta_type_node (*mapped_type_node)(const internal::meta_context &){};
+ internal::meta_type_node (*value_type_node)(const internal::meta_context &){};
+ size_type (*size_fn)(const void *){};
+ bool (*clear_fn)(void *){};
+ bool (*reserve_fn)(void *, const size_type){};
+ iterator (*begin_fn)(const meta_ctx &, void *, const void *){};
+ iterator (*end_fn)(const meta_ctx &, void *, const void *){};
+ bool (*insert_fn)(void *, const void *, const void *){};
+ size_type (*erase_fn)(void *, const void *){};
+ iterator (*find_fn)(const meta_ctx &, void *, const void *, const void *){};
+ const void *data{};
+ bool const_only{};
+};
+
+/*! @brief Possible modes of a meta any object. */
+using meta_any_policy = any_policy;
+
+/*! @brief Opaque wrapper for values of any type. */
+class meta_any {
+ using vtable_type = void(const internal::meta_traits op, const bool, const void *, void *);
+
+ template<typename Type>
+ static std::enable_if_t<std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>> basic_vtable([[maybe_unused]] const internal::meta_traits req, [[maybe_unused]] const bool const_only, [[maybe_unused]] const void *value, [[maybe_unused]] void *other) {
+ if constexpr(is_meta_pointer_like_v<Type>) {
+ if(req == internal::meta_traits::is_meta_pointer_like) {
+ if constexpr(std::is_function_v<typename std::pointer_traits<Type>::element_type>) {
+ static_cast<meta_any *>(other)->emplace<Type>(*static_cast<const Type *>(value));
+ } else if constexpr(!std::is_void_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>>) {
+ using in_place_type = decltype(adl_meta_pointer_like<Type>::dereference(*static_cast<const Type *>(value)));
+
+ if constexpr(std::is_constructible_v<bool, Type>) {
+ if(const auto &pointer_like = *static_cast<const Type *>(value); pointer_like) {
+ static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(pointer_like));
+ }
+ } else {
+ static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(*static_cast<const Type *>(value)));
+ }
+ }
+ }
+ }
+
+ if constexpr(is_complete_v<meta_sequence_container_traits<Type>>) {
+ if(req == internal::meta_traits::is_meta_sequence_container) {
+ const_only ? static_cast<meta_sequence_container *>(other)->rebind(*static_cast<const Type *>(value)) : static_cast<meta_sequence_container *>(other)->rebind(*static_cast<Type *>(const_cast<void *>(value)));
+ }
+ }
+
+ if constexpr(is_complete_v<meta_associative_container_traits<Type>>) {
+ if(req == internal::meta_traits::is_meta_associative_container) {
+ const_only ? static_cast<meta_associative_container *>(other)->rebind(*static_cast<const Type *>(value)) : static_cast<meta_associative_container *>(other)->rebind(*static_cast<Type *>(const_cast<void *>(value)));
+ }
+ }
+ }
+
+ void release() {
+ if(node.dtor.dtor && (storage.policy() == any_policy::owner)) {
+ node.dtor.dtor(storage.data());
+ }
+ }
+
+ meta_any(const meta_any &other, any ref) noexcept
+ : storage{std::move(ref)},
+ ctx{other.ctx},
+ node{storage ? other.node : internal::meta_type_node{}},
+ vtable{storage ? other.vtable : &basic_vtable<void>} {}
+
+public:
+ /*! Default constructor. */
+ meta_any() = default;
+
+ /**
+ * @brief Context aware constructor.
+ * @param area The context from which to search for meta types.
+ */
+ meta_any(meta_ctx_arg_t, const meta_ctx &area)
+ : ctx{&area} {}
+
+ /**
+ * @brief Constructs a wrapper by directly initializing the new object.
+ * @tparam Type Type of object to use to initialize the wrapper.
+ * @tparam Args Types of arguments to use to construct the new instance.
+ * @param args Parameters to use to construct the instance.
+ */
+ template<typename Type, typename... Args>
+ explicit meta_any(std::in_place_type_t<Type>, Args &&...args)
+ : meta_any{locator<meta_ctx>::value_or(), std::in_place_type<Type>, std::forward<Args>(args)...} {}
+
+ /**
+ * @brief Constructs a wrapper by directly initializing the new object.
+ * @tparam Type Type of object to use to initialize the wrapper.
+ * @tparam Args Types of arguments to use to construct the new instance.
+ * @param area The context from which to search for meta types.
+ * @param args Parameters to use to construct the instance.
+ */
+ template<typename Type, typename... Args>
+ explicit meta_any(const meta_ctx &area, std::in_place_type_t<Type>, Args &&...args)
+ : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
+ ctx{&area},
+ node{internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx))},
+ vtable{&basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>} {}
+
+ /**
+ * @brief Constructs a wrapper from a given value.
+ * @tparam Type Type of object to use to initialize the wrapper.
+ * @param value An instance of an object to use to initialize the wrapper.
+ */
+ template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
+ meta_any(Type &&value)
+ : meta_any{locator<meta_ctx>::value_or(), std::forward<Type>(value)} {}
+
+ /**
+ * @brief Constructs a wrapper from a given value.
+ * @tparam Type Type of object to use to initialize the wrapper.
+ * @param area The context from which to search for meta types.
+ * @param value An instance of an object to use to initialize the wrapper.
+ */
+ template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
+ meta_any(const meta_ctx &area, Type &&value)
+ : meta_any{area, std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
+
+ /**
+ * @brief Context aware copy constructor.
+ * @param area The context from which to search for meta types.
+ * @param other The instance to copy from.
+ */
+ meta_any(const meta_ctx &area, const meta_any &other)
+ : storage{other.storage},
+ ctx{&area},
+ node{other.node.resolve ? other.node.resolve(internal::meta_context::from(*ctx)) : other.node},
+ vtable{other.vtable} {}
+
+ /**
+ * @brief Context aware move constructor.
+ * @param area The context from which to search for meta types.
+ * @param other The instance to move from.
+ */
+ meta_any(const meta_ctx &area, meta_any &&other)
+ : storage{std::move(other.storage)},
+ ctx{&area},
+ node{other.node.resolve ? std::exchange(other.node, internal::meta_type_node{}).resolve(internal::meta_context::from(*ctx)) : std::exchange(other.node, internal::meta_type_node{})},
+ vtable{std::exchange(other.vtable, &basic_vtable<void>)} {}
+
+ /**
+ * @brief Copy constructor.
+ * @param other The instance to copy from.
+ */
+ meta_any(const meta_any &other) = default;
+
+ /**
+ * @brief Move constructor.
+ * @param other The instance to move from.
+ */
+ meta_any(meta_any &&other) noexcept
+ : storage{std::move(other.storage)},
+ ctx{other.ctx},
+ node{std::exchange(other.node, internal::meta_type_node{})},
+ vtable{std::exchange(other.vtable, &basic_vtable<void>)} {}
+
+ /*! @brief Frees the internal storage, whatever it means. */
+ ~meta_any() noexcept {
+ release();
+ }
+
+ /**
+ * @brief Copy assignment operator.
+ * @param other The instance to copy from.
+ * @return This meta any object.
+ */
+ meta_any &operator=(const meta_any &other) {
+ if(this != &other) {
+ release();
+ storage = other.storage;
+ ctx = other.ctx;
+ node = other.node;
+ vtable = other.vtable;
+ }
+
+ return *this;
+ }
+
+ /**
+ * @brief Move assignment operator.
+ * @param other The instance to move from.
+ * @return This meta any object.
+ */
+ meta_any &operator=(meta_any &&other) noexcept {
+ ENTT_ASSERT(this != &other, "Self move assignment");
+
+ release();
+ storage = std::move(other.storage);
+ ctx = other.ctx;
+ node = std::exchange(other.node, internal::meta_type_node{});
+ vtable = std::exchange(other.vtable, &basic_vtable<void>);
+ return *this;
+ }
+
+ /**
+ * @brief Value assignment operator.
+ * @tparam Type Type of object to use to initialize the wrapper.
+ * @param value An instance of an object to use to initialize the wrapper.
+ * @return This meta any object.
+ */
+ template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
+ meta_any &operator=(Type &&value) {
+ emplace<std::decay_t<Type>>(std::forward<Type>(value));
+ return *this;
+ }
+
+ /*! @copydoc any::type */
+ [[nodiscard]] inline meta_type type() const noexcept;
+
+ /*! @copydoc any::data */
+ [[nodiscard]] const void *data() const noexcept {
+ return storage.data();
+ }
+
+ /*! @copydoc any::data */
+ [[nodiscard]] void *data() noexcept {
+ return storage.data();
+ }
+
+ /**
+ * @brief Invokes the underlying function, if possible.
+ * @tparam Args Types of arguments to use to invoke the function.
+ * @param id Unique identifier.
+ * @param args Parameters to use to invoke the function.
+ * @return A wrapper containing the returned value, if any.
+ */
+ template<typename... Args>
+ meta_any invoke(const id_type id, Args &&...args) const;
+
+ /*! @copydoc invoke */
+ template<typename... Args>
+ meta_any invoke(const id_type id, Args &&...args);
+
+ /**
+ * @brief Sets the value of a given variable.
+ * @tparam Type Type of value to assign.
+ * @param id Unique identifier.
+ * @param value Parameter to use to set the underlying variable.
+ * @return True in case of success, false otherwise.
+ */
+ template<typename Type>
+ bool set(const id_type id, Type &&value);
+
+ /**
+ * @brief Gets the value of a given variable.
+ * @param id Unique identifier.
+ * @return A wrapper containing the value of the underlying variable.
+ */
+ [[nodiscard]] meta_any get(const id_type id) const;
+
+ /*! @copydoc get */
+ [[nodiscard]] meta_any get(const id_type id);
+
+ /**
+ * @brief Tries to cast an instance to a given type.
+ * @tparam Type Type to which to cast the instance.
+ * @return A (possibly null) pointer to the contained instance.
+ */
+ template<typename Type>
+ [[nodiscard]] const Type *try_cast() const {
+ const auto other = internal::resolve<std::remove_cv_t<Type>>(internal::meta_context::from(*ctx));
+ return static_cast<const Type *>(internal::try_cast(internal::meta_context::from(*ctx), node, other, data()));
+ }
+
+ /*! @copydoc try_cast */
+ template<typename Type>
+ [[nodiscard]] Type *try_cast() {
+ if constexpr(std::is_const_v<Type>) {
+ return std::as_const(*this).try_cast<std::remove_const_t<Type>>();
+ } else {
+ const auto other = internal::resolve<std::remove_cv_t<Type>>(internal::meta_context::from(*ctx));
+ return static_cast<Type *>(const_cast<void *>(internal::try_cast(internal::meta_context::from(*ctx), node, other, data())));
+ }
+ }
+
+ /**
+ * @brief Tries to cast an instance to a given type.
+ * @tparam Type Type to which to cast the instance.
+ * @return A reference to the contained instance.
+ */
+ template<typename Type>
+ [[nodiscard]] Type cast() const {
+ auto *const instance = try_cast<std::remove_reference_t<Type>>();
+ ENTT_ASSERT(instance, "Invalid instance");
+ return static_cast<Type>(*instance);
+ }
+
+ /*! @copydoc cast */
+ template<typename Type>
+ [[nodiscard]] Type cast() {
+ // forces const on non-reference types to make them work also with wrappers for const references
+ auto *const instance = try_cast<std::remove_reference_t<const Type>>();
+ ENTT_ASSERT(instance, "Invalid instance");
+ return static_cast<Type>(*instance);
+ }
+
+ /**
+ * @brief Converts an object in such a way that a given cast becomes viable.
+ * @param type Meta type to which the cast is requested.
+ * @return A valid meta any object if there exists a viable conversion, an
+ * invalid one otherwise.
+ */
+ [[nodiscard]] meta_any allow_cast(const meta_type &type) const;
+
+ /**
+ * @brief Converts an object in such a way that a given cast becomes viable.
+ * @param type Meta type to which the cast is requested.
+ * @return True if there exists a viable conversion, false otherwise.
+ */
+ [[nodiscard]] bool allow_cast(const meta_type &type) {
+ if(auto other = std::as_const(*this).allow_cast(type); other) {
+ if((other.storage.policy() == any_policy::owner)) {
+ std::swap(*this, other);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @brief Converts an object in such a way that a given cast becomes viable.
+ * @tparam Type Type to which the cast is requested.
+ * @return A valid meta any object if there exists a viable conversion, an
+ * invalid one otherwise.
+ */
+ template<typename Type>
+ [[nodiscard]] meta_any allow_cast() const {
+ if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
+ return meta_any{meta_ctx_arg, *ctx};
+ } else {
+ auto other = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
+ return allow_cast(meta_type{*ctx, other});
+ }
+ }
+
+ /**
+ * @brief Converts an object in such a way that a given cast becomes viable.
+ * @tparam Type Type to which the cast is requested.
+ * @return True if there exists a viable conversion, false otherwise.
+ */
+ template<typename Type>
+ [[nodiscard]] bool allow_cast() {
+ auto other = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
+ return allow_cast(meta_type{*ctx, other}) && (!(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) || storage.data() != nullptr);
+ }
+
+ /*! @copydoc any::emplace */
+ template<typename Type, typename... Args>
+ void emplace(Args &&...args) {
+ release();
+ storage.emplace<Type>(std::forward<Args>(args)...);
+ node = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
+ vtable = &basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
+ }
+
+ /*! @copydoc any::assign */
+ bool assign(const meta_any &other);
+
+ /*! @copydoc any::assign */
+ bool assign(meta_any &&other);
+
+ /*! @copydoc any::reset */
+ void reset() {
+ release();
+ storage.reset();
+ node = {};
+ vtable = &basic_vtable<void>;
+ }
+
+ /**
+ * @brief Returns a sequence container proxy.
+ * @return A sequence container proxy for the underlying object.
+ */
+ [[nodiscard]] meta_sequence_container as_sequence_container() noexcept {
+ meta_sequence_container proxy{*ctx};
+ vtable(internal::meta_traits::is_meta_sequence_container, policy() == meta_any_policy::cref, std::as_const(*this).data(), &proxy);
+ return proxy;
+ }
+
+ /*! @copydoc as_sequence_container */
+ [[nodiscard]] meta_sequence_container as_sequence_container() const noexcept {
+ meta_sequence_container proxy{*ctx};
+ vtable(internal::meta_traits::is_meta_sequence_container, true, data(), &proxy);
+ return proxy;
+ }
+
+ /**
+ * @brief Returns an associative container proxy.
+ * @return An associative container proxy for the underlying object.
+ */
+ [[nodiscard]] meta_associative_container as_associative_container() noexcept {
+ meta_associative_container proxy{*ctx};
+ vtable(internal::meta_traits::is_meta_associative_container, policy() == meta_any_policy::cref, std::as_const(*this).data(), &proxy);
+ return proxy;
+ }
+
+ /*! @copydoc as_associative_container */
+ [[nodiscard]] meta_associative_container as_associative_container() const noexcept {
+ meta_associative_container proxy{*ctx};
+ vtable(internal::meta_traits::is_meta_associative_container, true, data(), &proxy);
+ return proxy;
+ }
+
+ /**
+ * @brief Indirection operator for dereferencing opaque objects.
+ * @return A wrapper that shares a reference to an unmanaged object if the
+ * wrapped element is dereferenceable, an invalid meta any otherwise.
+ */
+ [[nodiscard]] meta_any operator*() const noexcept {
+ meta_any ret{meta_ctx_arg, *ctx};
+ vtable(internal::meta_traits::is_meta_pointer_like, true, storage.data(), &ret);
+ return ret;
+ }
+
+ /**
+ * @brief Returns false if a wrapper is invalid, true otherwise.
+ * @return False if the wrapper is invalid, true otherwise.
+ */
+ [[nodiscard]] explicit operator bool() const noexcept {
+ return !(node.info == nullptr);
+ }
+
+ /*! @copydoc any::operator== */
+ [[nodiscard]] bool operator==(const meta_any &other) const noexcept {
+ return (ctx == other.ctx) && ((!node.info && !other.node.info) || (node.info && other.node.info && *node.info == *other.node.info && storage == other.storage));
+ }
+
+ /*! @copydoc any::operator!= */
+ [[nodiscard]] bool operator!=(const meta_any &other) const noexcept {
+ return !(*this == other);
+ }
+
+ /*! @copydoc any::as_ref */
+ [[nodiscard]] meta_any as_ref() noexcept {
+ return meta_any{*this, storage.as_ref()};
+ }
+
+ /*! @copydoc any::as_ref */
+ [[nodiscard]] meta_any as_ref() const noexcept {
+ return meta_any{*this, storage.as_ref()};
+ }
+
+ /**
+ * @brief Returns the current mode of a meta any object.
+ * @return The current mode of the meta any object.
+ */
+ [[nodiscard]] meta_any_policy policy() const noexcept {
+ return storage.policy();
+ }
+
+private:
+ any storage{};
+ const meta_ctx *ctx{&locator<meta_ctx>::value_or()};
+ internal::meta_type_node node{};
+ vtable_type *vtable{&basic_vtable<void>};
+};
+
+/**
+ * @brief Forwards its argument and avoids copies for lvalue references.
+ * @tparam Type Type of argument to use to construct the new instance.
+ * @param value Parameter to use to construct the instance.
+ * @param ctx The context from which to search for meta types.
+ * @return A properly initialized and not necessarily owning wrapper.
+ */
+template<typename Type>
+[[nodiscard]] meta_any forward_as_meta(const meta_ctx &ctx, Type &&value) {
+ return meta_any{ctx, std::in_place_type<Type &&>, std::forward<Type>(value)};
+}
+
+/**
+ * @brief Forwards its argument and avoids copies for lvalue references.
+ * @tparam Type Type of argument to use to construct the new instance.
+ * @param value Parameter to use to construct the instance.
+ * @return A properly initialized and not necessarily owning wrapper.
+ */
+template<typename Type>
+[[nodiscard]] meta_any forward_as_meta(Type &&value) {
+ return forward_as_meta(locator<meta_ctx>::value_or(), std::forward<Type>(value));
+}
+
+/**
+ * @brief Opaque pointers to instances of any type.
+ *
+ * A handle doesn't perform copies and isn't responsible for the contained
+ * object. It doesn't prolong the lifetime of the pointed instance.
+ */
+struct meta_handle {
+ /*! Default constructor. */
+ meta_handle() = default;
+
+ /**
+ * @brief Context aware constructor.
+ * @param area The context from which to search for meta types.
+ */
+ meta_handle(meta_ctx_arg_t, const meta_ctx &area)
+ : any{meta_ctx_arg, area} {}
+
+ /**
+ * @brief Creates a handle that points to an unmanaged object.
+ * @param value An instance of an object to use to initialize the handle.
+ */
+ meta_handle(meta_any &value)
+ : any{value.as_ref()} {}
+
+ /**
+ * @brief Creates a handle that points to an unmanaged object.
+ * @param value An instance of an object to use to initialize the handle.
+ */
+ meta_handle(const meta_any &value)
+ : any{value.as_ref()} {}
+
+ /**
+ * @brief Creates a handle that points to an unmanaged object.
+ * @tparam Type Type of object to use to initialize the handle.
+ * @param ctx The context from which to search for meta types.
+ * @param value An instance of an object to use to initialize the handle.
+ */
+ template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
+ meta_handle(const meta_ctx &ctx, Type &value)
+ : any{ctx, std::in_place_type<Type &>, value} {}
+
+ /**
+ * @brief Creates a handle that points to an unmanaged object.
+ * @tparam Type Type of object to use to initialize the handle.
+ * @param value An instance of an object to use to initialize the handle.
+ */
+ template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
+ meta_handle(Type &value)
+ : meta_handle{locator<meta_ctx>::value_or(), value} {}
+
+ /**
+ * @brief Context aware copy constructor.
+ * @param area The context from which to search for meta types.
+ * @param other The instance to copy from.
+ */
+ meta_handle(const meta_ctx &area, const meta_handle &other)
+ : any{area, other.any} {}
+
+ /**
+ * @brief Context aware move constructor.
+ * @param area The context from which to search for meta types.
+ * @param other The instance to move from.
+ */
+ meta_handle(const meta_ctx &area, meta_handle &&other)
+ : any{area, std::move(other.any)} {}
+
+ /*! @brief Default copy constructor, deleted on purpose. */
+ meta_handle(const meta_handle &) = delete;
+
+ /*! @brief Default move constructor. */
+ meta_handle(meta_handle &&) = default;
+
+ /*! @brief Default destructor. */
+ ~meta_handle() noexcept = default;
+
+ /**
+ * @brief Default copy assignment operator, deleted on purpose.
+ * @return This meta handle.
+ */
+ meta_handle &operator=(const meta_handle &) = delete;
+
+ /**
+ * @brief Default move assignment operator.
+ * @return This meta handle.
+ */
+ meta_handle &operator=(meta_handle &&) = default;
+
+ /**
+ * @brief Returns false if a handle is invalid, true otherwise.
+ * @return False if the handle is invalid, true otherwise.
+ */
+ [[nodiscard]] explicit operator bool() const noexcept {
+ return static_cast<bool>(any);
+ }
+
+ /*! @copydoc meta_any::operator== */
+ [[nodiscard]] bool operator==(const meta_handle &other) const noexcept {
+ return (any == other.any);
+ }
+
+ /*! @copydoc meta_any::operator!= */
+ [[nodiscard]] bool operator!=(const meta_handle &other) const noexcept {
+ return !(*this == other);
+ }
+
+ /**
+ * @brief Access operator for accessing the contained opaque object.
+ * @return A wrapper that shares a reference to an unmanaged object.
+ */
+ [[nodiscard]] meta_any *operator->() {
+ return &any;
+ }
+
+ /*! @copydoc operator-> */
+ [[nodiscard]] const meta_any *operator->() const {
+ return &any;
+ }
+
+private:
+ meta_any any{meta_ctx_arg, locator<meta_ctx>::value_or()};
+};
+
+/*! @brief Opaque wrapper for properties of any type. */
+struct meta_prop {
+ /*! @brief Default constructor. */
+ meta_prop() noexcept = default;
+
+ /**
+ * @brief Context aware constructor for meta objects.
+ * @param area The context from which to search for meta types.
+ * @param curr The underlying node with which to construct the instance.
+ */
+ meta_prop(const meta_ctx &area, const internal::meta_prop_node &curr) noexcept
+ : node{&curr},
+ ctx{&area} {}
+
+ /**
+ * @brief Returns the stored value by const reference.
+ * @return A wrapper containing the value stored with the property.
+ */
+ [[nodiscard]] meta_any value() const {
+ return node->value ? node->type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, node->value.get()) : meta_any{meta_ctx_arg, *ctx};
+ }
+
+ /**
+ * @brief Returns the stored value by reference.
+ * @return A wrapper containing the value stored with the property.
+ */
+ [[nodiscard]] meta_any value() {
+ return node->value ? node->type(internal::meta_context::from(*ctx)).from_void(*ctx, node->value.get(), nullptr) : meta_any{meta_ctx_arg, *ctx};
+ }
+
+ /**
+ * @brief Returns true if an object is valid, false otherwise.
+ * @return True if the object is valid, false otherwise.
+ */
+ [[nodiscard]] explicit operator bool() const noexcept {
+ return (node != nullptr);
+ }
+
+ /**
+ * @brief Checks if two objects refer to the same type.
+ * @param other The object with which to compare.
+ * @return True if the objects refer to the same type, false otherwise.
+ */
+ [[nodiscard]] bool operator==(const meta_prop &other) const noexcept {
+ return (ctx == other.ctx && node == other.node);
+ }
+
+private:
+ const internal::meta_prop_node *node{};
+ const meta_ctx *ctx{};
+};
+
+/**
+ * @brief Checks if two objects refer to the same type.
+ * @param lhs An object, either valid or not.
+ * @param rhs An object, either valid or not.
+ * @return False if the objects refer to the same node, true otherwise.
+ */
+[[nodiscard]] inline bool operator!=(const meta_prop &lhs, const meta_prop &rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+/*! @brief Opaque wrapper for user defined data of any type. */
+struct meta_custom {
+ /*! @brief Default constructor. */
+ meta_custom() noexcept = default;
+
+ /**
+ * @brief Basic constructor for meta objects.
+ * @param curr The underlying node with which to construct the instance.
+ */
+ meta_custom(internal::meta_custom_node curr) noexcept
+ : node{std::move(curr)} {}
+
+ /**
+ * @brief Generic conversion operator.
+ * @tparam Type Type to which conversion is requested.
+ */
+ template<typename Type>
+ [[nodiscard]] operator Type *() const noexcept {
+ return (type_id<Type>().hash() == node.type) ? std::static_pointer_cast<Type>(node.value).get() : nullptr;
+ }
+
+ /**
+ * @brief Generic conversion operator.
+ * @tparam Type Type to which conversion is requested.
+ */
+ template<typename Type>
+ [[nodiscard]] operator Type &() const noexcept {
+ ENTT_ASSERT(type_id<Type>().hash() == node.type, "Invalid type");
+ return *std::static_pointer_cast<Type>(node.value);
+ }
+
+private:
+ internal::meta_custom_node node{};
+};
+
+/*! @brief Opaque wrapper for data members. */
+struct meta_data {
+ /*! @brief Unsigned integer type. */
+ using size_type = typename internal::meta_data_node::size_type;
+
+ /*! @brief Default constructor. */
+ meta_data() noexcept = default;
+
+ /**
+ * @brief Context aware constructor for meta objects.
+ * @param area The context from which to search for meta types.
+ * @param curr The underlying node with which to construct the instance.
+ */
+ meta_data(const meta_ctx &area, const internal::meta_data_node &curr) noexcept
+ : node{&curr},
+ ctx{&area} {}
+
+ /**
+ * @brief Returns the number of setters available.
+ * @return The number of setters available.
+ */
+ [[nodiscard]] size_type arity() const noexcept {
+ return node->arity;
+ }
+
+ /**
+ * @brief Indicates whether a data member is constant or not.
+ * @return True if the data member is constant, false otherwise.
+ */
+ [[nodiscard]] bool is_const() const noexcept {
+ return static_cast<bool>(node->traits & internal::meta_traits::is_const);
+ }
+
+ /**
+ * @brief Indicates whether a data member is static or not.
+ * @return True if the data member is static, false otherwise.
+ */
+ [[nodiscard]] bool is_static() const noexcept {
+ return static_cast<bool>(node->traits & internal::meta_traits::is_static);
+ }
+
+ /*! @copydoc meta_any::type */
+ [[nodiscard]] inline meta_type type() const noexcept;
+
+ /**
+ * @brief Sets the value of a given variable.
+ * @tparam Type Type of value to assign.
+ * @param instance An opaque instance of the underlying type.
+ * @param value Parameter to use to set the underlying variable.
+ * @return True in case of success, false otherwise.
+ */
+ template<typename Type>
+ // NOLINTNEXTLINE(modernize-use-nodiscard)
+ bool set(meta_handle instance, Type &&value) const {
+ return node->set && node->set(meta_handle{*ctx, std::move(instance)}, meta_any{*ctx, std::forward<Type>(value)});
+ }
+
+ /**
+ * @brief Gets the value of a given variable.
+ * @param instance An opaque instance of the underlying type.
+ * @return A wrapper containing the value of the underlying variable.
+ */
+ [[nodiscard]] meta_any get(meta_handle instance) const {
+ return node->get(*ctx, meta_handle{*ctx, std::move(instance)});
+ }
+
+ /**
+ * @brief Returns the type accepted by the i-th setter.
+ * @param index Index of the setter of which to return the accepted type.
+ * @return The type accepted by the i-th setter.
+ */
+ [[nodiscard]] inline meta_type arg(const size_type index) const noexcept;
+
+ /**
+ * @brief Returns a range to visit registered meta properties.
+ * @return An iterable range to visit registered meta properties.
+ */
+ [[nodiscard]] meta_range<meta_prop, typename decltype(internal::meta_data_node::prop)::const_iterator> prop() const noexcept {
+ return {{*ctx, node->prop.cbegin()}, {*ctx, node->prop.cend()}};
+ }
+
+ /**
+ * @brief Lookup utility for meta properties.
+ * @param key The key to use to search for a property.
+ * @return The registered meta property for the given key, if any.
+ */
+ [[nodiscard]] meta_prop prop(const id_type key) const {
+ const auto it = node->prop.find(key);
+ return it != node->prop.cend() ? meta_prop{*ctx, it->second} : meta_prop{};
+ }
+
+ /**
+ * @brief Returns all meta traits for a given meta object.
+ * @tparam Type The type to convert the meta traits to.
+ * @return The registered meta traits, if any.
+ */
+ template<typename Type>
+ [[nodiscard]] Type traits() const noexcept {
+ return internal::meta_to_user_traits<Type>(node->traits);
+ }
+
+ /**
+ * @brief Returns user defined data for a given meta object.
+ * @return User defined arbitrary data.
+ */
+ [[nodiscard]] meta_custom custom() const noexcept {
+ return {node->custom};
+ }
+
+ /**
+ * @brief Returns true if an object is valid, false otherwise.
+ * @return True if the object is valid, false otherwise.
+ */
+ [[nodiscard]] explicit operator bool() const noexcept {
+ return (node != nullptr);
+ }
+
+ /*! @copydoc meta_prop::operator== */
+ [[nodiscard]] bool operator==(const meta_data &other) const noexcept {
+ return (ctx == other.ctx && node == other.node);
+ }
+
+private:
+ const internal::meta_data_node *node{};
+ const meta_ctx *ctx{};
+};
+
+/**
+ * @brief Checks if two objects refer to the same type.
+ * @param lhs An object, either valid or not.
+ * @param rhs An object, either valid or not.
+ * @return False if the objects refer to the same node, true otherwise.
+ */
+[[nodiscard]] inline bool operator!=(const meta_data &lhs, const meta_data &rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+/*! @brief Opaque wrapper for member functions. */
+struct meta_func {
+ /*! @brief Unsigned integer type. */
+ using size_type = typename internal::meta_func_node::size_type;
+
+ /*! @brief Default constructor. */
+ meta_func() noexcept = default;
+
+ /**
+ * @brief Context aware constructor for meta objects.
+ * @param area The context from which to search for meta types.
+ * @param curr The underlying node with which to construct the instance.
+ */
+ meta_func(const meta_ctx &area, const internal::meta_func_node &curr) noexcept
+ : node{&curr},
+ ctx{&area} {}
+
+ /**
+ * @brief Returns the number of arguments accepted by a member function.
+ * @return The number of arguments accepted by the member function.
+ */
+ [[nodiscard]] size_type arity() const noexcept {
+ return node->arity;
+ }
+
+ /**
+ * @brief Indicates whether a member function is constant or not.
+ * @return True if the member function is constant, false otherwise.
+ */
+ [[nodiscard]] bool is_const() const noexcept {
+ return static_cast<bool>(node->traits & internal::meta_traits::is_const);
+ }
+
+ /**
+ * @brief Indicates whether a member function is static or not.
+ * @return True if the member function is static, false otherwise.
+ */
+ [[nodiscard]] bool is_static() const noexcept {
+ return static_cast<bool>(node->traits & internal::meta_traits::is_static);
+ }
+
+ /**
+ * @brief Returns the return type of a member function.
+ * @return The return type of the member function.
+ */
+ [[nodiscard]] inline meta_type ret() const noexcept;
+
+ /**
+ * @brief Returns the type of the i-th argument of a member function.
+ * @param index Index of the argument of which to return the type.
+ * @return The type of the i-th argument of a member function.
+ */
+ [[nodiscard]] inline meta_type arg(const size_type index) const noexcept;
+
+ /**
+ * @brief Invokes the underlying function, if possible.
+ * @param instance An opaque instance of the underlying type.
+ * @param args Parameters to use to invoke the function.
+ * @param sz Number of parameters to use to invoke the function.
+ * @return A wrapper containing the returned value, if any.
+ */
+ meta_any invoke(meta_handle instance, meta_any *const args, const size_type sz) const {
+ return sz == arity() ? node->invoke(*ctx, meta_handle{*ctx, std::move(instance)}, args) : meta_any{meta_ctx_arg, *ctx};
+ }
+
+ /**
+ * @copybrief invoke
+ * @tparam Args Types of arguments to use to invoke the function.
+ * @param instance An opaque instance of the underlying type.
+ * @param args Parameters to use to invoke the function.
+ * @return A wrapper containing the returned value, if any.
+ */
+ template<typename... Args>
+ // NOLINTNEXTLINE(modernize-use-nodiscard)
+ meta_any invoke(meta_handle instance, Args &&...args) const {
+ std::array<meta_any, sizeof...(Args)> arguments{meta_any{*ctx, std::forward<Args>(args)}...};
+ return invoke(std::move(instance), arguments.data(), sizeof...(Args));
+ }
+
+ /*! @copydoc meta_data::prop */
+ [[nodiscard]] meta_range<meta_prop, typename decltype(internal::meta_func_node::prop)::const_iterator> prop() const noexcept {
+ return {{*ctx, node->prop.cbegin()}, {*ctx, node->prop.cend()}};
+ }
+
+ /**
+ * @brief Lookup utility for meta properties.
+ * @param key The key to use to search for a property.
+ * @return The registered meta property for the given key, if any.
+ */
+ [[nodiscard]] meta_prop prop(const id_type key) const {
+ const auto it = node->prop.find(key);
+ return it != node->prop.cend() ? meta_prop{*ctx, it->second} : meta_prop{};
+ }
+
+ /*! @copydoc meta_data::traits */
+ template<typename Type>
+ [[nodiscard]] Type traits() const noexcept {
+ return internal::meta_to_user_traits<Type>(node->traits);
+ }
+
+ /*! @copydoc meta_data::custom */
+ [[nodiscard]] meta_custom custom() const noexcept {
+ return {node->custom};
+ }
+
+ /**
+ * @brief Returns the next overload of a given function, if any.
+ * @return The next overload of the given function, if any.
+ */
+ [[nodiscard]] meta_func next() const {
+ return node->next ? meta_func{*ctx, *node->next} : meta_func{};
+ }
+
+ /**
+ * @brief Returns true if an object is valid, false otherwise.
+ * @return True if the object is valid, false otherwise.
+ */
+ [[nodiscard]] explicit operator bool() const noexcept {
+ return (node != nullptr);
+ }
+
+ /*! @copydoc meta_prop::operator== */
+ [[nodiscard]] bool operator==(const meta_func &other) const noexcept {
+ return (ctx == other.ctx && node == other.node);
+ }
+
+private:
+ const internal::meta_func_node *node{};
+ const meta_ctx *ctx{};
+};
+
+/**
+ * @brief Checks if two objects refer to the same type.
+ * @param lhs An object, either valid or not.
+ * @param rhs An object, either valid or not.
+ * @return False if the objects refer to the same node, true otherwise.
+ */
+[[nodiscard]] inline bool operator!=(const meta_func &lhs, const meta_func &rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+/*! @brief Opaque wrapper for types. */
+class meta_type {
+ template<typename Func>
+ [[nodiscard]] auto lookup(meta_any *const args, const typename internal::meta_type_node::size_type sz, [[maybe_unused]] bool constness, Func next) const {
+ decltype(next()) candidate = nullptr;
+ size_type same{};
+ bool ambiguous{};
+
+ for(auto curr = next(); curr; curr = next()) {
+ if constexpr(std::is_same_v<std::decay_t<decltype(*curr)>, internal::meta_func_node>) {
+ if(constness && !static_cast<bool>(curr->traits & internal::meta_traits::is_const)) {
+ continue;
+ }
+ }
+
+ if(curr->arity == sz) {
+ size_type match{};
+ size_type pos{};
+
+ // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
+ for(; pos < sz && args[pos]; ++pos) {
+ const auto other = curr->arg(*ctx, pos);
+ const auto type = args[pos].type();
+
+ if(const auto &info = other.info(); info == type.info()) {
+ ++match;
+ } else if(!((type.node.details && (type.node.details->base.contains(info.hash()) || type.node.details->conv.contains(info.hash()))) || (type.node.conversion_helper && other.node.conversion_helper))) {
+ break;
+ }
+ }
+ // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+
+ if(pos == sz) {
+ if(!candidate || match > same) {
+ candidate = curr;
+ same = match;
+ ambiguous = false;
+ } else if(match == same) {
+ if constexpr(std::is_same_v<std::decay_t<decltype(*curr)>, internal::meta_func_node>) {
+ if(static_cast<bool>(curr->traits & internal::meta_traits::is_const) != static_cast<bool>(candidate->traits & internal::meta_traits::is_const)) {
+ candidate = static_cast<bool>(candidate->traits & internal::meta_traits::is_const) ? curr : candidate;
+ ambiguous = false;
+ continue;
+ }
+ }
+
+ ambiguous = true;
+ }
+ }
+ }
+ }
+
+ return ambiguous ? nullptr : candidate;
+ }
+
+public:
+ /*! @brief Unsigned integer type. */
+ using size_type = typename internal::meta_type_node::size_type;
+
+ /*! @brief Default constructor. */
+ meta_type() noexcept = default;
+
+ /**
+ * @brief Context aware constructor for meta objects.
+ * @param area The context from which to search for meta types.
+ * @param curr The underlying node with which to construct the instance.
+ */
+ meta_type(const meta_ctx &area, internal::meta_type_node curr) noexcept
+ : node{std::move(curr)},
+ ctx{&area} {}
+
+ /**
+ * @brief Context aware constructor for meta objects.
+ * @param area The context from which to search for meta types.
+ * @param curr The underlying node with which to construct the instance.
+ */
+ meta_type(const meta_ctx &area, const internal::meta_base_node &curr) noexcept
+ : meta_type{area, curr.type(internal::meta_context::from(area))} {}
+
+ /**
+ * @brief Returns the type info object of the underlying type.
+ * @return The type info object of the underlying type.
+ */
+ [[nodiscard]] const type_info &info() const noexcept {
+ return *node.info;
+ }
+
+ /**
+ * @brief Returns the identifier assigned to a type.
+ * @return The identifier assigned to the type.
+ */
+ [[nodiscard]] id_type id() const noexcept {
+ return node.id;
+ }
+
+ /**
+ * @brief Returns the size of the underlying type if known.
+ * @return The size of the underlying type if known, 0 otherwise.
+ */
+ [[nodiscard]] size_type size_of() const noexcept {
+ return node.size_of;
+ }
+
+ /**
+ * @brief Checks whether a type refers to an arithmetic type or not.
+ * @return True if the underlying type is an arithmetic type, false
+ * otherwise.
+ */
+ [[nodiscard]] bool is_arithmetic() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_arithmetic);
+ }
+
+ /**
+ * @brief Checks whether a type refers to an integral type or not.
+ * @return True if the underlying type is an integral type, false otherwise.
+ */
+ [[nodiscard]] bool is_integral() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_integral);
+ }
+
+ /**
+ * @brief Checks whether a type refers to a signed type or not.
+ * @return True if the underlying type is a signed type, false otherwise.
+ */
+ [[nodiscard]] bool is_signed() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_signed);
+ }
+
+ /**
+ * @brief Checks whether a type refers to an array type or not.
+ * @return True if the underlying type is an array type, false otherwise.
+ */
+ [[nodiscard]] bool is_array() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_array);
+ }
+
+ /**
+ * @brief Checks whether a type refers to an enum or not.
+ * @return True if the underlying type is an enum, false otherwise.
+ */
+ [[nodiscard]] bool is_enum() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_enum);
+ }
+
+ /**
+ * @brief Checks whether a type refers to a class or not.
+ * @return True if the underlying type is a class, false otherwise.
+ */
+ [[nodiscard]] bool is_class() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_class);
+ }
+
+ /**
+ * @brief Checks whether a type refers to a pointer or not.
+ * @return True if the underlying type is a pointer, false otherwise.
+ */
+ [[nodiscard]] bool is_pointer() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_pointer);
+ }
+
+ /**
+ * @brief Provides the type for which the pointer is defined.
+ * @return The type for which the pointer is defined or this type if it
+ * doesn't refer to a pointer type.
+ */
+ [[nodiscard]] meta_type remove_pointer() const noexcept {
+ return {*ctx, node.remove_pointer(internal::meta_context::from(*ctx))};
+ }
+
+ /**
+ * @brief Checks whether a type is a pointer-like type or not.
+ * @return True if the underlying type is pointer-like, false otherwise.
+ */
+ [[nodiscard]] bool is_pointer_like() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_meta_pointer_like);
+ }
+
+ /**
+ * @brief Checks whether a type refers to a sequence container or not.
+ * @return True if the type is a sequence container, false otherwise.
+ */
+ [[nodiscard]] bool is_sequence_container() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_meta_sequence_container);
+ }
+
+ /**
+ * @brief Checks whether a type refers to an associative container or not.
+ * @return True if the type is an associative container, false otherwise.
+ */
+ [[nodiscard]] bool is_associative_container() const noexcept {
+ return static_cast<bool>(node.traits & internal::meta_traits::is_meta_associative_container);
+ }
+
+ /**
+ * @brief Checks whether a type refers to a recognized class template
+ * specialization or not.
+ * @return True if the type is a recognized class template specialization,
+ * false otherwise.
+ */
+ [[nodiscard]] bool is_template_specialization() const noexcept {
+ return (node.templ.arity != 0u);
+ }
+
+ /**
+ * @brief Returns the number of template arguments.
+ * @return The number of template arguments.
+ */
+ [[nodiscard]] size_type template_arity() const noexcept {
+ return node.templ.arity;
+ }
+
+ /**
+ * @brief Returns a tag for the class template of the underlying type.
+ * @return The tag for the class template of the underlying type.
+ */
+ [[nodiscard]] inline meta_type template_type() const noexcept {
+ return node.templ.type ? meta_type{*ctx, node.templ.type(internal::meta_context::from(*ctx))} : meta_type{};
+ }
+
+ /**
+ * @brief Returns the type of the i-th template argument of a type.
+ * @param index Index of the template argument of which to return the type.
+ * @return The type of the i-th template argument of a type.
+ */
+ [[nodiscard]] inline meta_type template_arg(const size_type index) const noexcept {
+ return index < template_arity() ? meta_type{*ctx, node.templ.arg(internal::meta_context::from(*ctx), index)} : meta_type{};
+ }
+
+ /**
+ * @brief Checks if a type supports direct casting to another type.
+ * @param other The meta type to test for.
+ * @return True if direct casting is allowed, false otherwise.
+ */
+ [[nodiscard]] bool can_cast(const meta_type &other) const noexcept {
+ // casting this is UB in all cases but we aren't going to use the resulting pointer, so...
+ return (internal::try_cast(internal::meta_context::from(*ctx), node, other.node, this) != nullptr);
+ }
+
+ /**
+ * @brief Checks if a type supports conversion it to another type.
+ * @param other The meta type to test for.
+ * @return True if the conversion is allowed, false otherwise.
+ */
+ [[nodiscard]] bool can_convert(const meta_type &other) const noexcept {
+ return (internal::try_convert(internal::meta_context::from(*ctx), node, other.info(), other.is_arithmetic() || other.is_enum(), nullptr, [](const void *, auto &&...args) { return ((static_cast<void>(args), 1) + ... + 0u); }) != 0u);
+ }
+
+ /**
+ * @brief Returns a range to visit registered top-level base meta types.
+ * @return An iterable range to visit registered top-level base meta types.
+ */
+ [[nodiscard]] meta_range<meta_type, typename decltype(internal::meta_type_descriptor::base)::const_iterator> base() const noexcept {
+ using range_type = meta_range<meta_type, typename decltype(internal::meta_type_descriptor::base)::const_iterator>;
+ return node.details ? range_type{{*ctx, node.details->base.cbegin()}, {*ctx, node.details->base.cend()}} : range_type{};
+ }
+
+ /**
+ * @brief Returns a range to visit registered top-level meta data.
+ * @return An iterable range to visit registered top-level meta data.
+ */
+ [[nodiscard]] meta_range<meta_data, typename decltype(internal::meta_type_descriptor::data)::const_iterator> data() const noexcept {
+ using range_type = meta_range<meta_data, typename decltype(internal::meta_type_descriptor::data)::const_iterator>;
+ return node.details ? range_type{{*ctx, node.details->data.cbegin()}, {*ctx, node.details->data.cend()}} : range_type{};
+ }
+
+ /**
+ * @brief Lookup utility for meta data (bases are also visited).
+ * @param id Unique identifier.
+ * @return The registered meta data for the given identifier, if any.
+ */
+ [[nodiscard]] meta_data data(const id_type id) const {
+ const auto *elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), node, id);
+ return elem ? meta_data{*ctx, *elem} : meta_data{};
+ }
+
+ /**
+ * @brief Returns a range to visit registered top-level functions.
+ * @return An iterable range to visit registered top-level functions.
+ */
+ [[nodiscard]] meta_range<meta_func, typename decltype(internal::meta_type_descriptor::func)::const_iterator> func() const noexcept {
+ using return_type = meta_range<meta_func, typename decltype(internal::meta_type_descriptor::func)::const_iterator>;
+ return node.details ? return_type{{*ctx, node.details->func.cbegin()}, {*ctx, node.details->func.cend()}} : return_type{};
+ }
+
+ /**
+ * @brief Lookup utility for meta functions (bases are also visited).
+ *
+ * In case of overloaded functions, a random one is returned.
+ *
+ * @param id Unique identifier.
+ * @return The registered meta function for the given identifier, if any.
+ */
+ [[nodiscard]] meta_func func(const id_type id) const {
+ const auto *elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), node, id);
+ return elem ? meta_func{*ctx, *elem} : meta_func{};
+ }
+
+ /**
+ * @brief Creates an instance of the underlying type, if possible.
+ * @param args Parameters to use to construct the instance.
+ * @param sz Number of parameters to use to construct the instance.
+ * @return A wrapper containing the new instance, if any.
+ */
+ [[nodiscard]] meta_any construct(meta_any *const args, const size_type sz) const {
+ if(node.details) {
+ if(const auto *candidate = lookup(args, sz, false, [first = node.details->ctor.cbegin(), last = node.details->ctor.cend()]() mutable { return first == last ? nullptr : &(first++)->second; }); candidate) {
+ return candidate->invoke(*ctx, args);
+ }
+ }
+
+ if(sz == 0u && node.default_constructor) {
+ return node.default_constructor(*ctx);
+ }
+
+ return meta_any{meta_ctx_arg, *ctx};
+ }
+
+ /**
+ * @copybrief construct
+ * @tparam Args Types of arguments to use to construct the instance.
+ * @param args Parameters to use to construct the instance.
+ * @return A wrapper containing the new instance, if any.
+ */
+ template<typename... Args>
+ [[nodiscard]] meta_any construct(Args &&...args) const {
+ std::array<meta_any, sizeof...(Args)> arguments{meta_any{*ctx, std::forward<Args>(args)}...};
+ return construct(arguments.data(), sizeof...(Args));
+ }
+
+ /**
+ * @brief Wraps an opaque element of the underlying type.
+ * @param elem A valid pointer to an element of the underlying type.
+ * @return A wrapper that references the given instance.
+ */
+ [[nodiscard]] meta_any from_void(void *elem) const {
+ return (elem && node.from_void) ? node.from_void(*ctx, elem, nullptr) : meta_any{meta_ctx_arg, *ctx};
+ }
+
+ /*! @copydoc from_void */
+ [[nodiscard]] meta_any from_void(const void *elem) const {
+ return (elem && node.from_void) ? node.from_void(*ctx, nullptr, elem) : meta_any{meta_ctx_arg, *ctx};
+ }
+
+ /**
+ * @brief Invokes a function given an identifier, if possible.
+ * @param id Unique identifier.
+ * @param instance An opaque instance of the underlying type.
+ * @param args Parameters to use to invoke the function.
+ * @param sz Number of parameters to use to invoke the function.
+ * @return A wrapper containing the returned value, if any.
+ */
+ meta_any invoke(const id_type id, meta_handle instance, meta_any *const args, const size_type sz) const {
+ if(node.details) {
+ if(auto it = node.details->func.find(id); it != node.details->func.cend()) {
+ if(const auto *candidate = lookup(args, sz, instance && (instance->data() == nullptr), [curr = &it->second]() mutable { return curr ? std::exchange(curr, curr->next.get()) : nullptr; }); candidate) {
+ return candidate->invoke(*ctx, meta_handle{*ctx, std::move(instance)}, args);
+ }
+ }
+ }
+
+ for(auto &&curr: base()) {
+ if(auto elem = curr.second.invoke(id, *instance.operator->(), args, sz); elem) {
+ return elem;
+ }
+ }
+
+ return meta_any{meta_ctx_arg, *ctx};
+ }
+
+ /**
+ * @copybrief invoke
+ * @param id Unique identifier.
+ * @tparam Args Types of arguments to use to invoke the function.
+ * @param instance An opaque instance of the underlying type.
+ * @param args Parameters to use to invoke the function.
+ * @return A wrapper containing the returned value, if any.
+ */
+ template<typename... Args>
+ // NOLINTNEXTLINE(modernize-use-nodiscard)
+ meta_any invoke(const id_type id, meta_handle instance, Args &&...args) const {
+ std::array<meta_any, sizeof...(Args)> arguments{meta_any{*ctx, std::forward<Args>(args)}...};
+ return invoke(id, std::move(instance), arguments.data(), sizeof...(Args));
+ }
+
+ /**
+ * @brief Sets the value of a given variable.
+ * @tparam Type Type of value to assign.
+ * @param id Unique identifier.
+ * @param instance An opaque instance of the underlying type.
+ * @param value Parameter to use to set the underlying variable.
+ * @return True in case of success, false otherwise.
+ */
+ template<typename Type>
+ bool set(const id_type id, meta_handle instance, Type &&value) const {
+ const auto candidate = data(id);
+ return candidate && candidate.set(std::move(instance), std::forward<Type>(value));
+ }
+
+ /**
+ * @brief Gets the value of a given variable.
+ * @param id Unique identifier.
+ * @param instance An opaque instance of the underlying type.
+ * @return A wrapper containing the value of the underlying variable.
+ */
+ [[nodiscard]] meta_any get(const id_type id, meta_handle instance) const {
+ const auto candidate = data(id);
+ return candidate ? candidate.get(std::move(instance)) : meta_any{meta_ctx_arg, *ctx};
+ }
+
+ /**
+ * @brief Returns a range to visit registered top-level meta properties.
+ * @return An iterable range to visit registered top-level meta properties.
+ */
+ [[nodiscard]] meta_range<meta_prop, typename decltype(internal::meta_type_descriptor::prop)::const_iterator> prop() const noexcept {
+ using range_type = meta_range<meta_prop, typename decltype(internal::meta_type_descriptor::prop)::const_iterator>;
+ return node.details ? range_type{{*ctx, node.details->prop.cbegin()}, {*ctx, node.details->prop.cend()}} : range_type{};
+ }
+
+ /**
+ * @brief Lookup utility for meta properties (bases are also visited).
+ * @param key The key to use to search for a property.
+ * @return The registered meta property for the given key, if any.
+ */
+ [[nodiscard]] meta_prop prop(const id_type key) const {
+ const auto *elem = internal::look_for<&internal::meta_type_descriptor::prop>(internal::meta_context::from(*ctx), node, key);
+ return elem ? meta_prop{*ctx, *elem} : meta_prop{};
+ }
+
+ /*! @copydoc meta_data::traits */
+ template<typename Type>
+ [[nodiscard]] Type traits() const noexcept {
+ return internal::meta_to_user_traits<Type>(node.traits);
+ }
+
+ /*! @copydoc meta_data::custom */
+ [[nodiscard]] meta_custom custom() const noexcept {
+ return {node.custom};
+ }
+
+ /**
+ * @brief Returns true if an object is valid, false otherwise.
+ * @return True if the object is valid, false otherwise.
+ */
+ [[nodiscard]] explicit operator bool() const noexcept {
+ return !(ctx == nullptr);
+ }
+
+ /*! @copydoc meta_prop::operator== */
+ [[nodiscard]] bool operator==(const meta_type &other) const noexcept {
+ return (ctx == other.ctx) && ((!node.info && !other.node.info) || (node.info && other.node.info && *node.info == *other.node.info));
+ }
+
+private:
+ internal::meta_type_node node{};
+ const meta_ctx *ctx{};
+};
+
+/**
+ * @brief Checks if two objects refer to the same type.
+ * @param lhs An object, either valid or not.
+ * @param rhs An object, either valid or not.
+ * @return False if the objects refer to the same node, true otherwise.
+ */
+[[nodiscard]] inline bool operator!=(const meta_type &lhs, const meta_type &rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+[[nodiscard]] inline meta_type meta_any::type() const noexcept {
+ return node.info ? meta_type{*ctx, node} : meta_type{};
+}
+
+template<typename... Args>
+// NOLINTNEXTLINE(modernize-use-nodiscard)
+meta_any meta_any::invoke(const id_type id, Args &&...args) const {
+ return type().invoke(id, *this, std::forward<Args>(args)...);
+}
+
+template<typename... Args>
+meta_any meta_any::invoke(const id_type id, Args &&...args) {
+ return type().invoke(id, *this, std::forward<Args>(args)...);
+}
+
+template<typename Type>
+bool meta_any::set(const id_type id, Type &&value) {
+ return type().set(id, *this, std::forward<Type>(value));
+}
+
+[[nodiscard]] inline meta_any meta_any::get(const id_type id) const {
+ return type().get(id, *this);
+}
+
+[[nodiscard]] inline meta_any meta_any::get(const id_type id) {
+ return type().get(id, *this);
+}
+
+[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const {
+ return internal::try_convert(internal::meta_context::from(*ctx), node, type.info(), type.is_arithmetic() || type.is_enum(), data(), [this, &type]([[maybe_unused]] const void *instance, auto &&...args) {
+ if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, internal::meta_type_node> || ...)) {
+ return (args.from_void(*ctx, nullptr, instance), ...);
+ } else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, internal::meta_conv_node> || ...)) {
+ return (args.conv(*ctx, instance), ...);
+ } else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, decltype(internal::meta_type_node::conversion_helper)> || ...)) {
+ // exploits the fact that arithmetic types and enums are also default constructible
+ auto other = type.construct();
+ const auto value = (args(nullptr, instance), ...);
+ other.node.conversion_helper(other.data(), &value);
+ return other;
+ } else {
+ // forwards to force a compile-time error in case of available arguments
+ return meta_any{meta_ctx_arg, *ctx, std::forward<decltype(args)>(args)...};
+ }
+ });
+}
+
+inline bool meta_any::assign(const meta_any &other) {
+ auto value = other.allow_cast({*ctx, node});
+ return value && storage.assign(value.storage);
+}
+
+inline bool meta_any::assign(meta_any &&other) {
+ if(*node.info == *other.node.info) {
+ return storage.assign(std::move(other.storage));
+ }
+
+ return assign(std::as_const(other));
+}
+
+[[nodiscard]] inline meta_type meta_data::type() const noexcept {
+ return meta_type{*ctx, node->type(internal::meta_context::from(*ctx))};
+}
+
+[[nodiscard]] inline meta_type meta_data::arg(const size_type index) const noexcept {
+ return index < arity() ? node->arg(*ctx, index) : meta_type{};
+}
+
+[[nodiscard]] inline meta_type meta_func::ret() const noexcept {
+ return meta_type{*ctx, node->ret(internal::meta_context::from(*ctx))};
+}
+
+[[nodiscard]] inline meta_type meta_func::arg(const size_type index) const noexcept {
+ return index < arity() ? node->arg(*ctx, index) : meta_type{};
+}
+
+/*! @cond TURN_OFF_DOXYGEN */
+class meta_sequence_container::meta_iterator final {
+ using vtable_type = void(const void *, const std::ptrdiff_t, meta_any *);
+
+ template<typename It>
+ static void basic_vtable(const void *value, const std::ptrdiff_t offset, meta_any *other) {
+ const auto &it = *static_cast<const It *>(value);
+ other ? other->emplace<decltype(*it)>(*it) : std::advance(const_cast<It &>(it), offset);
+ }
+
+public:
+ using value_type = meta_any;
+ using pointer = input_iterator_pointer<value_type>;
+ using reference = value_type;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category = std::input_iterator_tag;
+ using iterator_concept = std::bidirectional_iterator_tag;
+
+ meta_iterator() = default;
+
+ template<typename It>
+ meta_iterator(const meta_ctx &area, It iter) noexcept
+ : ctx{&area},
+ vtable{&basic_vtable<It>},
+ handle{iter} {}
+
+ meta_iterator &operator++() noexcept {
+ vtable(handle.data(), 1, nullptr);
+ return *this;
+ }
+
+ meta_iterator operator++(int value) noexcept {
+ meta_iterator orig = *this;
+ vtable(handle.data(), ++value, nullptr);
+ return orig;
+ }
+
+ meta_iterator &operator--() noexcept {
+ vtable(handle.data(), -1, nullptr);
+ return *this;
+ }
+
+ meta_iterator operator--(int value) noexcept {
+ meta_iterator orig = *this;
+ vtable(handle.data(), --value, nullptr);
+ return orig;
+ }
+
+ [[nodiscard]] reference operator*() const {
+ reference other{meta_ctx_arg, *ctx};
+ vtable(handle.data(), 0, &other);
+ return other;
+ }
+
+ [[nodiscard]] pointer operator->() const {
+ return operator*();
+ }
+
+ [[nodiscard]] explicit operator bool() const noexcept {
+ return static_cast<bool>(handle);
+ }
+
+ [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept {
+ return handle == other.handle;
+ }
+
+ [[nodiscard]] bool operator!=(const meta_iterator &other) const noexcept {
+ return !(*this == other);
+ }
+
+ [[nodiscard]] const any &base() const noexcept {
+ return handle;
+ }
+
+private:
+ const meta_ctx *ctx{&locator<meta_ctx>::value_or()};
+ vtable_type *vtable{};
+ any handle{};
+};
+
+class meta_associative_container::meta_iterator final {
+ using vtable_type = void(const void *, std::pair<meta_any, meta_any> *);
+
+ template<bool KeyOnly, typename It>
+ static void basic_vtable(const void *value, std::pair<meta_any, meta_any> *other) {
+ if(const auto &it = *static_cast<const It *>(value); other) {
+ if constexpr(KeyOnly) {
+ other->first.emplace<decltype(*it)>(*it);
+ } else {
+ other->first.emplace<decltype((it->first))>(it->first);
+ other->second.emplace<decltype((it->second))>(it->second);
+ }
+ } else {
+ ++const_cast<It &>(it);
+ }
+ }
+
+public:
+ using value_type = std::pair<meta_any, meta_any>;
+ using pointer = input_iterator_pointer<value_type>;
+ using reference = value_type;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category = std::input_iterator_tag;
+ using iterator_concept = std::forward_iterator_tag;
+
+ meta_iterator() = default;
+
+ template<bool KeyOnly, typename It>
+ meta_iterator(const meta_ctx &area, std::bool_constant<KeyOnly>, It iter) noexcept
+ : ctx{&area},
+ vtable{&basic_vtable<KeyOnly, It>},
+ handle{iter} {}
+
+ meta_iterator &operator++() noexcept {
+ vtable(handle.data(), nullptr);
+ return *this;
+ }
+
+ meta_iterator operator++(int) noexcept {
+ meta_iterator orig = *this;
+ vtable(handle.data(), nullptr);
+ return orig;
+ }
+
+ [[nodiscard]] reference operator*() const {
+ reference other{{meta_ctx_arg, *ctx}, {meta_ctx_arg, *ctx}};
+ vtable(handle.data(), &other);
+ return other;
+ }
+
+ [[nodiscard]] pointer operator->() const {
+ return operator*();
+ }
+
+ [[nodiscard]] explicit operator bool() const noexcept {
+ return static_cast<bool>(handle);
+ }
+
+ [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept {
+ return handle == other.handle;
+ }
+
+ [[nodiscard]] bool operator!=(const meta_iterator &other) const noexcept {
+ return !(*this == other);
+ }
+
+private:
+ const meta_ctx *ctx{&locator<meta_ctx>::value_or()};
+ vtable_type *vtable{};
+ any handle{};
+};
+/*! @endcond */
+
+/**
+ * @brief Returns the meta value type of a container.
+ * @return The meta value type of the container.
+ */
+[[nodiscard]] inline meta_type meta_sequence_container::value_type() const noexcept {
+ return value_type_node ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{};
+}
+
+/**
+ * @brief Returns the size of a container.
+ * @return The size of the container.
+ */
+[[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const noexcept {
+ return size_fn(data);
+}
+
+/**
+ * @brief Resizes a container to contain a given number of elements.
+ * @param sz The new size of the container.
+ * @return True in case of success, false otherwise.
+ */
+inline bool meta_sequence_container::resize(const size_type sz) {
+ return !const_only && resize_fn(const_cast<void *>(data), sz);
+}
+
+/**
+ * @brief Clears the content of a container.
+ * @return True in case of success, false otherwise.
+ */
+inline bool meta_sequence_container::clear() {
+ return !const_only && clear_fn(const_cast<void *>(data));
+}
+
+/**
+ * @brief Reserves storage for at least the given number of elements.
+ * @param sz The new capacity of the container.
+ * @return True in case of success, false otherwise.
+ */
+inline bool meta_sequence_container::reserve(const size_type sz) {
+ return !const_only && reserve_fn(const_cast<void *>(data), sz);
+}
+
+/**
+ * @brief Returns an iterator to the first element of a container.
+ * @return An iterator to the first element of the container.
+ */
+[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() {
+ return begin_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
+}
+
+/**
+ * @brief Returns an iterator that is past the last element of a container.
+ * @return An iterator that is past the last element of the container.
+ */
+[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() {
+ return end_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
+}
+
+/**
+ * @brief Inserts an element at a specified location of a container.
+ * @param it Iterator before which the element will be inserted.
+ * @param value Element value to insert.
+ * @return A possibly invalid iterator to the inserted element.
+ */
+inline meta_sequence_container::iterator meta_sequence_container::insert(const iterator &it, meta_any value) {
+ // this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
+ if(const auto vtype = value_type_node(internal::meta_context::from(*ctx)); !const_only && (value.allow_cast({*ctx, vtype}) || value.allow_cast({*ctx, const_reference_node(internal::meta_context::from(*ctx))}))) {
+ const bool is_value_type = (value.type().info() == *vtype.info);
+ return insert_fn(*ctx, const_cast<void *>(data), is_value_type ? std::as_const(value).data() : nullptr, is_value_type ? nullptr : std::as_const(value).data(), it);
+ }
+
+ return iterator{};
+}
+
+/**
+ * @brief Removes a given element from a container.
+ * @param it Iterator to the element to remove.
+ * @return A possibly invalid iterator following the last removed element.
+ */
+inline meta_sequence_container::iterator meta_sequence_container::erase(const iterator &it) {
+ return const_only ? iterator{} : erase_fn(*ctx, const_cast<void *>(data), it);
+}
+
+/**
+ * @brief Returns a reference to the element at a given location of a container.
+ * @param pos The position of the element to return.
+ * @return A reference to the requested element properly wrapped.
+ */
+[[nodiscard]] inline meta_any meta_sequence_container::operator[](const size_type pos) {
+ auto it = begin();
+ it.operator++(static_cast<int>(pos) - 1);
+ return *it;
+}
+
+/**
+ * @brief Returns false if a proxy is invalid, true otherwise.
+ * @return False if the proxy is invalid, true otherwise.
+ */
+[[nodiscard]] inline meta_sequence_container::operator bool() const noexcept {
+ return (data != nullptr);
+}
+
+/**
+ * @brief Returns the meta key type of a container.
+ * @return The meta key type of the a container.
+ */
+[[nodiscard]] inline meta_type meta_associative_container::key_type() const noexcept {
+ return key_type_node ? meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))} : meta_type{};
+}
+
+/**
+ * @brief Returns the meta mapped type of a container.
+ * @return The meta mapped type of the a container.
+ */
+[[nodiscard]] inline meta_type meta_associative_container::mapped_type() const noexcept {
+ return mapped_type_node ? meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))} : meta_type{};
+}
+
+/*! @copydoc meta_sequence_container::value_type */
+[[nodiscard]] inline meta_type meta_associative_container::value_type() const noexcept {
+ return value_type_node ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{};
+}
+
+/*! @copydoc meta_sequence_container::size */
+[[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const noexcept {
+ return size_fn(data);
+}
+
+/*! @copydoc meta_sequence_container::clear */
+inline bool meta_associative_container::clear() {
+ return !const_only && clear_fn(const_cast<void *>(data));
+}
+
+/*! @copydoc meta_sequence_container::reserve */
+inline bool meta_associative_container::reserve(const size_type sz) {
+ return !const_only && reserve_fn(const_cast<void *>(data), sz);
+}
+
+/*! @copydoc meta_sequence_container::begin */
+[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() {
+ return begin_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
+}
+
+/*! @copydoc meta_sequence_container::end */
+[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() {
+ return end_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
+}
+
+/**
+ * @brief Inserts a key-only or key/value element into a container.
+ * @param key The key of the element to insert.
+ * @param value The value of the element to insert, if needed.
+ * @return A bool denoting whether the insertion took place.
+ */
+inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) {
+ return !const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})
+ && (!mapped_type_node || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))}))
+ && insert_fn(const_cast<void *>(data), std::as_const(key).data(), std::as_const(value).data());
+}
+
+/**
+ * @brief Removes the specified element from a container.
+ * @param key The key of the element to remove.
+ * @return A bool denoting whether the removal took place.
+ */
+inline meta_associative_container::size_type meta_associative_container::erase(meta_any key) {
+ return (!const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(const_cast<void *>(data), std::as_const(key).data()) : 0u;
+}
+
+/**
+ * @brief Returns an iterator to the element with a given key, if any.
+ * @param key The key of the element to search.
+ * @return An iterator to the element with the given key, if any.
+ */
+[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) {
+ return key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) ? find_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data, std::as_const(key).data()) : iterator{};
+}
+
+/**
+ * @brief Returns false if a proxy is invalid, true otherwise.
+ * @return False if the proxy is invalid, true otherwise.
+ */
+[[nodiscard]] inline meta_associative_container::operator bool() const noexcept {
+ return (data != nullptr);
+}
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/node.hpp b/deps/include/entt/meta/node.hpp new file mode 100644 index 0000000..fc680a3 --- /dev/null +++ b/deps/include/entt/meta/node.hpp @@ -0,0 +1,298 @@ +#ifndef ENTT_META_NODE_HPP
+#define ENTT_META_NODE_HPP
+
+#include <cstddef>
+#include <memory>
+#include <type_traits>
+#include <utility>
+#include "../config/config.h"
+#include "../container/dense_map.hpp"
+#include "../core/attribute.h"
+#include "../core/bit.hpp"
+#include "../core/enum.hpp"
+#include "../core/fwd.hpp"
+#include "../core/type_info.hpp"
+#include "../core/type_traits.hpp"
+#include "../core/utility.hpp"
+#include "context.hpp"
+#include "type_traits.hpp"
+
+namespace entt {
+
+class meta_any;
+class meta_type;
+struct meta_handle;
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+enum class meta_traits : std::uint32_t {
+ is_none = 0x0000,
+ is_const = 0x0001,
+ is_static = 0x0002,
+ is_arithmetic = 0x0004,
+ is_integral = 0x0008,
+ is_signed = 0x0010,
+ is_array = 0x0020,
+ is_enum = 0x0040,
+ is_class = 0x0080,
+ is_pointer = 0x0100,
+ is_meta_pointer_like = 0x0200,
+ is_meta_sequence_container = 0x0400,
+ is_meta_associative_container = 0x0800,
+ _user_defined_traits = 0xFFFF,
+ _entt_enum_as_bitmask = 0xFFFF
+};
+
+template<typename Type>
+[[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept {
+ static_assert(std::is_enum_v<Type>, "Invalid enum type");
+ constexpr auto shift = popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
+ return Type{static_cast<std::underlying_type_t<Type>>(static_cast<std::underlying_type_t<meta_traits>>(traits) >> shift)};
+}
+
+template<typename Type>
+[[nodiscard]] auto user_to_meta_traits(const Type value) noexcept {
+ static_assert(std::is_enum_v<Type>, "Invalid enum type");
+ constexpr auto shift = popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
+ const auto traits = static_cast<std::underlying_type_t<internal::meta_traits>>(static_cast<std::underlying_type_t<Type>>(value));
+ ENTT_ASSERT(traits < ((~static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits");
+ return meta_traits{traits << shift};
+}
+
+struct meta_type_node;
+
+struct meta_custom_node {
+ id_type type{};
+ std::shared_ptr<void> value{};
+};
+
+struct meta_prop_node {
+ meta_type_node (*type)(const meta_context &) noexcept {};
+ std::shared_ptr<void> value{};
+};
+
+struct meta_base_node {
+ meta_type_node (*type)(const meta_context &) noexcept {};
+ const void *(*cast)(const void *) noexcept {};
+};
+
+struct meta_conv_node {
+ meta_any (*conv)(const meta_ctx &, const void *){};
+};
+
+struct meta_ctor_node {
+ using size_type = std::size_t;
+
+ size_type arity{0u};
+ meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
+ meta_any (*invoke)(const meta_ctx &, meta_any *const){};
+};
+
+struct meta_dtor_node {
+ void (*dtor)(void *){};
+};
+
+struct meta_data_node {
+ using size_type = std::size_t;
+
+ meta_traits traits{meta_traits::is_none};
+ size_type arity{0u};
+ meta_type_node (*type)(const meta_context &) noexcept {};
+ meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
+ bool (*set)(meta_handle, meta_any){};
+ meta_any (*get)(const meta_ctx &, meta_handle){};
+ meta_custom_node custom{};
+ dense_map<id_type, meta_prop_node, identity> prop{};
+};
+
+struct meta_func_node {
+ using size_type = std::size_t;
+
+ meta_traits traits{meta_traits::is_none};
+ size_type arity{0u};
+ meta_type_node (*ret)(const meta_context &) noexcept {};
+ meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
+ meta_any (*invoke)(const meta_ctx &, meta_handle, meta_any *const){};
+ std::shared_ptr<meta_func_node> next{};
+ meta_custom_node custom{};
+ dense_map<id_type, meta_prop_node, identity> prop{};
+};
+
+struct meta_template_node {
+ using size_type = std::size_t;
+
+ size_type arity{0u};
+ meta_type_node (*type)(const meta_context &) noexcept {};
+ meta_type_node (*arg)(const meta_context &, const size_type) noexcept {};
+};
+
+struct meta_type_descriptor {
+ dense_map<id_type, meta_ctor_node, identity> ctor{};
+ dense_map<id_type, meta_base_node, identity> base{};
+ dense_map<id_type, meta_conv_node, identity> conv{};
+ dense_map<id_type, meta_data_node, identity> data{};
+ dense_map<id_type, meta_func_node, identity> func{};
+ dense_map<id_type, meta_prop_node, identity> prop{};
+};
+
+struct meta_type_node {
+ using size_type = std::size_t;
+
+ const type_info *info{};
+ id_type id{};
+ meta_traits traits{meta_traits::is_none};
+ size_type size_of{0u};
+ meta_type_node (*resolve)(const meta_context &) noexcept {};
+ meta_type_node (*remove_pointer)(const meta_context &) noexcept {};
+ meta_any (*default_constructor)(const meta_ctx &){};
+ double (*conversion_helper)(void *, const void *){};
+ meta_any (*from_void)(const meta_ctx &, void *, const void *){};
+ meta_template_node templ{};
+ meta_dtor_node dtor{};
+ meta_custom_node custom{};
+ std::shared_ptr<meta_type_descriptor> details{};
+};
+
+template<auto Member>
+auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id) {
+ if(node.details) {
+ if(const auto it = (node.details.get()->*Member).find(id); it != (node.details.get()->*Member).cend()) {
+ return &it->second;
+ }
+
+ for(auto &&curr: node.details->base) {
+ if(auto *elem = look_for<Member>(context, curr.second.type(context), id); elem) {
+ return elem;
+ }
+ }
+ }
+
+ return static_cast<typename std::remove_reference_t<decltype(node.details.get()->*Member)>::mapped_type *>(nullptr);
+}
+
+template<typename Type>
+meta_type_node resolve(const meta_context &) noexcept;
+
+template<typename... Args>
+[[nodiscard]] auto meta_arg_node(const meta_context &context, type_list<Args...>, [[maybe_unused]] const std::size_t index) noexcept {
+ [[maybe_unused]] std::size_t pos{};
+ meta_type_node (*value)(const meta_context &) noexcept = nullptr;
+ ((value = (pos++ == index ? &resolve<std::remove_cv_t<std::remove_reference_t<Args>>> : value)), ...);
+ ENTT_ASSERT(value != nullptr, "Out of bounds");
+ return value(context);
+}
+
+[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const meta_type_node &to, const void *instance) noexcept {
+ if(from.info && to.info && *from.info == *to.info) {
+ return instance;
+ }
+
+ if(from.details) {
+ for(auto &&curr: from.details->base) {
+ if(const void *elem = try_cast(context, curr.second.type(context), to, curr.second.cast(instance)); elem) {
+ return elem;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+template<typename Func>
+[[nodiscard]] inline auto try_convert(const meta_context &context, const meta_type_node &from, const type_info &to, const bool arithmetic_or_enum, const void *instance, Func func) {
+ if(from.info && *from.info == to) {
+ return func(instance, from);
+ }
+
+ if(from.details) {
+ if(auto it = from.details->conv.find(to.hash()); it != from.details->conv.cend()) {
+ return func(instance, it->second);
+ }
+
+ for(auto &&curr: from.details->base) {
+ if(auto other = try_convert(context, curr.second.type(context), to, arithmetic_or_enum, curr.second.cast(instance), func); other) {
+ return other;
+ }
+ }
+ }
+
+ if(from.conversion_helper && arithmetic_or_enum) {
+ return func(instance, from.conversion_helper);
+ }
+
+ return func(instance);
+}
+
+[[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
+ const auto it = context.value.find(info.hash());
+ return it != context.value.end() ? &it->second : nullptr;
+}
+
+template<typename Type>
+[[nodiscard]] meta_type_node resolve(const meta_context &context) noexcept {
+ static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
+
+ if(auto *elem = try_resolve(context, type_id<Type>()); elem) {
+ return *elem;
+ }
+
+ meta_type_node node{
+ &type_id<Type>(),
+ type_id<Type>().hash(),
+ (std::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
+ | (std::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
+ | (std::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
+ | (std::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
+ | (std::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
+ | (std::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
+ | (std::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
+ | (is_meta_pointer_like_v<Type> ? meta_traits::is_meta_pointer_like : meta_traits::is_none)
+ | (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_meta_sequence_container : meta_traits::is_none)
+ | (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_meta_associative_container : meta_traits::is_none),
+ size_of_v<Type>,
+ &resolve<Type>,
+ &resolve<std::remove_cv_t<std::remove_pointer_t<Type>>>};
+
+ if constexpr(std::is_default_constructible_v<Type>) {
+ node.default_constructor = +[](const meta_ctx &ctx) {
+ return meta_any{ctx, std::in_place_type<Type>};
+ };
+ }
+
+ if constexpr(std::is_arithmetic_v<Type>) {
+ node.conversion_helper = +[](void *lhs, const void *rhs) {
+ return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(*static_cast<const double *>(rhs))) : static_cast<double>(*static_cast<const Type *>(rhs));
+ };
+ } else if constexpr(std::is_enum_v<Type>) {
+ node.conversion_helper = +[](void *lhs, const void *rhs) {
+ return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(static_cast<std::underlying_type_t<Type>>(*static_cast<const double *>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
+ };
+ }
+
+ if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
+ node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) {
+ if(elem) {
+ return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *static_cast<std::decay_t<Type> *>(elem)};
+ }
+
+ return meta_any{ctx, std::in_place_type<const std::decay_t<Type> &>, *static_cast<const std::decay_t<Type> *>(celem)};
+ };
+ }
+
+ if constexpr(is_complete_v<meta_template_traits<Type>>) {
+ node.templ = meta_template_node{
+ meta_template_traits<Type>::args_type::size,
+ &resolve<typename meta_template_traits<Type>::class_type>,
+ +[](const meta_context &area, const std::size_t index) noexcept { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
+ }
+
+ return node;
+}
+
+} // namespace internal
+/*! @endcond */
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/pointer.hpp b/deps/include/entt/meta/pointer.hpp new file mode 100644 index 0000000..093ce2d --- /dev/null +++ b/deps/include/entt/meta/pointer.hpp @@ -0,0 +1,51 @@ +// IWYU pragma: always_keep
+
+#ifndef ENTT_META_POINTER_HPP
+#define ENTT_META_POINTER_HPP
+
+#include <memory>
+#include <type_traits>
+#include "type_traits.hpp"
+
+namespace entt {
+
+/**
+ * @brief Makes plain pointers pointer-like types for the meta system.
+ * @tparam Type Element type.
+ */
+template<typename Type>
+struct is_meta_pointer_like<Type *>
+ : std::true_type {};
+
+/**
+ * @brief Partial specialization used to reject pointers to arrays.
+ * @tparam Type Type of elements of the array.
+ * @tparam N Number of elements of the array.
+ */
+template<typename Type, std::size_t N>
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
+struct is_meta_pointer_like<Type (*)[N]>
+ : std::false_type {};
+
+/**
+ * @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta
+ * system.
+ * @tparam Type Element type.
+ */
+template<typename Type>
+struct is_meta_pointer_like<std::shared_ptr<Type>>
+ : std::true_type {};
+
+/**
+ * @brief Makes `std::unique_ptr`s of any type pointer-like types for the meta
+ * system.
+ * @tparam Type Element type.
+ * @tparam Args Other arguments.
+ */
+template<typename Type, typename... Args>
+struct is_meta_pointer_like<std::unique_ptr<Type, Args...>>
+ : std::true_type {};
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/policy.hpp b/deps/include/entt/meta/policy.hpp new file mode 100644 index 0000000..2974b89 --- /dev/null +++ b/deps/include/entt/meta/policy.hpp @@ -0,0 +1,58 @@ +#ifndef ENTT_META_POLICY_HPP
+#define ENTT_META_POLICY_HPP
+
+#include <type_traits>
+
+namespace entt {
+
+/*! @brief Empty class type used to request the _as ref_ policy. */
+struct as_ref_t final {
+ /*! @cond TURN_OFF_DOXYGEN */
+ template<typename Type>
+ static constexpr bool value = std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>;
+ /*! @endcond */
+};
+
+/*! @brief Empty class type used to request the _as cref_ policy. */
+struct as_cref_t final {
+ /*! @cond TURN_OFF_DOXYGEN */
+ template<typename Type>
+ static constexpr bool value = std::is_reference_v<Type>;
+ /*! @endcond */
+};
+
+/*! @brief Empty class type used to request the _as-is_ policy. */
+struct as_is_t final {
+ /*! @cond TURN_OFF_DOXYGEN */
+ template<typename>
+ static constexpr bool value = true;
+ /*! @endcond */
+};
+
+/*! @brief Empty class type used to request the _as void_ policy. */
+struct as_void_t final {
+ /*! @cond TURN_OFF_DOXYGEN */
+ template<typename>
+ static constexpr bool value = true;
+ /*! @endcond */
+};
+
+/**
+ * @brief Provides the member constant `value` to true if a type also is a meta
+ * policy, false otherwise.
+ * @tparam Type Type to check.
+ */
+template<typename Type>
+struct is_meta_policy
+ : std::bool_constant<std::is_same_v<Type, as_ref_t> || std::is_same_v<Type, as_cref_t> || std::is_same_v<Type, as_is_t> || std::is_same_v<Type, as_void_t>> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Type to check.
+ */
+template<typename Type>
+inline constexpr bool is_meta_policy_v = is_meta_policy<Type>::value;
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/range.hpp b/deps/include/entt/meta/range.hpp new file mode 100644 index 0000000..96e4664 --- /dev/null +++ b/deps/include/entt/meta/range.hpp @@ -0,0 +1,143 @@ +#ifndef ENTT_META_RANGE_HPP
+#define ENTT_META_RANGE_HPP
+
+#include <cstddef>
+#include <iterator>
+#include <utility>
+#include "../core/fwd.hpp"
+#include "../core/iterator.hpp"
+#include "context.hpp"
+
+namespace entt {
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename Type, typename It>
+struct meta_range_iterator final {
+ using value_type = std::pair<id_type, Type>;
+ using pointer = input_iterator_pointer<value_type>;
+ using reference = value_type;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category = std::input_iterator_tag;
+ using iterator_concept = std::random_access_iterator_tag;
+
+ constexpr meta_range_iterator() noexcept
+ : it{},
+ ctx{} {}
+
+ constexpr meta_range_iterator(const meta_ctx &area, const It iter) noexcept
+ : it{iter},
+ ctx{&area} {}
+
+ constexpr meta_range_iterator &operator++() noexcept {
+ return ++it, *this;
+ }
+
+ constexpr meta_range_iterator operator++(int) noexcept {
+ meta_range_iterator orig = *this;
+ return ++(*this), orig;
+ }
+
+ constexpr meta_range_iterator &operator--() noexcept {
+ return --it, *this;
+ }
+
+ constexpr meta_range_iterator operator--(int) noexcept {
+ meta_range_iterator orig = *this;
+ return operator--(), orig;
+ }
+
+ constexpr meta_range_iterator &operator+=(const difference_type value) noexcept {
+ it += value;
+ return *this;
+ }
+
+ constexpr meta_range_iterator operator+(const difference_type value) const noexcept {
+ meta_range_iterator copy = *this;
+ return (copy += value);
+ }
+
+ constexpr meta_range_iterator &operator-=(const difference_type value) noexcept {
+ return (*this += -value);
+ }
+
+ constexpr meta_range_iterator operator-(const difference_type value) const noexcept {
+ return (*this + -value);
+ }
+
+ [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
+ return {it[value].first, Type{*ctx, it[value].second}};
+ }
+
+ [[nodiscard]] constexpr pointer operator->() const noexcept {
+ return operator*();
+ }
+
+ [[nodiscard]] constexpr reference operator*() const noexcept {
+ return operator[](0);
+ }
+
+ template<typename... Args>
+ friend constexpr std::ptrdiff_t operator-(const meta_range_iterator<Args...> &, const meta_range_iterator<Args...> &) noexcept;
+
+ template<typename... Args>
+ friend constexpr bool operator==(const meta_range_iterator<Args...> &, const meta_range_iterator<Args...> &) noexcept;
+
+ template<typename... Args>
+ friend constexpr bool operator<(const meta_range_iterator<Args...> &, const meta_range_iterator<Args...> &) noexcept;
+
+private:
+ It it;
+ const meta_ctx *ctx;
+};
+
+template<typename... Args>
+[[nodiscard]] constexpr std::ptrdiff_t operator-(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
+ return lhs.it - rhs.it;
+}
+
+template<typename... Args>
+[[nodiscard]] constexpr bool operator==(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
+ return lhs.it == rhs.it;
+}
+
+template<typename... Args>
+[[nodiscard]] constexpr bool operator!=(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+template<typename... Args>
+[[nodiscard]] constexpr bool operator<(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
+ return lhs.it < rhs.it;
+}
+
+template<typename... Args>
+[[nodiscard]] constexpr bool operator>(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
+ return rhs < lhs;
+}
+
+template<typename... Args>
+[[nodiscard]] constexpr bool operator<=(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
+ return !(lhs > rhs);
+}
+
+template<typename... Args>
+[[nodiscard]] constexpr bool operator>=(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
+ return !(lhs < rhs);
+}
+
+} // namespace internal
+/*! @endcond */
+
+/**
+ * @brief Iterable range to use to iterate all types of meta objects.
+ * @tparam Type Type of meta objects returned.
+ * @tparam It Type of forward iterator.
+ */
+template<typename Type, typename It>
+using meta_range = iterable_adaptor<internal::meta_range_iterator<Type, It>>;
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/resolve.hpp b/deps/include/entt/meta/resolve.hpp new file mode 100644 index 0000000..a9f2f93 --- /dev/null +++ b/deps/include/entt/meta/resolve.hpp @@ -0,0 +1,102 @@ +#ifndef ENTT_META_RESOLVE_HPP
+#define ENTT_META_RESOLVE_HPP
+
+#include <type_traits>
+#include "../core/type_info.hpp"
+#include "../locator/locator.hpp"
+#include "context.hpp"
+#include "meta.hpp"
+#include "node.hpp"
+#include "range.hpp"
+
+namespace entt {
+
+/**
+ * @brief Returns the meta type associated with a given type.
+ * @tparam Type Type to use to search for a meta type.
+ * @param ctx The context from which to search for meta types.
+ * @return The meta type associated with the given type, if any.
+ */
+template<typename Type>
+[[nodiscard]] meta_type resolve(const meta_ctx &ctx) noexcept {
+ auto &&context = internal::meta_context::from(ctx);
+ return {ctx, internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(context)};
+}
+
+/**
+ * @brief Returns the meta type associated with a given type.
+ * @tparam Type Type to use to search for a meta type.
+ * @return The meta type associated with the given type, if any.
+ */
+template<typename Type>
+[[nodiscard]] meta_type resolve() noexcept {
+ return resolve<Type>(locator<meta_ctx>::value_or());
+}
+
+/**
+ * @brief Returns a range to use to visit all meta types.
+ * @param ctx The context from which to search for meta types.
+ * @return An iterable range to use to visit all meta types.
+ */
+[[nodiscard]] inline meta_range<meta_type, typename decltype(internal::meta_context::value)::const_iterator> resolve(const meta_ctx &ctx) noexcept {
+ auto &&context = internal::meta_context::from(ctx);
+ return {{ctx, context.value.cbegin()}, {ctx, context.value.cend()}};
+}
+
+/**
+ * @brief Returns a range to use to visit all meta types.
+ * @return An iterable range to use to visit all meta types.
+ */
+[[nodiscard]] inline meta_range<meta_type, typename decltype(internal::meta_context::value)::const_iterator> resolve() noexcept {
+ return resolve(locator<meta_ctx>::value_or());
+}
+
+/**
+ * @brief Returns the meta type associated with a given identifier, if any.
+ * @param ctx The context from which to search for meta types.
+ * @param id Unique identifier.
+ * @return The meta type associated with the given identifier, if any.
+ */
+[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const id_type id) noexcept {
+ for(auto &&curr: resolve(ctx)) {
+ if(curr.second.id() == id) {
+ return curr.second;
+ }
+ }
+
+ return meta_type{};
+}
+
+/**
+ * @brief Returns the meta type associated with a given identifier, if any.
+ * @param id Unique identifier.
+ * @return The meta type associated with the given identifier, if any.
+ */
+[[nodiscard]] inline meta_type resolve(const id_type id) noexcept {
+ return resolve(locator<meta_ctx>::value_or(), id);
+}
+
+/**
+ * @brief Returns the meta type associated with a given type info object.
+ * @param ctx The context from which to search for meta types.
+ * @param info The type info object of the requested type.
+ * @return The meta type associated with the given type info object, if any.
+ */
+[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const type_info &info) noexcept {
+ auto &&context = internal::meta_context::from(ctx);
+ const auto *elem = internal::try_resolve(context, info);
+ return elem ? meta_type{ctx, *elem} : meta_type{};
+}
+
+/**
+ * @brief Returns the meta type associated with a given type info object.
+ * @param info The type info object of the requested type.
+ * @return The meta type associated with the given type info object, if any.
+ */
+[[nodiscard]] inline meta_type resolve(const type_info &info) noexcept {
+ return resolve(locator<meta_ctx>::value_or(), info);
+}
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/template.hpp b/deps/include/entt/meta/template.hpp new file mode 100644 index 0000000..a928b06 --- /dev/null +++ b/deps/include/entt/meta/template.hpp @@ -0,0 +1,29 @@ +// IWYU pragma: always_keep
+
+#ifndef ENTT_META_TEMPLATE_HPP
+#define ENTT_META_TEMPLATE_HPP
+
+#include "../core/type_traits.hpp"
+
+namespace entt {
+
+/*! @brief Utility class to disambiguate class templates. */
+template<template<typename...> class>
+struct meta_class_template_tag {};
+
+/**
+ * @brief General purpose traits class for generating meta template information.
+ * @tparam Clazz Type of class template.
+ * @tparam Args Types of template arguments.
+ */
+template<template<typename...> class Clazz, typename... Args>
+struct meta_template_traits<Clazz<Args...>> {
+ /*! @brief Wrapped class template. */
+ using class_type = meta_class_template_tag<Clazz>;
+ /*! @brief List of template arguments. */
+ using args_type = type_list<Args...>;
+};
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/type_traits.hpp b/deps/include/entt/meta/type_traits.hpp new file mode 100644 index 0000000..7164065 --- /dev/null +++ b/deps/include/entt/meta/type_traits.hpp @@ -0,0 +1,54 @@ +#ifndef ENTT_META_TYPE_TRAITS_HPP
+#define ENTT_META_TYPE_TRAITS_HPP
+
+#include <type_traits>
+#include <utility>
+
+namespace entt {
+
+/**
+ * @brief Traits class template to be specialized to enable support for meta
+ * template information.
+ */
+template<typename>
+struct meta_template_traits;
+
+/**
+ * @brief Traits class template to be specialized to enable support for meta
+ * sequence containers.
+ */
+template<typename>
+struct meta_sequence_container_traits;
+
+/**
+ * @brief Traits class template to be specialized to enable support for meta
+ * associative containers.
+ */
+template<typename>
+struct meta_associative_container_traits;
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is a
+ * pointer-like type from the point of view of the meta system, false otherwise.
+ */
+template<typename>
+struct is_meta_pointer_like: std::false_type {};
+
+/**
+ * @brief Partial specialization to ensure that const pointer-like types are
+ * also accepted.
+ * @tparam Type Potentially pointer-like type.
+ */
+template<typename Type>
+struct is_meta_pointer_like<const Type>: is_meta_pointer_like<Type> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Potentially pointer-like type.
+ */
+template<typename Type>
+inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like<Type>::value;
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/meta/utility.hpp b/deps/include/entt/meta/utility.hpp new file mode 100644 index 0000000..613d894 --- /dev/null +++ b/deps/include/entt/meta/utility.hpp @@ -0,0 +1,539 @@ +#ifndef ENTT_META_UTILITY_HPP
+#define ENTT_META_UTILITY_HPP
+
+#include <cstddef>
+#include <functional>
+#include <type_traits>
+#include <utility>
+#include "../core/type_traits.hpp"
+#include "../locator/locator.hpp"
+#include "meta.hpp"
+#include "node.hpp"
+#include "policy.hpp"
+
+namespace entt {
+
+/**
+ * @brief Meta function descriptor traits.
+ * @tparam Ret Function return type.
+ * @tparam Args Function arguments.
+ * @tparam Static Function staticness.
+ * @tparam Const Function constness.
+ */
+template<typename Ret, typename Args, bool Static, bool Const>
+struct meta_function_descriptor_traits {
+ /*! @brief Meta function return type. */
+ using return_type = Ret;
+ /*! @brief Meta function arguments. */
+ using args_type = Args;
+
+ /*! @brief True if the meta function is static, false otherwise. */
+ static constexpr bool is_static = Static;
+ /*! @brief True if the meta function is const, false otherwise. */
+ static constexpr bool is_const = Const;
+};
+
+/*! @brief Primary template isn't defined on purpose. */
+template<typename, typename>
+struct meta_function_descriptor;
+
+/**
+ * @brief Meta function descriptor.
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Ret Function return type.
+ * @tparam Class Actual owner of the member function.
+ * @tparam Args Function arguments.
+ */
+template<typename Type, typename Ret, typename Class, typename... Args>
+struct meta_function_descriptor<Type, Ret (Class::*)(Args...) const>
+ : meta_function_descriptor_traits<
+ Ret,
+ std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<const Class &, Args...>>,
+ !std::is_base_of_v<Class, Type>,
+ true> {};
+
+/**
+ * @brief Meta function descriptor.
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Ret Function return type.
+ * @tparam Class Actual owner of the member function.
+ * @tparam Args Function arguments.
+ */
+template<typename Type, typename Ret, typename Class, typename... Args>
+struct meta_function_descriptor<Type, Ret (Class::*)(Args...)>
+ : meta_function_descriptor_traits<
+ Ret,
+ std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<Class &, Args...>>,
+ !std::is_base_of_v<Class, Type>,
+ false> {};
+
+/**
+ * @brief Meta function descriptor.
+ * @tparam Type Reflected type to which the meta data is associated.
+ * @tparam Class Actual owner of the data member.
+ * @tparam Ret Data member type.
+ */
+template<typename Type, typename Ret, typename Class>
+struct meta_function_descriptor<Type, Ret Class::*>
+ : meta_function_descriptor_traits<
+ Ret &,
+ std::conditional_t<std::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>,
+ !std::is_base_of_v<Class, Type>,
+ false> {};
+
+/**
+ * @brief Meta function descriptor.
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Ret Function return type.
+ * @tparam MaybeType First function argument.
+ * @tparam Args Other function arguments.
+ */
+template<typename Type, typename Ret, typename MaybeType, typename... Args>
+struct meta_function_descriptor<Type, Ret (*)(MaybeType, Args...)>
+ : meta_function_descriptor_traits<
+ Ret,
+ std::conditional_t<
+ std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>,
+ type_list<Args...>,
+ type_list<MaybeType, Args...>>,
+ !(std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>),
+ std::is_const_v<std::remove_reference_t<MaybeType>> && (std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>)> {};
+
+/**
+ * @brief Meta function descriptor.
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Ret Function return type.
+ */
+template<typename Type, typename Ret>
+struct meta_function_descriptor<Type, Ret (*)()>
+ : meta_function_descriptor_traits<
+ Ret,
+ type_list<>,
+ true,
+ false> {};
+
+/**
+ * @brief Meta function helper.
+ *
+ * Converts a function type to be associated with a reflected type into its meta
+ * function descriptor.
+ *
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Candidate The actual function to associate with the reflected type.
+ */
+template<typename Type, typename Candidate>
+class meta_function_helper {
+ template<typename Ret, typename... Args, typename Class>
+ static constexpr meta_function_descriptor<Type, Ret (Class::*)(Args...) const> get_rid_of_noexcept(Ret (Class::*)(Args...) const);
+
+ template<typename Ret, typename... Args, typename Class>
+ static constexpr meta_function_descriptor<Type, Ret (Class::*)(Args...)> get_rid_of_noexcept(Ret (Class::*)(Args...));
+
+ template<typename Ret, typename Class>
+ static constexpr meta_function_descriptor<Type, Ret Class::*> get_rid_of_noexcept(Ret Class::*);
+
+ template<typename Ret, typename... Args>
+ static constexpr meta_function_descriptor<Type, Ret (*)(Args...)> get_rid_of_noexcept(Ret (*)(Args...));
+
+ template<typename Class>
+ static constexpr meta_function_descriptor<Class, decltype(&Class::operator())> get_rid_of_noexcept(Class);
+
+public:
+ /*! @brief The meta function descriptor of the given function. */
+ using type = decltype(get_rid_of_noexcept(std::declval<Candidate>()));
+};
+
+/**
+ * @brief Helper type.
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Candidate The actual function to associate with the reflected type.
+ */
+template<typename Type, typename Candidate>
+using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::type;
+
+/**
+ * @brief Wraps a value depending on the given policy.
+ *
+ * This function always returns a wrapped value in the requested context.<br/>
+ * Therefore, if the passed value is itself a wrapped object with a different
+ * context, it undergoes a rebinding to the requested context.
+ *
+ * @tparam Policy Optional policy (no policy set by default).
+ * @tparam Type Type of value to wrap.
+ * @param ctx The context from which to search for meta types.
+ * @param value Value to wrap.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Policy = as_is_t, typename Type>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
+ if constexpr(std::is_same_v<Policy, as_void_t>) {
+ return meta_any{ctx, std::in_place_type<void>};
+ } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
+ return meta_any{ctx, std::in_place_type<Type>, value};
+ } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
+ static_assert(std::is_lvalue_reference_v<Type>, "Invalid type");
+ return meta_any{ctx, std::in_place_type<const std::remove_reference_t<Type> &>, std::as_const(value)};
+ } else {
+ return meta_any{ctx, std::forward<Type>(value)};
+ }
+}
+
+/**
+ * @brief Wraps a value depending on the given policy.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @tparam Type Type of value to wrap.
+ * @param value Value to wrap.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Policy = as_is_t, typename Type>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(Type &&value) {
+ return meta_dispatch<Policy, Type>(locator<meta_ctx>::value_or(), std::forward<Type>(value));
+}
+
+/**
+ * @brief Returns the meta type of the i-th element of a list of arguments.
+ * @tparam Type Type list of the actual types of arguments.
+ * @param ctx The context from which to search for meta types.
+ * @param index The index of the element for which to return the meta type.
+ * @return The meta type of the i-th element of the list of arguments.
+ */
+template<typename Type>
+[[nodiscard]] static meta_type meta_arg(const meta_ctx &ctx, const std::size_t index) noexcept {
+ auto &&context = internal::meta_context::from(ctx);
+ return {ctx, internal::meta_arg_node(context, Type{}, index)};
+}
+
+/**
+ * @brief Returns the meta type of the i-th element of a list of arguments.
+ * @tparam Type Type list of the actual types of arguments.
+ * @param index The index of the element for which to return the meta type.
+ * @return The meta type of the i-th element of the list of arguments.
+ */
+template<typename Type>
+[[nodiscard]] static meta_type meta_arg(const std::size_t index) noexcept {
+ return meta_arg<Type>(locator<meta_ctx>::value_or(), index);
+}
+
+/**
+ * @brief Sets the value of a given variable.
+ * @tparam Type Reflected type to which the variable is associated.
+ * @tparam Data The actual variable to set.
+ * @param instance An opaque instance of the underlying type, if required.
+ * @param value Parameter to use to set the variable.
+ * @return True in case of success, false otherwise.
+ */
+template<typename Type, auto Data>
+[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
+ if constexpr(!std::is_same_v<decltype(Data), Type> && !std::is_same_v<decltype(Data), std::nullptr_t>) {
+ if constexpr(std::is_member_function_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
+ using descriptor = meta_function_helper_t<Type, decltype(Data)>;
+ using data_type = type_list_element_t<descriptor::is_static, typename descriptor::args_type>;
+
+ if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
+ std::invoke(Data, *clazz, value.cast<data_type>());
+ return true;
+ }
+ } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
+ using data_type = std::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
+
+ if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
+ if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
+ std::invoke(Data, *clazz) = value.cast<data_type>();
+ return true;
+ }
+ }
+ } else {
+ using data_type = std::remove_reference_t<decltype(*Data)>;
+
+ if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
+ if(value.allow_cast<data_type>()) {
+ *Data = value.cast<data_type>();
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/**
+ * @brief Gets the value of a given variable.
+ *
+ * @warning
+ * The context provided is used only for the return type.<br/>
+ * It's up to the caller to bind the arguments to the right context(s).
+ *
+ * @tparam Type Reflected type to which the variable is associated.
+ * @tparam Data The actual variable to get.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param ctx The context from which to search for meta types.
+ * @param instance An opaque instance of the underlying type, if required.
+ * @return A meta any containing the value of the underlying variable.
+ */
+template<typename Type, auto Data, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_getter(const meta_ctx &ctx, [[maybe_unused]] meta_handle instance) {
+ if constexpr(std::is_member_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
+ if constexpr(!std::is_array_v<std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>>>) {
+ if constexpr(std::is_invocable_v<decltype(Data), Type &>) {
+ if(auto *clazz = instance->try_cast<Type>(); clazz) {
+ return meta_dispatch<Policy>(ctx, std::invoke(Data, *clazz));
+ }
+ }
+
+ if constexpr(std::is_invocable_v<decltype(Data), const Type &>) {
+ if(auto *fallback = instance->try_cast<const Type>(); fallback) {
+ return meta_dispatch<Policy>(ctx, std::invoke(Data, *fallback));
+ }
+ }
+ }
+
+ return meta_any{meta_ctx_arg, ctx};
+ } else if constexpr(std::is_pointer_v<decltype(Data)>) {
+ if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
+ return meta_any{meta_ctx_arg, ctx};
+ } else {
+ return meta_dispatch<Policy>(ctx, *Data);
+ }
+ } else {
+ return meta_dispatch<Policy>(ctx, Data);
+ }
+}
+
+/**
+ * @brief Gets the value of a given variable.
+ * @tparam Type Reflected type to which the variable is associated.
+ * @tparam Data The actual variable to get.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param instance An opaque instance of the underlying type, if required.
+ * @return A meta any containing the value of the underlying variable.
+ */
+template<typename Type, auto Data, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_getter(meta_handle instance) {
+ return meta_getter<Type, Data, Policy>(locator<meta_ctx>::value_or(), std::move(instance));
+}
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename Policy, typename Candidate, typename... Args>
+[[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) {
+ if constexpr(std::is_void_v<decltype(std::invoke(std::forward<Candidate>(candidate), args...))>) {
+ std::invoke(std::forward<Candidate>(candidate), args...);
+ return meta_any{ctx, std::in_place_type<void>};
+ } else {
+ return meta_dispatch<Policy>(ctx, std::invoke(std::forward<Candidate>(candidate), args...));
+ }
+}
+
+template<typename Type, typename Policy, typename Candidate, std::size_t... Index>
+[[nodiscard]] meta_any meta_invoke(const meta_ctx &ctx, [[maybe_unused]] meta_handle instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, std::index_sequence<Index...>) {
+ using descriptor = meta_function_helper_t<Type, std::remove_reference_t<Candidate>>;
+
+ // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
+ if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
+ if(const auto *const clazz = instance->try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
+ return meta_invoke_with_args<Policy>(ctx, std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+ }
+ } else if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
+ if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
+ return meta_invoke_with_args<Policy>(ctx, std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+ }
+ } else {
+ if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
+ return meta_invoke_with_args<Policy>(ctx, std::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+ }
+ }
+ // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+
+ return meta_any{meta_ctx_arg, ctx};
+}
+
+template<typename Type, typename... Args, std::size_t... Index>
+[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, std::index_sequence<Index...>) {
+ // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
+ if(((args + Index)->allow_cast<Args>() && ...)) {
+ return meta_any{ctx, std::in_place_type<Type>, (args + Index)->cast<Args>()...};
+ }
+ // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+
+ return meta_any{meta_ctx_arg, ctx};
+}
+
+} // namespace internal
+/*! @endcond */
+
+/**
+ * @brief Tries to _invoke_ an object given a list of erased parameters.
+ *
+ * @warning
+ * The context provided is used only for the return type.<br/>
+ * It's up to the caller to bind the arguments to the right context(s).
+ *
+ * @tparam Type Reflected type to which the object to _invoke_ is associated.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param ctx The context from which to search for meta types.
+ * @tparam Candidate The type of the actual object to _invoke_.
+ * @param instance An opaque instance of the underlying type, if required.
+ * @param candidate The actual object to _invoke_.
+ * @param args Parameters to use to _invoke_ the object.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Type, typename Policy = as_is_t, typename Candidate>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(const meta_ctx &ctx, meta_handle instance, Candidate &&candidate, meta_any *const args) {
+ return internal::meta_invoke<Type, Policy>(ctx, std::move(instance), std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
+}
+
+/**
+ * @brief Tries to _invoke_ an object given a list of erased parameters.
+ * @tparam Type Reflected type to which the object to _invoke_ is associated.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @tparam Candidate The type of the actual object to _invoke_.
+ * @param instance An opaque instance of the underlying type, if required.
+ * @param candidate The actual object to _invoke_.
+ * @param args Parameters to use to _invoke_ the object.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Type, typename Policy = as_is_t, typename Candidate>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
+ return meta_invoke<Type, Policy>(locator<meta_ctx>::value_or(), std::move(instance), std::forward<Candidate>(candidate), args);
+}
+
+/**
+ * @brief Tries to invoke a function given a list of erased parameters.
+ *
+ * @warning
+ * The context provided is used only for the return type.<br/>
+ * It's up to the caller to bind the arguments to the right context(s).
+ *
+ * @tparam Type Reflected type to which the function is associated.
+ * @tparam Candidate The actual function to invoke.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param ctx The context from which to search for meta types.
+ * @param instance An opaque instance of the underlying type, if required.
+ * @param args Parameters to use to invoke the function.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Type, auto Candidate, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(const meta_ctx &ctx, meta_handle instance, meta_any *const args) {
+ return internal::meta_invoke<Type, Policy>(ctx, std::move(instance), Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
+}
+
+/**
+ * @brief Tries to invoke a function given a list of erased parameters.
+ * @tparam Type Reflected type to which the function is associated.
+ * @tparam Candidate The actual function to invoke.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param instance An opaque instance of the underlying type, if required.
+ * @param args Parameters to use to invoke the function.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Type, auto Candidate, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, meta_any *const args) {
+ return meta_invoke<Type, Candidate, Policy>(locator<meta_ctx>::value_or(), std::move(instance), args);
+}
+
+/**
+ * @brief Tries to construct an instance given a list of erased parameters.
+ *
+ * @warning
+ * The context provided is used only for the return type.<br/>
+ * It's up to the caller to bind the arguments to the right context(s).
+ *
+ * @tparam Type Actual type of the instance to construct.
+ * @tparam Args Types of arguments expected.
+ * @param ctx The context from which to search for meta types.
+ * @param args Parameters to use to construct the instance.
+ * @return A meta any containing the new instance, if any.
+ */
+template<typename Type, typename... Args>
+[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
+ return internal::meta_construct<Type, Args...>(ctx, args, std::index_sequence_for<Args...>{});
+}
+
+/**
+ * @brief Tries to construct an instance given a list of erased parameters.
+ * @tparam Type Actual type of the instance to construct.
+ * @tparam Args Types of arguments expected.
+ * @param args Parameters to use to construct the instance.
+ * @return A meta any containing the new instance, if any.
+ */
+template<typename Type, typename... Args>
+[[nodiscard]] meta_any meta_construct(meta_any *const args) {
+ return meta_construct<Type, Args...>(locator<meta_ctx>::value_or(), args);
+}
+
+/**
+ * @brief Tries to construct an instance given a list of erased parameters.
+ *
+ * @warning
+ * The context provided is used only for the return type.<br/>
+ * It's up to the caller to bind the arguments to the right context(s).
+ *
+ * @tparam Type Reflected type to which the object to _invoke_ is associated.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @tparam Candidate The type of the actual object to _invoke_.
+ * @param ctx The context from which to search for meta types.
+ * @param candidate The actual object to _invoke_.
+ * @param args Parameters to use to _invoke_ the object.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Type, typename Policy = as_is_t, typename Candidate>
+[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) {
+ if constexpr(meta_function_helper_t<Type, Candidate>::is_static || std::is_class_v<std::remove_cv_t<std::remove_reference_t<Candidate>>>) {
+ return internal::meta_invoke<Type, Policy>(ctx, {}, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
+ } else {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
+ return internal::meta_invoke<Type, Policy>(ctx, *args, std::forward<Candidate>(candidate), args + 1u, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
+ }
+}
+
+/**
+ * @brief Tries to construct an instance given a list of erased parameters.
+ * @tparam Type Reflected type to which the object to _invoke_ is associated.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @tparam Candidate The type of the actual object to _invoke_.
+ * @param candidate The actual object to _invoke_.
+ * @param args Parameters to use to _invoke_ the object.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Type, typename Policy = as_is_t, typename Candidate>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(Candidate &&candidate, meta_any *const args) {
+ return meta_construct<Type, Policy>(locator<meta_ctx>::value_or(), std::forward<Candidate>(candidate), args);
+}
+
+/**
+ * @brief Tries to construct an instance given a list of erased parameters.
+ *
+ * @warning
+ * The context provided is used only for the return type.<br/>
+ * It's up to the caller to bind the arguments to the right context(s).
+ *
+ * @tparam Type Reflected type to which the function is associated.
+ * @tparam Candidate The actual function to invoke.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param ctx The context from which to search for meta types.
+ * @param args Parameters to use to invoke the function.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Type, auto Candidate, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(const meta_ctx &ctx, meta_any *const args) {
+ return meta_construct<Type, Policy>(ctx, Candidate, args);
+}
+
+/**
+ * @brief Tries to construct an instance given a list of erased parameters.
+ * @tparam Type Reflected type to which the function is associated.
+ * @tparam Candidate The actual function to invoke.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param args Parameters to use to invoke the function.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Type, auto Candidate, typename Policy = as_is_t>
+[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(meta_any *const args) {
+ return meta_construct<Type, Candidate, Policy>(locator<meta_ctx>::value_or(), args);
+}
+
+} // namespace entt
+
+#endif
|
