poly_defined.cpp 6.8 KB

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