meta: support for std::vector<bool> and the like
This commit is contained in:
@@ -24,7 +24,10 @@ namespace entt {
|
||||
* @tparam Trait Traits associated with the underlying container.
|
||||
*/
|
||||
template<typename Container, template<typename> class... Trait>
|
||||
struct meta_container_traits: public Trait<Container>... {};
|
||||
struct meta_container_traits: public Trait<Container>... {
|
||||
/*! @brief Type of container. */
|
||||
using type = Container;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@@ -33,21 +36,12 @@ struct meta_container_traits: public Trait<Container>... {};
|
||||
*/
|
||||
template<typename Container>
|
||||
struct basic_container {
|
||||
/*! @brief Iterator type of the container. */
|
||||
using iterator = typename Container::iterator;
|
||||
/*! @brief Iterator type of the container. */
|
||||
using const_iterator = typename Container::const_iterator;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename Container::size_type;
|
||||
/*! @brief Value type of the container. */
|
||||
using value_type = typename Container::value_type;
|
||||
|
||||
/**
|
||||
* @brief Returns the size of the given container.
|
||||
* @param cont The container for which to return the size.
|
||||
* @return The size of the given container.
|
||||
*/
|
||||
[[nodiscard]] static size_type size(const Container &cont) ENTT_NOEXCEPT {
|
||||
[[nodiscard]] static typename Container::size_type size(const Container &cont) ENTT_NOEXCEPT {
|
||||
return cont.size();
|
||||
}
|
||||
|
||||
@@ -56,7 +50,7 @@ struct basic_container {
|
||||
* @param cont The container for which to return the iterator.
|
||||
* @return An iterator to the first element of the given container.
|
||||
*/
|
||||
[[nodiscard]] static iterator begin(Container &cont) {
|
||||
[[nodiscard]] static typename Container::iterator begin(Container &cont) {
|
||||
return cont.begin();
|
||||
}
|
||||
|
||||
@@ -65,7 +59,7 @@ struct basic_container {
|
||||
* @param cont The container for which to return the iterator.
|
||||
* @return An iterator to the first element of the given container.
|
||||
*/
|
||||
[[nodiscard]] static const_iterator cbegin(const Container &cont) {
|
||||
[[nodiscard]] static typename Container::const_iterator cbegin(const Container &cont) {
|
||||
return cont.begin();
|
||||
}
|
||||
|
||||
@@ -74,7 +68,7 @@ struct basic_container {
|
||||
* @param cont The container for which to return the iterator.
|
||||
* @return An iterator past the last element of the given container.
|
||||
*/
|
||||
[[nodiscard]] static iterator end(Container &cont) {
|
||||
[[nodiscard]] static typename Container::iterator end(Container &cont) {
|
||||
return cont.end();
|
||||
}
|
||||
|
||||
@@ -83,7 +77,7 @@ struct basic_container {
|
||||
* @param cont The container for which to return the iterator.
|
||||
* @return An iterator past the last element of the given container.
|
||||
*/
|
||||
[[nodiscard]] static const_iterator cend(const Container &cont) {
|
||||
[[nodiscard]] static typename Container::const_iterator cend(const Container &cont) {
|
||||
return cont.end();
|
||||
}
|
||||
};
|
||||
@@ -95,9 +89,6 @@ struct basic_container {
|
||||
*/
|
||||
template<typename Container>
|
||||
struct basic_associative_container {
|
||||
/*! @brief Key type of the sequence container. */
|
||||
using key_type = typename Container::key_type;
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the element with key equivalent to the
|
||||
* given one, if any.
|
||||
@@ -105,12 +96,12 @@ struct basic_associative_container {
|
||||
* @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 typename Container::iterator find(Container &cont, const typename Container::key_type &key) {
|
||||
return cont.find(key);
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
[[nodiscard]] static typename Container::const_iterator cfind(const Container &cont, const key_type &key) {
|
||||
[[nodiscard]] static typename Container::const_iterator cfind(const Container &cont, const typename Container::key_type &key) {
|
||||
return cont.find(key);
|
||||
}
|
||||
};
|
||||
@@ -165,12 +156,12 @@ struct basic_sequence_container {
|
||||
* @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 typename Container::reference get(Container &cont, typename Container::size_type pos) {
|
||||
return cont[pos];
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
[[nodiscard]] static const typename Container::value_type & cget(const Container &cont, typename Container::size_type pos) {
|
||||
[[nodiscard]] static typename Container::const_reference cget(const Container &cont, typename Container::size_type pos) {
|
||||
return cont[pos];
|
||||
}
|
||||
};
|
||||
@@ -349,10 +340,7 @@ struct meta_associative_container_traits<std::map<Key, Value, Args...>>
|
||||
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;
|
||||
};
|
||||
{};
|
||||
|
||||
|
||||
/**
|
||||
@@ -372,10 +360,7 @@ struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>
|
||||
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;
|
||||
};
|
||||
{};
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1787,7 +1787,11 @@ class meta_sequence_container::meta_iterator {
|
||||
++any_cast<It &>(const_cast<any &>(from));
|
||||
break;
|
||||
case operation::DEREF:
|
||||
*static_cast<meta_any *>(to) = std::reference_wrapper{*any_cast<const It &>(from)};
|
||||
if constexpr(std::is_lvalue_reference_v<typename std::iterator_traits<It>::reference>) {
|
||||
*static_cast<meta_any *>(to) = std::reference_wrapper{*any_cast<const It &>(from)};
|
||||
} else {
|
||||
*static_cast<meta_any *>(to) = *any_cast<const It &>(from);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1866,8 +1870,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
vtable_type *vtable;
|
||||
any handle;
|
||||
vtable_type *vtable{};
|
||||
any handle{};
|
||||
};
|
||||
|
||||
|
||||
@@ -1876,7 +1880,7 @@ struct meta_sequence_container::meta_sequence_container_proxy {
|
||||
using traits_type = meta_sequence_container_traits<Type>;
|
||||
|
||||
[[nodiscard]] static meta_type value_type() ENTT_NOEXCEPT {
|
||||
return internal::meta_info<typename traits_type::value_type>::resolve();
|
||||
return internal::meta_info<typename Type::value_type>::resolve();
|
||||
}
|
||||
|
||||
[[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT {
|
||||
@@ -1910,9 +1914,13 @@ struct meta_sequence_container::meta_sequence_container_proxy {
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::pair<iterator, bool> insert(any &container, iterator it, meta_any &value) {
|
||||
if(auto * const cont = any_cast<Type>(&container); cont && value.allow_cast<const typename traits_type::value_type &>()) {
|
||||
auto ret = traits_type::insert(*cont, 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 };
|
||||
if(auto * const cont = any_cast<Type>(&container); cont) {
|
||||
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
|
||||
if(value.allow_cast<typename Type::const_reference>() || value.allow_cast<typename Type::value_type>()) {
|
||||
const auto *element = value.try_cast<std::remove_reference_t<typename Type::const_reference>>();
|
||||
auto ret = traits_type::insert(*cont, any_cast<const typename Type::iterator &>(it.handle), element ? *element : value.cast<typename Type::value_type>());
|
||||
return { iterator{std::move(ret.first)}, ret.second };
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -1920,7 +1928,7 @@ struct meta_sequence_container::meta_sequence_container_proxy {
|
||||
|
||||
[[nodiscard]] static std::pair<iterator, bool> erase(any &container, iterator it) {
|
||||
if(auto * const cont = any_cast<Type>(&container); cont) {
|
||||
auto ret = traits_type::erase(*cont, any_cast<const typename traits_type::iterator &>(it.handle));
|
||||
auto ret = traits_type::erase(*cont, any_cast<const typename Type::iterator &>(it.handle));
|
||||
return { iterator{std::move(ret.first)}, ret.second };
|
||||
}
|
||||
|
||||
@@ -1929,10 +1937,18 @@ struct meta_sequence_container::meta_sequence_container_proxy {
|
||||
|
||||
[[nodiscard]] static meta_any get(any &container, size_type pos) {
|
||||
if(auto * const cont = any_cast<Type>(&container); cont) {
|
||||
return std::reference_wrapper{traits_type::get(*cont, pos)};
|
||||
if constexpr(std::is_lvalue_reference_v<typename Type::reference>) {
|
||||
return std::reference_wrapper{traits_type::get(*cont, pos)};
|
||||
} else {
|
||||
return traits_type::get(*cont, pos);
|
||||
}
|
||||
}
|
||||
|
||||
return std::reference_wrapper{traits_type::cget(any_cast<const Type &>(container), pos)};
|
||||
if constexpr(std::is_lvalue_reference_v<typename Type::const_reference>) {
|
||||
return std::reference_wrapper{traits_type::cget(any_cast<const Type &>(container), pos)};
|
||||
} else {
|
||||
return traits_type::cget(any_cast<const Type &>(container), pos);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2132,8 +2148,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
vtable_type *vtable;
|
||||
any handle;
|
||||
vtable_type *vtable{};
|
||||
any handle{};
|
||||
};
|
||||
|
||||
|
||||
@@ -2142,19 +2158,19 @@ struct meta_associative_container::meta_associative_container_proxy {
|
||||
using traits_type = meta_associative_container_traits<Type>;
|
||||
|
||||
[[nodiscard]] static meta_type key_type() ENTT_NOEXCEPT {
|
||||
return internal::meta_info<typename traits_type::key_type>::resolve();
|
||||
return internal::meta_info<typename Type::key_type>::resolve();
|
||||
}
|
||||
|
||||
[[nodiscard]] static meta_type mapped_type() ENTT_NOEXCEPT {
|
||||
if constexpr(is_key_only_meta_associative_container_v<Type>) {
|
||||
return meta_type{};
|
||||
} else {
|
||||
return internal::meta_info<typename traits_type::mapped_type>::resolve();
|
||||
return internal::meta_info<typename Type::mapped_type>::resolve();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static meta_type value_type() ENTT_NOEXCEPT {
|
||||
return internal::meta_info<typename traits_type::value_type>::resolve();
|
||||
return internal::meta_info<typename Type::value_type>::resolve();
|
||||
}
|
||||
|
||||
[[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT {
|
||||
@@ -2183,12 +2199,12 @@ struct meta_associative_container::meta_associative_container_proxy {
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool insert(any &container, meta_any &key, meta_any &value) {
|
||||
if(auto * const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename traits_type::key_type &>()) {
|
||||
if(auto * const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
|
||||
if constexpr(is_key_only_meta_associative_container_v<Type>) {
|
||||
return traits_type::insert(*cont, key.cast<const typename traits_type::key_type &>());
|
||||
return traits_type::insert(*cont, key.cast<const typename Type::key_type &>());
|
||||
} else {
|
||||
if(value.allow_cast<const typename traits_type::mapped_type &>()) {
|
||||
return traits_type::insert(*cont, key.cast<const typename traits_type::key_type &>(), value.cast<const typename traits_type::mapped_type &>());
|
||||
if(value.allow_cast<const typename Type::mapped_type &>()) {
|
||||
return traits_type::insert(*cont, key.cast<const typename Type::key_type &>(), value.cast<const typename Type::mapped_type &>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2197,20 +2213,20 @@ struct meta_associative_container::meta_associative_container_proxy {
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool erase(any &container, meta_any &key) {
|
||||
if(auto * const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename traits_type::key_type &>()) {
|
||||
return traits_type::erase(*cont, key.cast<const typename traits_type::key_type &>());
|
||||
if(auto * const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
|
||||
return traits_type::erase(*cont, key.cast<const typename Type::key_type &>());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator find(any &container, meta_any &key) {
|
||||
if(key.allow_cast<const typename traits_type::key_type &>()) {
|
||||
if(key.allow_cast<const typename Type::key_type &>()) {
|
||||
if(auto * const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*cont, key.cast<const typename traits_type::key_type &>())};
|
||||
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*cont, key.cast<const typename Type::key_type &>())};
|
||||
}
|
||||
|
||||
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::cfind(any_cast<const Type &>(container), key.cast<const typename traits_type::key_type &>())};
|
||||
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::cfind(any_cast<const Type &>(container), key.cast<const typename Type::key_type &>())};
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
@@ -35,7 +35,7 @@ struct has_meta_sequence_container_traits: std::false_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>>
|
||||
struct has_meta_sequence_container_traits<Type, std::void_t<typename meta_sequence_container_traits<Type>::type::value_type>>
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
@@ -59,7 +59,7 @@ struct has_meta_associative_container_traits: std::false_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>>
|
||||
struct has_meta_associative_container_traits<Type, std::void_t<typename meta_associative_container_traits<Type>::type::key_type>>
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
@@ -83,7 +83,7 @@ struct is_key_only_meta_associative_container: std::true_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>>
|
||||
struct is_key_only_meta_associative_container<Type, std::void_t<typename meta_associative_container_traits<Type>::type::mapped_type>>
|
||||
: std::false_type
|
||||
{};
|
||||
|
||||
|
||||
@@ -436,3 +436,51 @@ TEST_F(MetaContainer, KeyOnlyAssociativeContainerConstMetaAny) {
|
||||
test(std::ref(set));
|
||||
test(std::cref(set));
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdVectorBool) {
|
||||
using proxy_type = typename std::vector<bool>::reference;
|
||||
using const_proxy_type = typename std::vector<bool>::const_reference;
|
||||
|
||||
std::vector<bool> vec{};
|
||||
entt::meta_any any{std::ref(vec)};
|
||||
auto cany = as_ref(std::as_const(any));
|
||||
|
||||
auto view = any.as_sequence_container();
|
||||
auto cview = cany.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<bool>());
|
||||
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_TRUE(view.resize(3u));
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
view[0].cast<proxy_type>() = true;
|
||||
view[1].cast<proxy_type>() = true;
|
||||
view[2].cast<proxy_type>() = false;
|
||||
|
||||
ASSERT_EQ(cview[1u].cast<const_proxy_type>(), true);
|
||||
|
||||
auto it = view.begin();
|
||||
auto ret = view.insert(it, true);
|
||||
|
||||
ASSERT_TRUE(ret.second);
|
||||
ASSERT_FALSE(view.insert(ret.first, 'c').second);
|
||||
ASSERT_TRUE(view.insert(++ret.first, false).second);
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ((*view.begin()).cast<proxy_type>(), true);
|
||||
ASSERT_EQ((*++cview.begin()).cast<const_proxy_type>(), false);
|
||||
|
||||
it = view.begin();
|
||||
ret = view.erase(it);
|
||||
|
||||
ASSERT_TRUE(ret.second);
|
||||
ASSERT_EQ(view.size(), 4u);
|
||||
ASSERT_EQ((*ret.first).cast<proxy_type>(), false);
|
||||
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(cview.size(), 0u);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user