table.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. #include <memory>
  2. #include <tuple>
  3. #include <type_traits>
  4. #include <utility>
  5. #include <vector>
  6. #include <gtest/gtest.h>
  7. #include <entt/container/table.hpp>
  8. #include <entt/core/iterator.hpp>
  9. #include "../../common/config.h"
  10. #include "../../common/linter.hpp"
  11. #include "../../common/throwing_allocator.hpp"
  12. TEST(Table, Constructors) {
  13. const std::vector<int> vec_of_int{1};
  14. const std::vector<char> vec_of_char{'a'};
  15. entt::table<int, char> table{};
  16. ASSERT_TRUE(table.empty());
  17. table = entt::table<int, char>{std::allocator<void>{}};
  18. ASSERT_TRUE(table.empty());
  19. table = entt::table<int, char>{vec_of_int, vec_of_char};
  20. ASSERT_EQ(table.size(), 1);
  21. table = entt::table<int, char>{std::vector<int>{1, 2}, std::vector<char>{'a', 'b'}};
  22. ASSERT_EQ(table.size(), 2);
  23. table = entt::table<int, char>{vec_of_int, vec_of_char, std::allocator<void>{}};
  24. ASSERT_EQ(table.size(), 1);
  25. table = entt::table<int, char>{std::vector<int>{1, 2}, std::vector<char>{'a', 'b'}, std::allocator<void>{}};
  26. ASSERT_EQ(table.size(), 2);
  27. }
  28. ENTT_DEBUG_TEST(TableDeathTest, Constructors) {
  29. const std::vector<int> vec_of_int{0};
  30. const std::vector<char> vec_of_char{};
  31. entt::table<int, char> table{};
  32. ASSERT_DEATH((table = entt::table<int, char>{vec_of_int, vec_of_char}), "");
  33. ASSERT_DEATH((table = entt::table<int, char>{std::vector<int>{}, std::vector<char>{'\0'}}), "");
  34. ASSERT_DEATH((table = entt::table<int, char>{vec_of_int, vec_of_char, std::allocator<void>{}}), "");
  35. ASSERT_DEATH((table = entt::table<int, char>{std::vector<int>{}, std::vector<char>{'\0'}, std::allocator<void>{}}), "");
  36. }
  37. TEST(Table, Move) {
  38. entt::table<int, char> table;
  39. table.emplace(3, 'c');
  40. static_assert(std::is_move_constructible_v<decltype(table)>, "Move constructible type required");
  41. static_assert(std::is_move_assignable_v<decltype(table)>, "Move assignable type required");
  42. entt::table<int, char> other{std::move(table)};
  43. test::is_initialized(table);
  44. ASSERT_TRUE(table.empty());
  45. ASSERT_FALSE(other.empty());
  46. ASSERT_EQ(other[0u], std::make_tuple(3, 'c'));
  47. entt::table<int, char> extended{std::move(other), std::allocator<void>{}};
  48. test::is_initialized(other);
  49. ASSERT_TRUE(other.empty());
  50. ASSERT_FALSE(extended.empty());
  51. ASSERT_EQ(extended[0u], std::make_tuple(3, 'c'));
  52. table = std::move(extended);
  53. test::is_initialized(extended);
  54. ASSERT_FALSE(table.empty());
  55. ASSERT_TRUE(other.empty());
  56. ASSERT_TRUE(extended.empty());
  57. ASSERT_EQ(table[0u], std::make_tuple(3, 'c'));
  58. other = entt::table<int, char>{};
  59. other.emplace(1, 'a');
  60. other = std::move(table);
  61. test::is_initialized(table);
  62. ASSERT_TRUE(table.empty());
  63. ASSERT_FALSE(other.empty());
  64. ASSERT_EQ(other[0u], std::make_tuple(3, 'c'));
  65. }
  66. TEST(Table, Swap) {
  67. entt::table<int, char> table;
  68. entt::table<int, char> other;
  69. table.emplace(3, 'c');
  70. other.emplace(1, 'a');
  71. other.emplace(0, '\0');
  72. other.erase(0u);
  73. ASSERT_EQ(table.size(), 1u);
  74. ASSERT_EQ(other.size(), 1u);
  75. table.swap(other);
  76. ASSERT_EQ(table.size(), 1u);
  77. ASSERT_EQ(other.size(), 1u);
  78. ASSERT_EQ(table[0u], std::make_tuple(0, '\0'));
  79. ASSERT_EQ(other[0u], std::make_tuple(3, 'c'));
  80. }
  81. TEST(Table, Capacity) {
  82. entt::table<int, char> table;
  83. ASSERT_EQ(table.capacity(), 0u);
  84. ASSERT_TRUE(table.empty());
  85. table.reserve(64u);
  86. ASSERT_EQ(table.capacity(), 64u);
  87. ASSERT_TRUE(table.empty());
  88. table.reserve(0);
  89. ASSERT_EQ(table.capacity(), 64u);
  90. ASSERT_TRUE(table.empty());
  91. }
  92. TEST(Table, ShrinkToFit) {
  93. entt::table<int, char> table;
  94. table.reserve(64u);
  95. table.emplace(3, 'c');
  96. ASSERT_EQ(table.capacity(), 64u);
  97. ASSERT_FALSE(table.empty());
  98. table.shrink_to_fit();
  99. ASSERT_EQ(table.capacity(), 1u);
  100. ASSERT_FALSE(table.empty());
  101. table.clear();
  102. ASSERT_EQ(table.capacity(), 1u);
  103. ASSERT_TRUE(table.empty());
  104. table.shrink_to_fit();
  105. ASSERT_EQ(table.capacity(), 0u);
  106. ASSERT_TRUE(table.empty());
  107. }
  108. TEST(Table, Iterator) {
  109. using iterator = typename entt::table<int, char>::iterator;
  110. testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<int &, char &>>();
  111. testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<int &, char &>>>();
  112. testing::StaticAssertTypeEq<typename iterator::reference, std::tuple<int &, char &>>();
  113. entt::table<int, char> table;
  114. table.emplace(3, 'c');
  115. iterator end{table.begin()};
  116. iterator begin{};
  117. begin = table.end();
  118. std::swap(begin, end);
  119. ASSERT_EQ(begin, table.begin());
  120. ASSERT_EQ(end, table.end());
  121. ASSERT_NE(begin, end);
  122. ASSERT_EQ(begin++, table.begin());
  123. ASSERT_EQ(begin--, table.end());
  124. ASSERT_EQ(begin + 1, table.end());
  125. ASSERT_EQ(end - 1, table.begin());
  126. ASSERT_EQ(++begin, table.end());
  127. ASSERT_EQ(--begin, table.begin());
  128. ASSERT_EQ(begin += 1, table.end());
  129. ASSERT_EQ(begin -= 1, table.begin());
  130. ASSERT_EQ(begin + (end - begin), table.end());
  131. ASSERT_EQ(begin - (begin - end), table.end());
  132. ASSERT_EQ(end - (end - begin), table.begin());
  133. ASSERT_EQ(end + (begin - end), table.begin());
  134. ASSERT_EQ(begin[0u], *table.begin().operator->());
  135. ASSERT_LT(begin, end);
  136. ASSERT_LE(begin, table.begin());
  137. ASSERT_GT(end, begin);
  138. ASSERT_GE(end, table.end());
  139. table.emplace(0, '\0');
  140. begin = table.begin();
  141. ASSERT_EQ(begin[0u], std::make_tuple(3, 'c'));
  142. ASSERT_EQ(begin[1u], std::make_tuple(0, '\0'));
  143. }
  144. TEST(Table, ConstIterator) {
  145. using iterator = typename entt::table<int, char>::const_iterator;
  146. testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<const int &, const char &>>();
  147. testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<const int &, const char &>>>();
  148. testing::StaticAssertTypeEq<typename iterator::reference, std::tuple<const int &, const char &>>();
  149. entt::table<int, char> table;
  150. table.emplace(3, 'c');
  151. iterator cend{table.cbegin()};
  152. iterator cbegin{};
  153. cbegin = table.cend();
  154. std::swap(cbegin, cend);
  155. ASSERT_EQ(cbegin, std::as_const(table).begin());
  156. ASSERT_EQ(cend, std::as_const(table).end());
  157. ASSERT_EQ(cbegin, table.cbegin());
  158. ASSERT_EQ(cend, table.cend());
  159. ASSERT_NE(cbegin, cend);
  160. ASSERT_EQ(cbegin++, table.cbegin());
  161. ASSERT_EQ(cbegin--, table.cend());
  162. ASSERT_EQ(cbegin + 1, table.cend());
  163. ASSERT_EQ(cend - 1, table.cbegin());
  164. ASSERT_EQ(++cbegin, table.cend());
  165. ASSERT_EQ(--cbegin, table.cbegin());
  166. ASSERT_EQ(cbegin += 1, table.cend());
  167. ASSERT_EQ(cbegin -= 1, table.cbegin());
  168. ASSERT_EQ(cbegin + (cend - cbegin), table.cend());
  169. ASSERT_EQ(cbegin - (cbegin - cend), table.cend());
  170. ASSERT_EQ(cend - (cend - cbegin), table.cbegin());
  171. ASSERT_EQ(cend + (cbegin - cend), table.cbegin());
  172. ASSERT_EQ(cbegin[0u], *table.cbegin().operator->());
  173. ASSERT_LT(cbegin, cend);
  174. ASSERT_LE(cbegin, table.cbegin());
  175. ASSERT_GT(cend, cbegin);
  176. ASSERT_GE(cend, table.cend());
  177. table.emplace(0, '\0');
  178. cbegin = table.cbegin();
  179. ASSERT_EQ(cbegin[0u], std::make_tuple(3, 'c'));
  180. ASSERT_EQ(cbegin[1u], std::make_tuple(0, '\0'));
  181. }
  182. TEST(Table, ReverseIterator) {
  183. using reverse_iterator = typename entt::table<int, char>::reverse_iterator;
  184. testing::StaticAssertTypeEq<typename reverse_iterator::value_type, std::tuple<int &, char &>>();
  185. testing::StaticAssertTypeEq<typename reverse_iterator::pointer, entt::input_iterator_pointer<std::tuple<int &, char &>>>();
  186. testing::StaticAssertTypeEq<typename reverse_iterator::reference, std::tuple<int &, char &>>();
  187. entt::table<int, char> table;
  188. table.emplace(3, 'c');
  189. reverse_iterator end{table.rbegin()};
  190. reverse_iterator begin{};
  191. begin = table.rend();
  192. std::swap(begin, end);
  193. ASSERT_EQ(begin, table.rbegin());
  194. ASSERT_EQ(end, table.rend());
  195. ASSERT_NE(begin, end);
  196. ASSERT_EQ(begin++, table.rbegin());
  197. ASSERT_EQ(begin--, table.rend());
  198. ASSERT_EQ(begin + 1, table.rend());
  199. ASSERT_EQ(end - 1, table.rbegin());
  200. ASSERT_EQ(++begin, table.rend());
  201. ASSERT_EQ(--begin, table.rbegin());
  202. ASSERT_EQ(begin += 1, table.rend());
  203. ASSERT_EQ(begin -= 1, table.rbegin());
  204. ASSERT_EQ(begin + (end - begin), table.rend());
  205. ASSERT_EQ(begin - (begin - end), table.rend());
  206. ASSERT_EQ(end - (end - begin), table.rbegin());
  207. ASSERT_EQ(end + (begin - end), table.rbegin());
  208. ASSERT_EQ(begin[0u], *table.rbegin().operator->());
  209. ASSERT_LT(begin, end);
  210. ASSERT_LE(begin, table.rbegin());
  211. ASSERT_GT(end, begin);
  212. ASSERT_GE(end, table.rend());
  213. table.emplace(0, '\0');
  214. begin = table.rbegin();
  215. ASSERT_EQ(begin[0u], std::make_tuple(0, '\0'));
  216. ASSERT_EQ(begin[1u], std::make_tuple(3, 'c'));
  217. }
  218. TEST(Table, ConstReverseIterator) {
  219. using const_reverse_iterator = typename entt::table<int, char>::const_reverse_iterator;
  220. testing::StaticAssertTypeEq<typename const_reverse_iterator::value_type, std::tuple<const int &, const char &>>();
  221. testing::StaticAssertTypeEq<typename const_reverse_iterator::pointer, entt::input_iterator_pointer<std::tuple<const int &, const char &>>>();
  222. testing::StaticAssertTypeEq<typename const_reverse_iterator::reference, std::tuple<const int &, const char &>>();
  223. entt::table<int, char> table;
  224. table.emplace(3, 'c');
  225. const_reverse_iterator cend{table.crbegin()};
  226. const_reverse_iterator cbegin{};
  227. cbegin = table.crend();
  228. std::swap(cbegin, cend);
  229. ASSERT_EQ(cbegin, std::as_const(table).rbegin());
  230. ASSERT_EQ(cend, std::as_const(table).rend());
  231. ASSERT_EQ(cbegin, table.crbegin());
  232. ASSERT_EQ(cend, table.crend());
  233. ASSERT_NE(cbegin, cend);
  234. ASSERT_EQ(cbegin++, table.crbegin());
  235. ASSERT_EQ(cbegin--, table.crend());
  236. ASSERT_EQ(cbegin + 1, table.crend());
  237. ASSERT_EQ(cend - 1, table.crbegin());
  238. ASSERT_EQ(++cbegin, table.crend());
  239. ASSERT_EQ(--cbegin, table.crbegin());
  240. ASSERT_EQ(cbegin += 1, table.crend());
  241. ASSERT_EQ(cbegin -= 1, table.crbegin());
  242. ASSERT_EQ(cbegin + (cend - cbegin), table.crend());
  243. ASSERT_EQ(cbegin - (cbegin - cend), table.crend());
  244. ASSERT_EQ(cend - (cend - cbegin), table.crbegin());
  245. ASSERT_EQ(cend + (cbegin - cend), table.crbegin());
  246. ASSERT_EQ(cbegin[0u], *table.crbegin().operator->());
  247. ASSERT_LT(cbegin, cend);
  248. ASSERT_LE(cbegin, table.crbegin());
  249. ASSERT_GT(cend, cbegin);
  250. ASSERT_GE(cend, table.crend());
  251. table.emplace(0, '\0');
  252. cbegin = table.crbegin();
  253. ASSERT_EQ(cbegin[0u], std::make_tuple(0, '\0'));
  254. ASSERT_EQ(cbegin[1u], std::make_tuple(3, 'c'));
  255. }
  256. TEST(Table, IteratorConversion) {
  257. entt::table<int, char> table;
  258. table.emplace(3, 'c');
  259. const typename entt::table<int, char>::iterator it = table.begin();
  260. typename entt::table<int, char>::const_iterator cit = it;
  261. testing::StaticAssertTypeEq<decltype(*it), std::tuple<int &, char &>>();
  262. testing::StaticAssertTypeEq<decltype(*cit), std::tuple<const int &, const char &>>();
  263. ASSERT_EQ(*it.operator->(), std::make_tuple(3, 'c'));
  264. ASSERT_EQ(*it.operator->(), *cit);
  265. ASSERT_EQ(it - cit, 0);
  266. ASSERT_EQ(cit - it, 0);
  267. ASSERT_LE(it, cit);
  268. ASSERT_LE(cit, it);
  269. ASSERT_GE(it, cit);
  270. ASSERT_GE(cit, it);
  271. ASSERT_EQ(it, cit);
  272. ASSERT_NE(++cit, it);
  273. }
  274. TEST(Table, Emplace) {
  275. entt::table<int, char> table;
  276. testing::StaticAssertTypeEq<decltype(table.emplace()), std::tuple<int &, char &>>();
  277. ASSERT_EQ(table.emplace(), std::make_tuple(int{}, char{}));
  278. ASSERT_EQ(table.emplace(3, 'c'), std::make_tuple(3, 'c'));
  279. }
  280. TEST(Table, Erase) {
  281. entt::table<int, char> table;
  282. table.emplace(3, 'c');
  283. table.emplace(0, '\0');
  284. table.erase(table.begin());
  285. ASSERT_EQ(table.size(), 1u);
  286. ASSERT_EQ(table[0u], std::make_tuple(0, '\0'));
  287. table.emplace(3, 'c');
  288. table.erase(1u);
  289. ASSERT_EQ(table.size(), 1u);
  290. ASSERT_EQ(table[0u], std::make_tuple(0, '\0'));
  291. table.erase(0u);
  292. ASSERT_EQ(table.size(), 0u);
  293. }
  294. ENTT_DEBUG_TEST(TableDeathTest, Erase) {
  295. entt::table<int, char> table;
  296. ASSERT_DEATH(table.erase(0u), "");
  297. table.emplace(3, 'c');
  298. ASSERT_DEATH(table.erase(1u), "");
  299. }
  300. TEST(Table, Indexing) {
  301. entt::table<int, char> table;
  302. table.emplace(3, 'c');
  303. table.emplace(0, '\0');
  304. ASSERT_EQ(table[0u], std::make_tuple(3, 'c'));
  305. ASSERT_EQ(std::as_const(table)[1u], std::make_tuple(0, '\0'));
  306. }
  307. ENTT_DEBUG_TEST(TableDeathTest, Indexing) {
  308. entt::table<int, char> table;
  309. ASSERT_DEATH([[maybe_unused]] auto value = table[0u], "");
  310. ASSERT_DEATH([[maybe_unused]] auto value = std::as_const(table)[0u], "");
  311. }
  312. TEST(Table, Clear) {
  313. entt::table<int, char> table;
  314. table.emplace(3, 'c');
  315. table.emplace(0, '\0');
  316. ASSERT_EQ(table.size(), 2u);
  317. table.clear();
  318. ASSERT_EQ(table.size(), 0u);
  319. table.emplace(3, 'c');
  320. table.emplace(0, '\0');
  321. table.erase(0u);
  322. ASSERT_EQ(table.size(), 1u);
  323. table.clear();
  324. ASSERT_EQ(table.size(), 0u);
  325. }
  326. TEST(Table, CustomAllocator) {
  327. const test::throwing_allocator<void> allocator{};
  328. entt::basic_table<std::vector<int, test::throwing_allocator<int>>, std::vector<char, test::throwing_allocator<char>>> table{allocator};
  329. table.reserve(1u);
  330. ASSERT_NE(table.capacity(), 0u);
  331. table.emplace(3, 'c');
  332. table.emplace(0, '\0');
  333. decltype(table) other{std::move(table), allocator};
  334. test::is_initialized(table);
  335. ASSERT_TRUE(table.empty());
  336. ASSERT_FALSE(other.empty());
  337. ASSERT_NE(other.capacity(), 0u);
  338. ASSERT_EQ(other.size(), 2u);
  339. table = std::move(other);
  340. test::is_initialized(other);
  341. ASSERT_FALSE(table.empty());
  342. ASSERT_TRUE(other.empty());
  343. ASSERT_NE(table.capacity(), 0u);
  344. ASSERT_EQ(table.size(), 2u);
  345. table.swap(other);
  346. table = std::move(other);
  347. test::is_initialized(other);
  348. ASSERT_FALSE(table.empty());
  349. ASSERT_TRUE(other.empty());
  350. ASSERT_NE(table.capacity(), 0u);
  351. ASSERT_EQ(table.size(), 2u);
  352. table.clear();
  353. ASSERT_NE(table.capacity(), 0u);
  354. ASSERT_EQ(table.size(), 0u);
  355. }
  356. TEST(Table, ThrowingAllocator) {
  357. test::throwing_allocator<void> allocator{};
  358. entt::basic_table<std::vector<int, test::throwing_allocator<int>>, std::vector<char, test::throwing_allocator<char>>> table{allocator};
  359. allocator.throw_counter<int>(0u);
  360. ASSERT_THROW(table.reserve(1u), test::throwing_allocator_exception);
  361. allocator.throw_counter<int>(0u);
  362. allocator.throw_counter<char>(0u);
  363. ASSERT_THROW(table.emplace(), test::throwing_allocator_exception);
  364. ASSERT_THROW(table.emplace(3, 'c'), test::throwing_allocator_exception);
  365. }