1
0

memory.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #include <array>
  2. #include <cmath>
  3. #include <cstddef>
  4. #include <limits>
  5. #include <memory>
  6. #include <tuple>
  7. #include <type_traits>
  8. #include <utility>
  9. #include <vector>
  10. #include <gtest/gtest.h>
  11. #include <common/basic_test_allocator.hpp>
  12. #include <common/config.h>
  13. #include <common/throwing_allocator.hpp>
  14. #include <common/throwing_type.hpp>
  15. #include <common/tracked_memory_resource.hpp>
  16. #include <entt/core/memory.hpp>
  17. TEST(ToAddress, Functionalities) {
  18. const std::shared_ptr<int> shared = std::make_shared<int>();
  19. auto *plain = std::addressof(*shared);
  20. ASSERT_EQ(entt::to_address(shared), plain);
  21. ASSERT_EQ(entt::to_address(plain), plain);
  22. }
  23. TEST(PoccaPocmaAndPocs, Functionalities) {
  24. test::basic_test_allocator<int> lhs, rhs;
  25. test::basic_test_allocator<int, std::false_type> no_pocs;
  26. // code coverage purposes
  27. ASSERT_FALSE(lhs == rhs);
  28. ASSERT_NO_THROW(entt::propagate_on_container_swap(no_pocs, no_pocs));
  29. // honestly, I don't even know how one is supposed to test such a thing :)
  30. entt::propagate_on_container_copy_assignment(lhs, rhs);
  31. entt::propagate_on_container_move_assignment(lhs, rhs);
  32. entt::propagate_on_container_swap(lhs, rhs);
  33. }
  34. ENTT_DEBUG_TEST(PoccaPocmaAndPocsDeathTest, Functionalities) {
  35. test::basic_test_allocator<int, std::false_type> lhs, rhs;
  36. ASSERT_DEATH(entt::propagate_on_container_swap(lhs, rhs), "");
  37. }
  38. TEST(IsPowerOfTwo, Functionalities) {
  39. // constexpr-ness guaranteed
  40. constexpr auto zero_is_power_of_two = entt::is_power_of_two(0u);
  41. ASSERT_FALSE(zero_is_power_of_two);
  42. ASSERT_TRUE(entt::is_power_of_two(1u));
  43. ASSERT_TRUE(entt::is_power_of_two(2u));
  44. ASSERT_TRUE(entt::is_power_of_two(4u));
  45. ASSERT_FALSE(entt::is_power_of_two(7u));
  46. ASSERT_TRUE(entt::is_power_of_two(128u));
  47. ASSERT_FALSE(entt::is_power_of_two(200u));
  48. }
  49. TEST(NextPowerOfTwo, Functionalities) {
  50. // constexpr-ness guaranteed
  51. constexpr auto next_power_of_two_of_zero = entt::next_power_of_two(0u);
  52. ASSERT_EQ(next_power_of_two_of_zero, 1u);
  53. ASSERT_EQ(entt::next_power_of_two(1u), 1u);
  54. ASSERT_EQ(entt::next_power_of_two(2u), 2u);
  55. ASSERT_EQ(entt::next_power_of_two(3u), 4u);
  56. ASSERT_EQ(entt::next_power_of_two(17u), 32u);
  57. ASSERT_EQ(entt::next_power_of_two(32u), 32u);
  58. ASSERT_EQ(entt::next_power_of_two(33u), 64u);
  59. ASSERT_EQ(entt::next_power_of_two(static_cast<std::size_t>(std::pow(2, 16))), static_cast<std::size_t>(std::pow(2, 16)));
  60. ASSERT_EQ(entt::next_power_of_two(static_cast<std::size_t>(std::pow(2, 16) + 1u)), static_cast<std::size_t>(std::pow(2, 17)));
  61. }
  62. ENTT_DEBUG_TEST(NextPowerOfTwoDeathTest, Functionalities) {
  63. ASSERT_DEATH(static_cast<void>(entt::next_power_of_two((std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)) + 1)), "");
  64. }
  65. TEST(FastMod, Functionalities) {
  66. // constexpr-ness guaranteed
  67. constexpr auto fast_mod_of_zero = entt::fast_mod(0u, 8u);
  68. ASSERT_EQ(fast_mod_of_zero, 0u);
  69. ASSERT_EQ(entt::fast_mod(7u, 8u), 7u);
  70. ASSERT_EQ(entt::fast_mod(8u, 8u), 0u);
  71. }
  72. TEST(AllocateUnique, Functionalities) {
  73. test::throwing_allocator<test::throwing_type> allocator{};
  74. allocator.throw_counter<test::throwing_type>(0u);
  75. ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, false)), test::throwing_allocator_exception);
  76. ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, test::throwing_type{true})), test::throwing_type_exception);
  77. std::unique_ptr<test::throwing_type, entt::allocation_deleter<test::throwing_allocator<test::throwing_type>>> ptr = entt::allocate_unique<test::throwing_type>(allocator, false);
  78. ASSERT_TRUE(ptr);
  79. ASSERT_EQ(*ptr, false);
  80. ptr.reset();
  81. ASSERT_FALSE(ptr);
  82. }
  83. #if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)
  84. TEST(AllocateUnique, NoUsesAllocatorConstruction) {
  85. test::tracked_memory_resource memory_resource{};
  86. std::pmr::polymorphic_allocator<int> allocator{&memory_resource};
  87. using type = std::unique_ptr<int, entt::allocation_deleter<std::pmr::polymorphic_allocator<int>>>;
  88. [[maybe_unused]] const type ptr = entt::allocate_unique<int>(allocator, 0);
  89. ASSERT_EQ(memory_resource.do_allocate_counter(), 1u);
  90. ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
  91. }
  92. TEST(AllocateUnique, UsesAllocatorConstruction) {
  93. using string_type = typename test::tracked_memory_resource::string_type;
  94. test::tracked_memory_resource memory_resource{};
  95. std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};
  96. using type = std::unique_ptr<string_type, entt::allocation_deleter<std::pmr::polymorphic_allocator<string_type>>>;
  97. [[maybe_unused]] const type ptr = entt::allocate_unique<string_type>(allocator, test::tracked_memory_resource::default_value);
  98. ASSERT_GT(memory_resource.do_allocate_counter(), 1u);
  99. ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
  100. }
  101. #endif
  102. TEST(UsesAllocatorConstructionArgs, NoUsesAllocatorConstruction) {
  103. const auto value = 4;
  104. const auto args = entt::uses_allocator_construction_args<int>(std::allocator<int>{}, value);
  105. ASSERT_EQ(std::tuple_size_v<decltype(args)>, 1u);
  106. testing::StaticAssertTypeEq<decltype(args), const std::tuple<const int &>>();
  107. ASSERT_EQ(std::get<0>(args), value);
  108. }
  109. TEST(UsesAllocatorConstructionArgs, LeadingAllocatorConvention) {
  110. const auto value = 4;
  111. const auto args = entt::uses_allocator_construction_args<std::tuple<int, char>>(std::allocator<int>{}, value, 'c');
  112. ASSERT_EQ(std::tuple_size_v<decltype(args)>, 4u);
  113. testing::StaticAssertTypeEq<decltype(args), const std::tuple<std::allocator_arg_t, const std::allocator<int> &, const int &, char &&>>();
  114. ASSERT_EQ(std::get<2>(args), value);
  115. }
  116. TEST(UsesAllocatorConstructionArgs, TrailingAllocatorConvention) {
  117. const auto size = 4u;
  118. const auto args = entt::uses_allocator_construction_args<std::vector<int>>(std::allocator<int>{}, size);
  119. ASSERT_EQ(std::tuple_size_v<decltype(args)>, 2u);
  120. testing::StaticAssertTypeEq<decltype(args), const std::tuple<const unsigned int &, const std::allocator<int> &>>();
  121. ASSERT_EQ(std::get<0>(args), size);
  122. }
  123. TEST(UsesAllocatorConstructionArgs, PairPiecewiseConstruct) {
  124. const auto size = 4u;
  125. const auto tup = std::make_tuple(size);
  126. const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, std::piecewise_construct, std::make_tuple(3), tup);
  127. ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
  128. testing::StaticAssertTypeEq<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<const unsigned int &, const std::allocator<int> &>>>();
  129. ASSERT_EQ(std::get<0>(std::get<2>(args)), size);
  130. }
  131. TEST(UsesAllocatorConstructionArgs, PairNoArgs) {
  132. [[maybe_unused]] const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{});
  133. ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
  134. testing::StaticAssertTypeEq<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<>, std::tuple<const std::allocator<int> &>>>();
  135. }
  136. TEST(UsesAllocatorConstructionArgs, PairValues) {
  137. const auto size = 4u;
  138. const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, 3, size);
  139. ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
  140. testing::StaticAssertTypeEq<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<const unsigned int &, const std::allocator<int> &>>>();
  141. ASSERT_EQ(std::get<0>(std::get<2>(args)), size);
  142. }
  143. TEST(UsesAllocatorConstructionArgs, PairConstLValueReference) {
  144. const auto value = std::make_pair(3, 4u);
  145. const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, value);
  146. ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
  147. testing::StaticAssertTypeEq<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<const int &>, std::tuple<const unsigned int &, const std::allocator<int> &>>>();
  148. ASSERT_EQ(std::get<0>(std::get<1>(args)), 3);
  149. ASSERT_EQ(std::get<0>(std::get<2>(args)), 4u);
  150. }
  151. TEST(UsesAllocatorConstructionArgs, PairRValueReference) {
  152. [[maybe_unused]] const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, std::make_pair(3, 4u));
  153. ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
  154. testing::StaticAssertTypeEq<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<unsigned int &&, const std::allocator<int> &>>>();
  155. }
  156. TEST(MakeObjUsingAllocator, Functionalities) {
  157. const auto size = 4u;
  158. test::throwing_allocator<int> allocator{};
  159. allocator.throw_counter<int>(0u);
  160. ASSERT_THROW((entt::make_obj_using_allocator<std::vector<int, test::throwing_allocator<int>>>(allocator, size)), test::throwing_allocator_exception);
  161. const auto vec = entt::make_obj_using_allocator<std::vector<int>>(std::allocator<int>{}, size);
  162. ASSERT_FALSE(vec.empty());
  163. ASSERT_EQ(vec.size(), size);
  164. }
  165. TEST(UninitializedConstructUsingAllocator, NoUsesAllocatorConstruction) {
  166. alignas(int) std::array<std::byte, sizeof(int)> storage{};
  167. const std::allocator<int> allocator{};
  168. // NOLINTNEXTLINE(*-reinterpret-cast)
  169. int *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<int *>(storage.data()), allocator, 1);
  170. ASSERT_EQ(*value, 1);
  171. }
  172. #if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)
  173. # include <memory_resource>
  174. TEST(UninitializedConstructUsingAllocator, UsesAllocatorConstruction) {
  175. using string_type = typename test::tracked_memory_resource::string_type;
  176. test::tracked_memory_resource memory_resource{};
  177. const std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};
  178. alignas(string_type) std::array<std::byte, sizeof(string_type)> storage{};
  179. // NOLINTNEXTLINE(*-reinterpret-cast)
  180. string_type *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<string_type *>(storage.data()), allocator, test::tracked_memory_resource::default_value);
  181. ASSERT_GT(memory_resource.do_allocate_counter(), 0u);
  182. ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
  183. ASSERT_EQ(*value, test::tracked_memory_resource::default_value);
  184. value->~string_type();
  185. }
  186. #endif