poly_deduced.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #include <functional>
  2. #include <type_traits>
  3. #include <gtest/gtest.h>
  4. #include <entt/core/type_traits.hpp>
  5. #include <entt/poly/poly.hpp>
  6. struct Deduced: entt::type_list<> {
  7. template<typename Base>
  8. struct type: Base {
  9. void incr() { entt::poly_call<0>(*this); }
  10. void set(int v) { entt::poly_call<1>(*this, v); }
  11. int get() const { return entt::poly_call<2>(*this); }
  12. void decr() { entt::poly_call<3>(*this); }
  13. int mul(int v) const { return static_cast<int>(entt::poly_call<4>(*this, v)); }
  14. };
  15. template<typename Type>
  16. struct members {
  17. static void decr(Type &self) { self.set(self.get()-1); }
  18. static double mul(const Type &self, double v) { return v * self.get(); }
  19. };
  20. template<typename Type>
  21. using impl = entt::value_list<
  22. &Type::incr,
  23. &Type::set,
  24. &Type::get,
  25. &members<Type>::decr,
  26. &members<Type>::mul
  27. >;
  28. };
  29. struct impl {
  30. impl() = default;
  31. impl(int v): value{v} {}
  32. void incr() { ++value; }
  33. void set(int v) { value = v; }
  34. int get() const { return value; }
  35. void decrement() { --value; }
  36. double multiply(double v) const { return v * value; }
  37. int value{};
  38. };
  39. struct alignas(64u) over_aligned: impl {};
  40. TEST(PolyDeduced, Functionalities) {
  41. impl instance{};
  42. entt::poly<Deduced> empty{};
  43. entt::poly<Deduced> in_place{std::in_place_type<impl>, 3};
  44. entt::poly<Deduced> alias{std::in_place_type<impl &>, instance};
  45. entt::poly<Deduced> value{impl{}};
  46. ASSERT_FALSE(empty);
  47. ASSERT_TRUE(in_place);
  48. ASSERT_TRUE(alias);
  49. ASSERT_TRUE(value);
  50. ASSERT_EQ(empty.type(), entt::type_info{});
  51. ASSERT_EQ(in_place.type(), entt::type_id<impl>());
  52. ASSERT_EQ(alias.type(), entt::type_id<impl>());
  53. ASSERT_EQ(value.type(), entt::type_id<impl>());
  54. ASSERT_EQ(alias.data(), &instance);
  55. ASSERT_EQ(std::as_const(alias).data(), &instance);
  56. empty = impl{};
  57. ASSERT_TRUE(empty);
  58. ASSERT_NE(empty.data(), nullptr);
  59. ASSERT_NE(std::as_const(empty).data(), nullptr);
  60. ASSERT_EQ(empty.type(), entt::type_id<impl>());
  61. ASSERT_EQ(empty->get(), 0);
  62. empty.template emplace<impl>(3);
  63. ASSERT_TRUE(empty);
  64. ASSERT_EQ(empty->get(), 3);
  65. entt::poly<Deduced> ref = in_place.as_ref();
  66. ASSERT_TRUE(ref);
  67. ASSERT_NE(ref.data(), nullptr);
  68. ASSERT_EQ(ref.data(), in_place.data());
  69. ASSERT_EQ(std::as_const(ref).data(), std::as_const(in_place).data());
  70. ASSERT_EQ(ref.type(), entt::type_id<impl>());
  71. ASSERT_EQ(ref->get(), 3);
  72. entt::poly<Deduced> null{};
  73. std::swap(empty, null);
  74. ASSERT_FALSE(empty);
  75. entt::poly<Deduced> copy = in_place;
  76. ASSERT_TRUE(copy);
  77. ASSERT_EQ(copy->get(), 3);
  78. entt::poly<Deduced> move = std::move(copy);
  79. ASSERT_TRUE(move);
  80. ASSERT_FALSE(copy);
  81. ASSERT_EQ(move->get(), 3);
  82. move.reset();
  83. ASSERT_FALSE(move);
  84. ASSERT_EQ(move.type(), entt::type_info{});
  85. }
  86. TEST(PolyDeduced, Owned) {
  87. entt::poly<Deduced> poly{impl{}};
  88. auto *ptr = static_cast<impl *>(poly.data());
  89. ASSERT_TRUE(poly);
  90. ASSERT_NE(poly.data(), nullptr);
  91. ASSERT_NE(std::as_const(poly).data(), nullptr);
  92. ASSERT_EQ(ptr->value, 0);
  93. ASSERT_EQ(poly->get(), 0);
  94. poly->set(1);
  95. poly->incr();
  96. ASSERT_EQ(ptr->value, 2);
  97. ASSERT_EQ(poly->get(), 2);
  98. ASSERT_EQ(poly->mul(3), 6);
  99. poly->decr();
  100. ASSERT_EQ(ptr->value, 1);
  101. ASSERT_EQ(poly->get(), 1);
  102. ASSERT_EQ(poly->mul(3), 3);
  103. }
  104. TEST(PolyDeduced, Reference) {
  105. impl instance{};
  106. entt::poly<Deduced> poly{std::in_place_type<impl &>, instance};
  107. ASSERT_TRUE(poly);
  108. ASSERT_NE(poly.data(), nullptr);
  109. ASSERT_NE(std::as_const(poly).data(), nullptr);
  110. ASSERT_EQ(instance.value, 0);
  111. ASSERT_EQ(poly->get(), 0);
  112. poly->set(1);
  113. poly->incr();
  114. ASSERT_EQ(instance.value, 2);
  115. ASSERT_EQ(poly->get(), 2);
  116. ASSERT_EQ(poly->mul(3), 6);
  117. poly->decr();
  118. ASSERT_EQ(instance.value, 1);
  119. ASSERT_EQ(poly->get(), 1);
  120. ASSERT_EQ(poly->mul(3), 3);
  121. }
  122. TEST(PolyDeduced, ConstReference) {
  123. impl instance{};
  124. entt::poly<Deduced> poly{std::in_place_type<const impl &>, instance};
  125. ASSERT_TRUE(poly);
  126. ASSERT_EQ(poly.data(), nullptr);
  127. ASSERT_NE(std::as_const(poly).data(), nullptr);
  128. ASSERT_EQ(instance.value, 0);
  129. ASSERT_EQ(poly->get(), 0);
  130. ASSERT_DEATH(poly->set(1), "");
  131. ASSERT_DEATH(poly->incr(), "");
  132. ASSERT_EQ(instance.value, 0);
  133. ASSERT_EQ(poly->get(), 0);
  134. ASSERT_EQ(poly->mul(3), 0);
  135. ASSERT_DEATH(poly->decr(), "");
  136. ASSERT_EQ(instance.value, 0);
  137. ASSERT_EQ(poly->get(), 0);
  138. ASSERT_EQ(poly->mul(3), 0);
  139. }
  140. TEST(PolyDeduced, AsRef) {
  141. entt::poly<Deduced> poly{impl{}};
  142. auto ref = poly.as_ref();
  143. auto cref = std::as_const(poly).as_ref();
  144. ASSERT_NE(poly.data(), nullptr);
  145. ASSERT_NE(ref.data(), nullptr);
  146. ASSERT_EQ(cref.data(), nullptr);
  147. ASSERT_NE(std::as_const(cref).data(), nullptr);
  148. std::swap(ref, cref);
  149. ASSERT_EQ(ref.data(), nullptr);
  150. ASSERT_NE(std::as_const(ref).data(), nullptr);
  151. ASSERT_NE(cref.data(), nullptr);
  152. ref = ref.as_ref();
  153. cref = std::as_const(cref).as_ref();
  154. ASSERT_EQ(ref.data(), nullptr);
  155. ASSERT_NE(std::as_const(ref).data(), nullptr);
  156. ASSERT_EQ(cref.data(), nullptr);
  157. ASSERT_NE(std::as_const(cref).data(), nullptr);
  158. ref = impl{};
  159. cref = impl{};
  160. ASSERT_NE(ref.data(), nullptr);
  161. ASSERT_NE(cref.data(), nullptr);
  162. }
  163. TEST(PolyDeduced, SBOVsZeroedSBOSize) {
  164. entt::poly<Deduced> sbo{impl{}};
  165. const auto broken = sbo.data();
  166. entt::poly<Deduced> other = std::move(sbo);
  167. ASSERT_NE(broken, other.data());
  168. entt::basic_poly<Deduced, 0u> dyn{impl{}};
  169. const auto valid = dyn.data();
  170. entt::basic_poly<Deduced, 0u> same = std::move(dyn);
  171. ASSERT_EQ(valid, same.data());
  172. // everything works as expected
  173. same->incr();
  174. ASSERT_EQ(same->get(), 1);
  175. }
  176. TEST(PolyDeduced, Alignment) {
  177. static constexpr auto alignment = alignof(over_aligned);
  178. auto test = [](auto *target, auto cb) {
  179. const auto *data = target[0].data();
  180. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[0u].data()) % alignment) == 0u);
  181. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[1u].data()) % alignment) == 0u);
  182. std::swap(target[0], target[1]);
  183. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[0u].data()) % alignment) == 0u);
  184. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[1u].data()) % alignment) == 0u);
  185. cb(data, target[1].data());
  186. };
  187. entt::basic_poly<Deduced, alignment> nosbo[2] = { over_aligned{}, over_aligned{} };
  188. test(nosbo, [](auto *pre, auto *post) { ASSERT_EQ(pre, post); });
  189. entt::basic_poly<Deduced, alignment, alignment> sbo[2] = { over_aligned{}, over_aligned{} };
  190. test(sbo, [](auto *pre, auto *post) { ASSERT_NE(pre, post); });
  191. }