diff --git a/TODO b/TODO
index 56cbf8754..14fa2c7ee 100644
--- a/TODO
+++ b/TODO
@@ -15,10 +15,12 @@
- spatial query
- runtime types pool
- off-line/off-memory/remote
- - poly
- ...
WIP:
+* HP: any/meta_any/poly: ::REF -> ::CREF?
+* HP: meta, support for custom deref function other than operator*
+* HP: meta, as_cref_t other than as_ref_t
* HP: headless (sparse set only) view
* HP: pass the registry to pools, basic poly storage should have only component member
* HP: make view pack work also with groups, make packs input iterator only, add view adapter for external sources
@@ -27,6 +29,8 @@ WIP:
* HP: any/poly: configurable sbo size, compile-time policies like sbo-required.
* HP: registry: use a poly object for pools, no more pool_data type.
* HP: make runtime views use opaque storage and therefore return also elements.
+* HP: meta_sequence_container & Co can be replaced by a poly object.
+* HP: poly: support for data members
* suppress warnings in meta.hpp (uninitialized members)
* add exclude-only views to combine with packs
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
diff --git a/docs/md/meta.md b/docs/md/meta.md
index f880e2b52..3077db21b 100644
--- a/docs/md/meta.md
+++ b/docs/md/meta.md
@@ -215,9 +215,9 @@ const bool equal = (any == other);
Also, `meta_any` adds support for containers and pointer-like types (see the
following sections for more details).
Similar to `any`, this class can also be used to create _aliases_ for unmanaged
-objects either upon construction using `std::ref` or from an existing instance
-by means of the `as_ref` function. However, unlike `any`,` meta_any` treats an
-empty instance and one initialized with `void` differently:
+objects either upon construction using `std::ref` and `std::cref` or from an
+existing instance by means of the `as_ref` function. However, unlike `any`,
+`meta_any` treats an empty instance and one initialized with `void` differently:
```cpp
entt::meta_any empty{};
@@ -228,9 +228,10 @@ While `any` treats both objects as empty, `meta_any` treats objects initialized
with `void` as if they were _valid_ ones. This allows to differentiate between
failed function calls and function calls that are successful but return
nothing.
-Finally, the member functions `try_cast`, `cast` and `convert` are used to know
-if the underlying object has a given type as a base or if it can be converted
-implicitly to it. There is in fact no `any_cast` equivalent for `meta_any`.
+Finally, the member functions `try_cast`, `cast` and `allow_cast` are used to
+cast the underlying object to a given type (either a reference or a value type)
+or to _convert_ a `meta_any` in such a way that a cast becomes viable for the
+resulting object. There is in fact no `any_cast` equivalent for `meta_any`.
## Enjoy the runtime
@@ -684,13 +685,14 @@ There are a few alternatives available at the moment:
entt::meta().func<&my_type::member_function, entt::as_void_t>("member"_hs);
```
-* The _as-ref_ policy, associated with the type `entt::as_ref_t`.
- It allows to build wrappers that act as references to unmanaged objects.
- Modifying the object contained in the wrapper for which the _reference_ was
- requested will make it possible to directly modify the instance used to
+* The _as-ref_ and _as-cref_ policies, associated with the types
+ `entt::as_ref_t` and `entt::as_cref_t`.
+ They allow to build wrappers that act as references to unmanaged objects.
+ Accessing the object contained in the wrapper for which the _reference_ was
+ requested will make it possible to directly access the instance used to
initialize the wrapper itself.
- This policy works with constructors (for example, when objects are taken from
- an external container rather than created on demand), data members and
+ These policies work with constructors (for example, when objects are taken
+ from an external container rather than created on demand), data members and
functions in general (as long as their return types are lvalue references).
As an example of use:
diff --git a/src/entt/meta/container.hpp b/src/entt/meta/container.hpp
index f7fc2df66..68ad54997 100644
--- a/src/entt/meta/container.hpp
+++ b/src/entt/meta/container.hpp
@@ -273,12 +273,12 @@ struct fixed_sequence_container {
template
struct meta_sequence_container_traits>
: container_traits<
- std::vector,
- basic_container,
- basic_dynamic_container,
- basic_sequence_container,
- dynamic_sequence_container
- >
+ std::vector,
+ basic_container,
+ basic_dynamic_container,
+ basic_sequence_container,
+ dynamic_sequence_container
+ >
{};
@@ -290,11 +290,11 @@ struct meta_sequence_container_traits>
template
struct meta_sequence_container_traits>
: container_traits<
- std::array,
- basic_container,
- basic_sequence_container,
- fixed_sequence_container
- >
+ std::array,
+ basic_container,
+ basic_sequence_container,
+ fixed_sequence_container
+ >
{};
@@ -307,13 +307,13 @@ struct meta_sequence_container_traits>
template
struct meta_associative_container_traits>
: container_traits<
- std::map,
- basic_container,
- basic_associative_container,
- basic_dynamic_container,
- basic_dynamic_associative_container,
- dynamic_associative_key_value_container
- >
+ std::map,
+ basic_container,
+ basic_associative_container,
+ basic_dynamic_container,
+ basic_dynamic_associative_container,
+ dynamic_associative_key_value_container
+ >
{
/*! @brief Mapped type of the sequence container. */
using mapped_type = typename std::map::mapped_type;
@@ -330,13 +330,13 @@ struct meta_associative_container_traits>
template
struct meta_associative_container_traits>
: container_traits<
- std::unordered_map,
- basic_container,
- basic_associative_container,
- basic_dynamic_container,
- basic_dynamic_associative_container,
- dynamic_associative_key_value_container
- >
+ std::unordered_map,
+ basic_container,
+ basic_associative_container,
+ basic_dynamic_container,
+ basic_dynamic_associative_container,
+ dynamic_associative_key_value_container
+ >
{
/*! @brief Mapped type of the sequence container. */
using mapped_type = typename std::unordered_map::mapped_type;
@@ -351,13 +351,13 @@ struct meta_associative_container_traits
template
struct meta_associative_container_traits>
: container_traits<
- std::set,
- basic_container,
- basic_associative_container,
- basic_dynamic_container,
- basic_dynamic_associative_container,
- dynamic_associative_key_only_container
- >
+ std::set,
+ basic_container,
+ basic_associative_container,
+ basic_dynamic_container,
+ basic_dynamic_associative_container,
+ dynamic_associative_key_only_container
+ >
{};
@@ -370,13 +370,13 @@ struct meta_associative_container_traits>
template
struct meta_associative_container_traits>
: container_traits<
- std::unordered_set,
- basic_container,
- basic_associative_container,
- basic_dynamic_container,
- basic_dynamic_associative_container,
- dynamic_associative_key_only_container
- >
+ std::unordered_set,
+ basic_container,
+ basic_associative_container,
+ basic_dynamic_container,
+ basic_dynamic_associative_container,
+ dynamic_associative_key_only_container
+ >
{};
diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp
index 7daeed99d..c5656c8bb 100644
--- a/src/entt/meta/factory.hpp
+++ b/src/entt/meta/factory.hpp
@@ -35,8 +35,8 @@ struct meta_function_helper;
template
struct meta_function_helper {
- using return_type = std::remove_cv_t>;
- using args_type = std::tuple>...>;
+ using return_type = Ret;
+ using args_type = type_list;
static constexpr auto is_static = Static;
static constexpr auto is_const = Const;
@@ -48,12 +48,12 @@ struct meta_function_helper {
template
-constexpr meta_function_helper, Ret(Args...), Ret(std::add_lvalue_reference_t, Args...)>, true, !std::is_same_v>
+constexpr meta_function_helper, Ret(Args...), Ret(Class &, Args...)>, true, !std::is_same_v>
to_meta_function_helper(Ret(Class:: *)(Args...) const);
template
-constexpr meta_function_helper, Ret(Args...), Ret(std::add_lvalue_reference_t, Args...)>, false, !std::is_same_v>
+constexpr meta_function_helper, Ret(Args...), Ret(Class &, Args...)>, false, !std::is_same_v>
to_meta_function_helper(Ret(Class:: *)(Args...));
@@ -70,12 +70,13 @@ template
using meta_function_helper_t = decltype(to_meta_function_helper(std::declval()));
-template
-[[nodiscard]] meta_any construct(meta_any * const args, std::index_sequence) {
- [[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast()...);
- return ((std::get(direct) || (args+Indexes)->convert()) && ...)
- ? Type{(std::get(direct) ? *std::get(direct) : (args+Indexes)->cast())...}
- : meta_any{};
+template
+[[nodiscard]] meta_any construct(meta_any * const args, std::index_sequence) {
+ if(((args+Index)->allow_cast() && ...)) {
+ return Type{(args+Index)->cast()...};
+ }
+
+ return {};
}
@@ -85,11 +86,11 @@ template
if constexpr(std::is_function_v>> || std::is_member_function_pointer_v) {
using helper_type = meta_function_helper_t;
- using data_type = std::tuple_element_t, typename helper_type::args_type>;
+ using data_type = type_list_element_t, typename helper_type::args_type>;
if(auto * const clazz = instance->try_cast(); clazz) {
- if(auto * const direct = value.try_cast(); direct || value.convert()) {
- std::invoke(Data, *clazz, direct ? *direct : value.cast());
+ if(value.allow_cast()) {
+ std::invoke(Data, *clazz, value.cast());
accepted = true;
}
}
@@ -98,8 +99,8 @@ template
if constexpr(!std::is_array_v) {
if(auto * const clazz = instance->try_cast(); clazz) {
- if(auto * const direct = value.try_cast(); direct || value.convert()) {
- std::invoke(Data, clazz) = (direct ? *direct : value.cast());
+ if(value.allow_cast()) {
+ std::invoke(Data, clazz) = value.cast();
accepted = true;
}
}
@@ -108,8 +109,8 @@ template
using data_type = std::remove_cv_t>;
if constexpr(!std::is_array_v) {
- if(auto * const direct = value.try_cast(); direct || value.convert()) {
- *Data = (direct ? *direct : value.cast());
+ if(value.allow_cast()) {
+ *Data = value.cast();
accepted = true;
}
}
@@ -126,6 +127,8 @@ template
return meta_any{std::in_place_type, std::forward(value)};
} else if constexpr(std::is_same_v) {
return meta_any{std::ref(std::forward(value))};
+ } else if constexpr(std::is_same_v) {
+ return meta_any{std::cref(std::forward(value))};
} else {
static_assert(std::is_same_v, "Policy not supported");
return meta_any{std::forward(value)};
@@ -133,13 +136,13 @@ template
};
if constexpr(std::is_function_v>> || std::is_member_function_pointer_v) {
- auto * const clazz = instance->try_cast();
+ auto * const clazz = instance->try_cast, const Type, Type>>();
return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
} else if constexpr(std::is_member_object_pointer_v) {
if constexpr(std::is_array_v().*Data)>>>) {
return meta_any{};
} else {
- auto * const clazz = instance->try_cast();
+ auto * const clazz = instance->try_cast, Type, const Type>>();
return clazz ? dispatch(std::invoke(Data, clazz)) : meta_any{};
}
} else if constexpr(std::is_pointer_v>) {
@@ -154,38 +157,39 @@ template
}
-template
-[[nodiscard]] meta_any invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence) {
+template
+[[nodiscard]] meta_any invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence) {
using helper_type = meta_function_helper_t;
- auto dispatch = [](auto *... params) {
- if constexpr(std::is_void_v || std::is_same_v) {
- std::invoke(Candidate, *params...);
+ auto dispatch = [](auto &&... params) {
+ if constexpr(std::is_void_v> || std::is_same_v) {
+ std::invoke(Candidate, std::forward(params)...);
return meta_any{std::in_place_type};
} else if constexpr(std::is_same_v) {
- return meta_any{std::ref(std::invoke(Candidate, *params...))};
+ return meta_any{std::ref(std::invoke(Candidate, std::forward(params)...))};
+ } else if constexpr(std::is_same_v) {
+ return meta_any{std::cref(std::invoke(Candidate, std::forward(params)...))};
} else {
static_assert(std::is_same_v, "Policy not supported");
- return meta_any{std::invoke(Candidate, *params...)};
+ return meta_any{std::invoke(Candidate, std::forward(params)...)};
}
};
- [[maybe_unused]] const auto direct = std::make_tuple([](meta_any *any, auto *value) {
- using arg_type = std::remove_reference_t;
-
- if(!value && any->convert()) {
- value = any->try_cast();
+ if constexpr(std::is_invocable_v...>) {
+ if(const auto * const clazz = instance->try_cast(); clazz && ((args+Index)->allow_cast>() && ...)) {
+ return dispatch(*clazz, (args+Index)->cast>()...);
+ }
+ } else if constexpr(std::is_invocable_v...>) {
+ if(auto * const clazz = instance->try_cast(); clazz && ((args+Index)->allow_cast>() && ...)) {
+ return dispatch(*clazz, (args+Index)->cast>()...);
}
-
- return value;
- }(args+Indexes, (args+Indexes)->try_cast>())...);
-
- if constexpr(std::is_invocable_v, std::tuple_element_t...>) {
- auto * const clazz = instance->try_cast();
- return (clazz && (std::get(direct) && ...)) ? dispatch(clazz, std::get(direct)...) : meta_any{};
} else {
- return (std::get(direct) && ...) ? dispatch(std::get(direct)...) : meta_any{};
+ if(((args+Index)->allow_cast>() && ...)) {
+ return dispatch((args+Index)->cast>()...);
+ }
}
+
+ return meta_any{};
}
@@ -469,17 +473,17 @@ public:
template
auto ctor() ENTT_NOEXCEPT {
using helper_type = internal::meta_function_helper_t;
- static_assert(std::is_same_v, "The function doesn't return an object of the required type");
+ static_assert(std::is_same_v>, Type>, "The function doesn't return an object of the required type");
auto * const type = internal::meta_info::resolve();
static internal::meta_ctor_node node{
type,
nullptr,
nullptr,
- std::tuple_size_v,
+ helper_type::args_type::size,
&helper_type::arg,
[](meta_any * const any) {
- return internal::invoke({}, any, std::make_index_sequence>{});
+ return internal::invoke({}, any, std::make_index_sequence{});
}
};
@@ -509,10 +513,10 @@ public:
type,
nullptr,
nullptr,
- std::tuple_size_v,
+ helper_type::args_type::size,
&helper_type::arg,
[](meta_any * const any) {
- return internal::construct>...>(any, std::make_index_sequence>{});
+ return internal::construct(any, std::make_index_sequence{});
}
};
@@ -583,7 +587,7 @@ public:
nullptr,
true,
&internal::meta_info::resolve,
- []() -> std::remove_const_t {
+ []() -> std::remove_cv_t {
if constexpr(std::is_same_v || std::is_const_v) {
return nullptr;
} else {
@@ -635,7 +639,7 @@ public:
nullptr,
false,
&internal::meta_info::resolve,
- []() -> std::remove_const_t {
+ []() -> std::remove_cv_t {
if constexpr(std::is_same_v || (std::is_member_object_pointer_v && std::is_const_v)) {
return nullptr;
} else {
@@ -677,13 +681,13 @@ public:
type,
nullptr,
nullptr,
- std::tuple_size_v,
+ helper_type::args_type::size,
helper_type::is_const,
helper_type::is_static,
&internal::meta_info, void, typename helper_type::return_type>>::resolve,
&helper_type::arg,
[](meta_handle instance, meta_any *args) {
- return internal::invoke(std::move(instance), args, std::make_index_sequence>{});
+ return internal::invoke(std::move(instance), args, std::make_index_sequence{});
}
};
diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp
index fa3916593..76bf8d381 100644
--- a/src/entt/meta/meta.hpp
+++ b/src/entt/meta/meta.hpp
@@ -330,7 +330,7 @@ public:
[[nodiscard]] const Type * try_cast() const {
if(node) {
if(const auto info = internal::meta_info::resolve()->info; node->info == info) {
- return static_cast(storage.data());
+ return any_cast(&storage);
} else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
return static_cast(base->cast(storage.data()));
}
@@ -344,12 +344,12 @@ public:
[[nodiscard]] Type * try_cast() {
if(node) {
if(const auto info = internal::meta_info::resolve()->info; node->info == info) {
- return static_cast(storage.data());
+ return any_cast(&storage);
} else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
- return static_cast(const_cast(base->cast(storage.data())));
+ return static_cast(const_cast *>(base->cast(static_cast &>(storage).data())));
}
}
-
+
return nullptr;
}
@@ -367,7 +367,7 @@ public:
*/
template
[[nodiscard]] Type cast() const {
- auto * const actual = try_cast>>();
+ auto * const actual = try_cast>();
ENTT_ASSERT(actual);
return static_cast(*actual);
}
@@ -375,30 +375,26 @@ public:
/*! @copydoc cast */
template
[[nodiscard]] Type cast() {
- if constexpr(!std::is_reference_v || std::is_const_v>) {
- // last attempt to make wrappers for const references return their values
- auto * const actual = std::as_const(*this).try_cast>>();
- ENTT_ASSERT(actual);
- return static_cast(*actual);
- } else {
- auto * const actual = try_cast>>();
- ENTT_ASSERT(actual);
- return static_cast(*actual);
- }
+ // forces const on non-reference types to make them work also with wrappers for const references
+ auto * const actual = try_cast, std::remove_reference_t, const Type>>();
+ ENTT_ASSERT(actual);
+ return static_cast(*actual);
}
/**
- * @brief Tries to convert an instance to a given type and returns it.
- * @tparam Type Type to which to convert the instance.
- * @return A valid meta any object if the conversion is possible, an invalid
- * one otherwise.
+ * @brief Tries to make an instance castable to a certain type.
+ * @tparam Type Type to which the cast is requested.
+ * @return A valid meta any object if there exists a a viable conversion
+ * that makes the cast possible, an invalid object otherwise.
*/
template
- [[nodiscard]] meta_any convert() const {
- if(node) {
- if(const auto info = internal::meta_info::resolve()->info; node->info == info) {
- return *this;
- } else if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info](const auto *curr) { return curr->type()->info == info; }, node); conv) {
+ [[nodiscard]] meta_any allow_cast() const {
+ if(try_cast>() != nullptr) {
+ return as_ref(*this);
+ } else if(node) {
+ if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info = internal::meta_info::resolve()->info](const auto *curr) {
+ return curr->type()->info == info;
+ }, node); conv) {
return conv->conv(storage.data());
}
}
@@ -407,22 +403,25 @@ public:
}
/**
- * @brief Tries to convert an instance to a given type.
- * @tparam Type Type to which to convert the instance.
- * @return True if the conversion is possible, false otherwise.
+ * @brief Tries to make an instance castable to a certain type.
+ * @tparam Type Type to which the cast is requested.
+ * @return True if there exists a a viable conversion that makes the cast
+ * possible, false otherwise.
*/
template
- bool convert() {
- bool valid = (node && node->info == internal::meta_info::resolve()->info);
-
- if(!valid) {
- if(auto any = std::as_const(*this).convert(); any) {
- swap(any, *this);
- valid = true;
+ bool allow_cast() {
+ if(try_cast, std::remove_reference_t, const Type>>() != nullptr) {
+ return true;
+ } else if(node) {
+ if(const auto * const conv = internal::find_if<&internal::meta_type_node::conv>([info = internal::meta_info::resolve()->info](const auto *curr) {
+ return curr->type()->info == info;
+ }, node); conv) {
+ swap(conv->conv(std::as_const(storage).data()), *this);
+ return true;
}
}
- return valid;
+ return false;
}
/**
@@ -570,6 +569,11 @@ struct meta_handle {
return &any;
}
+ /*! @brief operator-> */
+ [[nodiscard]] const meta_any * operator->() const {
+ return &any;
+ }
+
private:
meta_any any;
};
@@ -1767,8 +1771,8 @@ struct meta_sequence_container::meta_sequence_container_proxy {
}
[[nodiscard]] static std::pair insert(void *container, iterator it, meta_any value) {
- if(const auto *v_ptr = value.try_cast(); v_ptr || value.convert()) {
- auto ret = traits_type::insert(*static_cast(container), it.handle.cast(), v_ptr ? *v_ptr : value.cast());
+ if(value.allow_cast()) {
+ auto ret = traits_type::insert(*static_cast(container), it.handle.cast(), value.cast());
return { iterator{std::move(ret.first)}, ret.second };
}
@@ -2034,12 +2038,12 @@ struct meta_associative_container::meta_associative_container_proxy {
}
[[nodiscard]] static bool insert(void *container, meta_any key, meta_any value) {
- if(const auto *k_ptr = key.try_cast(); k_ptr || key.convert()) {
+ if(key.allow_cast()) {
if constexpr(is_key_only_meta_associative_container_v) {
- return traits_type::insert(*static_cast(container), k_ptr ? *k_ptr : key.cast());
+ return traits_type::insert(*static_cast(container), key.cast());
} else {
- if(const auto *m_ptr = value.try_cast(); m_ptr || value.convert()) {
- return traits_type::insert(*static_cast(container), k_ptr ? *k_ptr : key.cast(), m_ptr ? *m_ptr : value.cast());
+ if(value.allow_cast()) {
+ return traits_type::insert(*static_cast(container), key.cast(), value.cast());
}
}
}
@@ -2048,16 +2052,16 @@ struct meta_associative_container::meta_associative_container_proxy {
}
[[nodiscard]] static bool erase(void *container, meta_any key) {
- if(const auto *k_ptr = key.try_cast(); k_ptr || key.convert()) {
- return traits_type::erase(*static_cast(container), k_ptr ? *k_ptr : key.cast());
+ if(key.allow_cast()) {
+ return traits_type::erase(*static_cast(container), key.cast());
}
return false;
}
[[nodiscard]] static iterator find(void *container, meta_any key) {
- if(const auto *k_ptr = key.try_cast(); k_ptr || key.convert()) {
- return iterator{is_key_only_meta_associative_container{}, traits_type::find(*static_cast