20 #include <unordered_map> 27 template <
template <
typename,
typename,
typename,
typename,
typename>
47 testCustomSwap<folly::F14ValueMap>();
48 testCustomSwap<folly::F14NodeMap>();
49 testCustomSwap<folly::F14VectorMap>();
50 testCustomSwap<folly::F14FastMap>();
55 template <
typename,
typename,
typename,
typename,
typename>
class TMap,
58 void runAllocatedMemorySizeTest() {
72 if (preciseAllocInfo) {
79 for (
size_t i = 0;
i < 1000; ++
i) {
80 m.insert(std::make_pair(folly::to<K>(
i), V{}));
81 m.erase(folly::to<K>(
i / 10 + 2));
82 if (preciseAllocInfo) {
85 EXPECT_GE(m.getAllocatedMemorySize(),
sizeof(std::pair<K, V>) * m.size());
87 std::size_t
count = 0;
88 m.visitAllocationClasses([&](std::size_t, std::size_t)
mutable {});
89 m.visitAllocationClasses([&](std::size_t bytes, std::size_t n) {
93 if (preciseAllocInfo) {
112 template <
typename K,
typename V>
113 void runAllocatedMemorySizeTests() {
114 runAllocatedMemorySizeTest<folly::F14ValueMap, K, V>();
115 runAllocatedMemorySizeTest<folly::F14NodeMap, K, V>();
116 runAllocatedMemorySizeTest<folly::F14VectorMap, K, V>();
117 runAllocatedMemorySizeTest<folly::F14FastMap, K, V>();
121 TEST(F14Map, getAllocatedMemorySize) {
122 runAllocatedMemorySizeTests<bool, bool>();
123 runAllocatedMemorySizeTests<int, int>();
124 runAllocatedMemorySizeTests<bool, std::string>();
125 runAllocatedMemorySizeTests<double, std::string>();
126 runAllocatedMemorySizeTests<std::string, int>();
127 runAllocatedMemorySizeTests<std::string, std::string>();
128 runAllocatedMemorySizeTests<folly::fbstring, long>();
131 template <
typename M>
135 for (
int i = 0;
i < n; ++
i) {
140 std::unordered_map<uintptr_t, bool> visited;
141 for (
auto& entry : map) {
142 visited[
reinterpret_cast<uintptr_t
>(&entry)] =
false;
145 map.visitContiguousRanges([&](
auto b,
auto e) {
146 for (
auto i =
b;
i != e; ++
i) {
147 auto iter = visited.find(reinterpret_cast<uintptr_t>(
i));
155 for (
auto& e : visited) {
160 template <
typename M>
162 runVisitContiguousRangesTest<M>(0);
163 runVisitContiguousRangesTest<M>(5);
164 runVisitContiguousRangesTest<M>(1000);
167 TEST(F14ValueMap, visitContiguousRanges) {
168 runVisitContiguousRangesTest<folly::F14ValueMap<int, int>>();
171 TEST(F14NodeMap, visitContiguousRanges) {
172 runVisitContiguousRangesTest<folly::F14NodeMap<int, int>>();
175 TEST(F14VectorMap, visitContiguousRanges) {
176 runVisitContiguousRangesTest<folly::F14VectorMap<int, int>>();
179 TEST(F14FastMap, visitContiguousRanges) {
180 runVisitContiguousRangesTest<folly::F14FastMap<int, int>>();
184 #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE 191 #include <unordered_map> 196 using namespace folly;
198 using namespace folly::string_piece_literals;
206 template <
typename T>
212 h.insert(std::make_pair(
s(
"abc"),
s(
"ABC")));
216 h[
s(
"ghi")] =
s(
"GHI");
218 h.erase(h.find(
s(
"abc")));
236 h3.try_emplace(
s(
"xxx"));
237 h3.insert_or_assign(
s(
"yyy"),
s(
"YYY"));
244 h[to<std::string>(
i *
i *
i)] =
s(
"x");
254 h2.find(to<std::string>(i * i * i))->first, to<std::string>(i * i *
i));
255 EXPECT_TRUE(h2.find(to<std::string>(i * i * i + 2)) == h2.end());
266 T h8({{
s(
"abc"),
s(
"ABC")}, {
s(
"def"),
s(
"DEF")}});
267 T h9({{
s(
"abc"),
s(
"ABD")}, {
s(
"def"),
s(
"DEF")}});
283 auto k = to<std::string>(
i *
i *
i);
297 h8.emplace(
s(
"abc"),
s(
"ABC"));
301 h9 = {{
s(
"abc"),
s(
"ABD")}, {
s(
"def"),
s(
"DEF")}};
305 auto expectH8 = [&](
T& ref) {
EXPECT_EQ(&ref, &h8); };
321 template <
typename T>
325 auto b = h.bucket_count();
326 for (
unsigned i = 0;
i < n; ++
i) {
327 h.insert(std::make_pair(to<std::string>(
i),
s(
"")));
328 if (
b != h.bucket_count()) {
330 b = h.bucket_count();
338 template <
typename T>
340 using R = std::unordered_map<uint64_t, Tracked<2>>;
344 std::mt19937_64 gen(0);
345 std::uniform_int_distribution<> pctDist(0, 100);
346 std::uniform_int_distribution<uint64_t> bitsBitsDist(1, 6);
352 std::size_t rollbacks = 0;
353 std::size_t resizingSmallRollbacks = 0;
354 std::size_t resizingLargeRollbacks = 0;
356 for (std::size_t reps = 0; reps < 100000 || rollbacks < 10 ||
357 resizingSmallRollbacks < 1 || resizingLargeRollbacks < 1;
359 if (pctDist(gen) < 20) {
365 bool leakCheckOnly =
false;
368 auto discardBits = (
uint64_t{1} << bitsBitsDist(gen)) - 2;
369 auto k = gen() >> discardBits;
371 auto pct = pctDist(gen);
381 auto t = t0.insert(std::make_pair(
k,
v));
382 auto r = r0.insert(std::make_pair(
k,
v));
384 EXPECT_EQ(
t.first->second.val_, r.first->second.val_);
386 }
else if (pct < 25) {
388 auto t = t0.emplace(
k,
v);
389 auto r = r0.emplace(
k,
v);
391 EXPECT_EQ(
t.first->second.val_, r.first->second.val_);
393 }
else if (pct < 30) {
395 leakCheckOnly =
true;
396 t0.insert(t1.begin(), t1.end());
397 r0.insert(r1.begin(), r1.end());
398 }
else if (pct < 40) {
400 auto t = t0.erase(
k);
401 auto r = r0.erase(
k);
403 }
else if (pct < 47) {
421 }
else if (pct < 50) {
432 t = t0.erase(firstt, lastt);
438 r = r0.erase(firstr, lastr);
443 }
else if (pct < 58) {
448 if (
t != t0.end() && r != r0.end()) {
453 }
else if (pct < 60) {
455 auto t = t0.equal_range(
k);
456 auto r = r0.equal_range(
k);
457 EXPECT_EQ((
t.first ==
t.second), (r.first == r.second));
458 if (
t.first !=
t.second && r.first != r.second) {
460 EXPECT_EQ(
t.first->second.val_, r.first->second.val_);
466 }
else if (pct < 65) {
470 t += e.first * 37 + e.second.val_ + 1000;
474 r += e.first * 37 + e.second.val_ + 1000;
477 }
else if (pct < 69) {
482 }
else if (pct < 70) {
486 }
else if (pct < 72) {
492 }
else if (pct < 74) {
494 std::size_t capacity =
k & 0xffff;
499 }
else if (pct < 80) {
501 t0 =
T{t1.begin(), t1.end()};
502 r0 = R{r1.begin(), r1.end()};
503 }
else if (pct < 82) {
505 auto k2 = gen() >> discardBits;
507 T t({{
k,
v}, {k2, v}, {k2, v2}});
509 R r({{
k,
v}, {k2, v}, {k2, v2}});
511 }
else if (pct < 85) {
517 }
else if (pct < 88) {
519 T t(t1, t1.get_allocator());
521 R r(r1, r1.get_allocator());
523 }
else if (pct < 89) {
529 }
else if (pct < 90) {
532 auto ta = t1.get_allocator();
535 auto ra = r1.get_allocator();
537 }
else if (pct < 94) {
539 leakCheckOnly =
true;
542 }
else if (pct < 96) {
546 }
else if (pct < 98) {
549 }
else if (pct < 99) {
554 }
else if (pct < 100) {
556 auto scale = std::uniform_int_distribution<>(0, 8)(gen);
557 auto delta = std::uniform_int_distribution<>(-2, 2)(gen);
558 std::ptrdiff_t target = (t0.size() * scale) / 4 + delta;
560 t0.reserve(static_cast<std::size_t>(target));
561 r0.reserve(static_cast<std::size_t>(target));
564 }
catch (std::bad_alloc
const&) {
572 for (
auto&& kv : r0) {
573 t0[kv.first] = kv.second.val_;
577 if (t0.bucket_count() == t0.size() && t0.size() > 0) {
578 if (t0.size() < 10) {
579 ++resizingSmallRollbacks;
581 ++resizingLargeRollbacks;
585 assert(t0.size() == r0.size());
586 for (
auto&& kv : r0) {
587 auto t = t0.find(kv.first);
589 t != t0.end() &&
t->first == kv.first &&
590 t->second.val_ == kv.second.val_);
599 template <
typename T>
605 h.insert(std::make_pair(
s(
"abc"),
s(
"ABC")));
609 auto t1 = h.prehash(
s(
"def"));
611 t2 = h.prehash(
s(
"abc"));
617 runSimple<F14ValueMap<std::string, std::string>>();
621 runSimple<F14NodeMap<std::string, std::string>>();
625 runSimple<F14VectorMap<std::string, std::string>>();
629 runSimple<F14FastMap<std::string, std::string>>();
632 TEST(F14VectorMap, reverse_iterator) {
633 using TMap = F14VectorMap<uint64_t, uint64_t>;
635 for (
auto i = lo;
i < hi; ++
i) {
640 auto loIt = h.find(lo);
643 for (
auto rit = h.riter(loIt); rit != h.rend(); ++rit) {
646 TMap::const_iterator it = h.iter(rit);
657 while (newSize < 10
'000) { 658 populate(h, prevSize, newSize); 659 verify(h, 0, newSize); 660 verify(h, newSize / 2, newSize); 663 verify(h2, 0, newSize); 666 verify(h, 0, newSize); 672 TEST(F14ValueMap, rehash) { 673 runRehash<F14ValueMap<std::string, std::string>>(); 676 TEST(F14NodeMap, rehash) { 677 runRehash<F14NodeMap<std::string, std::string>>(); 680 TEST(F14VectorMap, rehash) { 681 runRehash<F14VectorMap<std::string, std::string>>(); 684 TEST(F14ValueMap, prehash) { 685 runPrehash<F14ValueMap<std::string, std::string>>(); 688 TEST(F14NodeMap, prehash) { 689 runPrehash<F14NodeMap<std::string, std::string>>(); 692 TEST(F14ValueMap, random) { 693 runRandom<F14ValueMap< 697 std::equal_to<uint64_t>, 698 SwapTrackingAlloc<std::pair<uint64_t const, Tracked<1>>>>>(); 701 TEST(F14NodeMap, random) { 702 runRandom<F14NodeMap< 706 std::equal_to<uint64_t>, 707 SwapTrackingAlloc<std::pair<uint64_t const, Tracked<1>>>>>(); 710 TEST(F14VectorMap, random) { 711 runRandom<F14VectorMap< 715 std::equal_to<uint64_t>, 716 SwapTrackingAlloc<std::pair<uint64_t const, Tracked<1>>>>>(); 719 TEST(F14FastMap, random) { 720 runRandom<F14FastMap< 724 std::equal_to<uint64_t>, 725 SwapTrackingAlloc<std::pair<uint64_t const, Tracked<1>>>>>(); 728 TEST(F14ValueMap, grow_stats) { 729 F14ValueMap<uint64_t, uint64_t> h; 730 for (unsigned i = 1; i <= 3072; ++i) { 733 // F14ValueMap just before rehash 734 F14TableStats::compute(h); 736 // F14ValueMap just after rehash 737 F14TableStats::compute(h); 740 TEST(F14ValueMap, steady_state_stats) { 741 // 10k keys, 14% probability of insert, 90% chance of erase, so the 742 // table should converge to 1400 size without triggering the rehash 743 // that would occur at 1536. 744 F14ValueMap<uint64_t, uint64_t> h; 745 std::mt19937_64 gen(0); 746 std::uniform_int_distribution<> dist(0, 10000); 747 for (std::size_t i = 0; i < 100000; ++i) { 748 auto key = dist(gen); 749 if (dist(gen) < 1400) { 750 h.insert_or_assign(key, i); 754 if (((i + 1) % 10000) == 0) { 755 auto stats = F14TableStats::compute(h); 756 // Verify that average miss probe length is bounded despite continued 757 // erase + reuse. p99 of the average across 10M random steps is 4.69, 759 EXPECT_LT(f14::expectedProbe(stats.missProbeLengthHisto), 10.0); 762 // F14ValueMap at steady state 763 F14TableStats::compute(h); 766 TEST(F14VectorMap, steady_state_stats) { 767 // 10k keys, 14% probability of insert, 90% chance of erase, so the 768 // table should converge to 1400 size without triggering the rehash 769 // that would occur at 1536. 770 F14VectorMap<std::string, uint64_t> h; 771 std::mt19937_64 gen(0); 772 std::uniform_int_distribution<> dist(0, 10000); 773 for (std::size_t i = 0; i < 100000; ++i) { 774 auto key = "0123456789ABCDEFGHIJKLMNOPQ" + to<std::string>(dist(gen)); 775 if (dist(gen) < 1400) { 776 h.insert_or_assign(key, i); 780 if (((i + 1) % 10000) == 0) { 781 auto stats = F14TableStats::compute(h); 782 // Verify that average miss probe length is bounded despite continued 783 // erase + reuse. p99 of the average across 10M random steps is 4.69, 785 EXPECT_LT(f14::expectedProbe(stats.missProbeLengthHisto), 10.0); 788 // F14ValueMap at steady state 789 F14TableStats::compute(h); 792 TEST(Tracked, baseline) { 798 EXPECT_EQ(a0.val_, b0.val_); 799 EXPECT_EQ(sumCounts, (Counts{1, 0, 0, 0})); 800 EXPECT_EQ(Tracked<0>::counts, (Counts{1, 0, 0, 0})); 804 Tracked<0> b0{std::move(a0)}; 805 EXPECT_EQ(a0.val_, b0.val_); 806 EXPECT_EQ(sumCounts, (Counts{0, 1, 0, 0})); 807 EXPECT_EQ(Tracked<0>::counts, (Counts{0, 1, 0, 0})); 812 EXPECT_EQ(a0.val_, b1.val_); 813 EXPECT_EQ(sumCounts, (Counts{0, 0, 1, 0})); 814 EXPECT_EQ(Tracked<1>::counts, (Counts{0, 0, 1, 0})); 818 Tracked<1> b1{std::move(a0)}; 819 EXPECT_EQ(a0.val_, b1.val_); 820 EXPECT_EQ(sumCounts, (Counts{0, 0, 0, 1})); 821 EXPECT_EQ(Tracked<1>::counts, (Counts{0, 0, 0, 1})); 827 EXPECT_EQ(a0.val_, b0.val_); 828 EXPECT_EQ(sumCounts, (Counts{0, 0, 0, 0, 1, 0})); 829 EXPECT_EQ(Tracked<0>::counts, (Counts{0, 0, 0, 0, 1, 0})); 835 EXPECT_EQ(a0.val_, b0.val_); 836 EXPECT_EQ(sumCounts, (Counts{0, 0, 0, 0, 0, 1})); 837 EXPECT_EQ(Tracked<0>::counts, (Counts{0, 0, 0, 0, 0, 1})); 843 EXPECT_EQ(a0.val_, b1.val_); 844 EXPECT_EQ(sumCounts, (Counts{0, 0, 1, 0, 0, 1, 0, 1})); 845 EXPECT_EQ(Tracked<1>::counts, (Counts{0, 0, 1, 0, 0, 1, 0, 1})); 851 EXPECT_EQ(a0.val_, b1.val_); 852 EXPECT_EQ(sumCounts, (Counts{0, 0, 0, 1, 0, 1, 0, 1})); 853 EXPECT_EQ(Tracked<1>::counts, (Counts{0, 0, 0, 1, 0, 1, 0, 1})); 857 // M should be a map from Tracked<0> to Tracked<1>. F should take a map 858 // and a pair const& or pair&& and cause it to be inserted 859 template <typename M, typename F> 861 std::string const& name, 863 uint64_t expectedDist = 0) { 864 static_assert(std::is_same<typename M::key_type, Tracked<0>>::value, ""); 865 static_assert(std::is_same<typename M::mapped_type, Tracked<1>>::value, ""); 867 typename M::value_type p{0, 0}; 871 // fresh key, value_type const& -> 874 Tracked<0>::counts.dist(Counts{1, 0, 0, 0}) + 875 Tracked<1>::counts.dist(Counts{1, 0, 0, 0}), 877 << name << "\n0 -> " << Tracked<0>::counts << "\n1 -> " 878 << Tracked<1>::counts; 881 typename M::value_type p{0, 0}; 884 insertFunc(m, std::move(p)); 885 // fresh key, value_type&& -> 886 // key copy is unfortunate but required 888 Tracked<0>::counts.dist(Counts{1, 0, 0, 0}) + 889 Tracked<1>::counts.dist(Counts{0, 1, 0, 0}), 891 << name << "\n0 -> " << Tracked<0>::counts << "\n1 -> " 892 << Tracked<1>::counts; 895 std::pair<Tracked<0>, Tracked<1>> p{0, 0}; 899 // fresh key, pair<key_type,mapped_type> const& -> 900 // 1 copy is required 902 Tracked<0>::counts.dist(Counts{1, 0, 0, 0}) + 903 Tracked<1>::counts.dist(Counts{1, 0, 0, 0}), 905 << name << "\n0 -> " << Tracked<0>::counts << "\n1 -> " 906 << Tracked<1>::counts; 909 std::pair<Tracked<0>, Tracked<1>> p{0, 0}; 912 insertFunc(m, std::move(p)); 913 // fresh key, pair<key_type,mapped_type>&& -> 914 // this is the happy path for insert(make_pair(.., ..)) 916 Tracked<0>::counts.dist(Counts{0, 1, 0, 0}) + 917 Tracked<1>::counts.dist(Counts{0, 1, 0, 0}), 919 << name << "\n0 -> " << Tracked<0>::counts << "\n1 -> " 920 << Tracked<1>::counts; 923 std::pair<Tracked<2>, Tracked<3>> p{0, 0}; 927 // fresh key, convertible const& -> 928 // key_type ops: Tracked<0>::counts 929 // mapped_type ops: Tracked<1>::counts 930 // key_src ops: Tracked<2>::counts 931 // mapped_src ops: Tracked<3>::counts; 933 // There are three strategies that could be optimal for particular 936 // - convert key and value in place to final position, destroy if 937 // insert fails. This is the strategy used by std::unordered_map 940 // - convert key and default value in place to final position, 941 // convert value only if insert succeeds. Nobody uses this strategy 943 // - convert key to a temporary, move key and convert value if 944 // insert succeeds. This is the strategy used by F14 and what is 947 // The expectedDist * 3 is just a hack for the emplace-pieces-by-value 948 // test, whose test harness copies the original pair and then uses 949 // move conversion instead of copy conversion. 951 Tracked<0>::counts.dist(Counts{0, 1, 1, 0}) + 952 Tracked<1>::counts.dist(Counts{0, 0, 1, 0}) + 953 Tracked<2>::counts.dist(Counts{0, 0, 0, 0}) + 954 Tracked<3>::counts.dist(Counts{0, 0, 0, 0}), 958 std::pair<Tracked<2>, Tracked<3>> p{0, 0}; 961 insertFunc(m, std::move(p)); 962 // fresh key, convertible&& -> 963 // key_type ops: Tracked<0>::counts 964 // mapped_type ops: Tracked<1>::counts 965 // key_src ops: Tracked<2>::counts 966 // mapped_src ops: Tracked<3>::counts; 968 Tracked<0>::counts.dist(Counts{0, 1, 0, 1}) + 969 Tracked<1>::counts.dist(Counts{0, 0, 0, 1}) + 970 Tracked<2>::counts.dist(Counts{0, 0, 0, 0}) + 971 Tracked<3>::counts.dist(Counts{0, 0, 0, 0}), 975 typename M::value_type p{0, 0}; 980 // duplicate key, value_type const& 982 Tracked<0>::counts.dist(Counts{0, 0, 0, 0}) + 983 Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 987 typename M::value_type p{0, 0}; 991 insertFunc(m, std::move(p)); 992 // duplicate key, value_type&& 994 Tracked<0>::counts.dist(Counts{0, 0, 0, 0}) + 995 Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 999 std::pair<Tracked<0>, Tracked<1>> p{0, 0}; 1004 // duplicate key, pair<key_type,mapped_type> const& 1006 Tracked<0>::counts.dist(Counts{0, 0, 0, 0}) + 1007 Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 1011 std::pair<Tracked<0>, Tracked<1>> p{0, 0}; 1015 insertFunc(m, std::move(p)); 1016 // duplicate key, pair<key_type,mapped_type>&& 1018 Tracked<0>::counts.dist(Counts{0, 0, 0, 0}) + 1019 Tracked<1>::counts.dist(Counts{0, 0, 0, 0}), 1023 std::pair<Tracked<2>, Tracked<3>> p{0, 0}; 1028 // duplicate key, convertible const& -> 1029 // key_type ops: Tracked<0>::counts 1030 // mapped_type ops: Tracked<1>::counts 1031 // key_src ops: Tracked<2>::counts 1032 // mapped_src ops: Tracked<3>::counts; 1034 Tracked<0>::counts.dist(Counts{0, 0, 1, 0}) + 1035 Tracked<1>::counts.dist(Counts{0, 0, 0, 0}) + 1036 Tracked<2>::counts.dist(Counts{0, 0, 0, 0}) + 1037 Tracked<3>::counts.dist(Counts{0, 0, 0, 0}), 1041 std::pair<Tracked<2>, Tracked<3>> p{0, 0}; 1045 insertFunc(m, std::move(p)); 1046 // duplicate key, convertible&& -> 1047 // key_type ops: Tracked<0>::counts 1048 // mapped_type ops: Tracked<1>::counts 1049 // key_src ops: Tracked<2>::counts 1050 // mapped_src ops: Tracked<3>::counts; 1052 Tracked<0>::counts.dist(Counts{0, 0, 0, 1}) + 1053 Tracked<1>::counts.dist(Counts{0, 0, 0, 0}) + 1054 Tracked<2>::counts.dist(Counts{0, 0, 0, 0}) + 1055 Tracked<3>::counts.dist(Counts{0, 0, 0, 0}), 1061 template <typename M, typename P> 1062 void operator()(M& m, P&& p) const { 1063 m.insert(std::forward<P>(p)); 1068 template <typename M, typename P> 1069 void operator()(M& m, P&& p) const { 1070 m.emplace(std::forward<P>(p)); 1075 template <typename M, typename U1, typename U2> 1076 void operator()(M& m, std::pair<U1, U2> const& p) const { 1077 m.emplace(p.first, p.second); 1080 template <typename M, typename U1, typename U2> 1081 void operator()(M& m, std::pair<U1, U2>&& p) const { 1082 m.emplace(std::move(p.first), std::move(p.second)); 1087 template <typename M, typename U1, typename U2> 1088 void operator()(M& m, std::pair<U1, U2> const& p) const { 1090 std::piecewise_construct, 1091 std::forward_as_tuple(p.first), 1092 std::forward_as_tuple(p.second)); 1095 template <typename M, typename U1, typename U2> 1096 void operator()(M& m, std::pair<U1, U2>&& p) const { 1098 std::piecewise_construct, 1099 std::forward_as_tuple(std::move(p.first)), 1100 std::forward_as_tuple(std::move(p.second))); 1104 // Simulates use of piecewise_construct without proper use of 1105 // forward_as_tuple. This code doesn't yield the normal pattern, but
1108 struct DoEmplace3Value {
1109 template <
typename M,
typename U1,
typename U2>
1110 void operator()(
M&
m, std::pair<U1, U2>
const& p)
const {
1112 std::piecewise_construct,
1113 std::tuple<U1>{p.first},
1114 std::tuple<U2>{p.second});
1117 template <
typename M,
typename U1,
typename U2>
1118 void operator()(
M& m, std::pair<U1, U2>&& p)
const {
1120 std::piecewise_construct,
1126 template <
typename M>
1128 runInsertCases<M>(name +
" insert", DoInsert{});
1129 runInsertCases<M>(name +
" emplace pair", DoEmplace1{});
1130 runInsertCases<M>(name +
" emplace k,v", DoEmplace2{});
1131 runInsertCases<M>(name +
" emplace pieces", DoEmplace3{});
1132 runInsertCases<M>(name +
" emplace pieces by value", DoEmplace3Value{}, 2);
1137 typename M::key_type
k;
1145 TEST(F14ValueMap, destructuring) {
1146 runInsertAndEmplace<F14ValueMap<Tracked<0>,
Tracked<1>>>(
"f14value");
1149 TEST(F14NodeMap, destructuring) {
1150 runInsertAndEmplace<F14NodeMap<Tracked<0>,
Tracked<1>>>(
"f14node");
1153 TEST(F14VectorMap, destructuring) {
1154 runInsertAndEmplace<F14VectorMap<Tracked<0>,
Tracked<1>>>(
"f14vector");
1157 TEST(F14VectorMap, destructuringErase) {
1159 typename M::value_type p1{0, 0};
1160 typename M::value_type p2{2, 2};
1167 LOG(
INFO) <<
"erase -> " 1177 TEST(F14ValueMap, maxSize) {
1178 F14ValueMap<int, int>
m;
1184 TEST(F14NodeMap, maxSize) {
1185 F14NodeMap<int, int>
m;
1191 TEST(F14VectorMap, vectorMaxSize) {
1192 F14VectorMap<int, int>
m;
1198 sizeof(std::pair<int, int>)));
1201 template <
typename M>
1202 void runMoveOnlyTest() {
1206 t0.insert(std::make_pair(50, 60));
1215 TEST(F14ValueMap, moveOnly) {
1216 runMoveOnlyTest<F14ValueMap<f14::MoveOnlyTestInt, int>>();
1217 runMoveOnlyTest<F14ValueMap<int, f14::MoveOnlyTestInt>>();
1218 runMoveOnlyTest<F14ValueMap<f14::MoveOnlyTestInt, f14::MoveOnlyTestInt>>();
1221 TEST(F14NodeMap, moveOnly) {
1222 runMoveOnlyTest<F14NodeMap<f14::MoveOnlyTestInt, int>>();
1223 runMoveOnlyTest<F14NodeMap<int, f14::MoveOnlyTestInt>>();
1224 runMoveOnlyTest<F14NodeMap<f14::MoveOnlyTestInt, f14::MoveOnlyTestInt>>();
1227 TEST(F14VectorMap, moveOnly) {
1228 runMoveOnlyTest<F14VectorMap<f14::MoveOnlyTestInt, int>>();
1229 runMoveOnlyTest<F14VectorMap<int, f14::MoveOnlyTestInt>>();
1230 runMoveOnlyTest<F14VectorMap<f14::MoveOnlyTestInt, f14::MoveOnlyTestInt>>();
1233 TEST(F14FastMap, moveOnly) {
1234 runMoveOnlyTest<F14FastMap<f14::MoveOnlyTestInt, int>>();
1235 runMoveOnlyTest<F14FastMap<int, f14::MoveOnlyTestInt>>();
1236 runMoveOnlyTest<F14FastMap<f14::MoveOnlyTestInt, f14::MoveOnlyTestInt>>();
1239 TEST(F14ValueMap, heterogeneousLookup) {
1243 constexpr
auto hello =
"hello"_sp;
1244 constexpr
auto buddy =
"buddy"_sp;
1245 constexpr
auto world =
"world"_sp;
1247 F14ValueMap<std::string, bool, Hasher, KeyEqual>
map;
1248 map.emplace(hello,
true);
1249 map.emplace(world,
false);
1251 auto checks = [hello, buddy](
auto& ref) {
1258 EXPECT_EQ(hello, ref.find(hello)->first);
1261 EXPECT_TRUE(ref.end() == ref.find(ref.prehash(buddy), buddy));
1265 EXPECT_TRUE(std::make_pair(ref.end(), ref.end()) == ref.equal_range(buddy));
1267 std::make_pair(ref.find(hello), ++ref.find(hello)) ==
1268 ref.equal_range(hello));
1275 template <
typename M>
1276 void runStatefulFunctorTest() {
1277 bool ranHasher =
false;
1278 bool ranEqual =
false;
1279 bool ranAlloc =
false;
1280 bool ranDealloc =
false;
1286 auto equal = [&](
int x,
int y) {
1290 auto alloc = [&](std::size_t n) {
1292 return std::malloc(n);
1294 auto dealloc = [&](
void* p, std::size_t) {
1317 TEST(F14ValueMap, statefulFunctors) {
1318 runStatefulFunctorTest<F14ValueMap<
1326 TEST(F14NodeMap, statefulFunctors) {
1327 runStatefulFunctorTest<F14NodeMap<
1335 TEST(F14VectorMap, statefulFunctors) {
1336 runStatefulFunctorTest<F14VectorMap<
1344 TEST(F14FastMap, statefulFunctors) {
1345 runStatefulFunctorTest<F14FastMap<
1353 template <
typename M>
1354 void runHeterogeneousInsertTest() {
1365 << Tracked<1>::counts;
1368 std::pair<int, int> p(10, 30);
1369 std::vector<std::pair<int, int>>
v({p});
1371 map.insert(std::pair<int, int>(10, 30));
1372 map.insert(std::pair<int const, int>(10, 30));
1374 map.insert(
v.begin(),
v.end());
1376 std::make_move_iterator(
v.begin()), std::make_move_iterator(
v.end()));
1377 map.insert_or_assign(10, 40);
1379 << Tracked<1>::counts;
1382 map.emplace(10, 30);
1384 std::piecewise_construct,
1385 std::forward_as_tuple(10),
1386 std::forward_as_tuple(30));
1388 map.try_emplace(10, 30);
1389 map.try_emplace(10);
1391 << Tracked<1>::counts;
1397 << Tracked<1>::counts;
1400 template <
typename M>
1401 void runHeterogeneousInsertStringTest() {
1402 using P = std::pair<StringPiece, std::string>;
1403 using CP = std::pair<const StringPiece, std::string>;
1406 P p{
"foo",
"hello"};
1407 std::vector<P>
v{p};
1410 map.insert(P(
"foo",
"hello"));
1416 map.insert({
"foo",
"hello"});
1417 map.insert(CP(
"foo",
"hello"));
1419 map.insert(
v.begin(),
v.end());
1421 std::make_move_iterator(
v.begin()), std::make_move_iterator(
v.end()));
1422 map.insert_or_assign(
"foo",
"hello");
1423 map.insert_or_assign(
StringPiece{
"foo"},
"hello");
1427 map.emplace(
"foo",
"hello");
1431 std::piecewise_construct,
1433 std::forward_as_tuple( 20,
'x'));
1435 map.try_emplace(
foo,
"hello");
1436 map.try_emplace(
foo);
1437 map.try_emplace(
"foo");
1438 map.try_emplace(
"foo",
"hello");
1439 map.try_emplace(
"foo", 20,
'x');
1447 TEST(F14ValueMap, heterogeneousInsert) {
1448 runHeterogeneousInsertTest<F14ValueMap<
1453 runHeterogeneousInsertStringTest<F14ValueMap<
1458 runHeterogeneousInsertStringTest<F14ValueMap<std::string, std::string>>();
1461 TEST(F14NodeMap, heterogeneousInsert) {
1462 runHeterogeneousInsertTest<F14NodeMap<
1467 runHeterogeneousInsertStringTest<F14NodeMap<
1472 runHeterogeneousInsertStringTest<F14NodeMap<std::string, std::string>>();
1475 TEST(F14VectorMap, heterogeneousInsert) {
1476 runHeterogeneousInsertTest<F14VectorMap<
1481 runHeterogeneousInsertStringTest<F14VectorMap<
1486 runHeterogeneousInsertStringTest<F14VectorMap<std::string, std::string>>();
1489 TEST(F14FastMap, heterogeneousInsert) {
1490 runHeterogeneousInsertTest<F14FastMap<
1495 runHeterogeneousInsertStringTest<F14FastMap<
1500 runHeterogeneousInsertStringTest<F14FastMap<std::string, std::string>>();
1504 #endif // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE 1505
void populate(Vector &v, const pair< int, int > &ss)
#define EXPECT_THROW(statement, expected_exception)
void limitTestAllocations(std::size_t allocationsBeforeException=0)
#define EXPECT_EQ(val1, val2)
constexpr detail::Map< Move > move
void runVisitContiguousRangesTest(int n)
—— Concurrent Priority Queue Implementation ——
#define EXPECT_GE(val1, val2)
constexpr T const & as_const(T &t) noexcept
static F14TableStats compute(T const &m)
void unlimitTestAllocations()
thread_local size_t testAllocatedBlockCount
constexpr auto size(C const &c) -> decltype(c.size())
static constexpr F14IntrinsicsMode getF14IntrinsicsMode()
static map< string, int > m
std::uniform_int_distribution< milliseconds::rep > dist
thread_local size_t testAllocatedMemorySize
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
#define EXPECT_TRUE(condition)
#define EXPECT_NE(val1, val2)
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
#define EXPECT_FALSE(condition)
#define ASSERT_TRUE(condition)
TEST(SequencedExecutor, CPUThreadPoolExecutor)
constexpr detail::First first
#define EXPECT_GT(val1, val2)