set_test.cpp 12 KB

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