any/meta:

* added alias constructor to any
* added alias constructor to meta_any
* added alias constructor to poly
* added support for const containers, const deref operator and const views to meta_any
This commit is contained in:
Michele Caini
2020-12-21 11:22:49 +01:00
parent 2daaf899d3
commit aa979b2046
9 changed files with 578 additions and 177 deletions

View File

@@ -267,15 +267,22 @@ A particularly interesting feature of this class is that it can also be used as
an opaque container for const and non-const references:
```cpp
int value;
int value = 42;
// reference construction
entt::any any{std::ref(value)};
entt::any cany{std::cref(value)};
// alias construction
int value = 42;
entt::any in_place{std::in_place_type<int &>, &value};
```
In other words, whenever `any` intercepts a `reference_wrapper`, it acts as a
pointer to the original instance rather than making a copy of it or moving it
internally. The _contained_ object is never destroyed and users must ensure that
its lifetime exceeds that of the container.<br/>
In other words, whenever `any` intercepts a `reference_wrapper` or is explicitly
told that users want to construct an alias, it acts as a pointer to the original
instance rather than making a copy of it or moving it internally. The contained
object is never destroyed and users must ensure that its lifetime exceeds that
of the container.<br/>
Similarly, it's possible to create non-owning copies of `any` from an existing
object:

View File

