Browse Source

meta: fake vtable for meta sequence containers

skypjack 2 years ago
parent
commit
44f30dc01c
2 changed files with 104 additions and 83 deletions
  1. 58 61
      src/entt/meta/container.hpp
  2. 46 22
      src/entt/meta/meta.hpp

+ 58 - 61
src/entt/meta/container.hpp

@@ -48,72 +48,69 @@ template<typename Type>
 struct basic_meta_sequence_container_traits {
     static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
 
-    using iterator = meta_sequence_container::iterator;
-    using size_type = std::size_t;
-
-    [[nodiscard]] static size_type size(const void *container) noexcept {
-        return static_cast<const Type *>(container)->size();
-    }
-
-    [[nodiscard]] static bool clear(void *container) {
-        if constexpr(dynamic_sequence_container<Type>::value) {
-            static_cast<Type *>(container)->clear();
+    using operation = internal::meta_sequence_container_operation;
+    using size_type = typename meta_sequence_container::size_type;
+    using iterator = typename meta_sequence_container::iterator;
+
+    static size_type basic_vtable(const operation op, const meta_ctx &ctx, const void *container, const void *value, iterator *it) {
+        switch(const Type *cont = static_cast<const Type *>(container); op) {
+        case operation::size:
+            return cont->size();
+        case operation::clear:
+            if constexpr(dynamic_sequence_container<Type>::value) {
+                const_cast<Type *>(cont)->clear();
+                return true;
+            } else {
+                break;
+            }
+        case operation::reserve:
+            if constexpr(reserve_aware_container<Type>::value) {
+                const_cast<Type *>(cont)->reserve(*static_cast<const size_type *>(value));
+                return true;
+            } else {
+                break;
+            }
+        case operation::resize:
+            if constexpr(dynamic_sequence_container<Type>::value) {
+                const_cast<Type *>(cont)->resize(*static_cast<const size_type *>(value));
+                return true;
+            } else {
+                break;
+            }
+        case operation::begin:
+            *it = iterator{ctx, const_cast<Type *>(cont)->begin()};
             return true;
-        } else {
-            return false;
-        }
-    }
-
-    [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
-        if constexpr(reserve_aware_container<Type>::value) {
-            static_cast<Type *>(container)->reserve(sz);
+        case operation::end:
+            *it = iterator{ctx, const_cast<Type *>(cont)->end()};
             return true;
-        } else {
-            return false;
-        }
-    }
-
-    [[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
-        if constexpr(dynamic_sequence_container<Type>::value) {
-            static_cast<Type *>(container)->resize(sz);
+        case operation::cbegin:
+            *it = iterator{ctx, cont->begin()};
             return true;
-        } else {
-            return false;
-        }
-    }
-
-    [[nodiscard]] static iterator iter(const meta_ctx &ctx, const void *container, const bool as_const, const bool as_end) {
-        if(as_const) {
-            const auto it = as_end ? static_cast<const Type *>(container)->end() : static_cast<const Type *>(container)->begin();
-            return iterator{ctx, it};
-        } else {
-            const auto it = as_end ? static_cast<Type *>(const_cast<void *>(container))->end() : static_cast<Type *>(const_cast<void *>(container))->begin();
-            return iterator{ctx, it};
-        }
-    }
-
-    [[nodiscard]] static iterator insert_or_erase([[maybe_unused]] const meta_ctx &ctx, [[maybe_unused]] void *container, [[maybe_unused]] const any &handle, [[maybe_unused]] meta_any &value) {
-        if constexpr(dynamic_sequence_container<Type>::value) {
-            typename Type::const_iterator it{};
-
-            if(auto *const non_const = any_cast<typename Type::iterator>(&handle); non_const) {
-                it = *non_const;
-            } else {
-                it = any_cast<const typename Type::const_iterator &>(handle);
-            }
-
-            if(auto *const cont = static_cast<Type *>(container); value) {
-                // 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>>();
-                    return iterator{ctx, cont->insert(it, element ? *element : value.cast<typename Type::value_type>())};
+        case operation::cend:
+            *it = iterator{ctx, cont->end()};
+            return true;
+        case operation::insert:
+        case operation::erase:
+            if constexpr(dynamic_sequence_container<Type>::value) {
+                auto *const non_const = any_cast<typename Type::iterator>(&it->base());
+                typename Type::const_iterator underlying{non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it->base())};
+
+                if(op == operation::insert) {
+                    // this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
+                    if(static_cast<meta_any *>(const_cast<void *>(value))->allow_cast<typename Type::const_reference>() || static_cast<meta_any *>(const_cast<void *>(value))->allow_cast<typename Type::value_type>()) {
+                        const auto *element = static_cast<meta_any *>(const_cast<void *>(value))->try_cast<std::remove_reference_t<typename Type::const_reference>>();
+                        *it = iterator{ctx, const_cast<Type *>(cont)->insert(underlying, element ? *element : static_cast<meta_any *>(const_cast<void *>(value))->cast<typename Type::value_type>())};
+                        return true;
+                    }
+                } else {
+                    *it = iterator{ctx, const_cast<Type *>(cont)->erase(underlying)};
+                    return true;
                 }
-            } else {
-                return iterator{ctx, cont->erase(it)};
             }
+            break;
         }
 
-        return iterator{};
+        return false;
     }
 };
 
@@ -121,8 +118,8 @@ template<typename Type>
 struct basic_meta_associative_container_traits {
     static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
 
-    using iterator = meta_associative_container::iterator;
-    using size_type = std::size_t;
+    using size_type = typename meta_associative_container::size_type;
+    using iterator = typename meta_associative_container::iterator;
 
     static constexpr auto key_only = key_only_associative_container<Type>::value;
 

+ 46 - 22
src/entt/meta/meta.hpp

@@ -26,9 +26,37 @@ namespace entt {
 class meta_any;
 class meta_type;
 
+/**
+ * @cond TURN_OFF_DOXYGEN
+ * Internal details not to be documented.
+ */
+
+namespace internal {
+
+enum class meta_sequence_container_operation {
+    size,
+    clear,
+    reserve,
+    resize,
+    begin,
+    end,
+    cbegin,
+    cend,
+    insert,
+    erase
+};
+
+} // namespace internal
+
+/**
+ * Internal details not to be documented.
+ * @endcond
+ */
+
 /*! @brief Proxy object for sequence containers. */
 class meta_sequence_container {
     class meta_iterator;
+    using operation = internal::meta_sequence_container_operation;
 
 public:
     /*! @brief Unsigned integer type. */
@@ -52,12 +80,7 @@ public:
     void rebind(any instance) noexcept {
         ENTT_ASSERT(instance.type() == type_id<Type>(), "Unexpected type");
         value_type_node = &internal::resolve<typename Type::value_type>;
-        size_fn = &meta_sequence_container_traits<Type>::size;
-        clear_fn = &meta_sequence_container_traits<Type>::clear;
-        reserve_fn = &meta_sequence_container_traits<Type>::reserve;
-        resize_fn = &meta_sequence_container_traits<Type>::resize;
-        iter_fn = &meta_sequence_container_traits<Type>::iter;
-        insert_or_erase_fn = &meta_sequence_container_traits<Type>::insert_or_erase;
+        vtable = &meta_sequence_container_traits<Type>::basic_vtable;
         storage = std::move(instance);
     }
 
@@ -76,12 +99,7 @@ public:
 private:
     const meta_ctx *ctx{};
     internal::meta_type_node (*value_type_node)(const internal::meta_context &){};
-    size_type (*size_fn)(const void *) noexcept {};
-    bool (*clear_fn)(void *){};
-    bool (*reserve_fn)(void *, const size_type){};
-    bool (*resize_fn)(void *, const size_type){};
-    iterator (*iter_fn)(const meta_ctx &, const void *, const bool, const bool){};
-    iterator (*insert_or_erase_fn)(const meta_ctx &, void *, const any &, meta_any &){};
+    size_type (*vtable)(const operation, const meta_ctx &, const void *, const void *, iterator *){};
     any storage{};
 };
 
@@ -1675,8 +1693,6 @@ inline bool meta_any::assign(meta_any &&other) {
  */
 
 class meta_sequence_container::meta_iterator final {
-    friend class meta_sequence_container;
-
     using vtable_type = void(const void *, const std::ptrdiff_t, meta_any *);
 
     template<typename It>
@@ -1750,6 +1766,10 @@ public:
         return !(*this == other);
     }
 
+    [[nodiscard]] const any &base() const noexcept {
+        return handle;
+    }
+
 private:
     const meta_ctx *ctx;
     vtable_type *vtable;
@@ -1847,7 +1867,7 @@ private:
  * @return The size of the container.
  */
 [[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const noexcept {
-    return size_fn(storage.data());
+    return vtable(operation::size, *ctx, std::as_const(storage).data(), nullptr, nullptr);
 }
 
 /**
@@ -1856,7 +1876,7 @@ private:
  * @return True in case of success, false otherwise.
  */
 inline bool meta_sequence_container::resize(const size_type sz) {
-    return (storage.policy() != any_policy::cref) && resize_fn(storage.data(), sz);
+    return (storage.policy() != any_policy::cref) && vtable(operation::resize, *ctx, storage.data(), &sz, nullptr);
 }
 
 /**
@@ -1864,7 +1884,7 @@ inline bool meta_sequence_container::resize(const size_type sz) {
  * @return True in case of success, false otherwise.
  */
 inline bool meta_sequence_container::clear() {
-    return (storage.policy() != any_policy::cref) && clear_fn(storage.data());
+    return (storage.policy() != any_policy::cref) && vtable(operation::clear, *ctx, storage.data(), nullptr, nullptr);
 }
 
 /**
@@ -1873,7 +1893,7 @@ inline bool meta_sequence_container::clear() {
  * @return True in case of success, false otherwise.
  */
 inline bool meta_sequence_container::reserve(const size_type sz) {
-    return (storage.policy() != any_policy::cref) && reserve_fn(storage.data(), sz);
+    return (storage.policy() != any_policy::cref) && vtable(operation::reserve, *ctx, storage.data(), &sz, nullptr);
 }
 
 /**
@@ -1881,7 +1901,9 @@ inline bool meta_sequence_container::reserve(const size_type sz) {
  * @return An iterator to the first element of the container.
  */
 [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() {
-    return iter_fn(*ctx, std::as_const(storage).data(), (storage.policy() == any_policy::cref), false);
+    iterator it{};
+    vtable(storage.policy() == any_policy::cref ? operation::cbegin : operation::begin, *ctx, std::as_const(storage).data(), nullptr, &it);
+    return it;
 }
 
 /**
@@ -1889,7 +1911,9 @@ inline bool meta_sequence_container::reserve(const size_type sz) {
  * @return An iterator that is past the last element of the container.
  */
 [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() {
-    return iter_fn(*ctx, std::as_const(storage).data(), (storage.policy() == any_policy::cref), true);
+    iterator it{};
+    vtable(storage.policy() == any_policy::cref ? operation::cend : operation::end, *ctx, std::as_const(storage).data(), nullptr, &it);
+    return it;
 }
 
 /**
@@ -1899,7 +1923,7 @@ inline bool meta_sequence_container::reserve(const size_type sz) {
  * @return A possibly invalid iterator to the inserted element.
  */
 inline meta_sequence_container::iterator meta_sequence_container::insert(iterator it, meta_any value) {
-    return (storage.policy() != any_policy::cref) ? insert_or_erase_fn(*ctx, storage.data(), it.handle, value) : iterator{};
+    return ((storage.policy() != any_policy::cref) && vtable(operation::insert, *ctx, storage.data(), &value, &it)) ? it : iterator{};
 }
 
 /**
@@ -1908,7 +1932,7 @@ inline meta_sequence_container::iterator meta_sequence_container::insert(iterato
  * @return A possibly invalid iterator following the last removed element.
  */
 inline meta_sequence_container::iterator meta_sequence_container::erase(iterator it) {
-    return insert(it, {});
+    return ((storage.policy() != any_policy::cref) && vtable(operation::erase, *ctx, storage.data(), nullptr, &it)) ? it : iterator{};
 }
 
 /**