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

poly: compile-time checks on embedded vtables + code coverage

Michele Caini 4 лет назад
Родитель
Сommit
5a956d2914
2 измененных файлов с 109 добавлено и 76 удалено
  1. 1 0
      src/entt/poly/poly.hpp
  2. 108 76
      test/entt/poly/poly.cpp

+ 1 - 0
src/entt/poly/poly.hpp

@@ -152,6 +152,7 @@ struct poly_base {
         auto &poly = static_cast<Poly &>(self);
 
         if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
+            static_assert(Member == 0u, "Unknown member");
             return poly.vtable(poly.storage, std::forward<Args>(args)...);
         } else {
             return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);

+ 108 - 76
test/entt/poly/poly.cpp

@@ -4,49 +4,67 @@
 #include <entt/core/type_traits.hpp>
 #include <entt/poly/poly.hpp>
 
-struct Deduced
-    : entt::type_list<> {
-    template<typename Base>
-    struct type: Base {
-        void incr() {
-            entt::poly_call<0>(*this);
-        }
+template<typename Base>
+struct common_type: Base {
+    void incr() {
+        entt::poly_call<0>(*this);
+    }
 
-        void set(int v) {
-            entt::poly_call<1>(*this, v);
-        }
+    void set(int v) {
+        entt::poly_call<1>(*this, v);
+    }
 
-        int get() const {
-            return entt::poly_call<2>(*this);
-        }
+    int get() const {
+        return entt::poly_call<2>(*this);
+    }
 
-        void decr() {
-            entt::poly_call<3>(*this);
-        }
+    void decr() {
+        entt::poly_call<3>(*this);
+    }
 
-        int mul(int v) const {
-            return static_cast<int>(entt::poly_call<4>(*this, v));
-        }
-    };
+    int mul(int v) const {
+        return entt::poly_call<4>(*this, v);
+    }
 
-    template<typename Type>
-    struct members {
-        static void decr(Type &self) {
-            self.set(self.get() - 1);
-        }
+    int rand() const {
+        return entt::poly_call<5>(*this);
+    }
+};
 
-        static double mul(const Type &self, double v) {
-            return v * self.get();
-        }
-    };
+template<typename Type>
+struct common_members {
+    static void decr(Type &self) {
+        self.set(self.get() - 1);
+    }
+
+    static double mul(const Type &self, double v) {
+        return v * self.get();
+    }
+};
+
+static int absolutely_random() {
+    return 42;
+}
+
+template<typename Type>
+using common_impl = entt::value_list<
+    &Type::incr,
+    &Type::set,
+    &Type::get,
+    &common_members<Type>::decr,
+    &common_members<Type>::mul,
+    &absolutely_random>;
+
+struct Deduced
+    : entt::type_list<> {
+    template<typename Base>
+    using type = common_type<Base>;
+
+    template<typename Type>
+    using members = common_members<Type>;
 
     template<typename Type>
-    using impl = entt::value_list<
-        &Type::incr,
-        &Type::set,
-        &Type::get,
-        &members<Type>::decr,
-        &members<Type>::mul>;
+    using impl = common_impl<Type>;
 };
 
 struct Defined
@@ -55,48 +73,43 @@ struct Defined
           void(int),
           int() const,
           void(),
-          int(int) const> {
+          int(int) const,
+          int() const> {
     template<typename Base>
-    struct type: Base {
-        void incr() {
-            entt::poly_call<0>(*this);
-        }
+    using type = common_type<Base>;
 
-        void set(int v) {
-            entt::poly_call<1>(*this, v);
-        }
-
-        int get() const {
-            return entt::poly_call<2>(*this);
-        }
+    template<typename Type>
+    using members = common_members<Type>;
 
-        void decr() {
-            entt::poly_call<3>(*this);
-        }
+    template<typename Type>
+    using impl = common_impl<Type>;
+};
 
-        int mul(int v) const {
-            return entt::poly_call<4>(*this, v);
+struct DeducedEmbedded
+    : entt::type_list<> {
+    template<typename Base>
+    struct type: Base {
+        int get() const {
+            return entt::poly_call<0>(*this);
         }
     };
 
     template<typename Type>
-    struct members {
-        static void decr(Type &self) {
-            self.decrement();
-        }
+    using impl = entt::value_list<&Type::get>;
+};
 
-        static double mul(const Type &self, double v) {
-            return self.multiply(v);
+struct DefinedEmbedded
+    : entt::type_list<int()> {
+    template<typename Base>
+    struct type: Base {
+        // non-const get on purpose
+        int get() {
+            return entt::poly_call<0>(*this);
         }
     };
 
     template<typename Type>
-    using impl = entt::value_list<
-        &Type::incr,
-        &Type::set,
-        &Type::get,
-        &members<Type>::decr,
-        &members<Type>::mul>;
+    using impl = entt::value_list<&Type::get>;
 };
 
 struct impl {
@@ -117,14 +130,6 @@ struct impl {
         return value;
     }
 
-    void decrement() {
-        --value;
-    }
-
-    double multiply(double v) const {
-        return v * value;
-    }
-
     int value{};
 };
 
@@ -144,6 +149,15 @@ using PolyTypes = ::testing::Types<Deduced, Defined>;
 TYPED_TEST_SUITE(Poly, PolyTypes, );
 TYPED_TEST_SUITE(PolyDeathTest, PolyTypes, );
 
+template<typename Type>
+struct PolyEmbedded: testing::Test {
+    using type = entt::basic_poly<Type>;
+};
+
+using PolyEmbeddedTypes = ::testing::Types<DeducedEmbedded, DefinedEmbedded>;
+
+TYPED_TEST_SUITE(PolyEmbedded, PolyEmbeddedTypes, );
+
 TYPED_TEST(Poly, Functionalities) {
     using poly_type = typename TestFixture::template type<>;
 
@@ -167,6 +181,8 @@ TYPED_TEST(Poly, Functionalities) {
     ASSERT_EQ(alias.data(), &instance);
     ASSERT_EQ(std::as_const(alias).data(), &instance);
 
+    ASSERT_EQ(value->rand(), 42);
+
     empty = impl{};
 
     ASSERT_TRUE(empty);
@@ -178,7 +194,7 @@ TYPED_TEST(Poly, Functionalities) {
     empty.template emplace<impl>(3);
 
     ASSERT_TRUE(empty);
-    ASSERT_EQ(empty->get(), 3);
+    ASSERT_EQ(std::as_const(empty)->get(), 3);
 
     poly_type ref = in_place.as_ref();
 
@@ -211,6 +227,22 @@ TYPED_TEST(Poly, Functionalities) {
     ASSERT_EQ(move.type(), entt::type_id<void>());
 }
 
+TYPED_TEST(PolyEmbedded, EmbeddedVtable) {
+    using poly_type = typename TestFixture::type;
+
+    poly_type poly{impl{}};
+    auto *ptr = static_cast<impl *>(poly.data());
+
+    ASSERT_TRUE(poly);
+    ASSERT_NE(poly.data(), nullptr);
+    ASSERT_NE(std::as_const(poly).data(), nullptr);
+    ASSERT_EQ(poly->get(), 0);
+
+    ptr->value = 2;
+
+    ASSERT_EQ(poly->get(), 2);
+}
+
 TYPED_TEST(Poly, Owned) {
     using poly_type = typename TestFixture::template type<>;
 
@@ -227,7 +259,7 @@ TYPED_TEST(Poly, Owned) {
     poly->incr();
 
     ASSERT_EQ(ptr->value, 2);
-    ASSERT_EQ(poly->get(), 2);
+    ASSERT_EQ(std::as_const(poly)->get(), 2);
     ASSERT_EQ(poly->mul(3), 6);
 
     poly->decr();
@@ -253,7 +285,7 @@ TYPED_TEST(Poly, Reference) {
     poly->incr();
 
     ASSERT_EQ(instance.value, 2);
-    ASSERT_EQ(poly->get(), 2);
+    ASSERT_EQ(std::as_const(poly)->get(), 2);
     ASSERT_EQ(poly->mul(3), 6);
 
     poly->decr();
@@ -276,7 +308,7 @@ TYPED_TEST(Poly, ConstReference) {
     ASSERT_EQ(poly->get(), 0);
 
     ASSERT_EQ(instance.value, 0);
-    ASSERT_EQ(poly->get(), 0);
+    ASSERT_EQ(std::as_const(poly)->get(), 0);
     ASSERT_EQ(poly->mul(3), 0);
 
     ASSERT_EQ(instance.value, 0);