meta: added meta_range and meta_iterator

This commit is contained in:
Michele Caini
2020-06-11 15:27:56 +02:00
parent 252de444fc
commit 9eac3faf3d
10 changed files with 345 additions and 62 deletions

View File

@@ -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"

View File

@@ -211,18 +211,6 @@ private:
};
template<auto Member, typename Type, typename Op>
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<Member, Type>(op, base.type());
}
}
template<auto Member, typename Op>
auto find_if(const Op &op, const meta_type_node *node)
-> std::decay_t<decltype(node->*Member)> {

View File

@@ -4,6 +4,7 @@
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <functional>
#include <type_traits>
#include <utility>
@@ -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<meta_prop> 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<typename Op>
[[deprecated("use prop() and entt::meta_range<meta_prop> instead")]]
std::enable_if_t<std::is_invocable_v<Op, meta_prop>>
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<meta_prop> 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<typename Op>
[[deprecated("use prop() and entt::meta_range<meta_prop> instead")]]
std::enable_if_t<std::is_invocable_v<Op, meta_prop>>
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<meta_prop> 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<typename Op>
[[deprecated("use prop() and entt::meta_range<meta_prop> instead")]]
std::enable_if_t<std::is_invocable_v<Op, meta_prop>>
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<Args>::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<meta_base> 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<typename Op>
[[deprecated("use base() and entt::meta_range<meta_base> instead")]]
std::enable_if_t<std::is_invocable_v<Op, meta_base>>
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<meta_conv> 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<typename Op>
[[deprecated("use conv() and entt::meta_range<meta_conv> 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<typename Type>
[[nodiscard]] meta_conv conv() const {
return internal::find_if<&internal::meta_type_node::conv>([type_id = internal::meta_info<Type>::resolve()->type_id](const auto *curr) {
return internal::find_if<&node_type::conv>([type_id = internal::meta_info<Type>::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<meta_ctor> 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<typename Op>
[[deprecated("use ctor() and entt::meta_range<meta_ctor> 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<Args...>(std::index_sequence_for<Args...>{});
}
/**
* @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<meta_data> 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<typename Op>
[[deprecated("use ctor() and entt::meta_range<meta_ctor> instead")]]
std::enable_if_t<std::is_invocable_v<Op, meta_data>>
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<meta_func> 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<typename Op>
[[deprecated("use ctor() and entt::meta_range<meta_ctor> instead")]]
std::enable_if_t<std::is_invocable_v<Op, meta_func>>
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<meta_prop> 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<typename Op>
[[deprecated("use prop() and entt::meta_range<meta_prop> instead")]]
std::enable_if_t<std::is_invocable_v<Op, meta_prop>>
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;
};

132
src/entt/meta/range.hpp Normal file
View File

@@ -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<typename Type>
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<node_type> it{};
};
/**
* @brief Iterable range to use to iterate all types of meta objects.
* @tparam Type Type of meta objects iterated.
*/
template<typename Type>
struct meta_range {
/*! @brief Node type. */
using node_type = typename Type::node_type;
/*! @brief Input iterator type. */
using iterator = meta_iterator<Type>;
/*! @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

View File

@@ -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

View File

@@ -0,0 +1,33 @@
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
#include <entt/meta/range.hpp>
#include <entt/meta/resolve.hpp>
struct MetaRange: ::testing::Test {
static void SetUpTestCase() {
entt::meta<int>().type("int"_hs);
entt::meta<double>().type("double"_hs);
}
};
TEST_F(MetaRange, Range) {
entt::meta_range<entt::meta_type> 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<double>().type_id());
ASSERT_EQ((*(++it)).type_id(), entt::resolve_id("int"_hs).type_id());
ASSERT_EQ((*it++).type_id(), entt::resolve<int>().type_id());
ASSERT_EQ(it, range.end());
}
TEST_F(MetaRange, EmptyRange) {
entt::meta_range<entt::meta_data> range{};
ASSERT_EQ(range.begin(), range.end());
}

View File

@@ -189,7 +189,7 @@ TEST_F(MetaType, Ctor) {
});
ASSERT_EQ(counter, 2);
ASSERT_TRUE((type.ctor()));
ASSERT_TRUE((type.ctor<>()));
ASSERT_TRUE((type.ctor<const base_t &, int>()));
ASSERT_TRUE((type.ctor<const derived_t &, double>()));
}
@@ -376,7 +376,7 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) {
ASSERT_EQ(*entt::internal::meta_context::global(), nullptr);
ASSERT_FALSE(entt::resolve<clazz_t>().prop(property_t::value));
ASSERT_FALSE(entt::resolve<clazz_t>().ctor());
ASSERT_FALSE(entt::resolve<clazz_t>().ctor<>());
ASSERT_FALSE(entt::resolve<clazz_t>().data("value"_hs));
ASSERT_FALSE(entt::resolve<clazz_t>().func("member"_hs));

View File

@@ -23,7 +23,7 @@ TEST(Lib, Meta) {
ASSERT_EQ(entt::resolve<velocity>(), 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);

View File

@@ -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);

View File

@@ -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);