@@ -128,8 +128,7 @@ class any {
public:
/*! @brief Default constructor. */
any() ENTT_NOEXCEPT
: vtable{&basic_vtable<void>},
instance{}
: any{std::in_place_type<void>}
{}
/**
@@ -144,7 +143,11 @@ public:
instance{}
{
if constexpr(!std::is_void_v<Type>) {
if constexpr(in_situ<Type>) {
if constexpr(std::is_lvalue_reference_v<Type>) {
static_assert(sizeof...(Args) == 1u && (std::is_pointer_v<std::remove_reference_t<Args>> && ...));
ENTT_ASSERT(((args != nullptr) && ...));
instance = (args, ...);
} else if constexpr(in_situ<Type>) {
new (&storage) Type{std::forward<Args>(args)...};
} else {
instance = new Type{std::forward<Args>(args)...};
@@ -159,8 +162,7 @@ public:
*/
template<typename Type>
any(std::reference_wrapper<Type> value) ENTT_NOEXCEPT
: vtable{&basic_vtable<Type &>},
instance{&value.get()}
: any{std::in_place_type<Type &>, &value.get()}
{}
/**
@@ -316,7 +318,7 @@ private:
*/
template<typename Type>
Type any_cast(const any &data) ENTT_NOEXCEPT {
auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
const auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
ENTT_ASSERT(instance);
return static_cast<Type>(*instance);
}

View File

@@ -5,11 +5,13 @@
#include <array>
#include <map>
#include <set>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "type_traits.hpp"
@@ -22,7 +24,7 @@ namespace entt {
* @tparam Trait Traits associated with the underlying container.
*/
template<typename Container, template<typename> class... Trait>
struct container_traits: public Trait<Container>... {};
struct meta_container_traits: public Trait<Container>... {};
/**
@@ -32,7 +34,7 @@ struct container_traits: public Trait<Container>... {};
template<typename Container>
struct basic_container {
/*! @brief Iterator type of the container. */
using iterator = typename Container::iterator;
using iterator = std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>;
/*! @brief Unsigned integer type. */
using size_type = typename Container::size_type;
/*! @brief Value type of the container. */
@@ -77,13 +79,13 @@ struct basic_associative_container {
using key_type = typename Container::key_type;
/**
* @brief Returns an iterator to the element with key equivalent to the given
* one, if any.
* @brief Returns an iterator to the element with key equivalent to the
* given one, if any.
* @param cont The container in which to search for the element.
* @param key The key of the element to search.
* @return An iterator to the element with the given key, if any.
*/
[[nodiscard]] static typename Container::iterator find(Container &cont, const key_type &key) {
[[nodiscard]] static std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator> find(Container &cont, const key_type &key) {
return cont.find(key);
}
};
@@ -100,8 +102,12 @@ struct basic_dynamic_container {
* @param cont The container for which to clear the content.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear(Container &cont) {
return cont.clear(), true;
[[nodiscard]] static bool clear([[maybe_unused]] Container &cont) {
if constexpr(std::is_const_v<Container>) {
return false;
} else {
return cont.clear(), true;
}
}
};
@@ -118,9 +124,13 @@ struct basic_dynamic_associative_container {
* @param key The element to remove.
* @return A bool denoting whether the removal took place.
*/
[[nodiscard]] static bool erase(Container &cont, const typename Container::key_type &key) {
const auto sz = cont.size();
return cont.erase(key) != sz;
[[nodiscard]] static bool erase([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
if constexpr(std::is_const_v<Container>) {
return false;
} else {
const auto sz = cont.size();
return cont.erase(key) != sz;
}
}
};
@@ -132,13 +142,13 @@ struct basic_dynamic_associative_container {
template<typename Container>
struct basic_sequence_container {
/**
* @brief Returns a reference to the element at the specified location of the
* given container (no bounds checking is performed).
* @brief Returns a reference to the element at the specified location of
* the given container (no bounds checking is performed).
* @param cont The container from which to get the element.
* @param pos The position of the element to return.
* @return A reference to the requested element.
*/
[[nodiscard]] static typename Container::value_type & get(Container &cont, typename Container::size_type pos) {
[[nodiscard]] static constness_as_t<typename Container::value_type, Container> & get(Container &cont, typename Container::size_type pos) {
return cont[pos];
}
};
@@ -156,8 +166,12 @@ struct dynamic_associative_key_only_container {
* @param key The element to insert.
* @return A bool denoting whether the insertion took place.
*/
[[nodiscard]] static bool insert(Container &cont, const typename Container::key_type &key) {
return cont.insert(key).second;
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
if constexpr(std::is_const_v<Container>) {
return false;
} else {
return cont.insert(key).second;
}
}
};
@@ -175,8 +189,12 @@ struct dynamic_associative_key_value_container {
* @param value The value of the element to insert.
* @return A bool denoting whether the insertion took place.
*/
[[nodiscard]] static bool insert(Container &cont, const typename Container::key_type &key, const typename Container::mapped_type &value) {
return cont.insert(std::make_pair(key, value)).second;
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key, [[maybe_unused]] const typename Container::mapped_type &value) {
if constexpr(std::is_const_v<Container>) {
return false;
} else {
return cont.insert(std::make_pair(key, value)).second;
}
}
};
@@ -188,37 +206,54 @@ struct dynamic_associative_key_value_container {
template<typename Container>
struct dynamic_sequence_container {
/**
* @brief Resizes the given container to contain the given number of elements.
* @brief Resizes the given container to contain the given number of
* elements.
* @param cont The container to resize.
* @param sz The new size of the container.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool resize(Container &cont, typename Container::size_type sz) {
return (cont.resize(sz), true);
[[nodiscard]] static bool resize([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::size_type sz) {
if constexpr(std::is_const_v<Container>) {
return false;
} else {
return cont.resize(sz), true;
}
}
/**
* @brief Inserts an element at the specified location of the given container.
* @brief Inserts an element at the specified location of the given
* container.
* @param cont The container into which to insert the element.
* @param it Iterator before which the element will be inserted.
* @param value Element value to insert.
* @return A pair consisting of an iterator to the inserted element (in case
* of success) and a bool denoting whether the insertion took place.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> insert(Container &cont, typename Container::iterator it, const typename Container::value_type &value) {
return { cont.insert(it, value), true };
[[nodiscard]] static std::pair<std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, bool>
insert([[maybe_unused]] Container &cont, [[maybe_unused]] std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator> it, [[maybe_unused]] const typename Container::value_type &value) {
if constexpr(std::is_const_v<Container>) {
return { {}, false };
} else {
return { cont.insert(it, value), true };
}
}
/**
* @brief Removes the element at the specified location from the given container.
* @brief Removes the element at the specified location from the given
* container.
* @param cont The container from which to remove the element.
* @param it Iterator to the element to remove.
* @return A pair consisting of an iterator following the last removed
* element (in case of success) and a bool denoting whether the insertion
* took place.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> erase(Container &cont, typename Container::iterator it) {
return { cont.erase(it), true };
[[nodiscard]] static std::pair<std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, bool>
erase([[maybe_unused]] Container &cont, [[maybe_unused]] std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator> it) {
if constexpr(std::is_const_v<Container>) {
return { {}, false };
} else {
return { cont.erase(it), true };
}
}
};
@@ -250,7 +285,8 @@ struct fixed_sequence_container {
* @return A pair consisting of an invalid iterator and a false value to
* indicate failure in all cases.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> insert(const Container &, typename Container::iterator, const typename Container::value_type &) {
[[nodiscard]] static std::pair<std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, bool>
insert(const Container &, std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, const typename Container::value_type &) {
return { {}, false };
}
@@ -259,7 +295,8 @@ struct fixed_sequence_container {
* @return A pair consisting of an invalid iterator and a false value to
* indicate failure in all cases.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> erase(const Container &, typename Container::iterator) {
[[nodiscard]] static std::pair<std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>, bool>
erase(const Container &, std::conditional_t<std::is_const_v<Container>, typename Container::const_iterator, typename Container::iterator>) {
return { {}, false };
}
};
@@ -272,7 +309,7 @@ struct fixed_sequence_container {
*/
template<typename Type, typename... Args>
struct meta_sequence_container_traits<std::vector<Type, Args...>>
: container_traits<
: meta_container_traits<
std::vector<Type, Args...>,
basic_container,
basic_dynamic_container,
@@ -282,6 +319,23 @@ struct meta_sequence_container_traits<std::vector<Type, Args...>>
{};
/**
* @brief Meta sequence container traits for const `std::vector`s of any type.
* @tparam Type The type of elements.
* @tparam Args Other arguments.
*/
template<typename Type, typename... Args>
struct meta_sequence_container_traits<const std::vector<Type, Args...>>
: meta_container_traits<
const std::vector<Type, Args...>,
basic_container,
basic_dynamic_container,
basic_sequence_container,
dynamic_sequence_container
>
{};
/**
* @brief Meta sequence container traits for `std::array`s of any type.
* @tparam Type The type of elements.
@@ -289,7 +343,7 @@ struct meta_sequence_container_traits<std::vector<Type, Args...>>
*/
template<typename Type, auto N>
struct meta_sequence_container_traits<std::array<Type, N>>
: container_traits<
: meta_container_traits<
std::array<Type, N>,
basic_container,
basic_sequence_container,
@@ -298,6 +352,22 @@ struct meta_sequence_container_traits<std::array<Type, N>>
{};
/**
* @brief Meta sequence container traits for const `std::array`s of any type.
* @tparam Type The type of elements.
* @tparam N The number of elements.
*/
template<typename Type, auto N>
struct meta_sequence_container_traits<const std::array<Type, N>>
: meta_container_traits<
const std::array<Type, N>,
basic_container,
basic_sequence_container,
fixed_sequence_container
>
{};
/**
* @brief Meta associative container traits for `std::map`s of any type.
* @tparam Key The key type of elements.
@@ -306,7 +376,7 @@ struct meta_sequence_container_traits<std::array<Type, N>>
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::map<Key, Value, Args...>>
: container_traits<
: meta_container_traits<
std::map<Key, Value, Args...>,
basic_container,
basic_associative_container,
@@ -320,6 +390,28 @@ struct meta_associative_container_traits<std::map<Key, Value, Args...>>
};
/**
* @brief Meta associative container traits for const `std::map`s of any type.
* @tparam Key The key type of elements.
* @tparam Value The value type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<const std::map<Key, Value, Args...>>
: meta_container_traits<
const std::map<Key, Value, Args...>,
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<Key, Value, Args...>::mapped_type;
};
/**
* @brief Meta associative container traits for `std::unordered_map`s of any
* type.
@@ -329,7 +421,7 @@ struct meta_associative_container_traits<std::map<Key, Value, Args...>>
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
: container_traits<
: meta_container_traits<
std::unordered_map<Key, Value, Args...>,
basic_container,
basic_associative_container,
@@ -343,6 +435,29 @@ struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>
};
/**
* @brief Meta associative container traits for const `std::unordered_map`s of
* any type.
* @tparam Key The key type of elements.
* @tparam Value The value type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<const std::unordered_map<Key, Value, Args...>>
: meta_container_traits<
const std::unordered_map<Key, Value, Args...>,
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<Key, Value, Args...>::mapped_type;
};
/**
* @brief Meta associative container traits for `std::set`s of any type.
* @tparam Key The type of elements.
@@ -350,7 +465,7 @@ struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::set<Key, Args...>>
: container_traits<
: meta_container_traits<
std::set<Key, Args...>,
basic_container,
basic_associative_container,
@@ -361,6 +476,24 @@ struct meta_associative_container_traits<std::set<Key, Args...>>
{};
/**
* @brief Meta associative container traits for const `std::set`s of any type.
* @tparam Key The type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<const std::set<Key, Args...>>
: meta_container_traits<
const std::set<Key, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_only_container
>
{};
/**
* @brief Meta associative container traits for `std::unordered_set`s of any
* type.
@@ -369,7 +502,7 @@ struct meta_associative_container_traits<std::set<Key, Args...>>
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
: container_traits<
: meta_container_traits<
std::unordered_set<Key, Args...>,
basic_container,
basic_associative_container,
@@ -380,6 +513,25 @@ struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
{};
/**
* @brief Meta associative container traits for const `std::unordered_set`s of
* any type.
* @tparam Key The type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<const std::unordered_set<Key, Args...>>
: meta_container_traits<
const std::unordered_set<Key, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_only_container
>
{};
}

View File

@@ -118,7 +118,6 @@ struct meta_type_node {
const bool is_associative_container;
const size_type rank;
size_type(* const extent)(size_type);
bool(* const compare)(const void *, const void *);
meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT;
meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT;
meta_base_node *base{nullptr};
@@ -219,14 +218,6 @@ template<typename Type>
class ENTT_API meta_node {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Invalid type");
[[nodiscard]] static bool compare(const void *lhs, const void *rhs) {
if constexpr(!std::is_function_v<Type> && is_equality_comparable_v<Type>) {
return *static_cast<const Type *>(lhs) == *static_cast<const Type *>(rhs);
} else {
return lhs == rhs;
}
}
template<std::size_t... Index>
[[nodiscard]] static auto extent(meta_type_node::size_type dim, std::index_sequence<Index...>) {
meta_type_node::size_type ext{};
@@ -260,7 +251,6 @@ public:
[](meta_type_node::size_type dim) {
return extent(dim, std::make_index_sequence<std::rank_v<Type>>{});
},
&compare, // workaround for an issue with VS2017
&meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
&meta_node<std::remove_cv_t<std::remove_extent_t<Type>>>::resolve
};

View File

@@ -41,17 +41,15 @@ public:
using iterator = meta_iterator;
/*! @brief Default constructor. */
meta_sequence_container() ENTT_NOEXCEPT
: instance{nullptr}
{}
meta_sequence_container() ENTT_NOEXCEPT = default;
/**
* @brief Construct a proxy object for sequence containers.
* @tparam Type Type of container to wrap.
* @param container The container to wrap.
* @param instance The container to wrap.
*/
template<typename Type>
meta_sequence_container(Type *container) ENTT_NOEXCEPT
meta_sequence_container(Type &instance) ENTT_NOEXCEPT
: value_type_fn{&meta_sequence_container_proxy<Type>::value_type},
size_fn{&meta_sequence_container_proxy<Type>::size},
resize_fn{&meta_sequence_container_proxy<Type>::resize},
@@ -61,12 +59,12 @@ public:
insert_fn{&meta_sequence_container_proxy<Type>::insert},
erase_fn{&meta_sequence_container_proxy<Type>::erase},
get_fn{&meta_sequence_container_proxy<Type>::get},
instance{container}
storage{std::reference_wrapper{instance}}
{}
[[nodiscard]] inline meta_type value_type() const ENTT_NOEXCEPT;
[[nodiscard]] inline size_type size() const ENTT_NOEXCEPT;
inline bool resize(size_type) const;
inline bool resize(size_type);
inline bool clear();
[[nodiscard]] inline iterator begin();
[[nodiscard]] inline iterator end();
@@ -77,15 +75,15 @@ public:
private:
meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr;
size_type(* size_fn)(const void *) ENTT_NOEXCEPT = nullptr;
bool(* resize_fn)(void *, size_type) = nullptr;
bool(* clear_fn)(void *) = nullptr;
iterator(* begin_fn)(void *) = nullptr;
iterator(* end_fn)(void *) = nullptr;
std::pair<iterator, bool>(* insert_fn)(void *, iterator, meta_any) = nullptr;
std::pair<iterator, bool>(* erase_fn)(void *, iterator) = nullptr;
meta_any(* get_fn)(void *, size_type) = nullptr;
void *instance{};
size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr;
bool(* resize_fn)(any &, size_type) = nullptr;
bool(* clear_fn)(any &) = nullptr;
iterator(* begin_fn)(any &) = nullptr;
iterator(* end_fn)(any &) = nullptr;
std::pair<iterator, bool>(* insert_fn)(any &, iterator, meta_any &) = nullptr;
std::pair<iterator, bool>(* erase_fn)(any &, iterator) = nullptr;
meta_any(* get_fn)(any &, size_type) = nullptr;
any storage{};
};
@@ -103,17 +101,15 @@ public:
using iterator = meta_iterator;
/*! @brief Default constructor. */
meta_associative_container() ENTT_NOEXCEPT
: instance{nullptr}
{}
meta_associative_container() ENTT_NOEXCEPT = default;
/**
* @brief Construct a proxy object for associative containers.
* @tparam Type Type of container to wrap.
* @param container The container to wrap.
* @param instance The container to wrap.
*/
template<typename Type>
meta_associative_container(Type *container) ENTT_NOEXCEPT
meta_associative_container(Type &instance) ENTT_NOEXCEPT
: key_only_container{is_key_only_meta_associative_container_v<Type>},
key_type_fn{&meta_associative_container_proxy<Type>::key_type},
mapped_type_fn{&meta_associative_container_proxy<Type>::mapped_type},
@@ -125,7 +121,7 @@ public:
insert_fn{&meta_associative_container_proxy<Type>::insert},
erase_fn{&meta_associative_container_proxy<Type>::erase},
find_fn{&meta_associative_container_proxy<Type>::find},
instance{container}
storage{std::reference_wrapper{instance}}
{}
[[nodiscard]] inline bool key_only() const ENTT_NOEXCEPT;
@@ -146,41 +142,58 @@ private:
meta_type(* key_type_fn)() ENTT_NOEXCEPT = nullptr;
meta_type(* mapped_type_fn)() ENTT_NOEXCEPT = nullptr;
meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr;
size_type(* size_fn)(const void *) ENTT_NOEXCEPT = nullptr;
bool(* clear_fn)(void *) = nullptr;
iterator(* begin_fn)(void *) = nullptr;
iterator(* end_fn)(void *) = nullptr;
bool(* insert_fn)(void *, meta_any, meta_any) = nullptr;
bool(* erase_fn)(void *, meta_any) = nullptr;
iterator(* find_fn)(void *, meta_any) = nullptr;
void *instance{};
size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr;
bool(* clear_fn)(any &) = nullptr;
iterator(* begin_fn)(any &) = nullptr;
iterator(* end_fn)(any &) = nullptr;
bool(* insert_fn)(any &, meta_any &, meta_any &) = nullptr;
bool(* erase_fn)(any &, meta_any &) = nullptr;
iterator(* find_fn)(any &, meta_any &) = nullptr;
any storage{};
};
/*! @brief Opaque wrapper for values of any type. */
class meta_any {
enum class operation { DEREF, SEQ, ASSOC };
enum class operation { DEREF, CDEREF, SEQ, CSEQ, ASSOC, CASSOC };
using vtable_type = void(const operation, meta_any &, void *);
using vtable_type = void(const operation, const any &, void *);
template<typename Type>
static void basic_vtable(const operation op, [[maybe_unused]] meta_any &from, [[maybe_unused]] void *to) {
static void basic_vtable(const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) {
switch(op) {
case operation::DEREF:
if constexpr(is_meta_pointer_like_v<Type>) {
if(auto ptr = from.cast<Type>(); ptr) {
*static_cast<meta_any *>(to) = std::reference_wrapper{*ptr};
}
*static_cast<meta_any *>(to) = std::ref(*any_cast<const Type>(from));
}
break;
case operation::CDEREF:
if constexpr(is_meta_pointer_like_v<Type>) {
*static_cast<meta_any *>(to) = std::cref(*any_cast<const Type>(from));
}
break;
case operation::SEQ:
if constexpr(has_meta_sequence_container_traits_v<Type>) {
*static_cast<meta_sequence_container *>(to) = static_cast<Type *>(from.data());
if(auto *instance = any_cast<Type>(&const_cast<any &>(from)); instance) {
return *static_cast<meta_sequence_container *>(to) = *instance, void();
}
}
[[fallthrough]];
case operation::CSEQ:
if constexpr(has_meta_sequence_container_traits_v<Type>) {
*static_cast<meta_sequence_container *>(to) = any_cast<const Type &>(from);
}
break;
case operation::ASSOC:
if constexpr(has_meta_associative_container_traits_v<Type>) {
*static_cast<meta_associative_container *>(to) = static_cast<Type *>(from.data());
if(auto *instance = any_cast<Type>(&const_cast<any &>(from)); instance) {
return *static_cast<meta_associative_container *>(to) = *instance, void();
}
}
[[fallthrough]];
case operation::CASSOC:
if constexpr(has_meta_associative_container_traits_v<Type>) {
*static_cast<meta_associative_container *>(to) = any_cast<const Type &>(from);
}
break;
}
@@ -203,8 +216,8 @@ public:
template<typename Type, typename... Args>
explicit meta_any(std::in_place_type_t<Type>, Args &&... args)
: storage(std::in_place_type<Type>, std::forward<Args>(args)...),
vtable{&basic_vtable<Type>},
node{internal::meta_info<Type>::resolve()}
vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>},
node{internal::meta_info<std::remove_const_t<std::remove_reference_t<Type>>>::resolve()}
{}
/**
@@ -214,9 +227,7 @@ public:
*/
template<typename Type>
meta_any(std::reference_wrapper<Type> value)
: storage{value},
vtable{&basic_vtable<Type>},
node{internal::meta_info<Type>::resolve()}
: meta_any{std::in_place_type<Type &>, &value.get()}
{}
/**
@@ -443,7 +454,14 @@ public:
*/
[[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT {
meta_sequence_container proxy;
vtable(operation::SEQ, *this, &proxy);
vtable(operation::SEQ, storage, &proxy);
return proxy;
}
/*! @copydoc as_sequence_container */
[[nodiscard]] meta_sequence_container as_sequence_container() const ENTT_NOEXCEPT {
meta_sequence_container proxy;
vtable(operation::CSEQ, storage, &proxy);
return proxy;
}
@@ -453,7 +471,14 @@ public:
*/
[[nodiscard]] meta_associative_container as_associative_container() ENTT_NOEXCEPT {
meta_associative_container proxy;
vtable(operation::ASSOC, *this, &proxy);
vtable(operation::ASSOC, storage, &proxy);
return proxy;
}
/*! @copydoc as_associative_container */
[[nodiscard]] meta_associative_container as_associative_container() const ENTT_NOEXCEPT {
meta_associative_container proxy;
vtable(operation::CASSOC, storage, &proxy);
return proxy;
}
@@ -464,7 +489,14 @@ public:
*/
[[nodiscard]] meta_any operator*() ENTT_NOEXCEPT {
meta_any any{};
vtable(operation::DEREF, *this, &any);
vtable(operation::DEREF, storage, &any);
return any;
}
/*! @copydoc operator* */
[[nodiscard]] meta_any operator*() const ENTT_NOEXCEPT {
meta_any any{};
vtable(operation::CDEREF, storage, &any);
return any;
}
@@ -482,7 +514,7 @@ public:
* @return False if the two objects differ in their content, true otherwise.
*/
[[nodiscard]] bool operator==(const meta_any &other) const {
return (!node && !other.node) || (node && other.node && node->info == other.node->info && node->compare(storage.data(), other.storage.data()));
return (node == other.node) && (storage == other.storage);
}
/**
@@ -1671,13 +1703,13 @@ class meta_sequence_container::meta_iterator {
friend class meta_sequence_container;
template<typename It>
static void incr(meta_any any) {
++any.cast<It &>();
static void incr(any &ref) {
++any_cast<It &>(ref);
}
template<typename It>
[[nodiscard]] static meta_any deref(meta_any any) {
return std::reference_wrapper{*any.cast<const It &>()};
[[nodiscard]] static meta_any deref(const any &ref) {
return std::reference_wrapper{*any_cast<const It &>(ref)};
}
public:
@@ -1709,7 +1741,7 @@ public:
/*! @brief Pre-increment operator. @return This iterator. */
meta_iterator & operator++() ENTT_NOEXCEPT {
return next_fn(as_ref(handle)), *this;
return next_fn(handle), *this;
}
/*! @brief Post-increment operator. @return This iterator. */
@@ -1743,7 +1775,7 @@ public:
* @return The element to which the meta pointer points.
*/
[[nodiscard]] reference operator*() const {
return get_fn(as_ref(handle));
return get_fn(handle);
}
/**
@@ -1755,9 +1787,9 @@ public:
}
private:
void(* next_fn)(meta_any);
meta_any(* get_fn)(meta_any);
meta_any handle;
void(* next_fn)(any &);
meta_any(* get_fn)(const any &);
any handle;
};
@@ -1769,42 +1801,42 @@ struct meta_sequence_container::meta_sequence_container_proxy {
return internal::meta_info<typename traits_type::value_type>::resolve();
}
[[nodiscard]] static size_type size(const void *container) ENTT_NOEXCEPT {
return traits_type::size(*static_cast<const Type *>(container));
[[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT {
return traits_type::size(any_cast<const Type &>(container));
}
[[nodiscard]] static bool resize(void *container, size_type sz) {
return traits_type::resize(*static_cast<Type *>(container), sz);
[[nodiscard]] static bool resize(any &container, size_type sz) {
return traits_type::resize(any_cast<Type &>(container), sz);
}
[[nodiscard]] static bool clear(void *container) {
return traits_type::clear(*static_cast<Type *>(container));
[[nodiscard]] static bool clear(any &container) {
return traits_type::clear(any_cast<Type &>(container));
}
[[nodiscard]] static iterator begin(void *container) {
return iterator{traits_type::begin(*static_cast<Type *>(container))};
[[nodiscard]] static iterator begin(any &container) {
return iterator{traits_type::begin(any_cast<Type &>(container))};
}
[[nodiscard]] static iterator end(void *container) {
return iterator{traits_type::end(*static_cast<Type *>(container))};
[[nodiscard]] static iterator end(any &container) {
return iterator{traits_type::end(any_cast<Type &>(container))};
}
[[nodiscard]] static std::pair<iterator, bool> insert(void *container, iterator it, meta_any value) {
[[nodiscard]] static std::pair<iterator, bool> insert(any &container, iterator it, meta_any &value) {
if(value.allow_cast<const typename traits_type::value_type &>()) {
auto ret = traits_type::insert(*static_cast<Type *>(container), it.handle.cast<const typename traits_type::iterator &>(), value.cast<const typename traits_type::value_type &>());
auto ret = traits_type::insert(any_cast<Type &>(container), any_cast<const typename traits_type::iterator &>(it.handle), value.cast<const typename traits_type::value_type &>());
return { iterator{std::move(ret.first)}, ret.second };
}
return {};
}
[[nodiscard]] static std::pair<iterator, bool> erase(void *container, iterator it) {
auto ret = traits_type::erase(*static_cast<Type *>(container), it.handle.cast<const typename traits_type::iterator &>());
[[nodiscard]] static std::pair<iterator, bool> erase(any &container, iterator it) {
auto ret = traits_type::erase(any_cast<Type &>(container), any_cast<const typename traits_type::iterator &>(it.handle));
return { iterator{std::move(ret.first)}, ret.second };
}
[[nodiscard]] static meta_any get(void *container, size_type pos) {
return std::reference_wrapper{traits_type::get(*static_cast<Type *>(container), pos)};
[[nodiscard]] static meta_any get(any &container, size_type pos) {
return std::reference_wrapper{traits_type::get(any_cast<Type &>(container), pos)};
}
};
@@ -1823,7 +1855,7 @@ struct meta_sequence_container::meta_sequence_container_proxy {
* @return The size of the wrapped container.
*/
[[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const ENTT_NOEXCEPT {
return size_fn(instance);
return size_fn(storage);
}
@@ -1832,8 +1864,8 @@ struct meta_sequence_container::meta_sequence_container_proxy {
* @param sz The new size of the container.
* @return True in case of success, false otherwise.
*/
inline bool meta_sequence_container::resize(size_type sz) const {
return resize_fn(instance, sz);
inline bool meta_sequence_container::resize(size_type sz) {
return resize_fn(storage, sz);
}
@@ -1842,7 +1874,7 @@ inline bool meta_sequence_container::resize(size_type sz) const {
* @return True in case of success, false otherwise.
*/
inline bool meta_sequence_container::clear() {
return clear_fn(instance);
return clear_fn(storage);
}
@@ -1851,7 +1883,7 @@ inline bool meta_sequence_container::clear() {
* @return A meta iterator to the first element of the wrapped container.
*/
[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() {
return begin_fn(instance);
return begin_fn(storage);
}
@@ -1862,7 +1894,7 @@ inline bool meta_sequence_container::clear() {
* container.
*/
[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() {
return end_fn(instance);
return end_fn(storage);
}
@@ -1874,7 +1906,7 @@ inline bool meta_sequence_container::clear() {
* case of success) and a bool denoting whether the insertion took place.
*/
inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_container::insert(iterator it, meta_any value) {
return insert_fn(instance, it, as_ref(value));
return insert_fn(storage, it, value);
}
@@ -1886,7 +1918,7 @@ inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_containe
* took place.
*/
inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_container::erase(iterator it) {
return erase_fn(instance, it);
return erase_fn(storage, it);
}
@@ -1897,7 +1929,7 @@ inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_containe
* @return A reference to the requested element properly wrapped.
*/
[[nodiscard]] inline meta_any meta_sequence_container::operator[](size_type pos) {
return get_fn(instance, pos);
return get_fn(storage, pos);
}
@@ -1906,32 +1938,32 @@ inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_containe
* @return False if the proxy is invalid, true otherwise.
*/
[[nodiscard]] inline meta_sequence_container::operator bool() const ENTT_NOEXCEPT {
return (instance != nullptr);
return static_cast<bool>(storage);
}
/*! @brief Opaque iterator for meta associative containers. */
class meta_associative_container::meta_iterator {
template<typename It>
static void incr(meta_any any) {
++any.cast<It &>();
static void incr(any &any) {
++any_cast<It &>(any);
}
template<bool KeyOnly, typename It>
[[nodiscard]] static meta_any key(meta_any any) {
[[nodiscard]] static meta_any key(const any &ref) {
if constexpr(KeyOnly) {
return *any.cast<const It &>();
return *any_cast<const It &>(ref);
} else {
return any.cast<const It &>()->first;
return any_cast<const It &>(ref)->first;
}
}
template<bool KeyOnly, typename It>
[[nodiscard]] static meta_any value([[maybe_unused]] meta_any any) {
[[nodiscard]] static meta_any value([[maybe_unused]] const any &ref) {
if constexpr(KeyOnly) {
return meta_any{};
} else {
return std::reference_wrapper{any.cast<const It &>()->second};
return std::reference_wrapper{any_cast<const It &>(ref)->second};
}
}
@@ -1967,7 +1999,7 @@ public:
/*! @brief Pre-increment operator. @return This iterator. */
meta_iterator & operator++() ENTT_NOEXCEPT {
return next_fn(as_ref(handle)), *this;
return next_fn(handle), *this;
}
/*! @brief Post-increment operator. @return This iterator. */
@@ -2001,7 +2033,7 @@ public:
* @return The element to which the meta pointer points.
*/
[[nodiscard]] reference operator*() const {
return { key_fn(as_ref(handle)), value_fn(as_ref(handle)) };
return { key_fn(handle), value_fn(handle) };
}
/**
@@ -2013,10 +2045,10 @@ public:
}
private:
void(* next_fn)(meta_any);
meta_any(* key_fn)(meta_any);
meta_any(* value_fn)(meta_any);
meta_any handle;
void(* next_fn)(any &);
meta_any(* key_fn)(const any &);
meta_any(* value_fn)(const any &);
any handle;
};
@@ -2040,29 +2072,29 @@ struct meta_associative_container::meta_associative_container_proxy {
return internal::meta_info<typename traits_type::value_type>::resolve();
}
[[nodiscard]] static size_type size(const void *container) ENTT_NOEXCEPT {
return traits_type::size(*static_cast<const Type *>(container));
[[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT {
return traits_type::size(any_cast<const Type &>(container));
}
[[nodiscard]] static bool clear(void *container) {
return traits_type::clear(*static_cast<Type *>(container));
[[nodiscard]] static bool clear(any &container) {
return traits_type::clear(any_cast<Type &>(container));
}
[[nodiscard]] static iterator begin(void *container) {
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::begin(*static_cast<Type *>(container))};
[[nodiscard]] static iterator begin(any &container) {
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::begin(any_cast<Type &>(container))};
}
[[nodiscard]] static iterator end(void *container) {
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::end(*static_cast<Type *>(container))};
[[nodiscard]] static iterator end(any &container) {
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::end(any_cast<Type &>(container))};
}
[[nodiscard]] static bool insert(void *container, meta_any key, meta_any value) {
[[nodiscard]] static bool insert(any &container, meta_any &key, meta_any &value) {
if(key.allow_cast<const typename traits_type::key_type &>()) {
if constexpr(is_key_only_meta_associative_container_v<Type>) {
return traits_type::insert(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>());
return traits_type::insert(any_cast<Type &>(container), key.cast<const typename traits_type::key_type &>());
} else {
if(value.allow_cast<const typename traits_type::mapped_type &>()) {
return traits_type::insert(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>(), value.cast<const typename traits_type::mapped_type &>());
return traits_type::insert(any_cast<Type &>(container), key.cast<const typename traits_type::key_type &>(), value.cast<const typename traits_type::mapped_type &>());
}
}
}
@@ -2070,17 +2102,17 @@ struct meta_associative_container::meta_associative_container_proxy {
return false;
}
[[nodiscard]] static bool erase(void *container, meta_any key) {
[[nodiscard]] static bool erase(any &container, meta_any &key) {
if(key.allow_cast<const typename traits_type::key_type &>()) {
return traits_type::erase(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>());
return traits_type::erase(any_cast<Type &>(container), key.cast<const typename traits_type::key_type &>());
}
return false;
}
[[nodiscard]] static iterator find(void *container, meta_any key) {
[[nodiscard]] static iterator find(any &container, meta_any &key) {
if(key.allow_cast<const typename traits_type::key_type &>()) {
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*static_cast<Type *>(container), key.cast<const typename traits_type::key_type &>())};
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(any_cast<Type &>(container), key.cast<const typename traits_type::key_type &>())};
}
return {};
@@ -2124,25 +2156,25 @@ struct meta_associative_container::meta_associative_container_proxy {
/*! @copydoc meta_sequence_container::size */
[[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const ENTT_NOEXCEPT {
return size_fn(instance);
return size_fn(storage);
}
/*! @copydoc meta_sequence_container::clear */
inline bool meta_associative_container::clear() {
return clear_fn(instance);
return clear_fn(storage);
}
/*! @copydoc meta_sequence_container::begin */
[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() {
return begin_fn(instance);
return begin_fn(storage);
}
/*! @copydoc meta_sequence_container::end */
[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() {
return end_fn(instance);
return end_fn(storage);
}
@@ -2153,7 +2185,7 @@ inline bool meta_associative_container::clear() {
* @return A bool denoting whether the insertion took place.
*/
inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) {
return insert_fn(instance, as_ref(key), as_ref(value));
return insert_fn(storage, key, value);
}
@@ -2163,7 +2195,7 @@ inline bool meta_associative_container::insert(meta_any key, meta_any value = {}
* @return A bool denoting whether the removal took place.
*/
inline bool meta_associative_container::erase(meta_any key) {
return erase_fn(instance, as_ref(key));
return erase_fn(storage, key);
}
@@ -2174,7 +2206,7 @@ inline bool meta_associative_container::erase(meta_any key) {
* @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 find_fn(instance, as_ref(key));
return find_fn(storage, key);
}
@@ -2183,7 +2215,7 @@ inline bool meta_associative_container::erase(meta_any key) {
* @return False if the proxy is invalid, true otherwise.
*/
[[nodiscard]] inline meta_associative_container::operator bool() const ENTT_NOEXCEPT {
return (instance != nullptr);
return static_cast<bool>(storage);
}

View File

@@ -33,6 +33,16 @@ template<typename Type, typename = void>
struct has_meta_sequence_container_traits: std::false_type {};
/**
* @brief TODO
* @tparam Type TODO
*/
template<typename Type>
struct has_meta_sequence_container_traits<const Type>
: has_meta_sequence_container_traits<Type>
{};
/*! @copydoc has_meta_sequence_container_traits */
template<typename Type>
struct has_meta_sequence_container_traits<Type, std::void_t<typename meta_sequence_container_traits<Type>::value_type>>
@@ -57,6 +67,16 @@ template<typename, typename = void>
struct has_meta_associative_container_traits: std::false_type {};
/**
* @brief TODO
* @tparam Type TODO
*/
template<typename Type>
struct has_meta_associative_container_traits<const Type>
: has_meta_associative_container_traits<Type>
{};
/*! @copydoc has_meta_associative_container_traits */
template<typename Type>
struct has_meta_associative_container_traits<Type, std::void_t<typename meta_associative_container_traits<Type>::key_type>>
@@ -81,6 +101,16 @@ template<typename, typename = void>
struct is_key_only_meta_associative_container: std::true_type {};
/**
* @brief TODO
* @tparam Type TODO
*/
template<typename Type>
struct is_key_only_meta_associative_container<const Type>
: is_key_only_meta_associative_container<Type>
{};
/*! @copydoc is_key_only_meta_associative_container */
template<typename Type>
struct is_key_only_meta_associative_container<Type, std::void_t<typename meta_associative_container_traits<Type>::mapped_type>>

View File

@@ -7,6 +7,7 @@
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/any.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
@@ -195,7 +196,7 @@ public:
template<typename Type, typename... Args>
explicit poly(std::in_place_type_t<Type>, Args &&... args)
: storage{std::in_place_type<Type>, std::forward<Args>(args)...},
vtable{poly_vtable<Concept>::template instance<Type>()}
vtable{poly_vtable<Concept>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>()}
{}
/**
@@ -205,8 +206,7 @@ public:
*/
template<typename Type>
poly(std::reference_wrapper<Type> value)
: storage{value},
vtable{poly_vtable<Concept>::template instance<std::remove_const_t<Type>>()}
: poly{std::in_place_type<Type &>, &value.get()}
{}
/**
@@ -316,8 +316,9 @@ public:
* @return A poly that shares a reference to an unmanaged object.
*/
[[nodiscard]] friend poly as_ref(poly &other) ENTT_NOEXCEPT {
poly ref = as_ref(std::as_const(other));
poly ref;
ref.storage = as_ref(other.storage);
ref.vtable = other.vtable;
return ref;
}

View File

@@ -267,3 +267,169 @@ TEST_F(MetaContainer, StdSet) {
ASSERT_TRUE(view.clear());
ASSERT_EQ(view.size(), 0u);
}
TEST_F(MetaContainer, ConstSequenceContainer) {
std::vector<int> vec{};
entt::meta_any any{std::cref(vec)};
auto view = any.as_sequence_container();
ASSERT_TRUE(view);
ASSERT_EQ(view.value_type(), entt::resolve<int>());
ASSERT_EQ(view.size(), 0u);
ASSERT_EQ(view.begin(), view.end());
ASSERT_FALSE(view.resize(3u));
ASSERT_EQ(view.size(), 0u);
ASSERT_EQ(view.begin(), view.end());
vec.push_back(42);
ASSERT_EQ(view.size(), 1u);
ASSERT_NE(view.begin(), view.end());
ASSERT_DEATH(view[0].cast<int &>() = 2, ".*");
ASSERT_EQ(view[0].cast<const int &>(), 42);
auto it = view.begin();
auto ret = view.insert(it, 0);
ASSERT_FALSE(ret.second);
ASSERT_EQ(view.size(), 1u);
ASSERT_EQ((*it).cast<int>(), 42);
ASSERT_EQ(++it, view.end());
it = view.begin();
ret = view.erase(it);
ASSERT_FALSE(ret.second);
ASSERT_EQ(view.size(), 1u);
ASSERT_FALSE(view.clear());
ASSERT_EQ(view.size(), 1u);
}
TEST_F(MetaContainer, ConstKeyValueAssociativeContainer) {
std::map<int, char> map{};
entt::meta_any any{std::cref(map)};
auto view = any.as_associative_container();
ASSERT_TRUE(view);
ASSERT_FALSE(view.key_only());
ASSERT_EQ(view.key_type(), entt::resolve<int>());
ASSERT_EQ(view.mapped_type(), entt::resolve<char>());
ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
ASSERT_EQ(view.size(), 0u);
ASSERT_EQ(view.begin(), view.end());
map[2] = 'c';
ASSERT_EQ(view.size(), 1u);
ASSERT_NE(view.begin(), view.end());
ASSERT_DEATH((*view.find(2)).second.cast<char &>() = 'a', ".*");
ASSERT_EQ((*view.find(2)).second.cast<const char &>(), 'c');
ASSERT_FALSE(view.insert(0, 'a'));
ASSERT_EQ(view.size(), 1u);
ASSERT_EQ(view.find(0), view.end());
ASSERT_EQ((*view.find(2)).second.cast<char>(), 'c');
ASSERT_FALSE(view.erase(2));
ASSERT_EQ(view.size(), 1u);
ASSERT_NE(view.find(2), view.end());
ASSERT_FALSE(view.clear());
ASSERT_EQ(view.size(), 1u);
}
TEST_F(MetaContainer, ConstKeyOnlyAssociativeContainer) {
std::set<int> set{};
entt::meta_any any{std::cref(set)};
auto view = any.as_associative_container();
ASSERT_TRUE(view);
ASSERT_TRUE(view.key_only());
ASSERT_EQ(view.key_type(), entt::resolve<int>());
ASSERT_EQ(view.mapped_type(), entt::meta_type{});
ASSERT_EQ(view.value_type(), (entt::resolve<int>()));
ASSERT_EQ(view.size(), 0u);
ASSERT_EQ(view.begin(), view.end());
set.insert(2);
ASSERT_EQ(view.size(), 1u);
ASSERT_NE(view.begin(), view.end());
ASSERT_EQ((*view.find(2)).first.cast<int>(), 2);
ASSERT_EQ((*view.find(2)).first.cast<int &>(), 2);
ASSERT_EQ((*view.find(2)).first.cast<const int &>(), 2);
ASSERT_FALSE(view.insert(0));
ASSERT_EQ(view.size(), 1u);
ASSERT_EQ(view.find(0), view.end());
ASSERT_EQ((*view.find(2)).first.cast<int>(), 2);
ASSERT_FALSE(view.erase(2));
ASSERT_EQ(view.size(), 1u);
ASSERT_NE(view.find(2), view.end());
ASSERT_FALSE(view.clear());
ASSERT_EQ(view.size(), 1u);
}
TEST_F(MetaContainer, SequenceContainerConstMetaAny) {
auto test = [](const entt::meta_any any) {
auto view = any.as_sequence_container();
ASSERT_TRUE(view);
ASSERT_EQ(view.value_type(), entt::resolve<int>());
ASSERT_DEATH(view[0].cast<int &>() = 2, ".*");
ASSERT_EQ(view[0].cast<const int &>(), 42);
};
std::vector<int> vec{42};
test(vec);
test(std::ref(vec));
test(std::cref(vec));
}
TEST_F(MetaContainer, KeyValueAssociativeContainerConstMetaAny) {
auto test = [](const entt::meta_any any) {
auto view = any.as_associative_container();
ASSERT_TRUE(view);
ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
ASSERT_DEATH((*view.find(2)).second.cast<char &>() = 'a', ".*");
ASSERT_EQ((*view.find(2)).second.cast<const char &>(), 'c');
};
std::map<int, char> map{{2, 'c'}};
test(map);
test(std::ref(map));
test(std::cref(map));
}
TEST_F(MetaContainer, KeyOnlyAssociativeContainerConstMetaAny) {
auto test = [](const entt::meta_any any) {
auto view = any.as_associative_container();
ASSERT_TRUE(view);
ASSERT_EQ(view.value_type(), (entt::resolve<int>()));
ASSERT_EQ((*view.find(2)).first.cast<int>(), 2);
ASSERT_EQ((*view.find(2)).first.cast<int &>(), 2);
ASSERT_EQ((*view.find(2)).first.cast<const int &>(), 2);
};
std::set<int> set{2};
test(set);
test(std::ref(set));
test(std::cref(set));
}

View File

@@ -46,6 +46,27 @@ TEST(MetaPointerLike, DereferenceOperatorConstType) {
ASSERT_EQ(deref.cast<const int &>(), 42);
}
TEST(MetaPointerLike, DereferenceOperatorConstAny) {
auto test = [](const entt::meta_any any) {
auto deref = *any;
ASSERT_TRUE(deref);
ASSERT_FALSE(deref.type().is_pointer());
ASSERT_FALSE(deref.type().is_pointer_like());
ASSERT_EQ(deref.type(), entt::resolve<int>());
ASSERT_EQ(deref.try_cast<int>(), nullptr);
ASSERT_NE(deref.try_cast<const int>(), nullptr);
ASSERT_DEATH(deref.cast<int &>() = 0, ".*");
ASSERT_EQ(deref.cast<const int &>(), 42);
};
int value = 42;
test(&value);
test(&std::as_const(value));
}
TEST(MetaPointerLike, DereferenceOperatorRawPointer) {
int value = 0;
entt::meta_any any{&value};