diff --git a/src/entt/entt.hpp b/src/entt/entt.hpp index 8e0eca81f..692236767 100644 --- a/src/entt/entt.hpp +++ b/src/entt/entt.hpp @@ -24,6 +24,7 @@ #include "meta/factory.hpp" #include "meta/internal.hpp" #include "meta/meta.hpp" +#include "meta/range.hpp" #include "meta/resolve.hpp" #include "meta/policy.hpp" #include "process/process.hpp" diff --git a/src/entt/meta/internal.hpp b/src/entt/meta/internal.hpp index 8bfa991bd..ec0cf823c 100644 --- a/src/entt/meta/internal.hpp +++ b/src/entt/meta/internal.hpp @@ -211,18 +211,6 @@ private: }; -template -void visit(Op &op, const internal::meta_type_node *node) { - for(auto &&curr: meta_range{node->*Member}) { - op(Type{&curr}); - } - - for(auto &&base: meta_range{node->base}) { - visit(op, base.type()); - } -} - - template auto find_if(const Op &op, const meta_type_node *node) -> std::decay_t*Member)> { diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index 362c8240d..df26ed29b 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -11,6 +12,7 @@ #include "../core/fwd.hpp" #include "ctx.hpp" #include "internal.hpp" +#include "range.hpp" namespace entt { @@ -431,7 +433,7 @@ struct meta_handle { /*! @copydoc meta_any::operator* */ [[nodiscard]] meta_any operator *() const { - return any; + return *any; } private: @@ -441,11 +443,14 @@ private: /*! @brief Opaque container for meta properties of any type. */ struct meta_prop { + /*! @brief Node type. */ + using node_type = internal::meta_prop_node; + /** * @brief Constructs an instance from a given node. * @param curr The underlying node with which to construct the instance. */ - meta_prop(const internal::meta_prop_node *curr = nullptr) ENTT_NOEXCEPT + meta_prop(const node_type *curr = nullptr) ENTT_NOEXCEPT : node{curr} {} @@ -474,14 +479,17 @@ struct meta_prop { } private: - const internal::meta_prop_node *node; + const node_type *node; }; /*! @brief Opaque container for meta base classes. */ struct meta_base { + /*! @brief Node type. */ + using node_type = internal::meta_base_node; + /*! @copydoc meta_prop::meta_prop */ - meta_base(const internal::meta_base_node *curr = nullptr) ENTT_NOEXCEPT + meta_base(const node_type *curr = nullptr) ENTT_NOEXCEPT : node{curr} {} @@ -512,14 +520,17 @@ struct meta_base { } private: - const internal::meta_base_node *node; + const node_type *node; }; /*! @brief Opaque container for meta conversion functions. */ struct meta_conv { + /*! @brief Node type. */ + using node_type = internal::meta_conv_node; + /*! @copydoc meta_prop::meta_prop */ - meta_conv(const internal::meta_conv_node *curr = nullptr) ENTT_NOEXCEPT + meta_conv(const node_type *curr = nullptr) ENTT_NOEXCEPT : node{curr} {} @@ -547,17 +558,19 @@ struct meta_conv { } private: - const internal::meta_conv_node *node; + const node_type *node; }; /*! @brief Opaque container for meta constructors. */ struct meta_ctor { + /*! @brief Node type. */ + using node_type = internal::meta_ctor_node; /*! @brief Unsigned integer type. */ - using size_type = typename internal::meta_ctor_node::size_type; + using size_type = typename node_type::size_type; /*! @copydoc meta_prop::meta_prop */ - meta_ctor(const internal::meta_ctor_node *curr = nullptr) ENTT_NOEXCEPT + meta_ctor(const node_type *curr = nullptr) ENTT_NOEXCEPT : node{curr} {} @@ -601,15 +614,24 @@ struct meta_ctor { } /** - * @brief Iterates all the properties assigned to a meta constructor. + * @brief Returns a range to use to visit all meta properties. + * @return An iterable range to use to visit all meta properties. + */ + meta_range prop() const ENTT_NOEXCEPT { + return node->prop; + } + + /** + * @brief Iterates all meta properties assigned to a meta constructor. * @tparam Op Type of the function object to invoke. * @param op A valid function object. */ template + [[deprecated("use prop() and entt::meta_range instead")]] std::enable_if_t> prop(Op op) const { - for(auto &&curr: internal::meta_range{node->prop}) { - op(meta_prop{&curr}); + for(auto curr: prop()) { + op(curr); } } @@ -632,14 +654,17 @@ struct meta_ctor { } private: - const internal::meta_ctor_node *node; + const node_type *node; }; /*! @brief Opaque container for meta data. */ struct meta_data { + /*! @brief Node type. */ + using node_type = internal::meta_data_node; + /*! @copydoc meta_prop::meta_prop */ - meta_data(const internal::meta_data_node *curr = nullptr) ENTT_NOEXCEPT + meta_data(const node_type *curr = nullptr) ENTT_NOEXCEPT : node{curr} {} @@ -738,16 +763,22 @@ struct meta_data { return node->get(*instance, index); } + /*! @copydoc meta_ctor::prop */ + meta_range prop() const ENTT_NOEXCEPT { + return node->prop; + } + /** - * @brief Iterates all the properties assigned to a meta data. + * @brief Iterates all meta properties assigned to a meta data. * @tparam Op Type of the function object to invoke. * @param op A valid function object. */ template + [[deprecated("use prop() and entt::meta_range instead")]] std::enable_if_t> prop(Op op) const { - for(auto &&curr: internal::meta_range{node->prop}) { - op(meta_prop{&curr}); + for(auto curr: prop()) { + op(curr); } } @@ -770,17 +801,19 @@ struct meta_data { } private: - const internal::meta_data_node *node; + const node_type *node; }; /*! @brief Opaque container for meta functions. */ struct meta_func { + /*! @brief Node type. */ + using node_type = internal::meta_func_node; /*! @brief Unsigned integer type. */ - using size_type = typename internal::meta_func_node::size_type; + using size_type = typename node_type::size_type; /*! @copydoc meta_prop::meta_prop */ - meta_func(const internal::meta_func_node *curr = nullptr) ENTT_NOEXCEPT + meta_func(const node_type *curr = nullptr) ENTT_NOEXCEPT : node{curr} {} @@ -850,16 +883,22 @@ struct meta_func { return sizeof...(Args) == size() ? node->invoke(arguments[0], &arguments[sizeof...(Args) != 0]) : meta_any{}; } + /*! @copydoc meta_ctor::prop */ + meta_range prop() const ENTT_NOEXCEPT { + return node->prop; + } + /** - * @brief Iterates all the properties assigned to a meta function. + * @brief Iterates all meta properties assigned to a meta function. * @tparam Op Type of the function object to invoke. * @param op A valid function object. */ template + [[deprecated("use prop() and entt::meta_range instead")]] std::enable_if_t> prop(Op op) const { - for(auto &&curr: internal::meta_range{node->prop}) { - op(meta_prop{&curr}); + for(auto curr: prop()) { + op(curr); } } @@ -882,7 +921,7 @@ struct meta_func { } private: - const internal::meta_func_node *node; + const node_type *node; }; @@ -895,18 +934,20 @@ class meta_type { return std::find_if(range.cbegin(), range.cend(), [](const auto &candidate) { return candidate.size == sizeof...(Args) && ([](auto *from, auto *to) { return (from->type_id == to->type_id) - || internal::find_if<&internal::meta_type_node::base>([to](const auto *curr) { return curr->type()->type_id == to->type_id; }, from) - || internal::find_if<&internal::meta_type_node::conv>([to](const auto *curr) { return curr->type()->type_id == to->type_id; }, from); + || internal::find_if<&node_type::base>([to](const auto *curr) { return curr->type()->type_id == to->type_id; }, from) + || internal::find_if<&node_type::conv>([to](const auto *curr) { return curr->type()->type_id == to->type_id; }, from); }(internal::meta_info::resolve(), candidate.arg(Indexes)) && ...); }).operator->(); } public: + /*! @brief Node type. */ + using node_type = internal::meta_type_node; /*! @brief Unsigned integer type. */ - using size_type = typename internal::meta_type_node::size_type; + using size_type = typename node_type::size_type; /*! @copydoc meta_prop::meta_prop */ - meta_type(const internal::meta_type_node *curr = nullptr) ENTT_NOEXCEPT + meta_type(const node_type *curr = nullptr) ENTT_NOEXCEPT : node{curr} {} @@ -1049,15 +1090,27 @@ public: return node->remove_extent(); } + /** + * @brief Returns a range to use to visit top-level meta bases. + * @return An iterable range to use to visit top-level meta bases. + */ + meta_range base() const ENTT_NOEXCEPT { + return node->base; + } + /** * @brief Iterates all the meta bases of a meta type. * @tparam Op Type of the function object to invoke. * @param op A valid function object. */ template + [[deprecated("use base() and entt::meta_range instead")]] std::enable_if_t> base(Op op) const { - internal::visit<&internal::meta_type_node::base, meta_base>(op, node); + for(auto curr: base()) { + curr.type().base(op); + op(curr); + } } /** @@ -1066,19 +1119,36 @@ public: * @return The meta base associated with the given identifier, if any. */ [[nodiscard]] meta_base base(const id_type id) const { - return internal::find_if<&internal::meta_type_node::base>([id](const auto *curr) { + return internal::find_if<&node_type::base>([id](const auto *curr) { return curr->type()->id == id; }, node); } + /** + * @brief Returns a range to use to visit top-level meta conversion + * functions. + * @return An iterable range to use to visit top-level meta conversion + * functions. + */ + meta_range conv() const ENTT_NOEXCEPT { + return node->conv; + } + /** * @brief Iterates all the meta conversion functions of a meta type. * @tparam Op Type of the function object to invoke. * @param op A valid function object. */ template + [[deprecated("use conv() and entt::meta_range instead")]] void conv(Op op) const { - internal::visit<&internal::meta_type_node::conv, meta_conv>(op, node); + for(auto curr: conv()) { + op(curr); + } + + for(auto curr: base()) { + curr.type().conv(op); + } } /** @@ -1089,20 +1159,33 @@ public: */ template [[nodiscard]] meta_conv conv() const { - return internal::find_if<&internal::meta_type_node::conv>([type_id = internal::meta_info::resolve()->type_id](const auto *curr) { + return internal::find_if<&node_type::conv>([type_id = internal::meta_info::resolve()->type_id](const auto *curr) { return curr->type()->type_id == type_id; }, node); } + /** + * @brief Returns a range to use to visit top-level meta constructors. + * @return An iterable range to use to visit top-level meta constructors. + */ + meta_range ctor() const ENTT_NOEXCEPT { + return node->ctor; + } + /** * @brief Iterates all the meta constructors of a meta type. * @tparam Op Type of the function object to invoke. * @param op A valid function object. */ template + [[deprecated("use ctor() and entt::meta_range instead")]] void ctor(Op op) const { - for(auto &&curr: internal::meta_range{node->ctor}) { - op(meta_ctor{&curr}); + for(auto curr: ctor()) { + op(curr); + } + + for(auto curr: base()) { + curr.type().ctor(op); } } @@ -1116,6 +1199,14 @@ public: return ctor(std::index_sequence_for{}); } + /** + * @brief Returns a range to use to visit top-level meta data. + * @return An iterable range to use to visit top-level meta data. + */ + meta_range data() const ENTT_NOEXCEPT { + return node->data; + } + /** * @brief Iterates all the meta data of a meta type. * @@ -1125,9 +1216,16 @@ public: * @param op A valid function object. */ template + [[deprecated("use ctor() and entt::meta_range instead")]] std::enable_if_t> data(Op op) const { - internal::visit<&internal::meta_type_node::data, meta_data>(op, node); + for(auto curr: data()) { + op(curr); + } + + for(auto curr: base()) { + curr.type().data(op); + } } /** @@ -1139,11 +1237,19 @@ public: * @return The meta data associated with the given identifier, if any. */ [[nodiscard]] meta_data data(const id_type id) const { - return internal::find_if<&internal::meta_type_node::data>([id](const auto *curr) { + return internal::find_if<&node_type::data>([id](const auto *curr) { return curr->id == id; }, node); } + /** + * @brief Returns a range to use to visit top-level meta functions. + * @return An iterable range to use to visit top-level meta functions. + */ + meta_range func() const ENTT_NOEXCEPT { + return node->func; + } + /** * @brief Iterates all the meta functions of a meta type. * @@ -1153,9 +1259,16 @@ public: * @param op A valid function object. */ template + [[deprecated("use ctor() and entt::meta_range instead")]] std::enable_if_t> func(Op op) const { - internal::visit<&internal::meta_type_node::func, meta_func>(op, node); + for(auto curr: func()) { + op(curr); + } + + for(auto curr: base()) { + curr.type().func(op); + } } /** @@ -1167,7 +1280,7 @@ public: * @return The meta function associated with the given identifier, if any. */ [[nodiscard]] meta_func func(const id_type id) const { - return internal::find_if<&internal::meta_type_node::func>([id](const auto *curr) { + return internal::find_if<&node_type::func>([id](const auto *curr) { return curr->id == id; }, node); } @@ -1188,7 +1301,7 @@ public: auto construct_if = [this](meta_any *params) { meta_any any{}; - internal::find_if<&internal::meta_type_node::ctor>([params, &any](const auto *curr) { + internal::find_if<&node_type::ctor>([params, &any](const auto *curr) { return (curr->size == sizeof...(args)) && (any = curr->invoke(params)); }, node); @@ -1204,29 +1317,44 @@ public: } /** - * @brief Iterates all the properties assigned to a meta type. + * @brief Returns a range to use to visit top-level meta properties. + * @return An iterable range to use to visit top-level meta properties. + */ + meta_range prop() const ENTT_NOEXCEPT { + return node->prop; + } + + /** + * @brief Iterates all meta properties assigned to a meta type. * - * The properties of the base classes will also be returned, if any. + * Properties of the base classes will also be returned, if any. * * @tparam Op Type of the function object to invoke. * @param op A valid function object. */ template + [[deprecated("use prop() and entt::meta_range instead")]] std::enable_if_t> prop(Op op) const { - internal::visit<&internal::meta_type_node::prop, meta_prop>(op, node); + for(auto curr: prop()) { + op(curr); + } + + for(auto curr: base()) { + curr.type().prop(op); + } } /** * @brief Returns the property associated with a given key. * - * The properties of the base classes will also be visited, if any. + * Properties of the base classes will also be visited, if any. * * @param key The key to use to search for a property. * @return The property associated with the given key, if any. */ [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::find_if<&internal::meta_type_node::prop>([key = std::move(key)](const auto *curr) { + return internal::find_if<&node_type::prop>([key = std::move(key)](const auto *curr) { return curr->key() == key; }, node); } @@ -1255,7 +1383,7 @@ public: } private: - const internal::meta_type_node *node; + const node_type *node; }; diff --git a/src/entt/meta/range.hpp b/src/entt/meta/range.hpp new file mode 100644 index 000000000..45f326a1f --- /dev/null +++ b/src/entt/meta/range.hpp @@ -0,0 +1,132 @@ +#ifndef ENTT_META_RANGE_HPP +#define ENTT_META_RANGE_HPP + + +#include "internal.hpp" + + +namespace entt { + + +/** + * @brief Meta iterator to use to iterate all types of meta objects. + * @tparam Type Type of meta objects returned by the iterator. + */ +template +struct meta_iterator { + /*! @brief Signed integer type. */ + using difference_type = std::ptrdiff_t; + /*! @brief Type of meta objects returned by the iterator. */ + using value_type = Type; + /*! @brief Pointer type, `void` on purpose. */ + using pointer = void; + /*! @brief Type of proxy object. */ + using reference = value_type; + /*! @brief Iterator category. */ + using iterator_category = std::input_iterator_tag; + /*! @brief Node type. */ + using node_type = typename Type::node_type; + + /*! @brief Default constructor. */ + meta_iterator() ENTT_NOEXCEPT = default; + + /** + * @brief Constructs a meta iterator from a given node. + * @param head The underlying node with which to construct the iterator. + */ + meta_iterator(node_type *head) ENTT_NOEXCEPT + : it{head} + {} + + /*! @brief Pre-increment operator. @return This iterator. */ + meta_iterator & operator++() ENTT_NOEXCEPT { + return ++it, *this; + } + + /*! @brief Post-increment operator. @return A copy of this iterator. */ + meta_iterator operator++(int) ENTT_NOEXCEPT { + meta_iterator orig = *this; + return ++it, orig; + } + + /** + * @brief Indirection operator. + * @return A proxy object to the meta item pointed-to by the iterator. + */ + [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { + return it.operator->(); + } + + /** + * @brief Checks if two meta iterators refer to the same meta object. + * @param other The meta iterator with which to compare. + * @return True if the two meta iterators refer to the same meta object, + * false otherwise. + */ + [[nodiscard]] bool operator==(const meta_iterator &other) const ENTT_NOEXCEPT { + return other.it == it; + } + + /** + * @brief Checks if two meta iterators refer to the same meta object. + * @param other The meta iterator with which to compare. + * @return False if the two meta iterators refer to the same meta object, + * true otherwise. + */ + [[nodiscard]] bool operator!=(const meta_iterator &other) const ENTT_NOEXCEPT { + return !(*this == other); + } + +private: + internal::meta_iterator it{}; +}; + + +/** + * @brief Iterable range to use to iterate all types of meta objects. + * @tparam Type Type of meta objects iterated. + */ +template +struct meta_range { + /*! @brief Node type. */ + using node_type = typename Type::node_type; + /*! @brief Input iterator type. */ + using iterator = meta_iterator; + + /*! @brief Default constructor. */ + meta_range() ENTT_NOEXCEPT = default; + + /** + * @brief Constructs a meta range from a given node. + * @param head The underlying node with which to construct the range. + */ + meta_range(node_type *head) + : node{head} + {} + + /** + * @brief Returns an iterator to the beginning. + * @return An iterator to the first meta object of the range. + */ + iterator begin() const ENTT_NOEXCEPT { + return iterator{node}; + } + + /** + * @brief Returns an iterator to the end. + * @return An iterator to the element following the last meta object of the + * range. + */ + iterator end() const ENTT_NOEXCEPT { + return iterator{}; + } + +private: + node_type *node{nullptr}; +}; + + +} + + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8b26ff848..e45462c17 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -184,6 +184,7 @@ SETUP_BASIC_TEST(meta_ctor entt/meta/meta_ctor.cpp) SETUP_BASIC_TEST(meta_data entt/meta/meta_data.cpp) SETUP_BASIC_TEST(meta_func entt/meta/meta_func.cpp) SETUP_BASIC_TEST(meta_prop entt/meta/meta_prop.cpp) +SETUP_BASIC_TEST(meta_range entt/meta/meta_range.cpp) SETUP_BASIC_TEST(meta_type entt/meta/meta_type.cpp) # Test process diff --git a/test/entt/meta/meta_range.cpp b/test/entt/meta/meta_range.cpp new file mode 100644 index 000000000..e37ac7530 --- /dev/null +++ b/test/entt/meta/meta_range.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +struct MetaRange: ::testing::Test { + static void SetUpTestCase() { + entt::meta().type("int"_hs); + entt::meta().type("double"_hs); + } +}; + +TEST_F(MetaRange, Range) { + entt::meta_range range{entt::internal::meta_context::local()}; + auto it = range.begin(); + + ASSERT_NE(it, range.end()); + ASSERT_TRUE(it != range.end()); + ASSERT_FALSE(it == range.end()); + + ASSERT_EQ((*it).type_id(), entt::resolve().type_id()); + ASSERT_EQ((*(++it)).type_id(), entt::resolve_id("int"_hs).type_id()); + ASSERT_EQ((*it++).type_id(), entt::resolve().type_id()); + + ASSERT_EQ(it, range.end()); +} + +TEST_F(MetaRange, EmptyRange) { + entt::meta_range range{}; + ASSERT_EQ(range.begin(), range.end()); +} diff --git a/test/entt/meta/meta_type.cpp b/test/entt/meta/meta_type.cpp index e2271f6ae..a5cc05602 100644 --- a/test/entt/meta/meta_type.cpp +++ b/test/entt/meta/meta_type.cpp @@ -189,7 +189,7 @@ TEST_F(MetaType, Ctor) { }); ASSERT_EQ(counter, 2); - ASSERT_TRUE((type.ctor())); + ASSERT_TRUE((type.ctor<>())); ASSERT_TRUE((type.ctor())); ASSERT_TRUE((type.ctor())); } @@ -376,7 +376,7 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) { ASSERT_EQ(*entt::internal::meta_context::global(), nullptr); ASSERT_FALSE(entt::resolve().prop(property_t::value)); - ASSERT_FALSE(entt::resolve().ctor()); + ASSERT_FALSE(entt::resolve().ctor<>()); ASSERT_FALSE(entt::resolve().data("value"_hs)); ASSERT_FALSE(entt::resolve().func("member"_hs)); diff --git a/test/lib/meta/main.cpp b/test/lib/meta/main.cpp index c68aa7240..d6f6a0408 100644 --- a/test/lib/meta/main.cpp +++ b/test/lib/meta/main.cpp @@ -23,7 +23,7 @@ TEST(Lib, Meta) { ASSERT_EQ(entt::resolve(), entt::resolve_id("velocity"_hs)); auto pos = entt::resolve_id("position"_hs).construct(42., 3.); - auto vel = entt::resolve_id("velocity"_hs).ctor().invoke(); + auto vel = entt::resolve_id("velocity"_hs).ctor<>().invoke(); ASSERT_TRUE(pos && vel); diff --git a/test/lib/meta_plugin/main.cpp b/test/lib/meta_plugin/main.cpp index e43237da4..b3dd51a90 100644 --- a/test/lib/meta_plugin/main.cpp +++ b/test/lib/meta_plugin/main.cpp @@ -23,7 +23,7 @@ TEST(Lib, Meta) { ASSERT_TRUE(entt::resolve_id("velocity"_hs)); auto pos = entt::resolve_id("position"_hs).construct(42., 3.); - auto vel = entt::resolve_id("velocity"_hs).ctor().invoke(); + auto vel = entt::resolve_id("velocity"_hs).ctor<>().invoke(); ASSERT_TRUE(pos && vel); diff --git a/test/lib/meta_plugin_std/main.cpp b/test/lib/meta_plugin_std/main.cpp index e43237da4..b3dd51a90 100644 --- a/test/lib/meta_plugin_std/main.cpp +++ b/test/lib/meta_plugin_std/main.cpp @@ -23,7 +23,7 @@ TEST(Lib, Meta) { ASSERT_TRUE(entt::resolve_id("velocity"_hs)); auto pos = entt::resolve_id("position"_hs).construct(42., 3.); - auto vel = entt::resolve_id("velocity"_hs).ctor().invoke(); + auto vel = entt::resolve_id("velocity"_hs).ctor<>().invoke(); ASSERT_TRUE(pos && vel);