1
0
Эх сурвалжийг харах

meta: support for std::vector<bool> and the like

Michele Caini 5 жил өмнө
parent
commit
a03a569534

+ 15 - 30
src/entt/meta/container.hpp

@@ -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;
-};
+{};
 
 
 /**

+ 40 - 24
src/entt/meta/meta.hpp

@@ -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 {};

+ 3 - 3
src/entt/meta/type_traits.hpp

@@ -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
 {};
 

+ 48 - 0
test/entt/meta/meta_container.cpp

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