poly.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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
  7. : entt::type_list<> {
  8. template<typename Base>
  9. struct type: Base {
  10. void incr() {
  11. entt::poly_call<0>(*this);
  12. }
  13. void set(int v) {
  14. entt::poly_call<1>(*this, v);
  15. }
  16. int get() const {
  17. return entt::poly_call<2>(*this);
  18. }
  19. void decr() {
  20. entt::poly_call<3>(*this);
  21. }
  22. int mul(int v) const {
  23. return static_cast<int>(entt::poly_call<4>(*this, v));
  24. }
  25. };
  26. template<typename Type>
  27. struct members {
  28. static void decr(Type &self) {
  29. self.set(self.get() - 1);
  30. }
  31. static double mul(const Type &self, double v) {
  32. return v * self.get();
  33. }
  34. };
  35. template<typename Type>
  36. using impl = entt::value_list<
  37. &Type::incr,
  38. &Type::set,
  39. &Type::get,
  40. &members<Type>::decr,
  41. &members<Type>::mul>;
  42. };
  43. struct Defined
  44. : entt::type_list<
  45. void(),
  46. void(int),
  47. int() const,
  48. void(),
  49. int(int) const> {
  50. template<typename Base>
  51. struct type: Base {
  52. void incr() {
  53. entt::poly_call<0>(*this);
  54. }
  55. void set(int v) {
  56. entt::poly_call<1>(*this, v);
  57. }
  58. int get() const {
  59. return entt::poly_call<2>(*this);
  60. }
  61. void decr() {
  62. entt::poly_call<3>(*this);
  63. }
  64. int mul(int v) const {
  65. return entt::poly_call<4>(*this, v);
  66. }
  67. };
  68. template<typename Type>
  69. struct members {
  70. static void decr(Type &self) {
  71. self.decrement();
  72. }
  73. static double mul(const Type &self, double v) {
  74. return self.multiply(v);
  75. }
  76. };
  77. template<typename Type>
  78. using impl = entt::value_list<
  79. &Type::incr,
  80. &Type::set,
  81. &Type::get,
  82. &members<Type>::decr,
  83. &members<Type>::mul>;
  84. };
  85. struct impl {
  86. impl() = default;
  87. impl(int v)
  88. : value{v} {}
  89. void incr() {
  90. ++value;
  91. }
  92. void set(int v) {
  93. value = v;
  94. }
  95. int get() const {
  96. return value;
  97. }
  98. void decrement() {
  99. --value;
  100. }
  101. double multiply(double v) const {
  102. return v * value;
  103. }
  104. int value{};
  105. };
  106. template<typename Type>
  107. struct Poly: testing::Test {
  108. using basic = entt::poly<Type>;
  109. using zeroed = entt::basic_poly<Type, 0>;
  110. struct alignas(64u) over_aligned: impl {};
  111. static constexpr auto alignment = alignof(over_aligned);
  112. static inline entt::basic_poly<Type, alignment, alignment> sbo[2] = {over_aligned{}, over_aligned{}};
  113. static inline entt::basic_poly<Type, alignment> nosbo[2] = {over_aligned{}, over_aligned{}};
  114. };
  115. template<typename Type>
  116. using PolyDeathTest = Poly<Type>;
  117. using PolyTypes = ::testing::Types<Deduced, Defined>;
  118. TYPED_TEST_SUITE(Poly, PolyTypes, );
  119. TYPED_TEST_SUITE(PolyDeathTest, PolyTypes, );
  120. TYPED_TEST(Poly, Functionalities) {
  121. using poly_type = typename TestFixture::basic;
  122. impl instance{};
  123. poly_type empty{};
  124. poly_type in_place{std::in_place_type<impl>, 3};
  125. poly_type alias{std::in_place_type<impl &>, instance};
  126. poly_type value{impl{}};
  127. ASSERT_FALSE(empty);
  128. ASSERT_TRUE(in_place);
  129. ASSERT_TRUE(alias);
  130. ASSERT_TRUE(value);
  131. ASSERT_EQ(empty.type(), entt::type_id<void>());
  132. ASSERT_EQ(in_place.type(), entt::type_id<impl>());
  133. ASSERT_EQ(alias.type(), entt::type_id<impl>());
  134. ASSERT_EQ(value.type(), entt::type_id<impl>());
  135. ASSERT_EQ(alias.data(), &instance);
  136. ASSERT_EQ(std::as_const(alias).data(), &instance);
  137. empty = impl{};
  138. ASSERT_TRUE(empty);
  139. ASSERT_NE(empty.data(), nullptr);
  140. ASSERT_NE(std::as_const(empty).data(), nullptr);
  141. ASSERT_EQ(empty.type(), entt::type_id<impl>());
  142. ASSERT_EQ(empty->get(), 0);
  143. empty.template emplace<impl>(3);
  144. ASSERT_TRUE(empty);
  145. ASSERT_EQ(empty->get(), 3);
  146. poly_type ref = in_place.as_ref();
  147. ASSERT_TRUE(ref);
  148. ASSERT_NE(ref.data(), nullptr);
  149. ASSERT_EQ(ref.data(), in_place.data());
  150. ASSERT_EQ(std::as_const(ref).data(), std::as_const(in_place).data());
  151. ASSERT_EQ(ref.type(), entt::type_id<impl>());
  152. ASSERT_EQ(ref->get(), 3);
  153. poly_type null{};
  154. std::swap(empty, null);
  155. ASSERT_FALSE(empty);
  156. poly_type copy = in_place;
  157. ASSERT_TRUE(copy);
  158. ASSERT_EQ(copy->get(), 3);
  159. poly_type move = std::move(copy);
  160. ASSERT_TRUE(move);
  161. ASSERT_TRUE(copy);
  162. ASSERT_EQ(move->get(), 3);
  163. move.reset();
  164. ASSERT_FALSE(move);
  165. ASSERT_EQ(move.type(), entt::type_id<void>());
  166. }
  167. TYPED_TEST(Poly, Owned) {
  168. using poly_type = typename TestFixture::basic;
  169. poly_type poly{impl{}};
  170. auto *ptr = static_cast<impl *>(poly.data());
  171. ASSERT_TRUE(poly);
  172. ASSERT_NE(poly.data(), nullptr);
  173. ASSERT_NE(std::as_const(poly).data(), nullptr);
  174. ASSERT_EQ(ptr->value, 0);
  175. ASSERT_EQ(poly->get(), 0);
  176. poly->set(1);
  177. poly->incr();
  178. ASSERT_EQ(ptr->value, 2);
  179. ASSERT_EQ(poly->get(), 2);
  180. ASSERT_EQ(poly->mul(3), 6);
  181. poly->decr();
  182. ASSERT_EQ(ptr->value, 1);
  183. ASSERT_EQ(poly->get(), 1);
  184. ASSERT_EQ(poly->mul(3), 3);
  185. }
  186. TYPED_TEST(Poly, Reference) {
  187. using poly_type = typename TestFixture::basic;
  188. impl instance{};
  189. poly_type poly{std::in_place_type<impl &>, instance};
  190. ASSERT_TRUE(poly);
  191. ASSERT_NE(poly.data(), nullptr);
  192. ASSERT_NE(std::as_const(poly).data(), nullptr);
  193. ASSERT_EQ(instance.value, 0);
  194. ASSERT_EQ(poly->get(), 0);
  195. poly->set(1);
  196. poly->incr();
  197. ASSERT_EQ(instance.value, 2);
  198. ASSERT_EQ(poly->get(), 2);
  199. ASSERT_EQ(poly->mul(3), 6);
  200. poly->decr();
  201. ASSERT_EQ(instance.value, 1);
  202. ASSERT_EQ(poly->get(), 1);
  203. ASSERT_EQ(poly->mul(3), 3);
  204. }
  205. TYPED_TEST(Poly, ConstReference) {
  206. using poly_type = typename TestFixture::basic;
  207. impl instance{};
  208. poly_type poly{std::in_place_type<const impl &>, instance};
  209. ASSERT_TRUE(poly);
  210. ASSERT_EQ(poly.data(), nullptr);
  211. ASSERT_NE(std::as_const(poly).data(), nullptr);
  212. ASSERT_EQ(instance.value, 0);
  213. ASSERT_EQ(poly->get(), 0);
  214. ASSERT_EQ(instance.value, 0);
  215. ASSERT_EQ(poly->get(), 0);
  216. ASSERT_EQ(poly->mul(3), 0);
  217. ASSERT_EQ(instance.value, 0);
  218. ASSERT_EQ(poly->get(), 0);
  219. ASSERT_EQ(poly->mul(3), 0);
  220. }
  221. TYPED_TEST(PolyDeathTest, ConstReference) {
  222. using poly_type = typename TestFixture::basic;
  223. impl instance{};
  224. poly_type poly{std::in_place_type<const impl &>, instance};
  225. ASSERT_TRUE(poly);
  226. ASSERT_DEATH(poly->set(1), "");
  227. }
  228. TYPED_TEST(Poly, AsRef) {
  229. using poly_type = typename TestFixture::basic;
  230. poly_type poly{impl{}};
  231. auto ref = poly.as_ref();
  232. auto cref = std::as_const(poly).as_ref();
  233. ASSERT_NE(poly.data(), nullptr);
  234. ASSERT_NE(ref.data(), nullptr);
  235. ASSERT_EQ(cref.data(), nullptr);
  236. ASSERT_NE(std::as_const(cref).data(), nullptr);
  237. std::swap(ref, cref);
  238. ASSERT_EQ(ref.data(), nullptr);
  239. ASSERT_NE(std::as_const(ref).data(), nullptr);
  240. ASSERT_NE(cref.data(), nullptr);
  241. ref = ref.as_ref();
  242. cref = std::as_const(cref).as_ref();
  243. ASSERT_EQ(ref.data(), nullptr);
  244. ASSERT_NE(std::as_const(ref).data(), nullptr);
  245. ASSERT_EQ(cref.data(), nullptr);
  246. ASSERT_NE(std::as_const(cref).data(), nullptr);
  247. ref = impl{};
  248. cref = impl{};
  249. ASSERT_NE(ref.data(), nullptr);
  250. ASSERT_NE(cref.data(), nullptr);
  251. }
  252. TYPED_TEST(Poly, SBOVsZeroedSBOSize) {
  253. using poly_type = typename TestFixture::basic;
  254. using zeroed_type = typename TestFixture::zeroed;
  255. poly_type poly{impl{}};
  256. const auto broken = poly.data();
  257. poly_type other = std::move(poly);
  258. ASSERT_NE(broken, other.data());
  259. zeroed_type dyn{impl{}};
  260. const auto valid = dyn.data();
  261. zeroed_type same = std::move(dyn);
  262. ASSERT_EQ(valid, same.data());
  263. // everything works as expected
  264. same->incr();
  265. ASSERT_EQ(same->get(), 1);
  266. }
  267. TYPED_TEST(Poly, SboAlignment) {
  268. const auto *data = TestFixture::sbo[0].data();
  269. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::sbo[0u].data()) % TestFixture::alignment) == 0u);
  270. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::sbo[1u].data()) % TestFixture::alignment) == 0u);
  271. std::swap(TestFixture::sbo[0], TestFixture::sbo[1]);
  272. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::sbo[0u].data()) % TestFixture::alignment) == 0u);
  273. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::sbo[1u].data()) % TestFixture::alignment) == 0u);
  274. ASSERT_NE(data, TestFixture::sbo[1].data());
  275. }
  276. TYPED_TEST(Poly, NoSboAlignment) {
  277. const auto *data = TestFixture::nosbo[0].data();
  278. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::nosbo[0u].data()) % TestFixture::alignment) == 0u);
  279. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::nosbo[1u].data()) % TestFixture::alignment) == 0u);
  280. std::swap(TestFixture::nosbo[0], TestFixture::nosbo[1]);
  281. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::nosbo[0u].data()) % TestFixture::alignment) == 0u);
  282. ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::nosbo[1u].data()) % TestFixture::alignment) == 0u);
  283. ASSERT_EQ(data, TestFixture::nosbo[1].data());
  284. }