set_test.cpp 12 KB

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