Michele Caini 5 лет назад
Родитель
Сommit
83322664f1
3 измененных файлов с 95 добавлено и 15 удалено
  1. 83 12
      src/entt/core/any.hpp
  2. 2 2
      src/entt/meta/meta.hpp
  3. 10 1
      test/entt/core/any.cpp

+ 83 - 12
src/entt/core/any.hpp

@@ -13,6 +13,7 @@
 namespace entt {
 
 
+/*! @brief A type-safe container for single values of any type. */
 class any {
     enum class operation { COPY, MOVE, DTOR, ADDR, REF, TYPE };
 
@@ -99,6 +100,12 @@ public:
           instance{}
     {}
 
+    /**
+     * @brief Constructs an any by directly initializing the new object.
+     * @tparam Type Type of object to use to initialize the wrapper.
+     * @tparam Args Types of arguments to use to construct the new instance.
+     * @param args Parameters to use to construct the instance.
+     */
     template<typename Type, typename... Args>
     explicit any(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
         : vtable{&basic_vtable<Type>},
@@ -113,17 +120,31 @@ public:
         }
     }
 
+    /**
+     * @brief Constructs an any that holds an unmanaged object.
+     * @tparam Type Type of object to use to initialize the wrapper.
+     * @param value An instance of an object to use to initialize the wrapper.
+     */
     template<typename Type>
     any(std::reference_wrapper<Type> value)
         : vtable{&basic_vtable<std::add_lvalue_reference_t<Type>>},
           instance{&value.get()}
     {}
 
+    /**
+     * @brief Constructs an any from a given value.
+     * @tparam Type Type of object to use to initialize the wrapper.
+     * @param value An instance of an object to use to initialize the wrapper.
+     */
     template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, any>>>
     any(Type &&value)
         : any{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
     {}
 
+    /**
+     * @brief Copy constructor.
+     * @param other The instance to copy from.
+     */
     any(const any &other)
         : any{}
     {
@@ -131,6 +152,10 @@ public:
         vtable(operation::COPY, other, this);
     }
 
+    /**
+     * @brief Move constructor.
+     * @param other The instance to move from.
+     */
     any(any &&other) ENTT_NOEXCEPT
         : any{}
     {
@@ -138,44 +163,78 @@ public:
         vtable(operation::MOVE, other, this);
     }
 
+    /*! @brief Frees the internal storage, whatever it means. */
     ~any() {
         vtable(operation::DTOR, *this, nullptr);
     }
 
+    /**
+     * @brief Assignment operator.
+     * @param other The instance to assign from.
+     * @return This any any object.
+     */
     any & operator=(any other) {
         swap(*this, other);
         return *this;
     }
 
+    /**
+     * @brief Returns the type of the contained object.
+     * @return The type of the contained object, if any.
+     */
+    [[nodiscard]] type_info type() const ENTT_NOEXCEPT {
+        type_info info;
+        vtable(operation::TYPE, *this, &info);
+        return info;
+    }
+
+    /**
+     * @brief Returns an opaque pointer to the contained instance.
+     * @return An opaque pointer the contained instance, if any.
+     */
     [[nodiscard]] const void * data() const ENTT_NOEXCEPT {
         return vtable(operation::ADDR, *this, nullptr);
     }
 
+    /*! @copydoc data */
     [[nodiscard]] void * data() ENTT_NOEXCEPT {
         return const_cast<void *>(std::as_const(*this).data());
     }
 
+    /**
+     * @brief Replaces the contained object by creating a new instance directly.
+     * @tparam Type Type of object to use to initialize the wrapper.
+     * @tparam Args Types of arguments to use to construct the new instance.
+     * @param args Parameters to use to construct the instance.
+     */
     template<typename Type, typename... Args>
     void emplace(Args &&... args) {
         *this = any{std::in_place_type<Type>, std::forward<Args>(args)...};
     }
 
+    /**
+     * @brief Aliasing constructor.
+     * @return An any that shares a reference to an unmanaged object.
+     */
     [[nodiscard]] any ref() const ENTT_NOEXCEPT {
         any other{};
         vtable(operation::REF, *this, &other);
         return other;
     }
 
-    [[nodiscard]] type_info type() const ENTT_NOEXCEPT {
-        type_info info;
-        vtable(operation::TYPE, *this, &info);
-        return info;
-    }
-
+    /**
+     * @brief Returns false if a wrapper is empty, true otherwise.
+     * @return False if the wrapper is empty, true otherwise.
+     */
     [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
         return !(vtable(operation::ADDR, *this, nullptr) == nullptr);
     }
 
+    /**
+     * @brief Swaps two any objects.
+     * @param lhs A valid any object.
+     * @param rhs A valid any object.
+     */
     friend void swap(any &lhs, any &rhs) {
         any tmp{};
         lhs.vtable(operation::MOVE, lhs, &tmp);
@@ -190,33 +249,45 @@ private:
 };
 
 
+/**
+ * @brief Performs type-safe access to the contained object.
+ * @param any Target any object.
+ * @return The element converted to the requested type.
+ */
 template<typename Type>
 Type any_cast(const any &any) ENTT_NOEXCEPT {
-    ENTT_ASSERT(any.type() == type_id<Type>());
-    return *static_cast<const Type *>(any.data());
+    auto *instance = any_cast<std::remove_cv_t<std::remove_reference_t<Type>>>(&any);
+    ENTT_ASSERT(instance);
+    return static_cast<Type>(*instance);
 }
 
 
+/*! @copydoc any_cast */
 template<typename Type>
 Type any_cast(any &any) ENTT_NOEXCEPT {
-    ENTT_ASSERT(any.type() == type_id<Type>());
-    return *static_cast<Type *>(any.data());
+    auto *instance = any_cast<std::remove_cv_t<std::remove_reference_t<Type>>>(&any);
+    ENTT_ASSERT(instance);
+    return static_cast<Type>(*instance);
 }
 
 
+/*! @copydoc any_cast */
 template<typename Type>
 Type any_cast(any &&any) ENTT_NOEXCEPT {
-    ENTT_ASSERT(any.type() == type_id<Type>());
-    return std::move(*static_cast<Type *>(any.data()));
+    auto *instance = any_cast<std::remove_cv_t<std::remove_reference_t<Type>>>(&any);
+    ENTT_ASSERT(instance);
+    return static_cast<Type>(std::move(*instance));
 }
 
 
+/*! @copydoc any_cast */
 template<typename Type>
 const Type * any_cast(const any *any) ENTT_NOEXCEPT {
     return (any->type() == type_id<Type>() ? static_cast<const Type *>(any->data()) : nullptr);
 }
 
 
+/*! @copydoc any_cast */
 template<typename Type>
 Type * any_cast(any *any) ENTT_NOEXCEPT {
     return (any->type() == type_id<Type>() ? static_cast<Type *>(any->data()) : nullptr);

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

@@ -476,8 +476,8 @@ public:
     }
 
     /**
-     * @brief Returns false if a wrapper is empty, true otherwise.
-     * @return False if the wrapper is empty, true otherwise.
+     * @brief Returns false if a wrapper is invalid, true otherwise.
+     * @return False if the wrapper is invalid, true otherwise.
      */
     [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
         return !(node == nullptr);

+ 10 - 1
test/entt/core/any.cpp

@@ -540,6 +540,15 @@ TEST(Any, NoSBOWithVoidSwap) {
     ASSERT_EQ(entt::any_cast<fat>(lhs), (fat{{.1, .2, .3, .4}}));
 }
 
-TEST(Any, AnyCastTemporary) {
+TEST(Any, AnyCast) {
+    entt::any any{42};
+    const auto &cany = any;
+
+    ASSERT_EQ(entt::any_cast<char>(&any), nullptr);
+    ASSERT_EQ(entt::any_cast<char>(&cany), nullptr);
+    ASSERT_EQ(*entt::any_cast<int>(&any), 42);
+    ASSERT_EQ(*entt::any_cast<int>(&cany), 42);
+    ASSERT_EQ(entt::any_cast<int &>(any), 42);
+    ASSERT_EQ(entt::any_cast<const int &>(cany), 42);
     ASSERT_EQ(entt::any_cast<int>(42), 42);
 }