set_test.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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. }
  113. TYPED_TEST(SetTest, Move) {
  114. using SetT = TypeParam;
  115. SetT s;
  116. // Make sure we exceed the small size for some of the set types, but not all
  117. // of them, so we cover all the combinations of copying between small and
  118. // large.
  119. for (int i : llvm::seq(1, 24)) {
  120. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  121. ASSERT_TRUE(s.Insert(i).is_inserted());
  122. }
  123. SetT other_s1 = std::move(s);
  124. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 24)));
  125. // Add some more elements.
  126. for (int i : llvm::seq(24, 32)) {
  127. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  128. ASSERT_TRUE(other_s1.Insert(i).is_inserted());
  129. }
  130. ExpectSetElementsAre(other_s1, MakeElements(llvm::seq(1, 32)));
  131. }
  132. TYPED_TEST(SetTest, Conversions) {
  133. using SetT = TypeParam;
  134. using KeyT = SetT::KeyT;
  135. SetT s;
  136. ASSERT_TRUE(s.Insert(1).is_inserted());
  137. ASSERT_TRUE(s.Insert(2).is_inserted());
  138. ASSERT_TRUE(s.Insert(3).is_inserted());
  139. ASSERT_TRUE(s.Insert(4).is_inserted());
  140. SetView<KeyT> sv = s;
  141. SetView<const KeyT> csv = sv;
  142. SetView<const KeyT> csv2 = s;
  143. EXPECT_TRUE(sv.Contains(1));
  144. EXPECT_TRUE(csv.Contains(2));
  145. EXPECT_TRUE(csv2.Contains(3));
  146. }
  147. TYPED_TEST(SetTest, GrowToAllocSize) {
  148. using SetT = TypeParam;
  149. SetT s;
  150. // Grow when empty. May be a no-op for some small sizes.
  151. s.GrowToAllocSize(32);
  152. // Add some elements that will need to be propagated through subsequent
  153. // growths. Also delete some.
  154. ssize_t storage_bytes = s.ComputeMetrics().storage_bytes;
  155. for (int i : llvm::seq(1, 24)) {
  156. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  157. ASSERT_TRUE(s.Insert(i).is_inserted());
  158. }
  159. for (int i : llvm::seq(1, 8)) {
  160. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  161. ASSERT_TRUE(s.Erase(i));
  162. }
  163. // No further growth triggered.
  164. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  165. // No-op.
  166. s.GrowToAllocSize(16);
  167. ExpectSetElementsAre(s, MakeElements(llvm::seq(8, 24)));
  168. // No further growth triggered.
  169. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  170. // Get a few doubling based growths, and at least one beyond the largest small
  171. // size.
  172. s.GrowToAllocSize(64);
  173. ExpectSetElementsAre(s, MakeElements(llvm::seq(8, 24)));
  174. s.GrowToAllocSize(128);
  175. ExpectSetElementsAre(s, MakeElements(llvm::seq(8, 24)));
  176. s.GrowToAllocSize(256);
  177. ExpectSetElementsAre(s, MakeElements(llvm::seq(8, 24)));
  178. // Update the storage bytes after growth.
  179. EXPECT_LT(storage_bytes, s.ComputeMetrics().storage_bytes);
  180. storage_bytes = s.ComputeMetrics().storage_bytes;
  181. // Add some more, but not enough to trigger further growth, and then grow by
  182. // several more multiples of two to test handling large growth.
  183. for (int i : llvm::seq(24, 48)) {
  184. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  185. ASSERT_TRUE(s.Insert(i).is_inserted());
  186. }
  187. for (int i : llvm::seq(8, 16)) {
  188. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  189. ASSERT_TRUE(s.Erase(i));
  190. }
  191. // No growth from insertions.
  192. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  193. s.GrowToAllocSize(1024);
  194. ExpectSetElementsAre(s, MakeElements(llvm::seq(16, 48)));
  195. // Storage should have grown.
  196. EXPECT_LT(storage_bytes, s.ComputeMetrics().storage_bytes);
  197. }
  198. TYPED_TEST(SetTest, GrowForInsert) {
  199. using SetT = TypeParam;
  200. SetT s;
  201. s.GrowForInsertCount(42);
  202. ssize_t storage_bytes = s.ComputeMetrics().storage_bytes;
  203. for (int i : llvm::seq(1, 42)) {
  204. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  205. ASSERT_TRUE(s.Insert(i).is_inserted());
  206. }
  207. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 42)));
  208. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  209. // Erase many elements and grow again for another insert.
  210. for (int i : llvm::seq(1, 32)) {
  211. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  212. ASSERT_TRUE(s.Erase(i));
  213. }
  214. s.GrowForInsertCount(42);
  215. storage_bytes = s.ComputeMetrics().storage_bytes;
  216. for (int i : llvm::seq(42, 84)) {
  217. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  218. ASSERT_TRUE(s.Insert(i).is_inserted());
  219. }
  220. ExpectSetElementsAre(s, MakeElements(llvm::seq(32, 84)));
  221. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  222. // Erase all the elements, then grow for a much larger insertion and insert
  223. // again.
  224. for (int i : llvm::seq(32, 84)) {
  225. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  226. ASSERT_TRUE(s.Erase(i));
  227. }
  228. s.GrowForInsertCount(321);
  229. storage_bytes = s.ComputeMetrics().storage_bytes;
  230. for (int i : llvm::seq(128, 321 + 128)) {
  231. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  232. ASSERT_TRUE(s.Insert(i).is_inserted());
  233. }
  234. ExpectSetElementsAre(s, MakeElements(llvm::seq(128, 321 + 128)));
  235. EXPECT_EQ(storage_bytes, s.ComputeMetrics().storage_bytes);
  236. }
  237. TEST(SetContextTest, Basic) {
  238. llvm::SmallVector<TestData> keys;
  239. for (int i : llvm::seq(0, 513)) {
  240. keys.push_back(i * 100);
  241. }
  242. IndexKeyContext<TestData> key_context(keys);
  243. Set<ssize_t, 0, IndexKeyContext<TestData>> s;
  244. EXPECT_FALSE(s.Contains(42, key_context));
  245. EXPECT_TRUE(s.Insert(1, key_context).is_inserted());
  246. EXPECT_TRUE(s.Contains(1, key_context));
  247. auto result = s.Lookup(TestData(100), key_context);
  248. EXPECT_TRUE(result);
  249. EXPECT_EQ(1, result.key());
  250. auto i_result = s.Insert(1, IndexKeyContext<TestData>(keys));
  251. EXPECT_FALSE(i_result.is_inserted());
  252. EXPECT_TRUE(s.Contains(1, key_context));
  253. // Verify all the elements.
  254. ExpectSetElementsAre(s, {1});
  255. // Fill up a bunch to ensure we trigger growth a few times.
  256. for (int i : llvm::seq(2, 512)) {
  257. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  258. EXPECT_TRUE(s.Insert(i, key_context).is_inserted());
  259. }
  260. for (int i : llvm::seq(1, 512)) {
  261. SCOPED_TRACE(llvm::formatv("Key: {0}", i).str());
  262. EXPECT_TRUE(s.Contains(i, key_context));
  263. EXPECT_FALSE(s.Insert(i, key_context).is_inserted());
  264. }
  265. EXPECT_FALSE(s.Contains(0, key_context));
  266. EXPECT_FALSE(s.Contains(512, key_context));
  267. // Verify all the elements.
  268. ExpectSetElementsAre(s, MakeElements(llvm::seq(1, 512)));
  269. }
  270. } // namespace
  271. } // namespace Carbon