Переглянути джерело

meta/*: removed meta_storage, meta_any uses any internally

Michele Caini 5 роки тому
батько
коміт
5af7e96f70
3 змінених файлів з 30 додано та 221 видалено
  1. 28 59
      docs/md/meta.md
  2. 0 161
      src/entt/meta/internal.hpp
  3. 2 1
      src/entt/meta/meta.hpp

+ 28 - 59
docs/md/meta.md

@@ -8,7 +8,7 @@
 * [Introduction](#introduction)
 * [Names and identifiers](#names-and-identifiers)
 * [Reflection in a nutshell](#reflection-in-a-nutshell)
-  * [Any as in any type](#any-as-in-any-type)
+  * [Any to the rescue](#any-to-the-rescue)
   * [Enjoy the runtime](#enjoy-the-runtime)
   * [Container support](#container-support)
   * [Pointer-like types](#pointer-like-types)
@@ -192,75 +192,44 @@ Also, do not forget what these few lines hide under the hood: a built-in,
 non-intrusive and macro-free system for reflection in C++. Features that are
 definitely worth the price, at least for me.
 
-## Any as in any type
+## Any to the rescue
 
-The reflection system comes with its own `meta_any` type. It may seem redundant
-since C++17 introduced `std::any`, but it is not.<br/>
-In fact, the _type_ returned by an `std::any` is a const reference to an
-`std::type_info`, an implementation defined class that's not something everyone
-wants to see in a software. Furthermore, the class `std::type_info` suffers from
-some design flaws and there is even no way to _convert_ an `std::type_info` into
-a meta type, thus linking the two worlds.
+The reflection system offers a kind of _extended version_ of the `any` class
+(see the core module for more details).<br/>
+The purpose is to add some feature on top of those already present, so as to
+integrate it with the meta type system without having to duplicate the code.
 
-The class `meta_any` offers an API similar to that of its most famous
-counterpart and serves the same purpose of being an opaque container for any
-type of value.<br/>
-It minimizes the allocations required, which are almost absent thanks to _SBO_
-techniques. In fact, unless users deal with _fat types_ and create instances of
-them through the reflection system, allocations are at zero.
-
-Creating instances of `meta_any`, whether empty or from existing objects, is
-trivial:
+The API is very similar to that of the `any` type. The class `meta_any` _wraps_
+many of the feature to infer a meta node, before forwarding some or all of the
+arguments to the underlying storage.<br/>
+Among the few relevant differences, instances of `meta_any` are comparable,
+while those of `any` are not:
 
 ```cpp
-// a container for an int
-entt::meta_any any{0};
-
-// an empty container
-entt::meta_any empty{};
-```
+entt::meta_any any{42};
+entt::meta_any other{'c'};
 
-The `meta_any` class takes also the burden of destroying the contained object
-when required.<br/>
-Furthermore, an instance of `meta_any` is not tied to a specific type.
-Therefore, the wrapper will be reconfigured by assigning it an object of a
-different type than the one contained, so as to be able to handle the new
-instance.
-
-A particularly interesting feature of this class is that it can also be used as
-an opaque container for non-const unmanaged objects:
-
-```cpp
-int value;
-entt::meta_any any{std::ref(value)};
+const bool equal = (any == other);
 ```
 
-In other words, whenever `meta_any` intercepts a `reference_wrapper`, it acts as
-a reference to the original instance rather than making a copy of it. 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 `meta_any` from existing
-ones:
+Also, `meta_any` adds support for containers and pointer-like types (see the
+following sections for more details).<br/>
+Similar to `any`, this class can also be used to create _aliases_ for unmanaged
+objects. However, unlike `any`,` meta_any` treats an empty instance and one
+initialized with `void` differently:
 
 ```cpp
-// aliasing constructor
-entt::meta_any ref = any.ref();
+entt::meta_any any{};
+entt::meta_any other{std::in_place_type<void>};
 ```
 
-In this case, it doesn't matter if the starting container actually holds an
-object or acts already as a reference for unmanaged elements, the new instance
-thus created won't create copies and will only serve as a reference for the
-original item.<br/>
-It means that, starting from the example above, both `ref` and` any` will point
-to the same object, whether it's initially contained in `any` or already an
-unmanaged one. This is particularly useful for passing instances of `meta_any`
-belonging to the external context by reference to a function or a constructor
-rather than making copies of them.
-
-The `meta_any` class also has a `type` member function that returns the meta
-type of the contained value, if any. The member functions `try_cast`, `cast` and
-`convert` are then used to know if the underlying object has a given type as a
-base or if it can be converted implicitly to it.
+While `any` treats both objects as empty, `meta_any` treats objects initialized
+with `void` as if they were _valid_ ones. This allows to differentiate between
+failed function calls and function calls that are successful but return
+nothing.<br/>
+Finally, the member functions `try_cast`, `cast` and `convert` are used to know
+if the underlying object has a given type as a base or if it can be converted
+implicitly to it. There is in fact no `any_cast` equivalent for `meta_any`.
 
 ## Enjoy the runtime
 

+ 0 - 161
src/entt/meta/internal.hpp

@@ -31,167 +31,6 @@ struct meta_handle;
 namespace internal {
 
 
-class meta_storage {
-    enum class operation { COPY, MOVE, DTOR, ADDR, REF };
-
-    using storage_type = std::aligned_storage_t<sizeof(double[2]), alignof(double[2])>;
-    using vtable_type = void *(const operation, const meta_storage &, meta_storage *);
-
-    template<typename Type>
-    static constexpr auto in_situ = sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v<Type>;
-
-    template<typename Type>
-    static void * basic_vtable(const operation op, const meta_storage &from, meta_storage *to) {
-        if constexpr(std::is_void_v<Type>) {
-            return nullptr;
-        } else if constexpr(std::is_lvalue_reference_v<Type>) {
-            switch(op) {
-            case operation::REF:
-                to->vtable = from.vtable;
-                [[fallthrough]];
-            case operation::COPY:
-            case operation::MOVE:
-                to->instance = from.instance;
-                break;
-            case operation::ADDR:
-                return from.instance;
-            case operation::DTOR:
-                break;
-            }
-        } else if constexpr(in_situ<Type>) {
-            auto *instance = std::launder(reinterpret_cast<Type *>(&const_cast<storage_type &>(from.storage)));
-
-            switch(op) {
-            case operation::COPY:
-                new (&to->storage) Type{std::as_const(*instance)};
-                break;
-            case operation::MOVE:
-                new (&to->storage) Type{std::move(*instance)};
-                [[fallthrough]];
-            case operation::DTOR:
-                instance->~Type();
-                break;
-            case operation::ADDR:
-                return instance;
-            case operation::REF:
-                to->vtable = basic_vtable<std::add_lvalue_reference_t<Type>>;
-                to->instance = instance;
-                break;
-            }
-        } else {
-            switch(op) {
-            case operation::COPY:
-                to->instance = new Type{std::as_const(*static_cast<Type *>(from.instance))};
-                break;
-            case operation::MOVE:
-                to->instance = from.instance;
-                break;
-            case operation::DTOR:
-                delete static_cast<Type *>(from.instance);
-                break;
-            case operation::ADDR:
-                return from.instance;
-            case operation::REF:
-                to->vtable = basic_vtable<std::add_lvalue_reference_t<Type>>;
-                to->instance = from.instance;
-                break;
-            }
-        }
-
-        return nullptr;
-    }
-
-public:
-    meta_storage() ENTT_NOEXCEPT
-        : vtable{&basic_vtable<void>},
-          instance{}
-    {}
-
-    template<typename Type, typename... Args>
-    explicit meta_storage(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
-        : vtable{&basic_vtable<Type>},
-          instance{}
-    {
-        if constexpr(!std::is_void_v<Type>) {
-            if constexpr(in_situ<Type>) {
-                new (&storage) Type{std::forward<Args>(args)...};
-            } else {
-                instance = new Type{std::forward<Args>(args)...};
-            }
-        }
-    }
-
-    template<typename Type>
-    meta_storage(std::reference_wrapper<Type> value)
-        : vtable{&basic_vtable<std::add_lvalue_reference_t<Type>>},
-          instance{&value.get()}
-    {}
-
-    template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_storage>>>
-    meta_storage(Type &&value)
-        : meta_storage{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
-    {}
-
-    meta_storage(const meta_storage &other)
-        : meta_storage{}
-    {
-        vtable = other.vtable;
-        vtable(operation::COPY, other, this);
-    }
-
-    meta_storage(meta_storage &&other) ENTT_NOEXCEPT
-        : meta_storage{}
-    {
-        vtable = std::exchange(other.vtable, &basic_vtable<void>);
-        vtable(operation::MOVE, other, this);
-    }
-
-    ~meta_storage() {
-        vtable(operation::DTOR, *this, nullptr);
-    }
-
-    meta_storage & operator=(meta_storage other) {
-        swap(*this, other);
-        return *this;
-    }
-
-    [[nodiscard]] const void * data() const ENTT_NOEXCEPT {
-        return vtable(operation::ADDR, *this, nullptr);
-    }
-
-    [[nodiscard]] void * data() ENTT_NOEXCEPT {
-        return vtable(operation::ADDR, *this, nullptr);
-    }
-
-    template<typename Type, typename... Args>
-    void emplace(Args &&... args) {
-        *this = meta_storage{std::in_place_type<Type>, std::forward<Args>(args)...};
-    }
-
-    [[nodiscard]] meta_storage ref() const ENTT_NOEXCEPT {
-        meta_storage other{};
-        vtable(operation::REF, *this, &other);
-        return other;
-    }
-
-    [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
-        return !(vtable(operation::ADDR, *this, nullptr) == nullptr);
-    }
-
-    friend void swap(meta_storage &lhs, meta_storage &rhs) {
-        meta_storage tmp{};
-        lhs.vtable(operation::MOVE, lhs, &tmp);
-        rhs.vtable(operation::MOVE, rhs, &lhs);
-        lhs.vtable(operation::MOVE, tmp, &rhs);
-        std::swap(lhs.vtable, rhs.vtable);
-    }
-
-private:
-    vtable_type *vtable;
-    union { void *instance; storage_type storage; };
-};
-
-
 struct meta_type_node;
 
 

+ 2 - 1
src/entt/meta/meta.hpp

@@ -10,6 +10,7 @@
 #include <type_traits>
 #include <utility>
 #include "../config/config.h"
+#include "../core/any.hpp"
 #include "../core/fwd.hpp"
 #include "../core/utility.hpp"
 #include "../core/type_info.hpp"
@@ -506,7 +507,7 @@ public:
     }
 
 private:
-    internal::meta_storage storage;
+    any storage;
     internal::meta_type_node *node;
     dereference_operator_type *deref;
     meta_sequence_container(* seq_factory)(void *);