Просмотр исходного кода

any:
* reintroduced operation::TYPE to avoid fat any types
* added optional req parameter to data
* much faster any_cast
* much faster operator==
* internal review

Michele Caini 4 лет назад
Родитель
Сommit
46b686910b
1 измененных файлов с 96 добавлено и 102 удалено
  1. 96 102
      src/entt/core/any.hpp

+ 96 - 102
src/entt/core/any.hpp

@@ -23,28 +23,15 @@ namespace entt {
  */
 template<std::size_t Len, std::size_t Align>
 class basic_any {
-    enum class operation: std::uint8_t { COPY, MOVE, DTOR, COMP, ADDR };
+    enum class operation: std::uint8_t { COPY, MOVE, DTOR, COMP, GET, TYPE };
     enum class policy: std::uint8_t { OWNER, REF, CREF };
 
     using storage_type = std::aligned_storage_t<Len + !Len, Align>;
-    using vtable_type = const void *(const operation, const basic_any &, void *);
+    using vtable_type = const void *(const operation, const basic_any &, const void *);
 
     template<typename Type>
     static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v<Type>;
 
-    template<typename Type>
-    [[nodiscard]] static constexpr policy type_to_policy() {
-        if constexpr(std::is_lvalue_reference_v<Type>) {
-            if constexpr(std::is_const_v<std::remove_reference_t<Type>>) {
-                return policy::CREF;
-            } else {
-                return policy::REF;
-            }
-        } else {
-            return policy::OWNER;
-        }
-    }
-
     template<typename Type>
     [[nodiscard]] static bool compare(const void *lhs, const void *rhs) {
         if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
@@ -55,58 +42,63 @@ class basic_any {
     }
 
     template<typename Type>
-    static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] void *to) {
-        static_assert(std::is_same_v<std::remove_reference_t<std::remove_const_t<Type>>, Type>, "Invalid type");
+    static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) {
+        static_assert(!std::is_same_v<Type, void> && std::is_same_v<std::remove_reference_t<std::remove_const_t<Type>>, Type>, "Invalid type");
+        const Type *instance = nullptr;
 
-        if constexpr(!std::is_void_v<Type>) {
-            const Type *instance = (in_situ<Type> && from.mode == policy::OWNER)
-                ? ENTT_LAUNDER(reinterpret_cast<const Type *>(&from.storage))
-                : static_cast<const Type *>(from.instance);
-
-            switch(op) {
-            case operation::COPY:
-                if constexpr(std::is_copy_constructible_v<Type>) {
-                    static_cast<basic_any *>(to)->emplace<Type>(*instance);
-                }
-                break;
-            case operation::MOVE:
-                if constexpr(in_situ<Type>) {
-                    if(from.mode == policy::OWNER) {
-                        return new (&static_cast<basic_any *>(to)->storage) Type{std::move(*const_cast<Type *>(instance))};
-                    }
-                }
-
-                return (static_cast<basic_any *>(to)->instance = std::exchange(const_cast<basic_any &>(from).instance, nullptr));
-            case operation::DTOR:
-                if constexpr(in_situ<Type>) {
-                    instance->~Type();
-                } else if constexpr(std::is_array_v<Type>) {
-                    delete[] instance;
-                } else {
-                    delete instance;
+        if constexpr(in_situ<Type>) {
+            instance = (from.mode == policy::OWNER) ? ENTT_LAUNDER(reinterpret_cast<const Type *>(&from.storage)) : static_cast<const Type *>(from.instance);
+        } else {
+            instance = static_cast<const Type *>(from.instance);
+        }
+        
+        switch(op) {
+        case operation::COPY:
+            if constexpr(std::is_copy_constructible_v<Type>) {
+                static_cast<basic_any *>(const_cast<void *>(to))->initialize<Type>(*instance);
+            }
+            break;
+        case operation::MOVE:
+            if constexpr(in_situ<Type>) {
+                if(from.mode == policy::OWNER) {
+                    return new (&static_cast<basic_any *>(const_cast<void *>(to))->storage) Type{std::move(*const_cast<Type *>(instance))};
                 }
-                break;
-            case operation::COMP:
-                return compare<Type>(instance, (*static_cast<const basic_any **>(to))->data()) ? to : nullptr;
-            case operation::ADDR:
-                return instance;
             }
+        
+            return (static_cast<basic_any *>(const_cast<void *>(to))->instance = std::exchange(const_cast<basic_any &>(from).instance, nullptr));
+        case operation::DTOR:
+            if constexpr(in_situ<Type>) {
+                instance->~Type();
+            } else if constexpr(std::is_array_v<Type>) {
+                delete[] instance;
+            } else {
+                delete instance;
+            }
+            break;
+        case operation::COMP:
+        {
+            const auto info = type_id<Type>();
+            auto *value = static_cast<const basic_any *>(to)->data(&info);
+            return (value && compare<Type>(instance, value)) ? to : nullptr;
+        }
+        case operation::GET:
+            return (!to || (*static_cast<const type_info *>(to) == type_id<Type>())) ? instance : nullptr;
+        case operation::TYPE:
+            *static_cast<type_info *>(const_cast<void *>(to)) = type_id<Type>();
+            break;
         }
 
         return nullptr;
     }
 
-    void destroy_if_owner() {
-        if(mode == policy::OWNER) {
-            vtable(operation::DTOR, *this, nullptr);
-        }
-    }
-
     template<typename Type, typename... Args>
     void initialize([[maybe_unused]] Args &&... args) {
         if constexpr(!std::is_void_v<Type>) {
+            vtable = basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>;
+
             if constexpr(std::is_lvalue_reference_v<Type>) {
                 static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments");
+                mode = std::is_const_v<std::remove_reference_t<Type>> ? policy::CREF : policy::REF;
                 instance = (std::addressof(args), ...);
             } else if constexpr(in_situ<Type>) {
                 if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
@@ -127,7 +119,6 @@ class basic_any {
     basic_any(const basic_any &other, const policy pol) ENTT_NOEXCEPT
         : instance{other.data()},
           vtable{other.vtable},
-          descriptor{other.descriptor},
           mode{pol}
     {}
 
@@ -140,8 +131,7 @@ public:
     /*! @brief Default constructor. */
     basic_any() ENTT_NOEXCEPT
         : instance{},
-          vtable{&basic_vtable<void>},
-          descriptor{type_id<void>()},
+          vtable{},
           mode{policy::OWNER}
     {}
 
@@ -153,10 +143,7 @@ public:
      */
     template<typename Type, typename... Args>
     explicit basic_any(std::in_place_type_t<Type>, Args &&... args)
-        : instance{},
-          vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>},
-          descriptor{type_id<std::remove_const_t<std::remove_reference_t<Type>>>()},
-          mode{type_to_policy<Type>()}
+        : basic_any{}
     {
         initialize<Type>(std::forward<Args>(args)...);
     }
@@ -168,10 +155,7 @@ public:
      */
     template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
     basic_any(Type &&value)
-        : instance{},
-          vtable{&basic_vtable<std::decay_t<Type>>},
-          descriptor{type_id<std::decay_t<Type>>()},
-          mode{policy::OWNER}
+        : basic_any{}
     {
         initialize<std::decay_t<Type>>(std::forward<Type>(value));
     }
@@ -183,7 +167,9 @@ public:
     basic_any(const basic_any &other)
         : basic_any{}
     {
-        other.vtable(operation::COPY, other, this);
+        if(other.vtable) {
+            other.vtable(operation::COPY, other, this);
+        }
     }
 
     /**
@@ -193,15 +179,18 @@ public:
     basic_any(basic_any &&other) ENTT_NOEXCEPT
         : instance{},
           vtable{other.vtable},
-          descriptor{other.descriptor},
           mode{other.mode}
     {
-        other.vtable(operation::MOVE, other, this);
+        if(other.vtable) {
+            other.vtable(operation::MOVE, other, this);
+        }
     }
 
     /*! @brief Frees the internal storage, whatever it means. */
     ~basic_any() {
-        destroy_if_owner();
+        if(vtable && mode == policy::OWNER) {
+            vtable(operation::DTOR, *this, nullptr);
+        }
     }
 
     /**
@@ -211,7 +200,11 @@ public:
      */
     basic_any & operator=(const basic_any &other) {
         reset();
-        other.vtable(operation::COPY, other, this);
+
+        if(other.vtable) {
+            other.vtable(operation::COPY, other, this);
+        }
+
         return *this;
     }
 
@@ -221,11 +214,14 @@ public:
      * @return This any object.
      */
     basic_any & operator=(basic_any &&other) ENTT_NOEXCEPT {
-        destroy_if_owner();
-        other.vtable(operation::MOVE, other, this);
-        vtable = other.vtable;
-        descriptor = other.descriptor;
-        mode = other.mode;
+        reset();
+
+        if(other.vtable) {
+            other.vtable(operation::MOVE, other, this);
+            vtable = other.vtable;
+            mode = other.mode;
+        }
+
         return *this;
     }
 
@@ -247,20 +243,27 @@ public:
      * @return The object type if any, `type_id<void>()` otherwise.
      */
     [[nodiscard]] type_info type() const ENTT_NOEXCEPT {
-        return descriptor;
+        if(vtable) {
+            type_info info{};
+            vtable(operation::TYPE, *this, &info);
+            return info;
+        }
+
+        return type_id<void>();
     }
 
     /**
      * @brief Returns an opaque pointer to the contained instance.
+     * @param req Optional expected type.
      * @return An opaque pointer the contained instance, if any.
      */
-    [[nodiscard]] const void * data() const ENTT_NOEXCEPT {
-        return vtable(operation::ADDR, *this, nullptr);
+    [[nodiscard]] const void * data(const type_info *req = nullptr) const ENTT_NOEXCEPT {
+        return vtable ? vtable(operation::GET, *this, req) : nullptr;
     }
 
     /*! @copydoc data */
-    [[nodiscard]] void * data() ENTT_NOEXCEPT {
-        return mode == policy::CREF ? nullptr : const_cast<void *>(vtable(operation::ADDR, *this, nullptr));
+    [[nodiscard]] void * data(const type_info *req = nullptr) ENTT_NOEXCEPT {
+        return (!vtable || mode == policy::CREF) ? nullptr : const_cast<void *>(vtable(operation::GET, *this, req));
     }
 
     /**
@@ -271,18 +274,17 @@ public:
      */
     template<typename Type, typename... Args>
     void emplace(Args &&... args) {
-        destroy_if_owner();
+        reset();
         initialize<Type>(std::forward<Args>(args)...);
-        vtable = &basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>;
-        descriptor = type_id<Type>();
-        mode = type_to_policy<Type>();
     }
 
     /*! @brief Destroys contained object */
     void reset() {
-        destroy_if_owner();
-        vtable = &basic_vtable<void>;
-        descriptor = type_id<void>();
+        if(vtable && mode == policy::OWNER) {
+            vtable(operation::DTOR, *this, nullptr);
+        }
+
+        vtable = nullptr;
         mode = policy::OWNER;
     }
 
@@ -291,7 +293,7 @@ public:
      * @return False if the wrapper is empty, true otherwise.
      */
     [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
-        return descriptor != type_id<void>();
+        return vtable != nullptr;
     }
 
     /**
@@ -300,8 +302,7 @@ public:
      * @return False if the two objects differ in their content, true otherwise.
      */
     bool operator==(const basic_any &other) const ENTT_NOEXCEPT {
-        const basic_any *trampoline = &other;
-        return descriptor == other.descriptor && (vtable(operation::COMP, *this, &trampoline) || !other.data());
+        return (!vtable && !other.vtable) || (vtable && other.vtable && vtable(operation::COMP, *this, &other));
     }
 
     /**
@@ -328,7 +329,6 @@ public:
 private:
     union { const void *instance; storage_type storage; };
     vtable_type *vtable;
-    type_info descriptor;
     policy mode;
 };
 
@@ -393,23 +393,17 @@ Type any_cast(basic_any<Len, Align> &&data) ENTT_NOEXCEPT {
 /*! @copydoc any_cast */
 template<typename Type, std::size_t Len, std::size_t Align>
 const Type * any_cast(const basic_any<Len, Align> *data) ENTT_NOEXCEPT {
-    if(data->type() == type_id<std::remove_const_t<std::remove_reference_t<Type>>>()) {
-        return static_cast<const Type *>(data->data());
-    }
-
-    return nullptr;
+    const auto info = type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
+    return static_cast<const Type *>(data->data(&info));
 }
 
 
 /*! @copydoc any_cast */
 template<typename Type, std::size_t Len, std::size_t Align>
 Type * any_cast(basic_any<Len, Align> *data) ENTT_NOEXCEPT {
-    if(data->type() == type_id<std::remove_const_t<std::remove_reference_t<Type>>>()) {
-        // last attempt to make wrappers for const references return their values
-        return static_cast<Type *>(static_cast<constness_as_t<basic_any<Len, Align>, Type> *>(data)->data());
-    }
-
-    return nullptr;
+    const auto info = type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
+    // last attempt to make wrappers for const references return their values
+    return static_cast<Type *>(static_cast<constness_as_t<basic_any<Len, Align>, Type> *>(data)->data(&info));
 }