F14MapTest.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501
  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/F14Map.h>
  17. #include <algorithm>
  18. #include <unordered_map>
  19. #include <folly/Conv.h>
  20. #include <folly/FBString.h>
  21. #include <folly/container/test/F14TestUtil.h>
  22. #include <folly/portability/GTest.h>
  23. template <template <typename, typename, typename, typename, typename>
  24. class TMap>
  25. void testCustomSwap() {
  26. using std::swap;
  27. TMap<
  28. int,
  29. int,
  30. folly::f14::DefaultHasher<int>,
  31. folly::f14::DefaultKeyEqual<int>,
  32. folly::f14::SwapTrackingAlloc<std::pair<int const, int>>>
  33. m0, m1;
  34. folly::f14::resetTracking();
  35. swap(m0, m1);
  36. EXPECT_EQ(
  37. 0, folly::f14::Tracked<0>::counts.dist(folly::f14::Counts{0, 0, 0, 0}));
  38. }
  39. TEST(F14Map, customSwap) {
  40. testCustomSwap<folly::F14ValueMap>();
  41. testCustomSwap<folly::F14NodeMap>();
  42. testCustomSwap<folly::F14VectorMap>();
  43. testCustomSwap<folly::F14FastMap>();
  44. }
  45. namespace {
  46. template <
  47. template <typename, typename, typename, typename, typename> class TMap,
  48. typename K,
  49. typename V>
  50. void runAllocatedMemorySizeTest() {
  51. using namespace folly::f14;
  52. using namespace folly::f14::detail;
  53. using A = SwapTrackingAlloc<std::pair<const K, V>>;
  54. resetTracking();
  55. {
  56. TMap<K, V, DefaultHasher<K>, DefaultKeyEqual<K>, A> m;
  57. // if F14 intrinsics are not available then we fall back to using
  58. // std::unordered_map underneath, but in that case the allocation
  59. // info is only best effort
  60. bool preciseAllocInfo = getF14IntrinsicsMode() != F14IntrinsicsMode::None;
  61. if (preciseAllocInfo) {
  62. EXPECT_EQ(testAllocatedMemorySize, 0);
  63. EXPECT_EQ(m.getAllocatedMemorySize(), 0);
  64. }
  65. auto emptyMapAllocatedMemorySize = testAllocatedMemorySize;
  66. auto emptyMapAllocatedBlockCount = testAllocatedBlockCount;
  67. for (size_t i = 0; i < 1000; ++i) {
  68. m.insert(std::make_pair(folly::to<K>(i), V{}));
  69. m.erase(folly::to<K>(i / 10 + 2));
  70. if (preciseAllocInfo) {
  71. EXPECT_EQ(testAllocatedMemorySize, m.getAllocatedMemorySize());
  72. }
  73. EXPECT_GE(m.getAllocatedMemorySize(), sizeof(std::pair<K, V>) * m.size());
  74. std::size_t size = 0;
  75. std::size_t count = 0;
  76. m.visitAllocationClasses([&](std::size_t, std::size_t) mutable {});
  77. m.visitAllocationClasses([&](std::size_t bytes, std::size_t n) {
  78. size += bytes * n;
  79. count += n;
  80. });
  81. if (preciseAllocInfo) {
  82. EXPECT_EQ(testAllocatedMemorySize, size);
  83. EXPECT_EQ(testAllocatedBlockCount, count);
  84. }
  85. }
  86. m = decltype(m){};
  87. EXPECT_EQ(testAllocatedMemorySize, emptyMapAllocatedMemorySize);
  88. EXPECT_EQ(testAllocatedBlockCount, emptyMapAllocatedBlockCount);
  89. m.reserve(5);
  90. EXPECT_GT(testAllocatedMemorySize, 0);
  91. m = {};
  92. EXPECT_GT(testAllocatedMemorySize, 0);
  93. }
  94. EXPECT_EQ(testAllocatedMemorySize, 0);
  95. EXPECT_EQ(testAllocatedBlockCount, 0);
  96. }
  97. template <typename K, typename V>
  98. void runAllocatedMemorySizeTests() {
  99. runAllocatedMemorySizeTest<folly::F14ValueMap, K, V>();
  100. runAllocatedMemorySizeTest<folly::F14NodeMap, K, V>();
  101. runAllocatedMemorySizeTest<folly::F14VectorMap, K, V>();
  102. runAllocatedMemorySizeTest<folly::F14FastMap, K, V>();
  103. }
  104. } // namespace
  105. TEST(F14Map, getAllocatedMemorySize) {
  106. runAllocatedMemorySizeTests<bool, bool>();
  107. runAllocatedMemorySizeTests<int, int>();
  108. runAllocatedMemorySizeTests<bool, std::string>();
  109. runAllocatedMemorySizeTests<double, std::string>();
  110. runAllocatedMemorySizeTests<std::string, int>();
  111. runAllocatedMemorySizeTests<std::string, std::string>();
  112. runAllocatedMemorySizeTests<folly::fbstring, long>();
  113. }
  114. template <typename M>
  115. void runVisitContiguousRangesTest(int n) {
  116. M map;
  117. for (int i = 0; i < n; ++i) {
  118. map[i] = i;
  119. map.erase(i / 2);
  120. }
  121. std::unordered_map<uintptr_t, bool> visited;
  122. for (auto& entry : map) {
  123. visited[reinterpret_cast<uintptr_t>(&entry)] = false;
  124. }
  125. map.visitContiguousRanges([&](auto b, auto e) {
  126. for (auto i = b; i != e; ++i) {
  127. auto iter = visited.find(reinterpret_cast<uintptr_t>(i));
  128. ASSERT_TRUE(iter != visited.end());
  129. EXPECT_FALSE(iter->second);
  130. iter->second = true;
  131. }
  132. });
  133. // ensure no entries were skipped
  134. for (auto& e : visited) {
  135. EXPECT_TRUE(e.second);
  136. }
  137. }
  138. template <typename M>
  139. void runVisitContiguousRangesTest() {
  140. runVisitContiguousRangesTest<M>(0); // empty
  141. runVisitContiguousRangesTest<M>(5); // single chunk
  142. runVisitContiguousRangesTest<M>(1000); // many chunks
  143. }
  144. TEST(F14ValueMap, visitContiguousRanges) {
  145. runVisitContiguousRangesTest<folly::F14ValueMap<int, int>>();
  146. }
  147. TEST(F14NodeMap, visitContiguousRanges) {
  148. runVisitContiguousRangesTest<folly::F14NodeMap<int, int>>();
  149. }
  150. TEST(F14VectorMap, visitContiguousRanges) {
  151. runVisitContiguousRangesTest<folly::F14VectorMap<int, int>>();
  152. }
  153. TEST(F14FastMap, visitContiguousRanges) {
  154. runVisitContiguousRangesTest<folly::F14FastMap<int, int>>();
  155. }
  156. ///////////////////////////////////
  157. #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
  158. ///////////////////////////////////
  159. #include <chrono>
  160. #include <random>
  161. #include <string>
  162. #include <typeinfo>
  163. #include <unordered_map>
  164. #include <folly/Range.h>
  165. #include <folly/hash/Hash.h>
  166. using namespace folly;
  167. using namespace folly::f14;
  168. using namespace folly::string_piece_literals;
  169. namespace {
  170. std::string s(char const* p) {
  171. return p;
  172. }
  173. } // namespace
  174. template <typename T>
  175. void runSimple() {
  176. T h;
  177. EXPECT_EQ(h.size(), 0);
  178. h.insert(std::make_pair(s("abc"), s("ABC")));
  179. EXPECT_TRUE(h.find(s("def")) == h.end());
  180. EXPECT_FALSE(h.find(s("abc")) == h.end());
  181. EXPECT_EQ(h[s("abc")], s("ABC"));
  182. h[s("ghi")] = s("GHI");
  183. EXPECT_EQ(h.size(), 2);
  184. h.erase(h.find(s("abc")));
  185. EXPECT_EQ(h.size(), 1);
  186. T h2(std::move(h));
  187. EXPECT_EQ(h.size(), 0);
  188. EXPECT_TRUE(h.begin() == h.end());
  189. EXPECT_EQ(h2.size(), 1);
  190. EXPECT_TRUE(h2.find(s("abc")) == h2.end());
  191. EXPECT_EQ(h2.begin()->first, s("ghi"));
  192. {
  193. auto i = h2.begin();
  194. EXPECT_FALSE(i == h2.end());
  195. ++i;
  196. EXPECT_TRUE(i == h2.end());
  197. }
  198. T h3;
  199. h3.try_emplace(s("xxx"));
  200. h3.insert_or_assign(s("yyy"), s("YYY"));
  201. h3 = std::move(h2);
  202. EXPECT_EQ(h2.size(), 0);
  203. EXPECT_EQ(h3.size(), 1);
  204. EXPECT_TRUE(h3.find(s("xxx")) == h3.end());
  205. for (uint64_t i = 0; i < 1000; ++i) {
  206. h[to<std::string>(i * i * i)] = s("x");
  207. EXPECT_EQ(h.size(), i + 1);
  208. }
  209. {
  210. using std::swap;
  211. swap(h, h2);
  212. }
  213. for (uint64_t i = 0; i < 1000; ++i) {
  214. EXPECT_TRUE(h2.find(to<std::string>(i * i * i)) != h2.end());
  215. EXPECT_EQ(
  216. h2.find(to<std::string>(i * i * i))->first, to<std::string>(i * i * i));
  217. EXPECT_TRUE(h2.find(to<std::string>(i * i * i + 2)) == h2.end());
  218. }
  219. T h4{h2};
  220. EXPECT_EQ(h2.size(), 1000);
  221. EXPECT_EQ(h4.size(), 1000);
  222. T h5{std::move(h2)};
  223. T h6;
  224. h6 = h4;
  225. T h7 = h4;
  226. T h8({{s("abc"), s("ABC")}, {s("def"), s("DEF")}});
  227. T h9({{s("abc"), s("ABD")}, {s("def"), s("DEF")}});
  228. EXPECT_EQ(h8.size(), 2);
  229. EXPECT_EQ(h8.count(s("abc")), 1);
  230. EXPECT_EQ(h8.count(s("xyz")), 0);
  231. EXPECT_TRUE(h7 != h8);
  232. EXPECT_TRUE(h8 != h9);
  233. h8 = std::move(h7);
  234. // h2 and h7 are moved from, h4, h5, h6, and h8 should be identical
  235. EXPECT_TRUE(h4 == h8);
  236. EXPECT_TRUE(h2.empty());
  237. EXPECT_TRUE(h7.empty());
  238. for (uint64_t i = 0; i < 1000; ++i) {
  239. auto k = to<std::string>(i * i * i);
  240. EXPECT_EQ(h4.count(k), 1);
  241. EXPECT_EQ(h5.count(k), 1);
  242. EXPECT_EQ(h6.count(k), 1);
  243. EXPECT_EQ(h8.count(k), 1);
  244. }
  245. EXPECT_TRUE(h2 == h7);
  246. EXPECT_TRUE(h4 != h7);
  247. EXPECT_EQ(h3.at(s("ghi")), s("GHI"));
  248. EXPECT_THROW(h3.at(s("abc")), std::out_of_range);
  249. h8.clear();
  250. h8.emplace(s("abc"), s("ABC"));
  251. EXPECT_GE(h8.bucket_count(), 1);
  252. h8 = {};
  253. EXPECT_GE(h8.bucket_count(), 1);
  254. h9 = {{s("abc"), s("ABD")}, {s("def"), s("DEF")}};
  255. EXPECT_TRUE(h8.empty());
  256. EXPECT_EQ(h9.size(), 2);
  257. auto expectH8 = [&](T& ref) { EXPECT_EQ(&ref, &h8); };
  258. expectH8((h8 = h2));
  259. expectH8((h8 = std::move(h2)));
  260. expectH8((h8 = {}));
  261. F14TableStats::compute(h);
  262. F14TableStats::compute(h2);
  263. F14TableStats::compute(h3);
  264. F14TableStats::compute(h4);
  265. F14TableStats::compute(h5);
  266. F14TableStats::compute(h6);
  267. F14TableStats::compute(h7);
  268. F14TableStats::compute(h8);
  269. F14TableStats::compute(h9);
  270. }
  271. template <typename T>
  272. void runRehash() {
  273. unsigned n = 10000;
  274. T h;
  275. auto b = h.bucket_count();
  276. for (unsigned i = 0; i < n; ++i) {
  277. h.insert(std::make_pair(to<std::string>(i), s("")));
  278. if (b != h.bucket_count()) {
  279. F14TableStats::compute(h);
  280. b = h.bucket_count();
  281. }
  282. }
  283. EXPECT_EQ(h.size(), n);
  284. F14TableStats::compute(h);
  285. }
  286. // T should be a map from uint64_t to Tracked<1> that uses SwapTrackingAlloc
  287. template <typename T>
  288. void runRandom() {
  289. using R = std::unordered_map<uint64_t, Tracked<2>>;
  290. resetTracking();
  291. std::mt19937_64 gen(0);
  292. std::uniform_int_distribution<> pctDist(0, 100);
  293. std::uniform_int_distribution<uint64_t> bitsBitsDist(1, 6);
  294. {
  295. T t0;
  296. T t1;
  297. R r0;
  298. R r1;
  299. std::size_t rollbacks = 0;
  300. std::size_t resizingSmallRollbacks = 0;
  301. std::size_t resizingLargeRollbacks = 0;
  302. for (std::size_t reps = 0; reps < 100000 || rollbacks < 10 ||
  303. resizingSmallRollbacks < 1 || resizingLargeRollbacks < 1;
  304. ++reps) {
  305. if (pctDist(gen) < 20) {
  306. // 10% chance allocator will fail after 0 to 3 more allocations
  307. limitTestAllocations(gen() & 3);
  308. } else {
  309. unlimitTestAllocations();
  310. }
  311. bool leakCheckOnly = false;
  312. // discardBits will be from 0 to 62
  313. auto discardBits = (uint64_t{1} << bitsBitsDist(gen)) - 2;
  314. auto k = gen() >> discardBits;
  315. auto v = gen();
  316. auto pct = pctDist(gen);
  317. try {
  318. EXPECT_EQ(t0.empty(), r0.empty());
  319. EXPECT_EQ(t0.size(), r0.size());
  320. EXPECT_EQ(2, Tracked<0>::counts.liveCount());
  321. EXPECT_EQ(t0.size() + t1.size(), Tracked<1>::counts.liveCount());
  322. EXPECT_EQ(r0.size() + r1.size(), Tracked<2>::counts.liveCount());
  323. if (pct < 15) {
  324. // insert
  325. auto t = t0.insert(std::make_pair(k, v));
  326. auto r = r0.insert(std::make_pair(k, v));
  327. EXPECT_EQ(t.first->first, r.first->first);
  328. EXPECT_EQ(t.first->second.val_, r.first->second.val_);
  329. EXPECT_EQ(t.second, r.second);
  330. } else if (pct < 25) {
  331. // emplace
  332. auto t = t0.emplace(k, v);
  333. auto r = r0.emplace(k, v);
  334. EXPECT_EQ(t.first->first, r.first->first);
  335. EXPECT_EQ(t.first->second.val_, r.first->second.val_);
  336. EXPECT_EQ(t.second, r.second);
  337. } else if (pct < 30) {
  338. // bulk insert
  339. leakCheckOnly = true;
  340. t0.insert(t1.begin(), t1.end());
  341. r0.insert(r1.begin(), r1.end());
  342. } else if (pct < 40) {
  343. // erase by key
  344. auto t = t0.erase(k);
  345. auto r = r0.erase(k);
  346. EXPECT_EQ(t, r);
  347. } else if (pct < 47) {
  348. // erase by iterator
  349. if (t0.size() > 0) {
  350. auto r = r0.find(k);
  351. if (r == r0.end()) {
  352. r = r0.begin();
  353. }
  354. k = r->first;
  355. auto t = t0.find(k);
  356. t = t0.erase(t);
  357. if (t != t0.end()) {
  358. EXPECT_NE(t->first, k);
  359. }
  360. r = r0.erase(r);
  361. if (r != r0.end()) {
  362. EXPECT_NE(r->first, k);
  363. }
  364. }
  365. } else if (pct < 50) {
  366. // bulk erase
  367. if (t0.size() > 0) {
  368. auto r = r0.find(k);
  369. if (r == r0.end()) {
  370. r = r0.begin();
  371. }
  372. k = r->first;
  373. auto t = t0.find(k);
  374. auto firstt = t;
  375. auto lastt = ++t;
  376. t = t0.erase(firstt, lastt);
  377. if (t != t0.end()) {
  378. EXPECT_NE(t->first, k);
  379. }
  380. auto firstr = r;
  381. auto lastr = ++r;
  382. r = r0.erase(firstr, lastr);
  383. if (r != r0.end()) {
  384. EXPECT_NE(r->first, k);
  385. }
  386. }
  387. } else if (pct < 58) {
  388. // find
  389. auto t = t0.find(k);
  390. auto r = r0.find(k);
  391. EXPECT_EQ((t == t0.end()), (r == r0.end()));
  392. if (t != t0.end() && r != r0.end()) {
  393. EXPECT_EQ(t->first, r->first);
  394. EXPECT_EQ(t->second.val_, r->second.val_);
  395. }
  396. EXPECT_EQ(t0.count(k), r0.count(k));
  397. } else if (pct < 60) {
  398. // equal_range
  399. auto t = t0.equal_range(k);
  400. auto r = r0.equal_range(k);
  401. EXPECT_EQ((t.first == t.second), (r.first == r.second));
  402. if (t.first != t.second && r.first != r.second) {
  403. EXPECT_EQ(t.first->first, r.first->first);
  404. EXPECT_EQ(t.first->second.val_, r.first->second.val_);
  405. t.first++;
  406. r.first++;
  407. EXPECT_TRUE(t.first == t.second);
  408. EXPECT_TRUE(r.first == r.second);
  409. }
  410. } else if (pct < 65) {
  411. // iterate
  412. uint64_t t = 0;
  413. for (auto& e : t0) {
  414. t += e.first * 37 + e.second.val_ + 1000;
  415. }
  416. uint64_t r = 0;
  417. for (auto& e : r0) {
  418. r += e.first * 37 + e.second.val_ + 1000;
  419. }
  420. EXPECT_EQ(t, r);
  421. } else if (pct < 69) {
  422. // swap
  423. using std::swap;
  424. swap(t0, t1);
  425. swap(r0, r1);
  426. } else if (pct < 70) {
  427. // swap
  428. t0.swap(t1);
  429. r0.swap(r1);
  430. } else if (pct < 72) {
  431. // default construct
  432. t0.~T();
  433. new (&t0) T();
  434. r0.~R();
  435. new (&r0) R();
  436. } else if (pct < 74) {
  437. // default construct with capacity
  438. std::size_t capacity = k & 0xffff;
  439. T t(capacity);
  440. t0 = std::move(t);
  441. R r(capacity);
  442. r0 = std::move(r);
  443. } else if (pct < 80) {
  444. // bulk iterator construct
  445. t0 = T{t1.begin(), t1.end()};
  446. r0 = R{r1.begin(), r1.end()};
  447. } else if (pct < 82) {
  448. // initializer list construct
  449. auto k2 = gen() >> discardBits;
  450. auto v2 = gen();
  451. T t({{k, v}, {k2, v}, {k2, v2}});
  452. t0 = std::move(t);
  453. R r({{k, v}, {k2, v}, {k2, v2}});
  454. r0 = std::move(r);
  455. } else if (pct < 85) {
  456. // copy construct
  457. T t(t1);
  458. t0 = std::move(t);
  459. R r(r1);
  460. r0 = std::move(r);
  461. } else if (pct < 88) {
  462. // copy construct
  463. T t(t1, t1.get_allocator());
  464. t0 = std::move(t);
  465. R r(r1, r1.get_allocator());
  466. r0 = std::move(r);
  467. } else if (pct < 89) {
  468. // move construct
  469. t0.~T();
  470. new (&t0) T(std::move(t1));
  471. r0.~R();
  472. new (&r0) R(std::move(r1));
  473. } else if (pct < 90) {
  474. // move construct
  475. t0.~T();
  476. auto ta = t1.get_allocator();
  477. new (&t0) T(std::move(t1), ta);
  478. r0.~R();
  479. auto ra = r1.get_allocator();
  480. new (&r0) R(std::move(r1), ra);
  481. } else if (pct < 94) {
  482. // copy assign
  483. leakCheckOnly = true;
  484. t0 = t1;
  485. r0 = r1;
  486. } else if (pct < 96) {
  487. // move assign
  488. t0 = std::move(t1);
  489. r0 = std::move(r1);
  490. } else if (pct < 98) {
  491. // operator==
  492. EXPECT_EQ((t0 == t1), (r0 == r1));
  493. } else if (pct < 99) {
  494. // clear
  495. F14TableStats::compute(t0);
  496. t0.clear();
  497. r0.clear();
  498. } else if (pct < 100) {
  499. // reserve
  500. auto scale = std::uniform_int_distribution<>(0, 8)(gen);
  501. auto delta = std::uniform_int_distribution<>(-2, 2)(gen);
  502. std::ptrdiff_t target = (t0.size() * scale) / 4 + delta;
  503. if (target >= 0) {
  504. t0.reserve(static_cast<std::size_t>(target));
  505. r0.reserve(static_cast<std::size_t>(target));
  506. }
  507. }
  508. } catch (std::bad_alloc const&) {
  509. ++rollbacks;
  510. F14TableStats::compute(t0);
  511. if (leakCheckOnly) {
  512. unlimitTestAllocations();
  513. t0.clear();
  514. for (auto&& kv : r0) {
  515. t0[kv.first] = kv.second.val_;
  516. }
  517. }
  518. if (t0.bucket_count() == t0.size() && t0.size() > 0) {
  519. if (t0.size() < 10) {
  520. ++resizingSmallRollbacks;
  521. } else {
  522. ++resizingLargeRollbacks;
  523. }
  524. }
  525. assert(t0.size() == r0.size());
  526. for (auto&& kv : r0) {
  527. auto t = t0.find(kv.first);
  528. EXPECT_TRUE(
  529. t != t0.end() && t->first == kv.first &&
  530. t->second.val_ == kv.second.val_);
  531. }
  532. }
  533. }
  534. }
  535. EXPECT_EQ(testAllocatedMemorySize, 0);
  536. }
  537. template <typename T>
  538. void runPrehash() {
  539. T h;
  540. EXPECT_EQ(h.size(), 0);
  541. h.insert(std::make_pair(s("abc"), s("ABC")));
  542. EXPECT_TRUE(h.find(s("def")) == h.end());
  543. EXPECT_FALSE(h.find(s("abc")) == h.end());
  544. auto t1 = h.prehash(s("def"));
  545. F14HashToken t2;
  546. t2 = h.prehash(s("abc"));
  547. EXPECT_TRUE(h.find(t1, s("def")) == h.end());
  548. EXPECT_FALSE(h.find(t2, s("abc")) == h.end());
  549. }
  550. TEST(F14ValueMap, simple) {
  551. runSimple<F14ValueMap<std::string, std::string>>();
  552. }
  553. TEST(F14NodeMap, simple) {
  554. runSimple<F14NodeMap<std::string, std::string>>();
  555. }
  556. TEST(F14VectorMap, simple) {
  557. runSimple<F14VectorMap<std::string, std::string>>();
  558. }
  559. TEST(F14FastMap, simple) {
  560. runSimple<F14FastMap<std::string, std::string>>();
  561. }
  562. TEST(F14VectorMap, reverse_iterator) {
  563. using TMap = F14VectorMap<uint64_t, uint64_t>;
  564. auto populate = [](TMap& h, uint64_t lo, uint64_t hi) {
  565. for (auto i = lo; i < hi; ++i) {
  566. h.emplace(i, i);
  567. }
  568. };
  569. auto verify = [](TMap const& h, uint64_t lo, uint64_t hi) {
  570. auto loIt = h.find(lo);
  571. EXPECT_NE(h.end(), loIt);
  572. uint64_t val = lo;
  573. for (auto rit = h.riter(loIt); rit != h.rend(); ++rit) {
  574. EXPECT_EQ(val, rit->first);
  575. EXPECT_EQ(val, rit->second);
  576. TMap::const_iterator it = h.iter(rit);
  577. EXPECT_EQ(val, it->first);
  578. EXPECT_EQ(val, it->second);
  579. val++;
  580. }
  581. EXPECT_EQ(hi, val);
  582. };
  583. TMap h;
  584. size_t prevSize = 0;
  585. size_t newSize = 1;
  586. // verify iteration order across rehashes, copies, and moves
  587. while (newSize < 10'000) {
  588. populate(h, prevSize, newSize);
  589. verify(h, 0, newSize);
  590. verify(h, newSize / 2, newSize);
  591. TMap h2{h};
  592. verify(h2, 0, newSize);
  593. h = std::move(h2);
  594. verify(h, 0, newSize);
  595. prevSize = newSize;
  596. newSize *= 10;
  597. }
  598. }
  599. TEST(F14ValueMap, rehash) {
  600. runRehash<F14ValueMap<std::string, std::string>>();
  601. }
  602. TEST(F14NodeMap, rehash) {
  603. runRehash<F14NodeMap<std::string, std::string>>();
  604. }
  605. TEST(F14VectorMap, rehash) {
  606. runRehash<F14VectorMap<std::string, std::string>>();
  607. }
  608. TEST(F14ValueMap, prehash) {
  609. runPrehash<F14ValueMap<std::string, std::string>>();
  610. }
  611. TEST(F14NodeMap, prehash) {
  612. runPrehash<F14NodeMap<std::string, std::string>>();
  613. }
  614. TEST(F14ValueMap, random) {
  615. runRandom<F14ValueMap<
  616. uint64_t,
  617. Tracked<1>,
  618. std::hash<uint64_t>,
  619. std::equal_to<uint64_t>,
  620. SwapTrackingAlloc<std::pair<uint64_t const, Tracked<1>>>>>();
  621. }
  622. TEST(F14NodeMap, random) {
  623. runRandom<F14NodeMap<
  624. uint64_t,
  625. Tracked<1>,
  626. std::hash<uint64_t>,
  627. std::equal_to<uint64_t>,
  628. SwapTrackingAlloc<std::pair<uint64_t const, Tracked<1>>>>>();
  629. }
  630. TEST(F14VectorMap, random) {
  631. runRandom<F14VectorMap<
  632. uint64_t,
  633. Tracked<1>,
  634. std::hash<uint64_t>,
  635. std::equal_to<uint64_t>,
  636. SwapTrackingAlloc<std::pair<uint64_t const, Tracked<1>>>>>();
  637. }
  638. TEST(F14FastMap, random) {
  639. runRandom<F14FastMap<
  640. uint64_t,
  641. Tracked<1>,
  642. std::hash<uint64_t>,
  643. std::equal_to<uint64_t>,
  644. SwapTrackingAlloc<std::pair<uint64_t const, Tracked<1>>>>>();
  645. }
  646. TEST(F14ValueMap, grow_stats) {
  647. F14ValueMap<uint64_t, uint64_t> h;
  648. for (unsigned i = 1; i <= 3072; ++i) {
  649. h[i]++;
  650. }
  651. // F14ValueMap just before rehash
  652. F14TableStats::compute(h);
  653. h[0]++;
  654. // F14ValueMap just after rehash
  655. F14TableStats::compute(h);
  656. }
  657. TEST(F14ValueMap, steady_state_stats) {
  658. // 10k keys, 14% probability of insert, 90% chance of erase, so the
  659. // table should converge to 1400 size without triggering the rehash
  660. // that would occur at 1536.
  661. F14ValueMap<uint64_t, uint64_t> h;
  662. std::mt19937_64 gen(0);
  663. std::uniform_int_distribution<> dist(0, 10000);
  664. for (std::size_t i = 0; i < 100000; ++i) {
  665. auto key = dist(gen);
  666. if (dist(gen) < 1400) {
  667. h.insert_or_assign(key, i);
  668. } else {
  669. h.erase(key);
  670. }
  671. if (((i + 1) % 10000) == 0) {
  672. auto stats = F14TableStats::compute(h);
  673. // Verify that average miss probe length is bounded despite continued
  674. // erase + reuse. p99 of the average across 10M random steps is 4.69,
  675. // average is 2.96.
  676. EXPECT_LT(f14::expectedProbe(stats.missProbeLengthHisto), 10.0);
  677. }
  678. }
  679. // F14ValueMap at steady state
  680. F14TableStats::compute(h);
  681. }
  682. TEST(F14VectorMap, steady_state_stats) {
  683. // 10k keys, 14% probability of insert, 90% chance of erase, so the
  684. // table should converge to 1400 size without triggering the rehash
  685. // that would occur at 1536.
  686. F14VectorMap<std::string, uint64_t> h;
  687. std::mt19937_64 gen(0);
  688. std::uniform_int_distribution<> dist(0, 10000);
  689. for (std::size_t i = 0; i < 100000; ++i) {
  690. auto key = "0123456789ABCDEFGHIJKLMNOPQ" + to<std::string>(dist(gen));
  691. if (dist(gen) < 1400) {
  692. h.insert_or_assign(key, i);
  693. } else {
  694. h.erase(key);
  695. }
  696. if (((i + 1) % 10000) == 0) {
  697. auto stats = F14TableStats::compute(h);
  698. // Verify that average miss probe length is bounded despite continued
  699. // erase + reuse. p99 of the average across 10M random steps is 4.69,
  700. // average is 2.96.
  701. EXPECT_LT(f14::expectedProbe(stats.missProbeLengthHisto), 10.0);
  702. }
  703. }
  704. // F14ValueMap at steady state
  705. F14TableStats::compute(h);
  706. }
  707. TEST(Tracked, baseline) {
  708. Tracked<0> a0;
  709. {
  710. resetTracking();
  711. Tracked<0> b0{a0};
  712. EXPECT_EQ(a0.val_, b0.val_);
  713. EXPECT_EQ(sumCounts, (Counts{1, 0, 0, 0}));
  714. EXPECT_EQ(Tracked<0>::counts, (Counts{1, 0, 0, 0}));
  715. }
  716. {
  717. resetTracking();
  718. Tracked<0> b0{std::move(a0)};
  719. EXPECT_EQ(a0.val_, b0.val_);
  720. EXPECT_EQ(sumCounts, (Counts{0, 1, 0, 0}));
  721. EXPECT_EQ(Tracked<0>::counts, (Counts{0, 1, 0, 0}));
  722. }
  723. {
  724. resetTracking();
  725. Tracked<1> b1{a0};
  726. EXPECT_EQ(a0.val_, b1.val_);
  727. EXPECT_EQ(sumCounts, (Counts{0, 0, 1, 0}));
  728. EXPECT_EQ(Tracked<1>::counts, (Counts{0, 0, 1, 0}));
  729. }
  730. {
  731. resetTracking();
  732. Tracked<1> b1{std::move(a0)};
  733. EXPECT_EQ(a0.val_, b1.val_);
  734. EXPECT_EQ(sumCounts, (Counts{0, 0, 0, 1}));
  735. EXPECT_EQ(Tracked<1>::counts, (Counts{0, 0, 0, 1}));
  736. }
  737. {
  738. Tracked<0> b0;
  739. resetTracking();
  740. b0 = a0;
  741. EXPECT_EQ(a0.val_, b0.val_);
  742. EXPECT_EQ(sumCounts, (Counts{0, 0, 0, 0, 1, 0}));
  743. EXPECT_EQ(Tracked<0>::counts, (Counts{0, 0, 0, 0, 1, 0}));
  744. }
  745. {
  746. Tracked<0> b0;
  747. resetTracking();
  748. b0 = std::move(a0);
  749. EXPECT_EQ(a0.val_, b0.val_);
  750. EXPECT_EQ(sumCounts, (Counts{0, 0, 0, 0, 0, 1}));
  751. EXPECT_EQ(Tracked<0>::counts, (Counts{0, 0, 0, 0, 0, 1}));
  752. }
  753. {
  754. Tracked<1> b1;
  755. resetTracking();
  756. b1 = a0;
  757. EXPECT_EQ(a0.val_, b1.val_);
  758. EXPECT_EQ(sumCounts, (Counts{0, 0, 1, 0, 0, 1, 0, 1}));
  759. EXPECT_EQ(Tracked<1>::counts, (Counts{0, 0, 1, 0, 0, 1, 0, 1}));
  760. }
  761. {
  762. Tracked<1> b1;
  763. resetTracking();
  764. b1 = std::move(a0);
  765. EXPECT_EQ(a0.val_, b1.val_);
  766. EXPECT_EQ(sumCounts, (Counts{0, 0, 0, 1, 0, 1, 0, 1}));
  767. EXPECT_EQ(Tracked<1>::counts, (Counts{0, 0, 0, 1, 0, 1, 0, 1}));
  768. }
  769. }
  770. // M should be a map from Tracked<0> to Tracked<1>. F should take a map
  771. // and a pair const& or pair&& and cause it to be inserted
  772. template <typename M, typename F>
  773. void runInsertCases(
  774. std::string const& name,
  775. F const& insertFunc,
  776. uint64_t expectedDist = 0) {
  777. static_assert(std::is_same<typename M::key_type, Tracked<0>>::value, "");
  778. static_assert(std::is_same<typename M::mapped_type, Tracked<1>>::value, "");
  779. {
  780. typename M::value_type p{0, 0};
  781. M m;
  782. resetTracking();
  783. insertFunc(m, p);
  784. // fresh key, value_type const& ->
  785. // copy is expected
  786. EXPECT_EQ(
  787. Tracked<0>::counts.dist(Counts{1, 0, 0, 0}) +
  788. Tracked<1>::counts.dist(Counts{1, 0, 0, 0}),
  789. expectedDist)
  790. << name << "\n0 -> " << Tracked<0>::counts << "\n1 -> "
  791. << Tracked<1>::counts;
  792. }
  793. {
  794. typename M::value_type p{0, 0};
  795. M m;
  796. resetTracking();
  797. insertFunc(m, std::move(p));
  798. // fresh key, value_type&& ->
  799. // key copy is unfortunate but required
  800. EXPECT_EQ(
  801. Tracked<0>::counts.dist(Counts{1, 0, 0, 0}) +
  802. Tracked<1>::counts.dist(Counts{0, 1, 0, 0}),
  803. expectedDist)
  804. << name << "\n0 -> " << Tracked<0>::counts << "\n1 -> "
  805. << Tracked<1>::counts;
  806. }
  807. {
  808. std::pair<Tracked<0>, Tracked<1>> p{0, 0};
  809. M m;
  810. resetTracking();
  811. insertFunc(m, p);
  812. // fresh key, pair<key_type,mapped_type> const& ->
  813. // 1 copy is required
  814. EXPECT_EQ(
  815. Tracked<0>::counts.dist(Counts{1, 0, 0, 0}) +
  816. Tracked<1>::counts.dist(Counts{1, 0, 0, 0}),
  817. expectedDist)
  818. << name << "\n0 -> " << Tracked<0>::counts << "\n1 -> "
  819. << Tracked<1>::counts;
  820. }
  821. {
  822. std::pair<Tracked<0>, Tracked<1>> p{0, 0};
  823. M m;
  824. resetTracking();
  825. insertFunc(m, std::move(p));
  826. // fresh key, pair<key_type,mapped_type>&& ->
  827. // this is the happy path for insert(make_pair(.., ..))
  828. EXPECT_EQ(
  829. Tracked<0>::counts.dist(Counts{0, 1, 0, 0}) +
  830. Tracked<1>::counts.dist(Counts{0, 1, 0, 0}),
  831. expectedDist)
  832. << name << "\n0 -> " << Tracked<0>::counts << "\n1 -> "
  833. << Tracked<1>::counts;
  834. }
  835. {
  836. std::pair<Tracked<2>, Tracked<3>> p{0, 0};
  837. M m;
  838. resetTracking();
  839. insertFunc(m, p);
  840. // fresh key, convertible const& ->
  841. // key_type ops: Tracked<0>::counts
  842. // mapped_type ops: Tracked<1>::counts
  843. // key_src ops: Tracked<2>::counts
  844. // mapped_src ops: Tracked<3>::counts;
  845. // There are three strategies that could be optimal for particular
  846. // ratios of cost:
  847. //
  848. // - convert key and value in place to final position, destroy if
  849. // insert fails. This is the strategy used by std::unordered_map
  850. // and FBHashMap
  851. //
  852. // - convert key and default value in place to final position,
  853. // convert value only if insert succeeds. Nobody uses this strategy
  854. //
  855. // - convert key to a temporary, move key and convert value if
  856. // insert succeeds. This is the strategy used by F14 and what is
  857. // EXPECT_EQ here.
  858. // The expectedDist * 3 is just a hack for the emplace-pieces-by-value
  859. // test, whose test harness copies the original pair and then uses
  860. // move conversion instead of copy conversion.
  861. EXPECT_EQ(
  862. Tracked<0>::counts.dist(Counts{0, 1, 1, 0}) +
  863. Tracked<1>::counts.dist(Counts{0, 0, 1, 0}) +
  864. Tracked<2>::counts.dist(Counts{0, 0, 0, 0}) +
  865. Tracked<3>::counts.dist(Counts{0, 0, 0, 0}),
  866. expectedDist * 3);
  867. }
  868. {
  869. std::pair<Tracked<2>, Tracked<3>> p{0, 0};
  870. M m;
  871. resetTracking();
  872. insertFunc(m, std::move(p));
  873. // fresh key, convertible&& ->
  874. // key_type ops: Tracked<0>::counts
  875. // mapped_type ops: Tracked<1>::counts
  876. // key_src ops: Tracked<2>::counts
  877. // mapped_src ops: Tracked<3>::counts;
  878. EXPECT_EQ(
  879. Tracked<0>::counts.dist(Counts{0, 1, 0, 1}) +
  880. Tracked<1>::counts.dist(Counts{0, 0, 0, 1}) +
  881. Tracked<2>::counts.dist(Counts{0, 0, 0, 0}) +
  882. Tracked<3>::counts.dist(Counts{0, 0, 0, 0}),
  883. expectedDist);
  884. }
  885. {
  886. typename M::value_type p{0, 0};
  887. M m;
  888. m[0] = 0;
  889. resetTracking();
  890. insertFunc(m, p);
  891. // duplicate key, value_type const&
  892. EXPECT_EQ(
  893. Tracked<0>::counts.dist(Counts{0, 0, 0, 0}) +
  894. Tracked<1>::counts.dist(Counts{0, 0, 0, 0}),
  895. expectedDist);
  896. }
  897. {
  898. typename M::value_type p{0, 0};
  899. M m;
  900. m[0] = 0;
  901. resetTracking();
  902. insertFunc(m, std::move(p));
  903. // duplicate key, value_type&&
  904. EXPECT_EQ(
  905. Tracked<0>::counts.dist(Counts{0, 0, 0, 0}) +
  906. Tracked<1>::counts.dist(Counts{0, 0, 0, 0}),
  907. expectedDist);
  908. }
  909. {
  910. std::pair<Tracked<0>, Tracked<1>> p{0, 0};
  911. M m;
  912. m[0] = 0;
  913. resetTracking();
  914. insertFunc(m, p);
  915. // duplicate key, pair<key_type,mapped_type> const&
  916. EXPECT_EQ(
  917. Tracked<0>::counts.dist(Counts{0, 0, 0, 0}) +
  918. Tracked<1>::counts.dist(Counts{0, 0, 0, 0}),
  919. expectedDist);
  920. }
  921. {
  922. std::pair<Tracked<0>, Tracked<1>> p{0, 0};
  923. M m;
  924. m[0] = 0;
  925. resetTracking();
  926. insertFunc(m, std::move(p));
  927. // duplicate key, pair<key_type,mapped_type>&&
  928. EXPECT_EQ(
  929. Tracked<0>::counts.dist(Counts{0, 0, 0, 0}) +
  930. Tracked<1>::counts.dist(Counts{0, 0, 0, 0}),
  931. expectedDist);
  932. }
  933. {
  934. std::pair<Tracked<2>, Tracked<3>> p{0, 0};
  935. M m;
  936. m[0] = 0;
  937. resetTracking();
  938. insertFunc(m, p);
  939. // duplicate key, convertible const& ->
  940. // key_type ops: Tracked<0>::counts
  941. // mapped_type ops: Tracked<1>::counts
  942. // key_src ops: Tracked<2>::counts
  943. // mapped_src ops: Tracked<3>::counts;
  944. EXPECT_EQ(
  945. Tracked<0>::counts.dist(Counts{0, 0, 1, 0}) +
  946. Tracked<1>::counts.dist(Counts{0, 0, 0, 0}) +
  947. Tracked<2>::counts.dist(Counts{0, 0, 0, 0}) +
  948. Tracked<3>::counts.dist(Counts{0, 0, 0, 0}),
  949. expectedDist * 2);
  950. }
  951. {
  952. std::pair<Tracked<2>, Tracked<3>> p{0, 0};
  953. M m;
  954. m[0] = 0;
  955. resetTracking();
  956. insertFunc(m, std::move(p));
  957. // duplicate key, convertible&& ->
  958. // key_type ops: Tracked<0>::counts
  959. // mapped_type ops: Tracked<1>::counts
  960. // key_src ops: Tracked<2>::counts
  961. // mapped_src ops: Tracked<3>::counts;
  962. EXPECT_EQ(
  963. Tracked<0>::counts.dist(Counts{0, 0, 0, 1}) +
  964. Tracked<1>::counts.dist(Counts{0, 0, 0, 0}) +
  965. Tracked<2>::counts.dist(Counts{0, 0, 0, 0}) +
  966. Tracked<3>::counts.dist(Counts{0, 0, 0, 0}),
  967. expectedDist);
  968. }
  969. }
  970. struct DoInsert {
  971. template <typename M, typename P>
  972. void operator()(M& m, P&& p) const {
  973. m.insert(std::forward<P>(p));
  974. }
  975. };
  976. struct DoEmplace1 {
  977. template <typename M, typename P>
  978. void operator()(M& m, P&& p) const {
  979. m.emplace(std::forward<P>(p));
  980. }
  981. };
  982. struct DoEmplace2 {
  983. template <typename M, typename U1, typename U2>
  984. void operator()(M& m, std::pair<U1, U2> const& p) const {
  985. m.emplace(p.first, p.second);
  986. }
  987. template <typename M, typename U1, typename U2>
  988. void operator()(M& m, std::pair<U1, U2>&& p) const {
  989. m.emplace(std::move(p.first), std::move(p.second));
  990. }
  991. };
  992. struct DoEmplace3 {
  993. template <typename M, typename U1, typename U2>
  994. void operator()(M& m, std::pair<U1, U2> const& p) const {
  995. m.emplace(
  996. std::piecewise_construct,
  997. std::forward_as_tuple(p.first),
  998. std::forward_as_tuple(p.second));
  999. }
  1000. template <typename M, typename U1, typename U2>
  1001. void operator()(M& m, std::pair<U1, U2>&& p) const {
  1002. m.emplace(
  1003. std::piecewise_construct,
  1004. std::forward_as_tuple(std::move(p.first)),
  1005. std::forward_as_tuple(std::move(p.second)));
  1006. }
  1007. };
  1008. // Simulates use of piecewise_construct without proper use of
  1009. // forward_as_tuple. This code doesn't yield the normal pattern, but
  1010. // it should have exactly 1 additional move or copy of the key and 1
  1011. // additional move or copy of the mapped value.
  1012. struct DoEmplace3Value {
  1013. template <typename M, typename U1, typename U2>
  1014. void operator()(M& m, std::pair<U1, U2> const& p) const {
  1015. m.emplace(
  1016. std::piecewise_construct,
  1017. std::tuple<U1>{p.first},
  1018. std::tuple<U2>{p.second});
  1019. }
  1020. template <typename M, typename U1, typename U2>
  1021. void operator()(M& m, std::pair<U1, U2>&& p) const {
  1022. m.emplace(
  1023. std::piecewise_construct,
  1024. std::tuple<U1>{std::move(p.first)},
  1025. std::tuple<U2>{std::move(p.second)});
  1026. }
  1027. };
  1028. template <typename M>
  1029. void runInsertAndEmplace(std::string const& name) {
  1030. runInsertCases<M>(name + " insert", DoInsert{});
  1031. runInsertCases<M>(name + " emplace pair", DoEmplace1{});
  1032. runInsertCases<M>(name + " emplace k,v", DoEmplace2{});
  1033. runInsertCases<M>(name + " emplace pieces", DoEmplace3{});
  1034. runInsertCases<M>(name + " emplace pieces by value", DoEmplace3Value{}, 2);
  1035. // Calling the default pair constructor via emplace is valid, but not
  1036. // very useful in real life. Verify that it works.
  1037. M m;
  1038. typename M::key_type k;
  1039. EXPECT_EQ(m.count(k), 0);
  1040. m.emplace();
  1041. EXPECT_EQ(m.count(k), 1);
  1042. m.emplace();
  1043. EXPECT_EQ(m.count(k), 1);
  1044. }
  1045. TEST(F14ValueMap, destructuring) {
  1046. runInsertAndEmplace<F14ValueMap<Tracked<0>, Tracked<1>>>("f14value");
  1047. }
  1048. TEST(F14NodeMap, destructuring) {
  1049. runInsertAndEmplace<F14NodeMap<Tracked<0>, Tracked<1>>>("f14node");
  1050. }
  1051. TEST(F14VectorMap, destructuring) {
  1052. runInsertAndEmplace<F14VectorMap<Tracked<0>, Tracked<1>>>("f14vector");
  1053. }
  1054. TEST(F14VectorMap, destructuringErase) {
  1055. using M = F14VectorMap<Tracked<0>, Tracked<1>>;
  1056. typename M::value_type p1{0, 0};
  1057. typename M::value_type p2{2, 2};
  1058. M m;
  1059. m.insert(p1);
  1060. m.insert(p2);
  1061. resetTracking();
  1062. m.erase(p1.first);
  1063. LOG(INFO) << "erase -> "
  1064. << "key_type ops " << Tracked<0>::counts << ", mapped_type ops "
  1065. << Tracked<1>::counts;
  1066. // deleting p1 will cause p2 to be moved to the front of the values array
  1067. EXPECT_EQ(
  1068. Tracked<0>::counts.dist(Counts{0, 1, 0, 0}) +
  1069. Tracked<1>::counts.dist(Counts{0, 1, 0, 0}),
  1070. 0);
  1071. }
  1072. TEST(F14ValueMap, maxSize) {
  1073. F14ValueMap<int, int> m;
  1074. EXPECT_EQ(
  1075. m.max_size(),
  1076. std::numeric_limits<std::size_t>::max() / sizeof(std::pair<int, int>));
  1077. }
  1078. TEST(F14NodeMap, maxSize) {
  1079. F14NodeMap<int, int> m;
  1080. EXPECT_EQ(
  1081. m.max_size(),
  1082. std::numeric_limits<std::size_t>::max() / sizeof(std::pair<int, int>));
  1083. }
  1084. TEST(F14VectorMap, vectorMaxSize) {
  1085. F14VectorMap<int, int> m;
  1086. EXPECT_EQ(
  1087. m.max_size(),
  1088. std::min(
  1089. std::size_t{std::numeric_limits<uint32_t>::max()},
  1090. std::numeric_limits<std::size_t>::max() /
  1091. sizeof(std::pair<int, int>)));
  1092. }
  1093. template <typename M>
  1094. void runMoveOnlyTest() {
  1095. M t0;
  1096. t0[10] = 20;
  1097. t0.emplace(30, 40);
  1098. t0.insert(std::make_pair(50, 60));
  1099. M t1{std::move(t0)};
  1100. EXPECT_TRUE(t0.empty());
  1101. M t2;
  1102. EXPECT_TRUE(t2.empty());
  1103. t2 = std::move(t1);
  1104. EXPECT_EQ(t2.size(), 3);
  1105. }
  1106. TEST(F14ValueMap, moveOnly) {
  1107. runMoveOnlyTest<F14ValueMap<f14::MoveOnlyTestInt, int>>();
  1108. runMoveOnlyTest<F14ValueMap<int, f14::MoveOnlyTestInt>>();
  1109. runMoveOnlyTest<F14ValueMap<f14::MoveOnlyTestInt, f14::MoveOnlyTestInt>>();
  1110. }
  1111. TEST(F14NodeMap, moveOnly) {
  1112. runMoveOnlyTest<F14NodeMap<f14::MoveOnlyTestInt, int>>();
  1113. runMoveOnlyTest<F14NodeMap<int, f14::MoveOnlyTestInt>>();
  1114. runMoveOnlyTest<F14NodeMap<f14::MoveOnlyTestInt, f14::MoveOnlyTestInt>>();
  1115. }
  1116. TEST(F14VectorMap, moveOnly) {
  1117. runMoveOnlyTest<F14VectorMap<f14::MoveOnlyTestInt, int>>();
  1118. runMoveOnlyTest<F14VectorMap<int, f14::MoveOnlyTestInt>>();
  1119. runMoveOnlyTest<F14VectorMap<f14::MoveOnlyTestInt, f14::MoveOnlyTestInt>>();
  1120. }
  1121. TEST(F14FastMap, moveOnly) {
  1122. runMoveOnlyTest<F14FastMap<f14::MoveOnlyTestInt, int>>();
  1123. runMoveOnlyTest<F14FastMap<int, f14::MoveOnlyTestInt>>();
  1124. runMoveOnlyTest<F14FastMap<f14::MoveOnlyTestInt, f14::MoveOnlyTestInt>>();
  1125. }
  1126. TEST(F14ValueMap, heterogeneousLookup) {
  1127. using Hasher = folly::transparent<folly::hasher<folly::StringPiece>>;
  1128. using KeyEqual = folly::transparent<std::equal_to<folly::StringPiece>>;
  1129. constexpr auto hello = "hello"_sp;
  1130. constexpr auto buddy = "buddy"_sp;
  1131. constexpr auto world = "world"_sp;
  1132. F14ValueMap<std::string, bool, Hasher, KeyEqual> map;
  1133. map.emplace(hello, true);
  1134. map.emplace(world, false);
  1135. auto checks = [hello, buddy](auto& ref) {
  1136. // count
  1137. EXPECT_EQ(0, ref.count(buddy));
  1138. EXPECT_EQ(1, ref.count(hello));
  1139. // find
  1140. EXPECT_TRUE(ref.end() == ref.find(buddy));
  1141. EXPECT_EQ(hello, ref.find(hello)->first);
  1142. // prehash + find
  1143. EXPECT_TRUE(ref.end() == ref.find(ref.prehash(buddy), buddy));
  1144. EXPECT_EQ(hello, ref.find(ref.prehash(hello), hello)->first);
  1145. // equal_range
  1146. EXPECT_TRUE(std::make_pair(ref.end(), ref.end()) == ref.equal_range(buddy));
  1147. EXPECT_TRUE(
  1148. std::make_pair(ref.find(hello), ++ref.find(hello)) ==
  1149. ref.equal_range(hello));
  1150. };
  1151. checks(map);
  1152. checks(folly::as_const(map));
  1153. }
  1154. template <typename M>
  1155. void runStatefulFunctorTest() {
  1156. bool ranHasher = false;
  1157. bool ranEqual = false;
  1158. bool ranAlloc = false;
  1159. bool ranDealloc = false;
  1160. auto hasher = [&](int x) {
  1161. ranHasher = true;
  1162. return x;
  1163. };
  1164. auto equal = [&](int x, int y) {
  1165. ranEqual = true;
  1166. return x == y;
  1167. };
  1168. auto alloc = [&](std::size_t n) {
  1169. ranAlloc = true;
  1170. return std::malloc(n);
  1171. };
  1172. auto dealloc = [&](void* p, std::size_t) {
  1173. ranDealloc = true;
  1174. std::free(p);
  1175. };
  1176. {
  1177. M map(0, hasher, equal, {alloc, dealloc});
  1178. map[10]++;
  1179. map[10]++;
  1180. EXPECT_EQ(map[10], 2);
  1181. M map2(map);
  1182. M map3(std::move(map));
  1183. map = map2;
  1184. map2.clear();
  1185. map2 = std::move(map3);
  1186. }
  1187. EXPECT_TRUE(ranHasher);
  1188. EXPECT_TRUE(ranEqual);
  1189. EXPECT_TRUE(ranAlloc);
  1190. EXPECT_TRUE(ranDealloc);
  1191. }
  1192. TEST(F14ValueMap, statefulFunctors) {
  1193. runStatefulFunctorTest<F14ValueMap<
  1194. int,
  1195. int,
  1196. GenericHasher<int>,
  1197. GenericEqual<int>,
  1198. GenericAlloc<std::pair<int const, int>>>>();
  1199. }
  1200. TEST(F14NodeMap, statefulFunctors) {
  1201. runStatefulFunctorTest<F14NodeMap<
  1202. int,
  1203. int,
  1204. GenericHasher<int>,
  1205. GenericEqual<int>,
  1206. GenericAlloc<std::pair<int const, int>>>>();
  1207. }
  1208. TEST(F14VectorMap, statefulFunctors) {
  1209. runStatefulFunctorTest<F14VectorMap<
  1210. int,
  1211. int,
  1212. GenericHasher<int>,
  1213. GenericEqual<int>,
  1214. GenericAlloc<std::pair<int const, int>>>>();
  1215. }
  1216. TEST(F14FastMap, statefulFunctors) {
  1217. runStatefulFunctorTest<F14FastMap<
  1218. int,
  1219. int,
  1220. GenericHasher<int>,
  1221. GenericEqual<int>,
  1222. GenericAlloc<std::pair<int const, int>>>>();
  1223. }
  1224. template <typename M>
  1225. void runHeterogeneousInsertTest() {
  1226. M map;
  1227. resetTracking();
  1228. EXPECT_EQ(map.count(10), 0);
  1229. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0)
  1230. << Tracked<1>::counts;
  1231. resetTracking();
  1232. map[10] = 20;
  1233. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 1}), 0)
  1234. << Tracked<1>::counts;
  1235. resetTracking();
  1236. std::pair<int, int> p(10, 30);
  1237. std::vector<std::pair<int, int>> v({p});
  1238. map[10] = 30;
  1239. map.insert(std::pair<int, int>(10, 30));
  1240. map.insert(std::pair<int const, int>(10, 30));
  1241. map.insert(p);
  1242. map.insert(v.begin(), v.end());
  1243. map.insert(
  1244. std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
  1245. map.insert_or_assign(10, 40);
  1246. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0)
  1247. << Tracked<1>::counts;
  1248. resetTracking();
  1249. map.emplace(10, 30);
  1250. map.emplace(
  1251. std::piecewise_construct,
  1252. std::forward_as_tuple(10),
  1253. std::forward_as_tuple(30));
  1254. map.emplace(p);
  1255. map.try_emplace(10, 30);
  1256. map.try_emplace(10);
  1257. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0)
  1258. << Tracked<1>::counts;
  1259. resetTracking();
  1260. map.erase(10);
  1261. EXPECT_EQ(map.size(), 0);
  1262. EXPECT_EQ(Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 0)
  1263. << Tracked<1>::counts;
  1264. }
  1265. template <typename M>
  1266. void runHeterogeneousInsertStringTest() {
  1267. using P = std::pair<StringPiece, std::string>;
  1268. using CP = std::pair<const StringPiece, std::string>;
  1269. M map;
  1270. P p{"foo", "hello"};
  1271. std::vector<P> v{p};
  1272. StringPiece foo{"foo"};
  1273. map.insert(P("foo", "hello"));
  1274. // TODO(T31574848): the list-initialization below does not work on libstdc++
  1275. // versions (e.g., GCC < 6) with no implementation of N4387 ("perfect
  1276. // initialization" for pairs and tuples).
  1277. // StringPiece sp{"foo"};
  1278. // map.insert({sp, "hello"});
  1279. map.insert({"foo", "hello"});
  1280. map.insert(CP("foo", "hello"));
  1281. map.insert(p);
  1282. map.insert(v.begin(), v.end());
  1283. map.insert(
  1284. std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));
  1285. map.insert_or_assign("foo", "hello");
  1286. map.insert_or_assign(StringPiece{"foo"}, "hello");
  1287. EXPECT_EQ(map["foo"], "hello");
  1288. map.emplace(StringPiece{"foo"}, "hello");
  1289. map.emplace("foo", "hello");
  1290. map.emplace(p);
  1291. map.emplace();
  1292. map.emplace(
  1293. std::piecewise_construct,
  1294. std::forward_as_tuple(StringPiece{"foo"}),
  1295. std::forward_as_tuple(/* count */ 20, 'x'));
  1296. map.try_emplace(StringPiece{"foo"}, "hello");
  1297. map.try_emplace(foo, "hello");
  1298. map.try_emplace(foo);
  1299. map.try_emplace("foo");
  1300. map.try_emplace("foo", "hello");
  1301. map.try_emplace("foo", /* count */ 20, 'x');
  1302. map.erase(StringPiece{"foo"});
  1303. map.erase(foo);
  1304. map.erase("");
  1305. EXPECT_TRUE(map.empty());
  1306. }
  1307. TEST(F14ValueMap, heterogeneousInsert) {
  1308. runHeterogeneousInsertTest<F14ValueMap<
  1309. Tracked<1>,
  1310. int,
  1311. TransparentTrackedHash<1>,
  1312. TransparentTrackedEqual<1>>>();
  1313. runHeterogeneousInsertStringTest<F14ValueMap<
  1314. std::string,
  1315. std::string,
  1316. transparent<hasher<StringPiece>>,
  1317. transparent<DefaultKeyEqual<StringPiece>>>>();
  1318. }
  1319. TEST(F14NodeMap, heterogeneousInsert) {
  1320. runHeterogeneousInsertTest<F14NodeMap<
  1321. Tracked<1>,
  1322. int,
  1323. TransparentTrackedHash<1>,
  1324. TransparentTrackedEqual<1>>>();
  1325. runHeterogeneousInsertStringTest<F14NodeMap<
  1326. std::string,
  1327. std::string,
  1328. transparent<hasher<StringPiece>>,
  1329. transparent<DefaultKeyEqual<StringPiece>>>>();
  1330. }
  1331. TEST(F14VectorMap, heterogeneousInsert) {
  1332. runHeterogeneousInsertTest<F14VectorMap<
  1333. Tracked<1>,
  1334. int,
  1335. TransparentTrackedHash<1>,
  1336. TransparentTrackedEqual<1>>>();
  1337. runHeterogeneousInsertStringTest<F14VectorMap<
  1338. std::string,
  1339. std::string,
  1340. transparent<hasher<StringPiece>>,
  1341. transparent<DefaultKeyEqual<StringPiece>>>>();
  1342. }
  1343. TEST(F14FastMap, heterogeneousInsert) {
  1344. runHeterogeneousInsertTest<F14FastMap<
  1345. Tracked<1>,
  1346. int,
  1347. TransparentTrackedHash<1>,
  1348. TransparentTrackedEqual<1>>>();
  1349. runHeterogeneousInsertStringTest<F14FastMap<
  1350. std::string,
  1351. std::string,
  1352. transparent<hasher<StringPiece>>,
  1353. transparent<DefaultKeyEqual<StringPiece>>>>();
  1354. }
  1355. ///////////////////////////////////
  1356. #endif // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
  1357. ///////////////////////////////////