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

meta: support for pointer-like types

Michele Caini 5 лет назад
Родитель
Сommit
2566e3631b

+ 1 - 0
TODO

@@ -32,3 +32,4 @@ Next:
  - meta_any deref fails if operator* returns a temporary
  - remove dereferenceable detector from type traits (is broken)
  - update meta.md
+ - review _t

+ 1 - 0
src/entt/entt.hpp

@@ -25,6 +25,7 @@
 #include "meta/factory.hpp"
 #include "meta/internal.hpp"
 #include "meta/meta.hpp"
+#include "meta/pointer.hpp"
 #include "meta/policy.hpp"
 #include "meta/range.hpp"
 #include "meta/resolve.hpp"

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

@@ -275,7 +275,7 @@ struct meta_type_node {
     const bool is_function_pointer;
     const bool is_member_object_pointer;
     const bool is_member_function_pointer;
-    const bool is_dereferenceable;
+    const bool is_pointer_like;
     const bool is_sequence_container;
     const bool is_associative_container;
     const size_type rank;
@@ -419,7 +419,7 @@ public:
             std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
             std::is_member_object_pointer_v<Type>,
             std::is_member_function_pointer_v<Type>,
-            is_dereferenceable_v<Type>,
+            is_meta_pointer_like_v<Type>,
             has_meta_sequence_container_traits_v<Type>,
             has_meta_associative_container_traits_v<Type>,
             std::rank_v<Type>,

+ 6 - 5
src/entt/meta/meta.hpp

@@ -134,7 +134,7 @@ class meta_any {
     [[nodiscard]] static meta_any dereference_operator(meta_any &any) {
         meta_any other{};
 
-        if constexpr(is_dereferenceable_v<Type>) {
+        if constexpr(is_meta_pointer_like_v<Type>) {
             if constexpr(std::is_const_v<std::remove_reference_t<decltype(*std::declval<Type>())>>) {
                 other = *any.cast<Type>();
             } else {
@@ -1095,11 +1095,12 @@ public:
     }
 
     /**
-     * @brief Checks whether a type is dereferenceable or not.
-     * @return True if the underlying type is dereferenceable, false otherwise.
+     * @brief Checks whether a type is a pointer-like type or not.
+     * @return True if the underlying type is a pointer-like one, false
+     * otherwise.
      */
-    [[nodiscard]] bool is_dereferenceable() const ENTT_NOEXCEPT {
-        return node->is_dereferenceable;
+    [[nodiscard]] bool is_pointer_like() const ENTT_NOEXCEPT {
+        return node->is_pointer_like;
     }
 
     /**

+ 48 - 0
src/entt/meta/pointer.hpp

@@ -0,0 +1,48 @@
+#ifndef ENTT_META_POINTER_HPP
+#define ENTT_META_POINTER_HPP
+
+#include <memory>
+#include <type_traits>
+#include "type_traits.hpp"
+
+
+namespace entt {
+
+
+/**
+ * @brief Makes plain pointers pointer-like types for the meta system.
+ * @tparam Type Element type.
+ */
+template<typename Type>
+struct is_meta_pointer_like<Type *>
+        : std::true_type
+{};
+
+
+/**
+ * @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta
+ * system.
+ * @tparam Type Element type.
+ */
+template<typename Type>
+struct is_meta_pointer_like<std::shared_ptr<Type>>
+        : std::true_type
+{};
+
+
+/**
+ * @brief Makes `std::unique_ptr`s of any type pointer-like types for the meta
+ * system.
+ * @tparam Type Element type.
+ * @tparam Args Other arguments.
+ */
+template<typename Type, typename... Args>
+struct is_meta_pointer_like<std::unique_ptr<Type, Args...>>
+        : std::true_type
+{};
+
+
+}
+
+
+#endif

+ 17 - 0
src/entt/meta/type_traits.hpp

@@ -72,6 +72,23 @@ template<typename Type>
 inline constexpr auto has_meta_associative_container_traits_v = has_meta_associative_container_traits<Type>::value;
 
 
+/**
+ * @brief Provides the member constant `value` to true if a given type is a
+ * pointer-like type from the point of view of the meta system, false otherwise.
+ * @tparam Type Potentially pointer-like type.
+ */
+template<typename>
+struct is_meta_pointer_like: std::false_type {};
+
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Potentially pointer-like type.
+ */
+template<typename Type>
+inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like<Type>::value;
+
+
 }
 
 

+ 1 - 0
test/CMakeLists.txt

@@ -184,6 +184,7 @@ SETUP_BASIC_TEST(meta_conv entt/meta/meta_conv.cpp)
 SETUP_BASIC_TEST(meta_ctor entt/meta/meta_ctor.cpp)
 SETUP_BASIC_TEST(meta_data entt/meta/meta_data.cpp)
 SETUP_BASIC_TEST(meta_func entt/meta/meta_func.cpp)
+SETUP_BASIC_TEST(meta_pointer entt/meta/meta_pointer.cpp)
 SETUP_BASIC_TEST(meta_prop entt/meta/meta_prop.cpp)
 SETUP_BASIC_TEST(meta_range entt/meta/meta_range.cpp)
 SETUP_BASIC_TEST(meta_type entt/meta/meta_type.cpp)

+ 0 - 76
test/entt/meta/meta_any.cpp

@@ -622,79 +622,3 @@ TEST_F(MetaAny, UnmanageableType) {
     ASSERT_TRUE(std::as_const(any).convert<unmanageable_t>());
     ASSERT_FALSE(std::as_const(any).convert<int>());
 }
-
-TEST_F(MetaAny, DereferenceOperatorInvalidType) {
-    int value = 0;
-    entt::meta_any any{value};
-
-    ASSERT_FALSE(any.type().is_pointer());
-    ASSERT_FALSE(any.type().is_dereferenceable());
-    ASSERT_EQ(any.type(), entt::resolve<int>());
-
-    auto deref = *any;
-
-    ASSERT_FALSE(deref);
-}
-
-TEST_F(MetaAny, DereferenceOperatorConstType) {
-    const int value = 0;
-    entt::meta_any any{&value};
-
-    ASSERT_TRUE(any.type().is_pointer());
-    ASSERT_TRUE(any.type().is_dereferenceable());
-    ASSERT_EQ(any.type(), entt::resolve<const int *>());
-
-    auto deref = *any;
-
-    ASSERT_TRUE(deref);
-    ASSERT_FALSE(deref.type().is_pointer());
-    ASSERT_FALSE(deref.type().is_dereferenceable());
-    ASSERT_EQ(deref.type(), entt::resolve<int>());
-
-    deref.cast<int>() = 42;
-
-    ASSERT_EQ(*any.cast<const int *>(), 0);
-    ASSERT_EQ(value, 0);
-}
-
-TEST_F(MetaAny, DereferenceOperatorRawPointer) {
-    int value = 0;
-    entt::meta_any any{&value};
-
-    ASSERT_TRUE(any.type().is_pointer());
-    ASSERT_TRUE(any.type().is_dereferenceable());
-    ASSERT_EQ(any.type(), entt::resolve<int *>());
-
-    auto deref = *any;
-
-    ASSERT_TRUE(deref);
-    ASSERT_FALSE(deref.type().is_pointer());
-    ASSERT_FALSE(deref.type().is_dereferenceable());
-    ASSERT_EQ(deref.type(), entt::resolve<int>());
-
-    deref.cast<int>() = 42;
-
-    ASSERT_EQ(*any.cast<int *>(), 42);
-    ASSERT_EQ(value, 42);
-}
-
-TEST_F(MetaAny, DereferenceOperatorSmartPointer) {
-    auto value = std::make_shared<int>(0);
-    entt::meta_any any{value};
-
-    ASSERT_FALSE(any.type().is_pointer());
-    ASSERT_TRUE(any.type().is_dereferenceable());
-    ASSERT_EQ(any.type(), entt::resolve<std::shared_ptr<int>>());
-
-    auto deref = *any;
-
-    ASSERT_TRUE(deref);
-    ASSERT_FALSE(deref.type().is_pointer());
-    ASSERT_FALSE(deref.type().is_dereferenceable());
-    ASSERT_EQ(deref.type(), entt::resolve<int>());
-
-    deref.cast<int>() = 42;
-
-    ASSERT_EQ(*any.cast<std::shared_ptr<int>>(), 42);
-    ASSERT_EQ(*value, 42);
-}

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

@@ -1,10 +1,8 @@
 #include <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
 #include <entt/meta/container.hpp>
-#include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
 #include <entt/meta/resolve.hpp>
-#include <entt/meta/type_traits.hpp>
 
 TEST(MetaSequenceContainer, Empty) {
     entt::meta_sequence_container container{};

+ 81 - 0
test/entt/meta/meta_pointer.cpp

@@ -0,0 +1,81 @@
+#include <gtest/gtest.h>
+#include <entt/core/hashed_string.hpp>
+#include <entt/meta/meta.hpp>
+#include <entt/meta/pointer.hpp>
+#include <entt/meta/resolve.hpp>
+
+TEST(MetaPointerLike, DereferenceOperatorInvalidType) {
+    int value = 0;
+    entt::meta_any any{value};
+
+    ASSERT_FALSE(any.type().is_pointer());
+    ASSERT_FALSE(any.type().is_pointer_like());
+    ASSERT_EQ(any.type(), entt::resolve<int>());
+
+    auto deref = *any;
+
+    ASSERT_FALSE(deref);
+}
+
+TEST(MetaPointerLike, DereferenceOperatorConstType) {
+    const int value = 0;
+    entt::meta_any any{&value};
+
+    ASSERT_TRUE(any.type().is_pointer());
+    ASSERT_TRUE(any.type().is_pointer_like());
+    ASSERT_EQ(any.type(), entt::resolve<const int *>());
+
+    auto deref = *any;
+
+    ASSERT_TRUE(deref);
+    ASSERT_FALSE(deref.type().is_pointer());
+    ASSERT_FALSE(deref.type().is_pointer_like());
+    ASSERT_EQ(deref.type(), entt::resolve<int>());
+
+    deref.cast<int>() = 42;
+
+    ASSERT_EQ(*any.cast<const int *>(), 0);
+    ASSERT_EQ(value, 0);
+}
+
+TEST(MetaPointerLike, DereferenceOperatorRawPointer) {
+    int value = 0;
+    entt::meta_any any{&value};
+
+    ASSERT_TRUE(any.type().is_pointer());
+    ASSERT_TRUE(any.type().is_pointer_like());
+    ASSERT_EQ(any.type(), entt::resolve<int *>());
+
+    auto deref = *any;
+
+    ASSERT_TRUE(deref);
+    ASSERT_FALSE(deref.type().is_pointer());
+    ASSERT_FALSE(deref.type().is_pointer_like());
+    ASSERT_EQ(deref.type(), entt::resolve<int>());
+
+    deref.cast<int>() = 42;
+
+    ASSERT_EQ(*any.cast<int *>(), 42);
+    ASSERT_EQ(value, 42);
+}
+
+TEST(MetaPointerLike, DereferenceOperatorSmartPointer) {
+    auto value = std::make_shared<int>(0);
+    entt::meta_any any{value};
+
+    ASSERT_FALSE(any.type().is_pointer());
+    ASSERT_TRUE(any.type().is_pointer_like());
+    ASSERT_EQ(any.type(), entt::resolve<std::shared_ptr<int>>());
+
+    auto deref = *any;
+
+    ASSERT_TRUE(deref);
+    ASSERT_FALSE(deref.type().is_pointer());
+    ASSERT_FALSE(deref.type().is_pointer_like());
+    ASSERT_EQ(deref.type(), entt::resolve<int>());
+
+    deref.cast<int>() = 42;
+
+    ASSERT_EQ(*any.cast<std::shared_ptr<int>>(), 42);
+    ASSERT_EQ(*value, 42);
+}

+ 5 - 4
test/entt/meta/meta_type.cpp

@@ -3,10 +3,11 @@
 #include <vector>
 #include <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
+#include <entt/meta/container.hpp>
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
+#include <entt/meta/pointer.hpp>
 #include <entt/meta/resolve.hpp>
-#include <entt/meta/container.hpp>
 
 template<typename Type>
 void set(Type &prop, Type value) {
@@ -164,9 +165,9 @@ TEST_F(MetaType, Traits) {
     ASSERT_TRUE(entt::resolve<decltype(&clazz_t::member)>().is_member_function_pointer());
     ASSERT_FALSE(entt::resolve<decltype(&clazz_t::value)>().is_member_function_pointer());
 
-    ASSERT_TRUE(entt::resolve<int *>().is_dereferenceable());
-    ASSERT_TRUE(entt::resolve<std::shared_ptr<int>>().is_dereferenceable());
-    ASSERT_FALSE(entt::resolve<int>().is_dereferenceable());
+    ASSERT_TRUE(entt::resolve<int *>().is_pointer_like());
+    ASSERT_TRUE(entt::resolve<std::shared_ptr<int>>().is_pointer_like());
+    ASSERT_FALSE(entt::resolve<int>().is_pointer_like());
 
     ASSERT_TRUE(entt::resolve<std::vector<int>>().is_sequence_container());
     ASSERT_FALSE((entt::resolve<std::map<int, char>>().is_sequence_container()));