poly_defined.cpp 7.1 KB

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