F14SetTest.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/container/F14Set.h>
  17. #include <unordered_map>
  18. #include <folly/Conv.h>
  19. #include <folly/FBString.h>
  20. #include <folly/container/test/F14TestUtil.h>
  21. #include <folly/portability/GTest.h>
  22. template <template <typename, typename, typename, typename> class TSet>
  23. void testCustomSwap() {
  24. using std::swap;
  25. TSet<
  26. int,
  27. folly::f14::DefaultHasher<int>,
  28. folly::f14::DefaultKeyEqual<int>,
  29. folly::f14::SwapTrackingAlloc<int>>
  30. m0, m1;
  31. folly::f14::resetTracking();
  32. swap(m0, m1);
  33. EXPECT_EQ(
  34. 0, folly::f14::Tracked<0>::counts.dist(folly::f14::Counts{0, 0, 0, 0}));
  35. }
  36. TEST(F14Set, customSwap) {
  37. testCustomSwap<folly::F14ValueSet>();
  38. testCustomSwap<folly::F14NodeSet>();
  39. testCustomSwap<folly::F14VectorSet>();
  40. testCustomSwap<folly::F14FastSet>();
  41. }
  42. namespace {
  43. template <
  44. template <typename, typename, typename, typename> class TSet,
  45. typename K>
  46. void runAllocatedMemorySizeTest() {
  47. using namespace folly::f14;
  48. using namespace folly::f14::detail;
  49. using A = SwapTrackingAlloc<K>;
  50. resetTracking();
  51. {
  52. TSet<K, DefaultHasher<K>, DefaultKeyEqual<K>, A> s;
  53. // if F14 intrinsics are not available then we fall back to using
  54. // std::unordered_set underneath, but in that case the allocation
  55. // info is only best effort
  56. bool preciseAllocInfo = getF14IntrinsicsMode() != F14IntrinsicsMode::None;
  57. if (preciseAllocInfo) {
  58. EXPECT_EQ(testAllocatedMemorySize, 0);
  59. EXPECT_EQ(s.getAllocatedMemorySize(), 0);
  60. }
  61. auto emptySetAllocatedMemorySize = testAllocatedMemorySize;
  62. auto emptySetAllocatedBlockCount = testAllocatedBlockCount;
  63. for (size_t i = 0; i < 1000; ++i) {
  64. s.insert(folly::to<K>(i));
  65. s.erase(folly::to<K>(i / 10 + 2));
  66. if (preciseAllocInfo) {
  67. EXPECT_EQ(testAllocatedMemorySize, s.getAllocatedMemorySize());
  68. }
  69. EXPECT_GE(s.getAllocatedMemorySize(), sizeof(K) * s.size());
  70. std::size_t size = 0;
  71. std::size_t count = 0;
  72. s.visitAllocationClasses([&](std::size_t, std::size_t) mutable {});
  73. s.visitAllocationClasses([&](std::size_t bytes, std::size_t n) {
  74. size += bytes * n;
  75. count += n;
  76. });
  77. if (preciseAllocInfo) {
  78. EXPECT_EQ(testAllocatedMemorySize, size);
  79. EXPECT_EQ(testAllocatedBlockCount, count);
  80. }
  81. }
  82. s = decltype(s){};
  83. EXPECT_EQ(testAllocatedMemorySize, emptySetAllocatedMemorySize);
  84. EXPECT_EQ(testAllocatedBlockCount, emptySetAllocatedBlockCount);
  85. s.reserve(5);
  86. EXPECT_GT(testAllocatedMemorySize, 0);
  87. s = {};
  88. EXPECT_GT(testAllocatedMemorySize, 0);
  89. }
  90. EXPECT_EQ(testAllocatedMemorySize, 0);
  91. EXPECT_EQ(testAllocatedBlockCount, 0);
  92. }
  93. template <typename K>
  94. void runAllocatedMemorySizeTests() {
  95. runAllocatedMemorySizeTest<folly::F14ValueSet, K>();
  96. runAllocatedMemorySizeTest<folly::F14NodeSet, K>();
  97. runAllocatedMemorySizeTest<folly::F14VectorSet, K>();
  98. runAllocatedMemorySizeTest<folly::F14FastSet, K>();
  99. }
  100. } // namespace
  101. TEST(F14Set, getAllocatedMemorySize) {
  102. runAllocatedMemorySizeTests<bool>();
  103. runAllocatedMemorySizeTests<int>();
  104. runAllocatedMemorySizeTests<long>();
  105. runAllocatedMemorySizeTests<double>();
  106. runAllocatedMemorySizeTests<std::string>();
  107. runAllocatedMemorySizeTests<folly::fbstring>();
  108. }
  109. template <typename S>
  110. void runVisitContiguousRangesTest(int n) {
  111. S set;
  112. for (int i = 0; i < n; ++i) {
  113. set.insert(i);
  114. set.erase(i / 2);
  115. }
  116. std::unordered_map<uintptr_t, bool> visited;
  117. for (auto& entry : set) {
  118. visited[reinterpret_cast<uintptr_t>(&entry)] = false;
  119. }
  120. set.visitContiguousRanges([&](auto b, auto e) {
  121. for (auto i = b; i != e; ++i) {
  122. auto iter = visited.find(reinterpret_cast<uintptr_t>(i));
  123. ASSERT_TRUE(iter != visited.end());
  124. EXPECT_FALSE(iter->second);
  125. iter->second = true;
  126. }
  127. });
  128. // ensure no entries were skipped
  129. for (auto& e : visited) {
  130. EXPECT_TRUE(e.second);
  131. }
  132. }
  133. template <typename S>
  134. void runVisitContiguousRangesTest() {
  135. runVisitContiguousRangesTest<S>(0); // empty
  136. runVisitContiguousRangesTest<S>(5); // single chunk
  137. runVisitContiguousRangesTest<S>(1000); // many chunks
  138. }
  139. TEST(F14ValueSet, visitContiguousRanges) {
  140. runVisitContiguousRangesTest<folly::F14ValueSet<int>>();
  141. }
  142. TEST(F14NodeSet, visitContiguousRanges) {
  143. runVisitContiguousRangesTest<folly::F14NodeSet<int>>();
  144. }
  145. TEST(F14VectorSet, visitContiguousRanges) {
  146. runVisitContiguousRangesTest<folly::F14VectorSet<int>>();
  147. }
  148. TEST(F14FastSet, visitContiguousRanges) {
  149. runVisitContiguousRangesTest<folly::F14FastSet<int>>();
  150. }
  151. ///////////////////////////////////
  152. #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
  153. ///////////////////////////////////
  154. #include <chrono>
  155. #include <random>
  156. #include <string>
  157. #include <unordered_set>
  158. #include <folly/Range.h>
  159. using namespace folly;
  160. using namespace folly::f14;
  161. using namespace folly::string_piece_literals;
  162. namespace {
  163. std::string s(char const* p) {
  164. return p;
  165. }
  166. } // namespace
  167. template <typename T>
  168. void runSimple() {
  169. T h;
  170. EXPECT_EQ(h.size(), 0);
  171. h.insert(s("abc"));
  172. EXPECT_TRUE(h.find(s("def")) == h.end());
  173. EXPECT_FALSE(h.find(s("abc")) == h.end());
  174. h.insert(s("ghi"));
  175. EXPECT_EQ(h.size(), 2);
  176. h.erase(h.find(s("abc")));
  177. EXPECT_EQ(h.size(), 1);
  178. T h2(std::move(h));
  179. EXPECT_EQ(h.size(), 0);
  180. EXPECT_TRUE(h.begin() == h.end());
  181. EXPECT_EQ(h2.size(), 1);
  182. EXPECT_TRUE(h2.find(s("abc")) == h2.end());
  183. EXPECT_EQ(*h2.begin(), s("ghi"));
  184. {
  185. auto i = h2.begin();
  186. EXPECT_FALSE(i == h2.end());
  187. ++i;
  188. EXPECT_TRUE(i == h2.end());
  189. }
  190. T h3;
  191. h3.insert(s("xxx"));
  192. h3.insert(s("yyy"));
  193. h3 = std::move(h2);
  194. EXPECT_EQ(h2.size(), 0);
  195. EXPECT_EQ(h3.size(), 1);
  196. EXPECT_TRUE(h3.find(s("xxx")) == h3.end());
  197. for (uint64_t i = 0; i < 1000; ++i) {
  198. h.insert(std::move(to<std::string>(i * i * i)));
  199. EXPECT_EQ(h.size(), i + 1);
  200. }
  201. {
  202. using std::swap;
  203. swap(h, h2);
  204. }
  205. for (uint64_t i = 0; i < 1000; ++i) {
  206. EXPECT_TRUE(h2.find(to<std::string>(i * i * i)) != h2.end());
  207. EXPECT_EQ(*h2.find(to<std::string>(i * i * i)), to<std::string>(i * i * i));
  208. EXPECT_TRUE(h2.find(to<std::string>(i * i * i + 2)) == h2.end());
  209. }
  210. T h4{h2};
  211. EXPECT_EQ(h2.size(), 1000);
  212. EXPECT_EQ(h4.size(), 1000);
  213. T h5{std::move(h2)};
  214. T h6;
  215. h6 = h4;
  216. T h7 = h4;
  217. T h8({s("abc"), s("def")});
  218. T h9({s("abd"), s("def")});
  219. EXPECT_EQ(h8.size(), 2);
  220. EXPECT_EQ(h8.count(s("abc")), 1);
  221. EXPECT_EQ(h8.count(s("xyz")), 0);
  222. EXPECT_TRUE(h7 != h8);
  223. EXPECT_TRUE(h8 != h9);
  224. h8 = std::move(h7);
  225. // h2 and h7 are moved from, h4, h5, h6, and h8 should be identical
  226. EXPECT_TRUE(h4 == h8);
  227. EXPECT_TRUE(h2.empty());
  228. EXPECT_TRUE(h7.empty());
  229. for (uint64_t i = 0; i < 1000; ++i) {
  230. auto k = to<std::string>(i * i * i);
  231. EXPECT_EQ(h4.count(k), 1);
  232. EXPECT_EQ(h5.count(k), 1);
  233. EXPECT_EQ(h6.count(k), 1);
  234. EXPECT_EQ(h8.count(k), 1);
  235. }
  236. h8.clear();
  237. h8.emplace(s("abc"));
  238. EXPECT_GT(h8.bucket_count(), 1);
  239. h8 = {};
  240. EXPECT_GT(h8.bucket_count(), 1);
  241. h9 = {s("abc"), s("def")};
  242. EXPECT_TRUE(h8.empty());
  243. EXPECT_EQ(h9.size(), 2);
  244. auto expectH8 = [&](T& ref) { EXPECT_EQ(&ref, &h8); };
  245. expectH8((h8 = h2));
  246. expectH8((h8 = std::move(h2)));
  247. expectH8((h8 = {}));
  248. F14TableStats::compute(h);
  249. F14TableStats::compute(h2);
  250. F14TableStats::compute(h3);
  251. F14TableStats::compute(h4);
  252. F14TableStats::compute(h5);
  253. F14TableStats::compute(h6);
  254. F14TableStats::compute(h7);
  255. F14TableStats::compute(h8);
  256. }
  257. template <typename T>
  258. void runRehash() {
  259. unsigned n = 10000;
  260. T h;
  261. for (unsigned i = 0; i < n; ++i) {
  262. h.insert(to<std::string>(i));
  263. }
  264. EXPECT_EQ(h.size(), n);
  265. F14TableStats::compute(h);
  266. }
  267. // T should be a set of uint64_t
  268. template <typename T>
  269. void runRandom() {
  270. using R = std::unordered_set<uint64_t>;
  271. std::mt19937_64 gen(0);
  272. std::uniform_int_distribution<> pctDist(0, 100);
  273. std::uniform_int_distribution<uint64_t> bitsBitsDist(1, 6);
  274. T t0;
  275. T t1;
  276. R r0;
  277. R r1;
  278. for (std::size_t reps = 0; reps < 100000; ++reps) {
  279. // discardBits will be from 0 to 62
  280. auto discardBits = (uint64_t{1} << bitsBitsDist(gen)) - 2;
  281. auto k = gen() >> discardBits;
  282. auto pct = pctDist(gen);
  283. EXPECT_EQ(t0.size(), r0.size());
  284. if (pct < 15) {
  285. // insert
  286. auto t = t0.insert(k);
  287. auto r = r0.insert(k);
  288. EXPECT_EQ(t.second, r.second);
  289. EXPECT_EQ(*t.first, *r.first);
  290. } else if (pct < 25) {
  291. // emplace
  292. auto t = t0.emplace(k);
  293. auto r = r0.emplace(k);
  294. EXPECT_EQ(t.second, r.second);
  295. EXPECT_EQ(*t.first, *r.first);
  296. } else if (pct < 30) {
  297. // bulk insert
  298. t0.insert(t1.begin(), t1.end());
  299. r0.insert(r1.begin(), r1.end());
  300. } else if (pct < 40) {
  301. // erase by key
  302. auto t = t0.erase(k);
  303. auto r = r0.erase(k);
  304. EXPECT_EQ(t, r);
  305. } else if (pct < 47) {
  306. // erase by iterator
  307. if (t0.size() > 0) {
  308. auto r = r0.find(k);
  309. if (r == r0.end()) {
  310. r = r0.begin();
  311. }
  312. k = *r;
  313. auto t = t0.find(k);
  314. t = t0.erase(t);
  315. if (t != t0.end()) {
  316. EXPECT_NE(*t, k);
  317. }
  318. r = r0.erase(r);
  319. if (r != r0.end()) {
  320. EXPECT_NE(*r, k);
  321. }
  322. }
  323. } else if (pct < 50) {
  324. // bulk erase
  325. if (t0.size() > 0) {
  326. auto r = r0.find(k);
  327. if (r == r0.end()) {
  328. r = r0.begin();
  329. }
  330. k = *r;
  331. auto t = t0.find(k);
  332. auto firstt = t;
  333. auto lastt = ++t;
  334. t = t0.erase(firstt, lastt);
  335. if (t != t0.end()) {
  336. EXPECT_NE(*t, k);
  337. }
  338. auto firstr = r;
  339. auto lastr = ++r;
  340. r = r0.erase(firstr, lastr);
  341. if (r != r0.end()) {
  342. EXPECT_NE(*r, k);
  343. }
  344. }
  345. } else if (pct < 58) {
  346. // find
  347. auto t = t0.find(k);
  348. auto r = r0.find(k);
  349. EXPECT_EQ((t == t0.end()), (r == r0.end()));
  350. if (t != t0.end() && r != r0.end()) {
  351. EXPECT_EQ(*t, *r);
  352. }
  353. EXPECT_EQ(t0.count(k), r0.count(k));
  354. } else if (pct < 60) {
  355. // equal_range
  356. auto t = t0.equal_range(k);
  357. auto r = r0.equal_range(k);
  358. EXPECT_EQ((t.first == t.second), (r.first == r.second));
  359. if (t.first != t.second && r.first != r.second) {
  360. EXPECT_EQ(*t.first, *r.first);
  361. t.first++;
  362. r.first++;
  363. EXPECT_TRUE(t.first == t.second);
  364. EXPECT_TRUE(r.first == r.second);
  365. }
  366. } else if (pct < 65) {
  367. // iterate
  368. uint64_t t = 0;
  369. for (auto& e : t0) {
  370. t += e + 1000;
  371. }
  372. uint64_t r = 0;
  373. for (auto& e : r0) {
  374. r += e + 1000;
  375. }
  376. EXPECT_EQ(t, r);
  377. } else if (pct < 69) {
  378. // swap
  379. using std::swap;
  380. swap(t0, t1);
  381. swap(r0, r1);
  382. } else if (pct < 70) {
  383. // swap
  384. t0.swap(t1);
  385. r0.swap(r1);
  386. } else if (pct < 72) {
  387. // default construct
  388. t0.~T();
  389. new (&t0) T();
  390. r0.~R();
  391. new (&r0) R();
  392. } else if (pct < 74) {
  393. // default construct with capacity
  394. std::size_t capacity = k & 0xffff;
  395. t0.~T();
  396. new (&t0) T(capacity);
  397. r0.~R();
  398. new (&r0) R(capacity);
  399. } else if (pct < 80) {
  400. // bulk iterator construct
  401. t0.~T();
  402. new (&t0) T(r1.begin(), r1.end());
  403. r0.~R();
  404. new (&r0) R(r1.begin(), r1.end());
  405. } else if (pct < 82) {
  406. // initializer list construct
  407. auto k2 = gen() >> discardBits;
  408. t0.~T();
  409. new (&t0) T({k, k, k2});
  410. r0.~R();
  411. new (&r0) R({k, k, k2});
  412. } else if (pct < 88) {
  413. // copy construct
  414. t0.~T();
  415. new (&t0) T(t1);
  416. r0.~R();
  417. new (&r0) R(r1);
  418. } else if (pct < 90) {
  419. // move construct
  420. t0.~T();
  421. new (&t0) T(std::move(t1));
  422. r0.~R();
  423. new (&r0) R(std::move(r1));
  424. } else if (pct < 94) {
  425. // copy assign
  426. t0 = t1;
  427. r0 = r1;
  428. } else if (pct < 96) {
  429. // move assign
  430. t0 = std::move(t1);
  431. r0 = std::move(r1);
  432. } else if (pct < 98) {
  433. // operator==
  434. EXPECT_EQ((t0 == t1), (r0 == r1));
  435. } else if (pct < 99) {
  436. // clear
  437. t0.computeStats();
  438. t0.clear();
  439. r0.clear();
  440. } else if (pct < 100) {
  441. // reserve
  442. auto scale = std::uniform_int_distribution<>(0, 8)(gen);
  443. auto delta = std::uniform_int_distribution<>(-2, 2)(gen);
  444. std::ptrdiff_t target = (t0.size() * scale) / 4 + delta;
  445. if (target >= 0) {
  446. t0.reserve(static_cast<std::size_t>(target));
  447. r0.reserve(static_cast<std::size_t>(target));
  448. }
  449. }
  450. }
  451. }
  452. TEST(F14ValueSet, simple) {
  453. runSimple<F14ValueSet<std::string>>();
  454. }
  455. TEST(F14NodeSet, simple) {
  456. runSimple<F14NodeSet<std::string>>();
  457. }
  458. TEST(F14VectorSet, simple) {
  459. runSimple<F14VectorSet<std::string>>();
  460. }
  461. TEST(F14FastSet, simple) {
  462. // F14FastSet inherits from a conditional typedef. Verify it compiles.
  463. runRandom<F14FastSet<uint64_t>>();
  464. runSimple<F14FastSet<std::string>>();
  465. }
  466. TEST(F14Set, ContainerSize) {
  467. {
  468. folly::F14ValueSet<int> set;
  469. set.insert(10);
  470. EXPECT_EQ(sizeof(set), 4 * sizeof(void*));
  471. if (alignof(folly::max_align_t) == 16) {
  472. // chunks will be allocated as 2 max_align_t-s
  473. EXPECT_EQ(set.getAllocatedMemorySize(), 32);
  474. } else {
  475. // chunks will be allocated using aligned_malloc with the true size
  476. EXPECT_EQ(set.getAllocatedMemorySize(), 24);
  477. }
  478. }
  479. {
  480. folly::F14NodeSet<int> set;
  481. set.insert(10);
  482. EXPECT_EQ(sizeof(set), 4 * sizeof(void*));
  483. if (alignof(folly::max_align_t) == 16) {
  484. // chunks will be allocated as 2 max_align_t-s
  485. EXPECT_EQ(set.getAllocatedMemorySize(), 36);
  486. } else {
  487. // chunks will be allocated using aligned_malloc with the true size
  488. EXPECT_EQ(set.getAllocatedMemorySize(), 20 + 2 * sizeof(void*));
  489. }
  490. }
  491. {
  492. folly::F14VectorSet<int> set;
  493. set.insert(10);
  494. EXPECT_EQ(sizeof(set), 8 + 2 * sizeof(void*));
  495. EXPECT_EQ(set.getAllocatedMemorySize(), 32);
  496. }
  497. }
  498. TEST(F14VectorMap, reverse_iterator) {
  499. using TSet = F14VectorSet<uint64_t>;
  500. auto populate = [](TSet& h, uint64_t lo, uint64_t hi) {
  501. for (auto i = lo; i < hi; ++i) {
  502. h.insert(i);
  503. }
  504. };
  505. auto verify = [](TSet const& h, uint64_t lo, uint64_t hi) {
  506. auto loIt = h.find(lo);
  507. EXPECT_NE(h.end(), loIt);
  508. uint64_t val = lo;
  509. for (auto rit = h.riter(loIt); rit != h.rend(); ++rit) {
  510. EXPECT_EQ(val, *rit);
  511. TSet::const_iterator it = h.iter(rit);
  512. EXPECT_EQ(val, *it);
  513. val++;
  514. }
  515. EXPECT_EQ(hi, val);
  516. };
  517. TSet h;
  518. size_t prevSize = 0;
  519. size_t newSize = 1;
  520. // verify iteration order across rehashes, copies, and moves
  521. while (newSize < 10'000) {
  522. populate(h, prevSize, newSize);
  523. verify(h, 0, newSize);
  524. verify(h, newSize / 2, newSize);
  525. TSet h2{h};
  526. verify(h2, 0, newSize);
  527. h = std::move(h2);
  528. verify(h, 0, newSize);
  529. prevSize = newSize;
  530. newSize *= 10;
  531. }
  532. }
  533. TEST(F14ValueSet, rehash) {
  534. runRehash<F14ValueSet<std::string>>();
  535. }
  536. TEST(F14NodeSet, rehash) {
  537. runRehash<F14NodeSet<std::string>>();
  538. }
  539. TEST(F14VectorSet, rehash) {
  540. runRehash<F14VectorSet<std::string>>();
  541. }
  542. TEST(F14ValueSet, random) {
  543. runRandom<F14ValueSet<uint64_t>>();
  544. }
  545. TEST(F14NodeSet, random) {
  546. runRandom<F14NodeSet<uint64_t>>();
  547. }
  548. TEST(F14VectorSet, random) {
  549. runRandom<F14VectorSet<uint64_t>>();
  550. }
  551. TEST(F14ValueSet, grow_stats) {
  552. F14ValueSet<uint64_t> h;
  553. for (unsigned i = 1; i <= 3072; ++i) {
  554. h.insert(i);
  555. }
  556. // F14ValueSet just before rehash
  557. F14TableStats::compute(h);
  558. h.insert(0);
  559. // F14ValueSet just after rehash
  560. F14TableStats::compute(h);
  561. }
  562. TEST(F14ValueSet, steady_state_stats) {
  563. // 10k keys, 14% probability of insert, 90% chance of erase, so the
  564. // table should converge to 1400 size without triggering the rehash
  565. // that would occur at 1536.
  566. F14ValueSet<uint64_t> h;
  567. std::mt19937 gen(0);
  568. std::uniform_int_distribution<> dist(0, 10000);
  569. for (std::size_t i = 0; i < 100000; ++i) {
  570. auto key = dist(gen);
  571. if (dist(gen) < 1400) {
  572. h.insert(key);
  573. } else {
  574. h.erase(key);
  575. }
  576. if (((i + 1) % 10000) == 0) {
  577. auto stats = F14TableStats::compute(h);
  578. // Verify that average miss probe length is bounded despite continued
  579. // erase + reuse. p99 of the average across 10M random steps is 4.69,
  580. // average is 2.96.
  581. EXPECT_LT(f14::expectedProbe(stats.missProbeLengthHisto), 10.0);
  582. }
  583. }
  584. // F14ValueSet at steady state
  585. F14TableStats::compute(h);
  586. }
  587. // S should be a set of Tracked<0>. F should take a set
  588. // and a key_type const& or key_type&& and cause it to be inserted
  589. template <typename S, typename F>
  590. void runInsertCases(std::string const& /* name */, F const& insertFunc) {
  591. static_assert(std::is_same<typename S::value_type, Tracked<0>>::value, "");
  592. {
  593. typename S::value_type k{0};
  594. S s;
  595. resetTracking();
  596. insertFunc(s, k);
  597. // fresh key, value_type const& ->
  598. // copy is expected
  599. EXPECT_EQ(Tracked<0>::counts.dist(Counts{1, 0, 0, 0}), 0);
  600. }
  601. {
  602. typename S::value_type k{0};
  603. S s;
  604. resetTracking();
  605. insertFunc(s, std::move(k));
  606. // fresh key, value_type&& ->
  607. // move is expected
  608. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 1, 0, 0}), 0);
  609. }
  610. }
  611. struct DoInsert {
  612. template <typename M, typename P>
  613. void operator()(M& m, P&& p) const {
  614. m.insert(std::forward<P>(p));
  615. }
  616. };
  617. struct DoEmplace1 {
  618. template <typename M, typename P>
  619. void operator()(M& m, P&& p) const {
  620. m.emplace(std::forward<P>(p));
  621. }
  622. };
  623. template <typename S>
  624. void runInsertAndEmplace() {
  625. {
  626. typename S::value_type k1{0};
  627. typename S::value_type k2{0};
  628. S s;
  629. resetTracking();
  630. EXPECT_TRUE(s.insert(k1).second);
  631. // copy is expected on successful insert
  632. EXPECT_EQ(Tracked<0>::counts.dist(Counts{1, 0, 0, 0}), 0);
  633. resetTracking();
  634. EXPECT_FALSE(s.insert(k2).second);
  635. // no copies or moves on failing insert
  636. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 0, 0, 0}), 0);
  637. }
  638. {
  639. typename S::value_type k1{0};
  640. typename S::value_type k2{0};
  641. S s;
  642. resetTracking();
  643. EXPECT_TRUE(s.insert(std::move(k1)).second);
  644. // move is expected on successful insert
  645. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 1, 0, 0}), 0);
  646. resetTracking();
  647. EXPECT_FALSE(s.insert(std::move(k2)).second);
  648. // no copies or moves on failing insert
  649. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 0, 0, 0}), 0);
  650. }
  651. {
  652. typename S::value_type k1{0};
  653. typename S::value_type k2{0};
  654. uint64_t k3 = 0;
  655. S s;
  656. resetTracking();
  657. EXPECT_TRUE(s.emplace(k1).second);
  658. // copy is expected on successful emplace
  659. EXPECT_EQ(Tracked<0>::counts.dist(Counts{1, 0, 0, 0}), 0);
  660. resetTracking();
  661. EXPECT_FALSE(s.emplace(k2).second);
  662. // no copies or moves on failing emplace with value_type
  663. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 0, 0, 0}), 0);
  664. resetTracking();
  665. EXPECT_FALSE(s.emplace(k3).second);
  666. // copy convert expected for failing emplace with wrong type
  667. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 0, 1, 0}), 0);
  668. s.clear();
  669. resetTracking();
  670. EXPECT_TRUE(s.emplace(k3).second);
  671. // copy convert + move expected for successful emplace with wrong type
  672. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 1, 1, 0}), 0);
  673. }
  674. {
  675. typename S::value_type k1{0};
  676. typename S::value_type k2{0};
  677. uint64_t k3 = 0;
  678. S s;
  679. resetTracking();
  680. EXPECT_TRUE(s.emplace(std::move(k1)).second);
  681. // move is expected on successful emplace
  682. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 1, 0, 0}), 0);
  683. resetTracking();
  684. EXPECT_FALSE(s.emplace(std::move(k2)).second);
  685. // no copies or moves on failing emplace with value_type
  686. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 0, 0, 0}), 0);
  687. resetTracking();
  688. EXPECT_FALSE(s.emplace(std::move(k3)).second);
  689. // move convert expected for failing emplace with wrong type
  690. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 0, 0, 1}), 0);
  691. s.clear();
  692. resetTracking();
  693. EXPECT_TRUE(s.emplace(std::move(k3)).second);
  694. // move convert + move expected for successful emplace with wrong type
  695. EXPECT_EQ(Tracked<0>::counts.dist(Counts{0, 1, 0, 1}), 0);
  696. }
  697. // Calling the default pair constructor via emplace is valid, but not
  698. // very useful in real life. Verify that it works.
  699. S s;
  700. typename S::value_type k;
  701. EXPECT_EQ(s.count(k), 0);
  702. s.emplace();
  703. EXPECT_EQ(s.count(k), 1);
  704. s.emplace();
  705. EXPECT_EQ(s.count(k), 1);
  706. }
  707. TEST(F14ValueSet, destructuring) {
  708. runInsertAndEmplace<F14ValueSet<Tracked<0>>>();
  709. }
  710. TEST(F14NodeSet, destructuring) {
  711. runInsertAndEmplace<F14NodeSet<Tracked<0>>>();
  712. }
  713. TEST(F14VectorSet, destructuring) {
  714. runInsertAndEmplace<F14VectorSet<Tracked<0>>>();
  715. }
  716. TEST(F14ValueSet, maxSize) {
  717. F14ValueSet<int> s;
  718. EXPECT_EQ(
  719. s.max_size(), std::numeric_limits<std::size_t>::max() / sizeof(int));
  720. }
  721. TEST(F14NodeSet, maxSize) {
  722. F14NodeSet<int> s;
  723. EXPECT_EQ(
  724. s.max_size(), std::numeric_limits<std::size_t>::max() / sizeof(int));
  725. }
  726. TEST(F14VectorSet, maxSize) {
  727. F14VectorSet<int> s;
  728. EXPECT_EQ(
  729. s.max_size(),
  730. std::min(
  731. std::size_t{std::numeric_limits<uint32_t>::max()},
  732. std::numeric_limits<std::size_t>::max() / sizeof(int)));
  733. }
  734. template <typename S>
  735. void runMoveOnlyTest() {
  736. S t0;
  737. t0.emplace(10);
  738. t0.insert(20);
  739. S t1{std::move(t0)};
  740. EXPECT_TRUE(t0.empty());
  741. S t2;
  742. EXPECT_TRUE(t2.empty());
  743. t2 = std::move(t1);
  744. EXPECT_EQ(t2.size(), 2);
  745. }
  746. TEST(F14ValueSet, moveOnly) {
  747. runMoveOnlyTest<F14ValueSet<f14::MoveOnlyTestInt>>();
  748. }
  749. TEST(F14NodeSet, moveOnly) {
  750. runMoveOnlyTest<F14NodeSet<f14::MoveOnlyTestInt>>();
  751. }
  752. TEST(F14VectorSet, moveOnly) {
  753. runMoveOnlyTest<F14VectorSet<f14::MoveOnlyTestInt>>();
  754. }
  755. TEST(F14FastSet, moveOnly) {
  756. runMoveOnlyTest<F14FastSet<f14::MoveOnlyTestInt>>();
  757. }
  758. template <typename S>
  759. void runEraseIntoTest() {
  760. S t0;
  761. S t1;
  762. auto insertIntoT0 = [&t0](auto&& value) {
  763. EXPECT_FALSE(value.destroyed);
  764. t0.emplace(std::move(value));
  765. };
  766. auto insertIntoT0Mut = [&](typename S::value_type&& value) mutable {
  767. insertIntoT0(std::move(value));
  768. };
  769. t0.insert(10);
  770. t1.insert(20);
  771. t1.eraseInto(t1.begin(), insertIntoT0);
  772. EXPECT_TRUE(t1.empty());
  773. EXPECT_EQ(t0.size(), 2);
  774. EXPECT_TRUE(t0.find(10) != t0.end());
  775. EXPECT_TRUE(t0.find(20) != t0.end());
  776. t1.insert(20);
  777. t1.insert(30);
  778. t1.insert(40);
  779. t1.eraseInto(t1.begin(), t1.end(), insertIntoT0Mut);
  780. EXPECT_TRUE(t1.empty());
  781. EXPECT_EQ(t0.size(), 4);
  782. EXPECT_TRUE(t0.find(30) != t0.end());
  783. EXPECT_TRUE(t0.find(40) != t0.end());
  784. t1.insert(50);
  785. size_t erased = t1.eraseInto(*t1.find(50), insertIntoT0);
  786. EXPECT_EQ(erased, 1);
  787. EXPECT_TRUE(t1.empty());
  788. EXPECT_EQ(t0.size(), 5);
  789. EXPECT_TRUE(t0.find(50) != t0.end());
  790. typename S::value_type key{60};
  791. erased = t1.eraseInto(key, insertIntoT0Mut);
  792. EXPECT_EQ(erased, 0);
  793. EXPECT_EQ(t0.size(), 5);
  794. }
  795. TEST(F14ValueSet, eraseInto) {
  796. runEraseIntoTest<F14ValueSet<f14::MoveOnlyTestInt>>();
  797. }
  798. TEST(F14NodeSet, eraseInto) {
  799. runEraseIntoTest<F14NodeSet<f14::MoveOnlyTestInt>>();
  800. }
  801. TEST(F14VectorSet, eraseInto) {
  802. runEraseIntoTest<F14VectorSet<f14::MoveOnlyTestInt>>();
  803. }
  804. TEST(F14FastSet, eraseInto) {
  805. runEraseIntoTest<F14FastSet<f14::MoveOnlyTestInt>>();
  806. }
  807. TEST(F14ValueSet, heterogeneous) {
  808. // note: std::string is implicitly convertible to but not from StringPiece
  809. using Hasher = folly::transparent<folly::hasher<folly::StringPiece>>;
  810. using KeyEqual = folly::transparent<std::equal_to<folly::StringPiece>>;
  811. constexpr auto hello = "hello"_sp;
  812. constexpr auto buddy = "buddy"_sp;
  813. constexpr auto world = "world"_sp;
  814. F14ValueSet<std::string, Hasher, KeyEqual> set;
  815. set.emplace(hello);
  816. set.emplace(world);
  817. auto checks = [hello, buddy](auto& ref) {
  818. // count
  819. EXPECT_EQ(0, ref.count(buddy));
  820. EXPECT_EQ(1, ref.count(hello));
  821. // find
  822. EXPECT_TRUE(ref.end() == ref.find(buddy));
  823. EXPECT_EQ(hello, *ref.find(hello));
  824. // prehash + find
  825. EXPECT_TRUE(ref.end() == ref.find(ref.prehash(buddy), buddy));
  826. EXPECT_EQ(hello, *ref.find(ref.prehash(hello), hello));
  827. // equal_range
  828. EXPECT_TRUE(std::make_pair(ref.end(), ref.end()) == ref.equal_range(buddy));
  829. EXPECT_TRUE(
  830. std::make_pair(ref.find(hello), ++ref.find(hello)) ==
  831. ref.equal_range(hello));
  832. };
  833. checks(set);
  834. checks(folly::as_const(set));
  835. }
  836. template <typename S>
  837. void runStatefulFunctorTest() {
  838. bool ranHasher = false;
  839. bool ranEqual = false;
  840. bool ranAlloc = false;
  841. bool ranDealloc = false;
  842. auto hasher = [&](int x) {
  843. ranHasher = true;
  844. return x;
  845. };
  846. auto equal = [&](int x, int y) {
  847. ranEqual = true;
  848. return x == y;
  849. };
  850. auto alloc = [&](std::size_t n) {
  851. ranAlloc = true;
  852. return std::malloc(n);
  853. };
  854. auto dealloc = [&](void* p, std::size_t) {
  855. ranDealloc = true;
  856. std::free(p);
  857. };
  858. {
  859. S set(0, hasher, equal, {alloc, dealloc});
  860. set.insert(10);
  861. set.insert(10);
  862. EXPECT_EQ(set.size(), 1);
  863. S set2(set);
  864. S set3(std::move(set));
  865. set = set2;
  866. set2.clear();
  867. set2 = std::move(set3);
  868. }
  869. EXPECT_TRUE(ranHasher);
  870. EXPECT_TRUE(ranEqual);
  871. EXPECT_TRUE(ranAlloc);
  872. EXPECT_TRUE(ranDealloc);
  873. }
  874. TEST(F14ValueSet, statefulFunctors) {
  875. runStatefulFunctorTest<F14ValueSet<
  876. int,
  877. GenericHasher<int>,
  878. GenericEqual<int>,
  879. GenericAlloc<int>>>();
  880. }
  881. TEST(F14NodeSet, statefulFunctors) {
  882. runStatefulFunctorTest<F14NodeSet<
  883. int,
  884. GenericHasher<int>,
  885. GenericEqual<int>,
  886. GenericAlloc<int>>>();
  887. }
  888. TEST(F14VectorSet, statefulFunctors) {
  889. runStatefulFunctorTest<F14VectorSet<
  890. int,
  891. GenericHasher<int>,
  892. GenericEqual<int>,
  893. GenericAlloc<int>>>();
  894. }
  895. TEST(F14FastSet, statefulFunctors) {
  896. runStatefulFunctorTest<F14FastSet<
  897. int,
  898. GenericHasher<int>,
  899. GenericEqual<int>,
  900. GenericAlloc<int>>>();
  901. }
  902. template <typename S>
  903. void runHeterogeneousInsertTest() {
  904. S set;
  905. resetTracking();
  906. EXPECT_EQ(set.count(10), 0);
  907. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0)
  908. << Tracked<1>::counts;
  909. resetTracking();
  910. set.insert(10);
  911. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 1}), 0)
  912. << Tracked<1>::counts;
  913. resetTracking();
  914. int k = 10;
  915. std::vector<int> v({10});
  916. set.insert(10);
  917. set.insert(k);
  918. set.insert(v.begin(), v.end());
  919. set.insert(
  920. std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
  921. set.emplace(10);
  922. set.emplace(k);
  923. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0)
  924. << Tracked<1>::counts;
  925. resetTracking();
  926. set.erase(20);
  927. EXPECT_EQ(set.size(), 1);
  928. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0)
  929. << Tracked<1>::counts;
  930. resetTracking();
  931. set.erase(10);
  932. EXPECT_EQ(set.size(), 0);
  933. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0)
  934. << Tracked<1>::counts;
  935. set.insert(10);
  936. resetTracking();
  937. set.eraseInto(10, [](auto&&) {});
  938. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0)
  939. << Tracked<1>::counts;
  940. }
  941. template <typename S>
  942. void runHeterogeneousInsertStringTest() {
  943. S set;
  944. StringPiece k{"foo"};
  945. std::vector<StringPiece> v{k};
  946. set.insert(k);
  947. set.insert("foo");
  948. set.insert(StringPiece{"foo"});
  949. set.insert(v.begin(), v.end());
  950. set.insert(
  951. std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
  952. set.emplace();
  953. set.emplace(k);
  954. set.emplace("foo");
  955. set.emplace(StringPiece("foo"));
  956. set.erase("");
  957. set.erase(k);
  958. set.erase(StringPiece{"foo"});
  959. EXPECT_TRUE(set.empty());
  960. }
  961. TEST(F14ValueSet, heterogeneousInsert) {
  962. runHeterogeneousInsertTest<F14ValueSet<
  963. Tracked<1>,
  964. TransparentTrackedHash<1>,
  965. TransparentTrackedEqual<1>>>();
  966. runHeterogeneousInsertStringTest<F14ValueSet<
  967. std::string,
  968. transparent<hasher<StringPiece>>,
  969. transparent<DefaultKeyEqual<StringPiece>>>>();
  970. }
  971. TEST(F14NodeSet, heterogeneousInsert) {
  972. runHeterogeneousInsertTest<F14NodeSet<
  973. Tracked<1>,
  974. TransparentTrackedHash<1>,
  975. TransparentTrackedEqual<1>>>();
  976. runHeterogeneousInsertStringTest<F14NodeSet<
  977. std::string,
  978. transparent<hasher<StringPiece>>,
  979. transparent<DefaultKeyEqual<StringPiece>>>>();
  980. }
  981. TEST(F14VectorSet, heterogeneousInsert) {
  982. runHeterogeneousInsertTest<F14VectorSet<
  983. Tracked<1>,
  984. TransparentTrackedHash<1>,
  985. TransparentTrackedEqual<1>>>();
  986. runHeterogeneousInsertStringTest<F14VectorSet<
  987. std::string,
  988. transparent<hasher<StringPiece>>,
  989. transparent<DefaultKeyEqual<StringPiece>>>>();
  990. }
  991. TEST(F14FastSet, heterogeneousInsert) {
  992. runHeterogeneousInsertTest<F14FastSet<
  993. Tracked<1>,
  994. TransparentTrackedHash<1>,
  995. TransparentTrackedEqual<1>>>();
  996. runHeterogeneousInsertStringTest<F14FastSet<
  997. std::string,
  998. transparent<hasher<StringPiece>>,
  999. transparent<DefaultKeyEqual<StringPiece>>>>();
  1000. }
  1001. namespace {
  1002. struct CharArrayHasher {
  1003. template <std::size_t N>
  1004. std::size_t operator()(std::array<char, N> const& value) const {
  1005. return folly::Hash{}(
  1006. StringPiece{value.data(), &value.data()[value.size()]});
  1007. }
  1008. };
  1009. template <
  1010. template <typename, typename, typename, typename> class S,
  1011. std::size_t N>
  1012. struct RunAllValueSizeTests {
  1013. void operator()() const {
  1014. using Key = std::array<char, N>;
  1015. static_assert(sizeof(Key) == N, "");
  1016. S<Key, CharArrayHasher, std::equal_to<Key>, std::allocator<Key>> set;
  1017. for (int i = 0; i < 100; ++i) {
  1018. Key key{{static_cast<char>(i)}};
  1019. set.insert(key);
  1020. }
  1021. while (!set.empty()) {
  1022. set.erase(set.begin());
  1023. }
  1024. RunAllValueSizeTests<S, N - 1>{}();
  1025. }
  1026. };
  1027. template <template <typename, typename, typename, typename> class S>
  1028. struct RunAllValueSizeTests<S, 0> {
  1029. void operator()() const {}
  1030. };
  1031. } // namespace
  1032. TEST(F14ValueSet, valueSize) {
  1033. RunAllValueSizeTests<F14ValueSet, 32>{}();
  1034. }
  1035. ///////////////////////////////////
  1036. #endif // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
  1037. ///////////////////////////////////