set_test.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "common/set.h"
  5. #include <gmock/gmock.h>
  6. #include <gtest/gtest.h>
  7. #include <initializer_list>
  8. #include <type_traits>
  9. #include <vector>
  10. #include "common/raw_hashtable_test_helpers.h"
  11. namespace Carbon {
  12. namespace {
  13. using RawHashtable::IndexKeyContext;
  14. using RawHashtable::MoveOnlyTestData;
  15. using RawHashtable::TestData;
  16. using ::testing::UnorderedElementsAreArray;
  17. template <typename SetT, typename MatcherRangeT>
  18. auto ExpectSetElementsAre(SetT&& s, MatcherRangeT element_matchers) -> void {
  19. // Collect the elements into a container.
  20. using KeyT = typename std::remove_reference<SetT>::type::KeyT;
  21. std::vector<std::reference_wrapper<KeyT>> entries;
  22. s.ForEach([&entries](KeyT& k) { entries.push_back(std::ref(k)); });
  23. // Use the GoogleMock unordered container matcher to validate and show errors
  24. // on wrong elements.
  25. EXPECT_THAT(entries, UnorderedElementsAreArray(element_matchers));
  26. }
  27. // Allow directly using an initializer list.
  28. template <typename SetT, typename MatcherT>
  29. auto ExpectSetElementsAre(SetT&& s,
  30. std::initializer_list<MatcherT> element_matchers)
  31. -> void {
  32. std::vector<MatcherT> element_matchers_storage = element_matchers;
  33. ExpectSetElementsAre(s, element_matchers_storage);
  34. }
  35. template <typename RangeT, typename... RangeTs>
  36. auto MakeElements(RangeT&& range, RangeTs&&... ranges) {
  37. std::vector<typename RangeT::value_type> elements;
  38. auto add_range = [&elements](RangeT&& r) {
  39. for (const auto&& e : r) {
  40. elements.push_back(e);
  41. }
  42. };
  43. add_range(std::forward<RangeT>(range));
  44. (add_range(std::forward<RangeTs>(ranges)), ...);
  45. return elements;
  46. }
  47. template <typename SetT>
  48. class SetTest : public ::testing::Test {};
  49. template <typename SetT>
  50. class MoveOnlySetTest : public ::testing::Test {};
  51. using Types = ::testing::Types<Set<int>, Set<int, 16>, Set<int, 128>,
  52. Set<TestData>, Set<TestData, 16>>;
  53. TYPED_TEST_SUITE(SetTest, Types);
  54. using MoveOnlyTypes =
  55. ::testing::Types<Set<MoveOnlyTestData>, Set<MoveOnlyTestData, 16>,
  56. Set<MoveOnlyTestData, 64>>;
  57. TYPED_TEST_SUITE(MoveOnlySetTest, MoveOnlyTypes);
  58. TYPED_TEST(SetTest, Basic) {
  59. using SetT = TypeParam;
  60. SetT s;
  61. EXPECT_FALSE(s.Contains(42));
  62. EXPECT_TRUE(s.Insert(1).is_inserted());
  63. EXPECT_TRUE(s.Contains(1));
  64. auto result = s.Lookup(1);
  65. EXPECT_TRUE(result);
  66. EXPECT_EQ(1, result.key());
  67. auto i_result = s.Insert(1);
  68. EXPECT_FALSE(i_result.is_inserted());
  69. EXPECT_TRUE(s.Contains(1));
  70. // Verify all the elements.
  71. ExpectSetElementsAre(s, {1});
  72. // Fill up a bunch to ensure we trigger growth a few times.
  73. for (int i : llvm::seq(2, 512)) {
  74. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  75. EXPECT_TRUE(s.Insert(i).is_inserted());
  76. }
  77. for (int i : llvm::seq(1, 512)) {
  78. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  79. EXPECT_TRUE(s.Contains(i));
  80. EXPECT_FALSE(s.Insert(i).is_inserted());
  81. }
  82. EXPECT_FALSE(s.Contains(513));
  83. // Verify all the elements.
  84. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 512)));
  85. }
  86. TYPED_TEST(SetTest, FactoryApi) {
  87. using SetT = TypeParam;
  88. SetT s;
  89. EXPECT_TRUE(s.Insert(1, [](int k, void* key_storage) {
  90. return new (key_storage) int(k);
  91. }).is_inserted());
  92. ASSERT_TRUE(s.Contains(1));
  93. // Reinsertion doesn't invoke the callback.
  94. EXPECT_FALSE(s.Insert(1, [](int, void*) -> int* {
  95. llvm_unreachable("Should never be called!");
  96. }).is_inserted());
  97. }
  98. TYPED_TEST(SetTest, Copy) {
  99. using SetT = TypeParam;
  100. SetT s;
  101. // Make sure we exceed the small size for some of the set types, but not all
  102. // of them, so we cover all the combinations of copying between small and
  103. // large.
  104. for (int i : llvm::seq(1, 24)) {
  105. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  106. ASSERT_TRUE(s.Insert(i).is_inserted());
  107. }
  108. SetT other_s1 = s;
  109. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 24)));
  110. // Add some more elements to the original.
  111. for (int i : llvm::seq(24, 32)) {
  112. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  113. ASSERT_TRUE(s.Insert(i).is_inserted());
  114. }
  115. // The first copy doesn't change.
  116. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 24)));
  117. // A new copy does.
  118. SetT other_s2 = s;
  119. ExpectSetElementsAre(other_s2, MakeElements(llvm::seq(1, 32)));
  120. // Copy-assign updates.
  121. other_s1 = s;
  122. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 32)));
  123. // Self-assign is a no-op.
  124. other_s1 = const_cast<const SetT&>(other_s1);
  125. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 32)));
  126. // But mutating original still doesn't change copies.
  127. for (int i : llvm::seq(32, 48)) {
  128. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  129. ASSERT_TRUE(s.Insert(i).is_inserted());
  130. }
  131. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 32)));
  132. ExpectSetElementsAre(other_s2, MakeElements(llvm::seq(1, 32)));
  133. }
  134. TYPED_TEST(SetTest, Move) {
  135. using SetT = TypeParam;
  136. SetT s;
  137. // Make sure we exceed the small size for some of the set types, but not all
  138. // of them, so we cover all the combinations of copying between small and
  139. // large.
  140. for (int i : llvm::seq(1, 24)) {
  141. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  142. EXPECT_TRUE(s.Insert(i).is_inserted());
  143. }
  144. SetT other_s1 = std::move(s);
  145. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 24)));
  146. // Add some more elements.
  147. for (int i : llvm::seq(24, 32)) {
  148. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  149. ASSERT_TRUE(other_s1.Insert(i).is_inserted());
  150. }
  151. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 32)));
  152. // Move back over a moved-from.
  153. s = std::move(other_s1);
  154. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 32)));
  155. // Copy over moved-from state also works.
  156. other_s1 = s;
  157. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 32)));
  158. // Now add still more elements.
  159. for (int i : llvm::seq(32, 48)) {
  160. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  161. ASSERT_TRUE(other_s1.Insert(i).is_inserted());
  162. }
  163. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 48)));
  164. // Move-assign over the copy looks like the moved-from table not the copy.
  165. other_s1 = std::move(s);
  166. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 32)));
  167. // Self-swap (which does a self-move) works and is a no-op.
  168. std::swap(other_s1, other_s1);
  169. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 32)));
  170. // Test copying of a moved-from table over a valid table and
  171. // self-move-assign. The former is required to be valid, and the latter is
  172. // in at least the case of self-move-assign-when-moved-from, but the result
  173. // can be in any state so just do them and ensure we don't crash.
  174. SetT other_s2 = other_s1;
  175. // NOLINTNEXTLINE(bugprone-use-after-move): Testing required use-after-move.
  176. other_s2 = s;
  177. other_s1 = std::move(other_s1);
  178. s = std::move(s);
  179. }
  180. TYPED_TEST(MoveOnlySetTest, Move) {
  181. using SetT = TypeParam;
  182. static_assert(!std::is_copy_assignable_v<SetT>);
  183. static_assert(!std::is_copy_constructible_v<SetT>);
  184. static_assert(std::is_move_assignable_v<SetT>);
  185. static_assert(std::is_move_constructible_v<SetT>);
  186. auto make_set = [] {
  187. SetT s;
  188. // Make sure we exceed the small size for some of the set types, but not all
  189. // of them, so we cover all the combinations of copying between small and
  190. // large.
  191. for (int i : llvm::seq(1, 24)) {
  192. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  193. EXPECT_TRUE(s.Insert(i).is_inserted());
  194. }
  195. return s;
  196. };
  197. SetT s = make_set();
  198. SetT other_s1 = std::move(s);
  199. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 24)));
  200. // Add some more elements.
  201. for (int i : llvm::seq(24, 32)) {
  202. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  203. ASSERT_TRUE(other_s1.Insert(i).is_inserted());
  204. }
  205. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 32)));
  206. // Move back over a moved-from.
  207. s = std::move(other_s1);
  208. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 32)));
  209. // Now add still more elements, crossing the small size limit for all tested
  210. // map types.
  211. for (int i : llvm::seq(32, 72)) {
  212. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  213. ASSERT_TRUE(s.Insert(i).is_inserted());
  214. }
  215. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 72)));
  216. // Assignment replaces the contents.
  217. s = make_set();
  218. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 24)));
  219. // Self-swap (which does a self-move) works and is a no-op.
  220. std::swap(s, s);
  221. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 24)));
  222. }
  223. TYPED_TEST(SetTest, Conversions) {
  224. using SetT = TypeParam;
  225. using KeyT = SetT::KeyT;
  226. SetT s;
  227. ASSERT_TRUE(s.Insert(1).is_inserted());
  228. ASSERT_TRUE(s.Insert(2).is_inserted());
  229. ASSERT_TRUE(s.Insert(3).is_inserted());
  230. ASSERT_TRUE(s.Insert(4).is_inserted());
  231. SetView<KeyT> sv = s;
  232. SetView<const KeyT> csv = sv;
  233. SetView<const KeyT> csv2 = s;
  234. EXPECT_TRUE(sv.Contains(1));
  235. EXPECT_TRUE(csv.Contains(2));
  236. EXPECT_TRUE(csv2.Contains(3));
  237. }
  238. TYPED_TEST(SetTest, GrowToAllocSize) {
  239. using SetT = TypeParam;
  240. SetT s;
  241. // Grow when empty. May be a no-op for some small sizes.
  242. s.GrowToAllocSize(32);
  243. // Add some elements that will need to be propagated through subsequent
  244. // growths. Also delete some.
  245. ssize_t storage_bytes = s.ComputeMetrics().storage_bytes;
  246. for (int i : llvm::seq(1, 24)) {
  247. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  248. ASSERT_TRUE(s.Insert(i).is_inserted());
  249. }
  250. for (int i : llvm::seq(1, 8)) {
  251. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  252. ASSERT_TRUE(s.Erase(i));
  253. }
  254. // No further growth triggered.
  255. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  256. // No-op.
  257. s.GrowToAllocSize(16);
  258. ExpectSetElementsAre(s, MakeElements(llvm::seq(8, 24)));
  259. // No further growth triggered.
  260. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  261. // Get a few doubling based growths, and at least one beyond the largest small
  262. // size.
  263. s.GrowToAllocSize(64);
  264. ExpectSetElementsAre(s, MakeElements(llvm::seq(8, 24)));
  265. s.GrowToAllocSize(128);
  266. ExpectSetElementsAre(s, MakeElements(llvm::seq(8, 24)));
  267. s.GrowToAllocSize(256);
  268. ExpectSetElementsAre(s, MakeElements(llvm::seq(8, 24)));
  269. // Update the storage bytes after growth.
  270. EXPECT_LT(storage_bytes, s.ComputeMetrics().storage_bytes);
  271. storage_bytes = s.ComputeMetrics().storage_bytes;
  272. // Add some more, but not enough to trigger further growth, and then grow by
  273. // several more multiples of two to test handling large growth.
  274. for (int i : llvm::seq(24, 48)) {
  275. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  276. ASSERT_TRUE(s.Insert(i).is_inserted());
  277. }
  278. for (int i : llvm::seq(8, 16)) {
  279. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  280. ASSERT_TRUE(s.Erase(i));
  281. }
  282. // No growth from insertions.
  283. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  284. s.GrowToAllocSize(1024);
  285. ExpectSetElementsAre(s, MakeElements(llvm::seq(16, 48)));
  286. // Storage should have grown.
  287. EXPECT_LT(storage_bytes, s.ComputeMetrics().storage_bytes);
  288. }
  289. TYPED_TEST(SetTest, GrowForInsert) {
  290. using SetT = TypeParam;
  291. SetT s;
  292. s.GrowForInsertCount(42);
  293. ssize_t storage_bytes = s.ComputeMetrics().storage_bytes;
  294. for (int i : llvm::seq(1, 42)) {
  295. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  296. ASSERT_TRUE(s.Insert(i).is_inserted());
  297. }
  298. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 42)));
  299. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  300. // Erase many elements and grow again for another insert.
  301. for (int i : llvm::seq(1, 32)) {
  302. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  303. ASSERT_TRUE(s.Erase(i));
  304. }
  305. s.GrowForInsertCount(42);
  306. storage_bytes = s.ComputeMetrics().storage_bytes;
  307. for (int i : llvm::seq(42, 84)) {
  308. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  309. ASSERT_TRUE(s.Insert(i).is_inserted());
  310. }
  311. ExpectSetElementsAre(s, MakeElements(llvm::seq(32, 84)));
  312. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  313. // Erase all the elements, then grow for a much larger insertion and insert
  314. // again.
  315. for (int i : llvm::seq(32, 84)) {
  316. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  317. ASSERT_TRUE(s.Erase(i));
  318. }
  319. s.GrowForInsertCount(321);
  320. storage_bytes = s.ComputeMetrics().storage_bytes;
  321. for (int i : llvm::seq(128, 321 + 128)) {
  322. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  323. ASSERT_TRUE(s.Insert(i).is_inserted());
  324. }
  325. ExpectSetElementsAre(s, MakeElements(llvm::seq(128, 321 + 128)));
  326. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  327. }
  328. TEST(SetContextTest, Basic) {
  329. llvm::SmallVector<TestData> keys;
  330. for (int i : llvm::seq(0, 513)) {
  331. keys.push_back(i * 100);
  332. }
  333. IndexKeyContext<TestData> key_context(keys);
  334. Set<ssize_t, 0, IndexKeyContext<TestData>> s;
  335. EXPECT_FALSE(s.Contains(42, key_context));
  336. EXPECT_TRUE(s.Insert(1, key_context).is_inserted());
  337. EXPECT_TRUE(s.Contains(1, key_context));
  338. auto result = s.Lookup(TestData(100), key_context);
  339. EXPECT_TRUE(result);
  340. EXPECT_EQ(1, result.key());
  341. auto i_result = s.Insert(1, IndexKeyContext<TestData>(keys));
  342. EXPECT_FALSE(i_result.is_inserted());
  343. EXPECT_TRUE(s.Contains(1, key_context));
  344. EXPECT_TRUE(
  345. s.Insert(TestData(200), [] { return 2; }, key_context).is_inserted());
  346. EXPECT_TRUE(s.Contains(2, key_context));
  347. EXPECT_TRUE(s.Contains(TestData(200), key_context));
  348. // Verify all the elements.
  349. ExpectSetElementsAre(s, {1, 2});
  350. // Fill up a bunch to ensure we trigger growth a few times.
  351. for (int i : llvm::seq(3, 512)) {
  352. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  353. EXPECT_TRUE(s.Insert(i, key_context).is_inserted());
  354. }
  355. for (int i : llvm::seq(1, 512)) {
  356. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  357. EXPECT_TRUE(s.Contains(i, key_context));
  358. EXPECT_FALSE(s.Insert(i, key_context).is_inserted());
  359. }
  360. EXPECT_FALSE(s.Contains(0, key_context));
  361. EXPECT_FALSE(s.Contains(512, key_context));
  362. EXPECT_FALSE(s.Contains(TestData(0), key_context));
  363. EXPECT_FALSE(s.Contains(TestData(51200), key_context));
  364. // Verify all the elements.
  365. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 512)));
  366. }
  367. } // namespace
  368. } // namespace Carbon