#ifndef ENTT_META_NODE_HPP #define ENTT_META_NODE_HPP #include "../config/config.h" #include "../core/bit.hpp" #include "../core/concepts.hpp" #include "../core/enum.hpp" #include "../core/fwd.hpp" #include "../core/type_info.hpp" #include "../core/type_traits.hpp" #include "../core/utility.hpp" #include "../stl/array.hpp" #include "../stl/bit.hpp" #include "../stl/cstddef.hpp" #include "../stl/cstdint.hpp" #include "../stl/memory.hpp" #include "../stl/type_traits.hpp" #include "../stl/utility.hpp" #include "../stl/vector.hpp" #include "context.hpp" #include "fwd.hpp" #include "type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { enum class meta_traits : stl::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_pointer_like = 0x0200, is_sequence_container = 0x0400, is_associative_container = 0x0800, _user_defined_traits = 0xFFFF, _entt_enum_as_bitmask = 0xFFFF }; template requires stl::is_enum_v [[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept { constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); return Type{static_cast>(static_cast>(traits) >> shift)}; } template requires stl::is_enum_v [[nodiscard]] auto user_to_meta_traits(const Type value) noexcept { constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); const auto traits = static_cast>(static_cast>(value)); ENTT_ASSERT(traits < ((~static_cast>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits"); return meta_traits{traits << shift}; } struct meta_type_node; struct meta_custom_node { id_type id{}; stl::shared_ptr value{}; }; struct meta_base_node { id_type id{}; const meta_type_node &(*type)(const meta_context &) noexcept {}; const void *(*cast)(const void *) noexcept {}; }; struct meta_conv_node { id_type id{}; meta_any (*conv)(const meta_ctx &, const void *){}; }; struct meta_ctor_node { using size_type = stl::size_t; id_type id{}; 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_data_node { using size_type = stl::size_t; id_type id{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type set_arity{0u}; size_type get_arity{0u}; meta_type (*set_arg)(const meta_ctx &, const size_type) noexcept {}; meta_type (*get_arg)(const meta_ctx &, const size_type) noexcept {}; const meta_type_node &(*type)(const meta_context &) noexcept {}; bool (*set)(meta_handle, meta_any *const){}; meta_any (*get)(meta_handle, meta_any *const){}; meta_custom_node custom{}; }; struct meta_func_node { using size_type = stl::size_t; id_type id{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type arity{0u}; const meta_type_node &(*ret)(const meta_context &) noexcept {}; meta_type (*arg)(const meta_ctx &, const size_type) noexcept {}; meta_any (*invoke)(meta_handle, meta_any *const){}; stl::unique_ptr next; meta_custom_node custom{}; }; struct meta_template_node { using size_type = stl::size_t; size_type arity{0u}; const meta_type_node &(*resolve)(const meta_context &) noexcept {}; const meta_type_node &(*arg)(const meta_context &, const size_type) noexcept {}; }; struct meta_type_descriptor { stl::vector ctor{}; stl::vector base{}; stl::vector conv{}; stl::vector data{}; stl::vector func{}; }; struct meta_type_node { using size_type = stl::size_t; const type_info *info{}; id_type alias{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type size_of{0u}; const 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_custom_node custom{}; stl::unique_ptr details{}; }; template [[nodiscard]] auto *find_member(Type &from, const Value value) { for(auto &&elem: from) { if(elem.id == value) { return &elem; } } return static_cast(nullptr); } [[nodiscard]] inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t *const ref) { while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); } return curr; } template [[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) { using value_type = stl::remove_reference_t*Member))>::value_type; if(node.details) { if(auto *member = find_member((node.details.get()->*Member), id); member != nullptr) { return member; } if(recursive) { for(auto &&curr: node.details->base) { if(auto *elem = look_for(context, curr.type(context), id, recursive); elem) { return elem; } } } } return static_cast(nullptr); } template const meta_type_node &resolve(const meta_context &) noexcept; template [[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list, const stl::size_t index) noexcept { using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept; constexpr stl::array list{&resolve>...}; ENTT_ASSERT(index < sizeof...(Args), "Out of bounds"); return list[index](context); } [[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const id_type to, const void *instance) noexcept { if(from.details) { for(auto &&curr: from.details->base) { if(const void *other = curr.cast(instance); curr.id == to) { return other; } else if(const void *elem = try_cast(context, curr.type(context), to, other); elem) { return elem; } } } return nullptr; } template auto setup_node_for() noexcept { meta_type_node node{ &type_id(), type_id().hash(), nullptr, (stl::is_arithmetic_v ? meta_traits::is_arithmetic : meta_traits::is_none) | (stl::is_integral_v ? meta_traits::is_integral : meta_traits::is_none) | (stl::is_signed_v ? meta_traits::is_signed : meta_traits::is_none) | (stl::is_array_v ? meta_traits::is_array : meta_traits::is_none) | (stl::is_enum_v ? meta_traits::is_enum : meta_traits::is_none) | (stl::is_class_v ? meta_traits::is_class : meta_traits::is_none) | (stl::is_pointer_v ? meta_traits::is_pointer : meta_traits::is_none) | (is_meta_pointer_like_v ? meta_traits::is_pointer_like : meta_traits::is_none) | (is_complete_v> ? meta_traits::is_sequence_container : meta_traits::is_none) | (is_complete_v> ? meta_traits::is_associative_container : meta_traits::is_none), size_of_v, &resolve>>}; if constexpr(stl::is_default_constructible_v) { node.default_constructor = +[](const meta_ctx &ctx) { return meta_any{ctx, stl::in_place_type}; }; } if constexpr(stl::is_arithmetic_v) { node.conversion_helper = +[](void *lhs, const void *rhs) { return lhs ? static_cast(*static_cast(lhs) = static_cast(*static_cast(rhs))) : static_cast(*static_cast(rhs)); }; } else if constexpr(stl::is_enum_v) { node.conversion_helper = +[](void *lhs, const void *rhs) { return lhs ? static_cast(*static_cast(lhs) = static_cast(static_cast>(*static_cast(rhs)))) : static_cast(*static_cast(rhs)); }; } if constexpr(!stl::is_void_v && !stl::is_function_v) { node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) { if(elem && celem) { // ownership construction request return meta_any{ctx, stl::in_place, static_cast *>(elem)}; } if(elem) { // non-const reference construction request return meta_any{ctx, stl::in_place_type &>, *static_cast *>(elem)}; } // const reference construction request return meta_any{ctx, stl::in_place_type &>, *static_cast *>(celem)}; }; } if constexpr(is_complete_v>) { node.templ = meta_template_node{ meta_template_traits::args_type::size, &resolve::class_type>, +[](const meta_context &area, const stl::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits::args_type{}, index); }}; } return node; } template [[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept { static const meta_type_node node = setup_node_for(); const auto it = context.bucket.find(node.info->hash()); return (it == context.bucket.cend()) ? node : *it->second; } } // namespace internal /*! @endcond */ } // namespace entt #endif