26 #include "gmock/gmock.h" 27 #include "gtest/gtest.h" 38 namespace container_internal {
42 static auto GetSlots(
const C& c) -> decltype(c.slots_) {
49 using ::testing::DoubleNear;
50 using ::testing::ElementsAre;
54 using ::testing::Pair;
55 using ::testing::UnorderedElementsAre;
70 TEST(Util, GrowthAndCapacity) {
73 for (
size_t growth = 0; growth < 10000; ++growth) {
78 if (growth != 0 && capacity > 1) {
85 capacity = 2 * capacity + 1) {
86 SCOPED_TRACE(capacity);
88 EXPECT_THAT(growth, Lt(capacity));
101 std::vector<size_t> offsets(8);
102 std::generate_n(offsets.begin(), 8, gen);
103 EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64));
105 std::generate_n(offsets.begin(), 8, gen);
106 EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64));
125 uint64_t ctrl = 0x1716151413121110;
126 uint64_t
hash = 0x12;
127 constexpr uint64_t msbs = 0x8080808080808080ULL;
128 constexpr uint64_t lsbs = 0x0101010101010101ULL;
129 auto x = ctrl ^ (lsbs *
hash);
130 uint64_t mask = (x - lsbs) & ~x & msbs;
131 EXPECT_EQ(0x0000000080800000, mask);
164 7, 5, 3, 1, 1, 1, 1, 1};
165 EXPECT_THAT(
Group{group}.
Match(0), ElementsAre());
166 EXPECT_THAT(
Group{group}.
Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
167 EXPECT_THAT(
Group{group}.
Match(3), ElementsAre(3, 10));
168 EXPECT_THAT(
Group{group}.
Match(5), ElementsAre(5, 9));
169 EXPECT_THAT(
Group{group}.
Match(7), ElementsAre(7, 8));
172 EXPECT_THAT(
Group{group}.
Match(0), ElementsAre());
173 EXPECT_THAT(
Group{group}.
Match(1), ElementsAre(1, 5, 7));
174 EXPECT_THAT(
Group{group}.
Match(2), ElementsAre(2, 4));
176 FAIL() <<
"No test coverage for Group::kWidth==" <<
Group::kWidth;
183 7, 5, 3, 1, 1, 1, 1, 1};
189 FAIL() <<
"No test coverage for Group::kWidth==" <<
Group::kWidth;
196 7, 5, 3, 1, 1, 1, 1, 1};
202 FAIL() <<
"No test coverage for Group::kWidth==" <<
Group::kWidth;
206 TEST(Batch, DropDeletes) {
207 constexpr
size_t kCapacity = 63;
209 std::vector<ctrl_t> ctrl(kCapacity + 1 + kGroupWidth);
212 for (
size_t i = 0;
i != kCapacity; ++
i) {
213 ctrl[
i] = pattern[
i % pattern.size()];
214 if (
i < kGroupWidth - 1)
215 ctrl[
i + kCapacity + 1] = pattern[
i % pattern.size()];
219 for (
size_t i = 0;
i < kCapacity + 1 + kGroupWidth; ++
i) {
220 ctrl_t expected = pattern[
i % (kCapacity + 1) % pattern.size()];
222 if (expected == kDeleted) expected =
kEmpty;
224 EXPECT_EQ(ctrl[
i], expected)
225 << i <<
" " <<
int{pattern[i % pattern.size()]};
229 TEST(
Group, CountLeadingEmptyOrDeleted) {
231 const std::vector<ctrl_t> full_examples = {0, 1, 2, 3, 5, 9, 127,
kSentinel};
233 for (
ctrl_t empty : empty_examples) {
236 for (
ctrl_t full : full_examples) {
252 using slot_type = int64_t;
253 using key_type = int64_t;
254 using init_type = int64_t;
256 static void construct(
void*, int64_t* slot, int64_t
v) { *slot =
v; }
257 static void destroy(
void*, int64_t*) {}
258 static void transfer(
void*, int64_t* new_slot, int64_t* old_slot) {
259 *new_slot = *old_slot;
262 static int64_t&
element(slot_type* slot) {
return *slot; }
265 static auto apply(F&& f, int64_t x) -> decltype(std::forward<F>(f)(x, x)) {
266 return std::forward<F>(f)(x, x);
271 template <
class F,
class K,
class V,
272 class =
typename std::enable_if<
274 decltype(std::declval<F>()(
275 std::declval<const absl::string_view&>(), std::piecewise_construct,
276 std::declval<std::tuple<K>>(),
280 return std::forward<F>(f)(key, std::piecewise_construct,
std::move(p.first),
288 template <
class... Ts>
289 slot_type(ctor, Ts&&... ts) :
pair(std::forward<Ts>(ts)...) {}
291 std::pair<std::string, std::string>
pair;
294 using key_type = std::string;
295 using init_type = std::pair<std::string, std::string>;
297 template <
class allocator_type,
class... Args>
298 static void construct(allocator_type*
alloc, slot_type* slot, Args... args) {
300 *alloc, slot,
typename slot_type::ctor(), std::forward<Args>(args)...);
303 template <
class allocator_type>
304 static void destroy(allocator_type*
alloc, slot_type* slot) {
308 template <
class allocator_type>
309 static void transfer(allocator_type* alloc, slot_type* new_slot,
310 slot_type* old_slot) {
315 static std::pair<std::string, std::string>&
element(slot_type* slot) {
319 template <
class F,
class... Args>
320 static auto apply(F&& f, Args&&... args)
322 PairArgs(std::forward<Args>(args)...))) {
324 PairArgs(std::forward<Args>(args)...));
328 struct StringHash :
absl::Hash<absl::string_view> {
329 using is_transparent = void;
331 struct StringEq : std::equal_to<absl::string_view> {
332 using is_transparent = void;
336 : raw_hash_set<StringPolicy, StringHash, StringEq, std::allocator<int>> {
337 using Base =
typename StringTable::raw_hash_set;
343 : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
344 std::equal_to<int64_t>, std::allocator<int64_t>> {
345 using Base =
typename IntTable::raw_hash_set;
349 template <
typename T>
350 struct CustomAlloc : std::allocator<T> {
353 template <
typename U>
354 CustomAlloc(
const CustomAlloc<U>& other) {}
356 template<
class U>
struct rebind {
357 using other = CustomAlloc<U>;
361 struct CustomAllocIntTable
362 : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
363 std::equal_to<int64_t>, CustomAlloc<int64_t>> {
364 using Base =
typename CustomAllocIntTable::raw_hash_set;
370 size_t operator()(
const T&)
const {
375 struct BadTable : raw_hash_set<IntPolicy, BadFastHash, std::equal_to<int>,
376 std::allocator<int>> {
377 using Base =
typename BadTable::raw_hash_set;
382 TEST(Table, EmptyFunctorOptimization) {
383 static_assert(std::is_empty<std::equal_to<absl::string_view>>::
value,
"");
384 static_assert(std::is_empty<std::allocator<int>>::
value,
"");
394 struct StatelessHash {
397 struct StatefulHash : StatelessHash {
404 raw_hash_set<StringPolicy, StatelessHash,
405 std::equal_to<absl::string_view>, std::allocator<int>>));
408 sizeof(MockTable) +
sizeof(StatefulHash),
410 raw_hash_set<StringPolicy, StatefulHash,
411 std::equal_to<absl::string_view>, std::allocator<int>>));
416 EXPECT_EQ(0, t.size());
417 EXPECT_TRUE(t.empty());
423 asm volatile(
"" : :
"r,m"(
v) :
"memory");
427 TEST(Table, Prefetch) {
436 #if defined(NDEBUG) && defined(__GNUC__) && defined(__x86_64__) && \ 437 !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \ 438 !defined(THREAD_SANITIZER) && !defined(UNDEFINED_BEHAVIOR_SANITIZER) && \ 439 !defined(__EMSCRIPTEN__) 443 static constexpr
int size = 1 << 22;
444 for (
int i = 0;
i <
size; ++
i) t.insert(
i);
446 int64_t no_prefetch = 0, prefetch = 0;
447 for (
int iter = 0; iter < 10; ++iter) {
448 int64_t time = now();
449 for (
int i = 0;
i <
size; ++
i) {
450 DoNotOptimize(t.find(
i));
452 no_prefetch += now() - time;
455 for (
int i = 0;
i <
size; ++
i) {
457 DoNotOptimize(t.find(
i));
459 prefetch += now() - time;
463 EXPECT_GE(1.0 * no_prefetch / prefetch, 1.3);
467 TEST(Table, LookupEmpty) {
470 EXPECT_TRUE(it == t.end());
473 TEST(Table, Insert1) {
475 EXPECT_TRUE(t.find(0) == t.end());
476 auto res = t.emplace(0);
477 EXPECT_TRUE(res.second);
478 EXPECT_THAT(*res.first, 0);
479 EXPECT_EQ(1, t.size());
480 EXPECT_THAT(*t.find(0), 0);
483 TEST(Table, Insert2) {
485 EXPECT_TRUE(t.find(0) == t.end());
486 auto res = t.emplace(0);
487 EXPECT_TRUE(res.second);
488 EXPECT_THAT(*res.first, 0);
489 EXPECT_EQ(1, t.size());
490 EXPECT_TRUE(t.find(1) == t.end());
492 EXPECT_TRUE(res.second);
493 EXPECT_THAT(*res.first, 1);
494 EXPECT_EQ(2, t.size());
495 EXPECT_THAT(*t.find(0), 0);
496 EXPECT_THAT(*t.find(1), 1);
499 TEST(Table, InsertCollision) {
501 EXPECT_TRUE(t.find(1) == t.end());
502 auto res = t.emplace(1);
503 EXPECT_TRUE(res.second);
504 EXPECT_THAT(*res.first, 1);
505 EXPECT_EQ(1, t.size());
507 EXPECT_TRUE(t.find(2) == t.end());
509 EXPECT_THAT(*res.first, 2);
510 EXPECT_TRUE(res.second);
511 EXPECT_EQ(2, t.size());
513 EXPECT_THAT(*t.find(1), 1);
514 EXPECT_THAT(*t.find(2), 2);
519 TEST(Table, InsertCollisionAndFindAfterDelete) {
524 for (
size_t i = 0;
i < kNumInserts; ++
i) {
525 auto res = t.emplace(
i);
526 EXPECT_TRUE(res.second);
527 EXPECT_THAT(*res.first,
i);
528 EXPECT_EQ(
i + 1, t.size());
533 for (
size_t i = 0;
i < kNumInserts; ++
i) {
534 EXPECT_EQ(1, t.erase(
i)) <<
i;
535 for (
size_t j =
i + 1; j < kNumInserts; ++j) {
536 EXPECT_THAT(*t.find(j), j);
537 auto res = t.emplace(j);
538 EXPECT_FALSE(res.second) <<
i <<
" " << j;
539 EXPECT_THAT(*res.first, j);
540 EXPECT_EQ(kNumInserts -
i - 1, t.size());
543 EXPECT_TRUE(t.empty());
546 TEST(Table, LazyEmplace) {
549 auto it = t.lazy_emplace(
"abc", [&](
const StringTable::constructor& f) {
554 EXPECT_THAT(*it, Pair(
"abc",
"ABC"));
556 it = t.lazy_emplace(
"abc", [&](
const StringTable::constructor& f) {
560 EXPECT_FALSE(called);
561 EXPECT_THAT(*it, Pair(
"abc",
"ABC"));
564 TEST(Table, ContainsEmpty) {
567 EXPECT_FALSE(t.contains(0));
570 TEST(Table, Contains1) {
573 EXPECT_TRUE(t.insert(0).second);
574 EXPECT_TRUE(t.contains(0));
575 EXPECT_FALSE(t.contains(1));
577 EXPECT_EQ(1, t.erase(0));
578 EXPECT_FALSE(t.contains(0));
581 TEST(Table, Contains2) {
584 EXPECT_TRUE(t.insert(0).second);
585 EXPECT_TRUE(t.contains(0));
586 EXPECT_FALSE(t.contains(1));
589 EXPECT_FALSE(t.contains(0));
592 int decompose_constructed;
593 struct DecomposeType {
594 DecomposeType(
int i) :
i(i) {
595 ++decompose_constructed;
598 explicit DecomposeType(
const char* d) : DecomposeType(*d) {}
603 struct DecomposeHash {
604 using is_transparent = void;
605 size_t operator()(DecomposeType
a)
const {
return a.i; }
606 size_t operator()(
int a)
const {
return a; }
607 size_t operator()(
const char* a)
const {
return *
a; }
611 using is_transparent = void;
612 bool operator()(DecomposeType
a, DecomposeType
b)
const {
return a.i == b.i; }
613 bool operator()(DecomposeType a,
int b)
const {
return a.i ==
b; }
614 bool operator()(DecomposeType a,
const char* b)
const {
return a.i == *
b; }
617 struct DecomposePolicy {
618 using slot_type = DecomposeType;
619 using key_type = DecomposeType;
620 using init_type = DecomposeType;
622 template <
typename T>
623 static void construct(
void*, DecomposeType* slot, T&& v) {
624 *slot = DecomposeType(std::forward<T>(v));
626 static void destroy(
void*, DecomposeType*) {}
627 static DecomposeType&
element(slot_type* slot) {
return *slot; }
629 template <
class F,
class T>
630 static auto apply(F&& f,
const T& x) -> decltype(std::forward<F>(f)(x, x)) {
631 return std::forward<F>(f)(x, x);
635 template <
typename Hash,
typename Eq>
636 void TestDecompose(
bool construct_three) {
637 DecomposeType elem{0};
639 const char* three_p =
"3";
640 const auto& three = three_p;
642 raw_hash_set<DecomposePolicy, Hash, Eq, std::allocator<int>> set1;
644 decompose_constructed = 0;
645 int expected_constructed = 0;
646 EXPECT_EQ(expected_constructed, decompose_constructed);
648 EXPECT_EQ(expected_constructed, decompose_constructed);
650 EXPECT_EQ(++expected_constructed, decompose_constructed);
652 EXPECT_EQ(++expected_constructed, decompose_constructed);
653 EXPECT_EQ(expected_constructed, decompose_constructed);
657 EXPECT_EQ(expected_constructed, decompose_constructed);
662 EXPECT_EQ(expected_constructed, decompose_constructed);
666 set1.insert(set1.begin(), 1);
667 EXPECT_EQ(expected_constructed, decompose_constructed);
671 set1.insert(set1.begin(), one);
672 EXPECT_EQ(expected_constructed, decompose_constructed);
677 EXPECT_EQ(expected_constructed, decompose_constructed);
679 expected_constructed += construct_three;
680 EXPECT_EQ(expected_constructed, decompose_constructed);
682 EXPECT_EQ(expected_constructed, decompose_constructed);
684 expected_constructed += construct_three;
685 EXPECT_EQ(expected_constructed, decompose_constructed);
689 set1.emplace_hint(set1.begin(), 1);
690 EXPECT_EQ(expected_constructed, decompose_constructed);
691 set1.emplace_hint(set1.begin(),
"3");
692 expected_constructed += construct_three;
693 EXPECT_EQ(expected_constructed, decompose_constructed);
694 set1.emplace_hint(set1.begin(), one);
695 EXPECT_EQ(expected_constructed, decompose_constructed);
696 set1.emplace_hint(set1.begin(), three);
697 expected_constructed += construct_three;
698 EXPECT_EQ(expected_constructed, decompose_constructed);
702 TEST(Table, Decompose) {
703 TestDecompose<DecomposeHash, DecomposeEq>(
false);
705 struct TransparentHashIntOverload {
706 size_t operator()(DecomposeType
a)
const {
return a.i; }
707 size_t operator()(
int a)
const {
return a; }
709 struct TransparentEqIntOverload {
710 bool operator()(DecomposeType
a, DecomposeType
b)
const {
713 bool operator()(DecomposeType a,
int b)
const {
return a.i ==
b; }
715 TestDecompose<TransparentHashIntOverload, DecomposeEq>(
true);
716 TestDecompose<TransparentHashIntOverload, TransparentEqIntOverload>(
true);
717 TestDecompose<DecomposeHash, TransparentEqIntOverload>(
true);
722 size_t MaxDensitySize(
size_t n) {
725 for (
size_t i = 0;
i !=
n; ++
i) t.emplace(
i);
726 const size_t c = t.bucket_count();
727 while (c == t.bucket_count()) t.emplace(n++);
731 struct Modulo1000Hash {
732 size_t operator()(
int x)
const {
return x % 1000; }
735 struct Modulo1000HashTable
736 :
public raw_hash_set<IntPolicy, Modulo1000Hash, std::equal_to<int>,
737 std::allocator<int>> {};
740 TEST(Table, RehashWithNoResize) {
741 Modulo1000HashTable t;
745 const size_t kMinFullGroups = 7;
746 std::vector<int>
keys;
747 for (
size_t i = 0;
i < MaxDensitySize(
Group::kWidth * kMinFullGroups); ++
i) {
752 const size_t capacity = t.capacity();
758 for (
size_t i = erase_begin;
i < erase_end; ++
i) {
759 EXPECT_EQ(1, t.erase(keys[
i])) << i;
761 keys.erase(keys.begin() + erase_begin, keys.begin() + erase_end);
763 auto last_key = keys.back();
767 ASSERT_GT(last_key_num_probes, kMinFullGroups);
773 ASSERT_EQ(capacity, t.capacity());
775 ASSERT_TRUE(t.find(x) != t.end()) << x;
776 for (
const auto& k : keys) {
777 ASSERT_TRUE(t.find(k) != t.end()) << k;
784 TEST(Table, InsertEraseStressTest) {
786 const size_t kMinElementCount = 250;
787 std::deque<int>
keys;
789 for (; i < MaxDensitySize(kMinElementCount); ++
i) {
793 const size_t kNumIterations = 1000000;
794 for (; i < kNumIterations; ++
i) {
795 ASSERT_EQ(1, t.erase(keys.front()));
802 TEST(Table, InsertOverloads) {
806 t.insert({
"ABC", {}});
807 t.insert({
"DEF",
"!!!"});
809 EXPECT_THAT(t, UnorderedElementsAre(Pair(
"",
""), Pair(
"ABC",
""),
810 Pair(
"DEF",
"!!!")));
813 TEST(Table, LargeTable) {
815 for (int64_t
i = 0;
i != 100000; ++
i) t.emplace(
i << 40);
816 for (int64_t
i = 0;
i != 100000; ++
i) ASSERT_EQ(
i << 40, *t.find(
i << 40));
820 TEST(Table, EnsureNonQuadraticAsInRust) {
821 static const size_t kLargeSize = 1 << 15;
824 for (
size_t i = 0;
i != kLargeSize; ++
i) {
830 for (
const auto& entry : t) t2.insert(entry);
833 TEST(Table, ClearBug) {
836 constexpr
size_t max_size = capacity / 2 + 1;
837 for (
size_t i = 0;
i < max_size; ++
i) {
840 ASSERT_EQ(capacity, t.capacity());
841 intptr_t original =
reinterpret_cast<intptr_t
>(&*t.find(2));
843 ASSERT_EQ(capacity, t.capacity());
844 for (
size_t i = 0;
i < max_size; ++
i) {
847 ASSERT_EQ(capacity, t.capacity());
848 intptr_t second =
reinterpret_cast<intptr_t
>(&*t.find(2));
852 EXPECT_LT(std::abs(original - second),
858 EXPECT_TRUE(t.find(0) == t.end());
859 auto res = t.emplace(0);
860 EXPECT_TRUE(res.second);
861 EXPECT_EQ(1, t.size());
863 EXPECT_EQ(0, t.size());
864 EXPECT_TRUE(t.find(0) == t.end());
867 TEST(Table, EraseMaintainsValidIterator) {
869 const int kNumElements = 100;
870 for (
int i = 0;
i < kNumElements;
i ++) {
871 EXPECT_TRUE(t.emplace(
i).second);
873 EXPECT_EQ(t.size(), kNumElements);
875 int num_erase_calls = 0;
877 while (it != t.end()) {
882 EXPECT_TRUE(t.empty());
883 EXPECT_EQ(num_erase_calls, kNumElements);
892 std::vector<int64_t> CollectBadMergeKeys(
size_t N) {
895 auto topk_range = [](
size_t b,
size_t e, IntTable* t) -> std::vector<int64_t> {
896 for (
size_t i = b;
i != e; ++
i) {
899 std::vector<int64_t> res;
900 res.reserve(kGroupSize);
901 auto it = t->begin();
902 for (
size_t i = b;
i != e &&
i != b + kGroupSize; ++
i, ++it) {
908 std::vector<int64_t> bad_keys;
913 for (
size_t b = 0; bad_keys.size() < N; b += N) {
914 auto keys = topk_range(b, b + N, &t);
915 bad_keys.insert(bad_keys.end(),
keys.begin(),
keys.end());
916 t.erase(t.begin(), t.end());
917 EXPECT_TRUE(t.empty());
928 friend ProbeStats
operator+(
const ProbeStats&
a,
const ProbeStats&
b) {
930 res.all_probes_histogram.resize(std::max(res.all_probes_histogram.size(),
931 b.all_probes_histogram.size()));
932 std::transform(b.all_probes_histogram.begin(), b.all_probes_histogram.end(),
933 res.all_probes_histogram.begin(),
934 res.all_probes_histogram.begin(), std::plus<size_t>());
935 res.single_table_ratios.insert(res.single_table_ratios.end(),
936 b.single_table_ratios.begin(),
937 b.single_table_ratios.end());
942 double AvgRatio()
const {
943 return std::accumulate(single_table_ratios.begin(),
944 single_table_ratios.end(), 0.0) /
945 single_table_ratios.size();
949 double MaxRatio()
const {
950 return *std::max_element(single_table_ratios.begin(),
951 single_table_ratios.end());
955 double PercentileRatio(
double Percentile = 0.95)
const {
957 auto mid = r.begin() +
static_cast<size_t>(r.size() * Percentile);
958 if (mid != r.end()) {
959 std::nth_element(r.begin(), mid, r.end());
967 size_t MaxProbe()
const {
return all_probes_histogram.size(); }
970 std::vector<double> ProbeNormalizedHistogram()
const {
971 double total_elements = std::accumulate(all_probes_histogram.begin(),
972 all_probes_histogram.end(), 0ull);
973 std::vector<double> res;
974 for (
size_t p : all_probes_histogram) {
975 res.push_back(p / total_elements);
980 size_t PercentileProbe(
double Percentile = 0.99)
const {
982 for (
double p : ProbeNormalizedHistogram()) {
983 if (Percentile > p) {
993 friend std::ostream&
operator<<(std::ostream&
out,
const ProbeStats& s) {
994 out <<
"{AvgRatio:" << s.AvgRatio() <<
", MaxRatio:" << s.MaxRatio()
995 <<
", PercentileRatio:" << s.PercentileRatio()
996 <<
", MaxProbe:" << s.MaxProbe() <<
", Probes=[";
997 for (
double p : s.ProbeNormalizedHistogram()) {
1006 struct ExpectedStats {
1012 friend std::ostream&
operator<<(std::ostream&
out,
const ExpectedStats& s) {
1013 out <<
"{AvgRatio:" << s.avg_ratio <<
", MaxRatio:" << s.max_ratio
1014 <<
", PercentileRatios: [";
1015 for (
auto el : s.pecentile_ratios) {
1016 out << el.first <<
":" << el.second <<
", ";
1018 out <<
"], PercentileProbes: [";
1019 for (
auto el : s.pecentile_probes) {
1020 out << el.first <<
":" << el.second <<
", ";
1028 void VerifyStats(
size_t size,
const ExpectedStats& exp,
1029 const ProbeStats& stats) {
1030 EXPECT_LT(stats.AvgRatio(), exp.avg_ratio) << size <<
" " << stats;
1031 EXPECT_LT(stats.MaxRatio(), exp.max_ratio) << size <<
" " << stats;
1032 for (
auto pr : exp.pecentile_ratios) {
1033 EXPECT_LE(stats.PercentileRatio(pr.first), pr.second)
1034 << size <<
" " << pr.first <<
" " << stats;
1037 for (
auto pr : exp.pecentile_probes) {
1038 EXPECT_LE(stats.PercentileProbe(pr.first), pr.second)
1039 << size <<
" " << pr.first <<
" " << stats;
1043 using ProbeStatsPerSize = std::map<size_t, ProbeStats>;
1049 ProbeStats CollectProbeStatsOnKeysXoredWithSeed(
const std::vector<int64_t>&
keys,
1051 const size_t reserve_size = keys.size() * 2;
1055 int64_t seed = 0x71b1a19b907d6e33;
1056 while (num_iters--) {
1057 seed =
static_cast<int64_t
>(
static_cast<uint64_t
>(seed) * 17 + 13);
1059 t1.reserve(reserve_size);
1060 for (
const auto& key : keys) {
1061 t1.emplace(key ^ seed);
1065 stats.all_probes_histogram.resize(
1066 std::max(stats.all_probes_histogram.size(), probe_histogram.size()));
1067 std::transform(probe_histogram.begin(), probe_histogram.end(),
1068 stats.all_probes_histogram.begin(),
1069 stats.all_probes_histogram.begin(), std::plus<size_t>());
1071 size_t total_probe_seq_length = 0;
1072 for (
size_t i = 0;
i < probe_histogram.size(); ++
i) {
1073 total_probe_seq_length +=
i * probe_histogram[
i];
1075 stats.single_table_ratios.push_back(total_probe_seq_length * 1.0 /
1077 t1.erase(t1.begin(), t1.end());
1082 ExpectedStats XorSeedExpectedStats() {
1083 constexpr
bool kRandomizesInserts =
1094 if (kRandomizesInserts) {
1098 {{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}};
1103 {{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}};
1106 if (kRandomizesInserts) {
1110 {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}};
1115 {{0.95, 0}, {0.99, 1}, {0.999, 4}, {0.9999, 10}}};
1122 TEST(Table, DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength) {
1123 ProbeStatsPerSize stats;
1125 for (
size_t size : sizes) {
1127 CollectProbeStatsOnKeysXoredWithSeed(CollectBadMergeKeys(size), 200);
1129 auto expected = XorSeedExpectedStats();
1130 for (
size_t size : sizes) {
1131 auto& stat = stats[
size];
1132 VerifyStats(size, expected, stat);
1140 ProbeStats CollectProbeStatsOnLinearlyTransformedKeys(
1141 const std::vector<int64_t>& keys,
size_t num_iters) {
1144 std::random_device rd;
1145 std::mt19937 rng(rd());
1146 auto linear_transform = [](
size_t x,
size_t y) {
return x * 17 + y * 13; };
1147 std::uniform_int_distribution<size_t> dist(0, keys.size()-1);
1148 while (num_iters--) {
1150 size_t num_keys = keys.size() / 10;
1151 size_t start = dist(rng);
1152 for (
size_t i = 0;
i != num_keys; ++
i) {
1153 for (
size_t j = 0; j != 10; ++j) {
1154 t1.emplace(linear_transform(keys[(
i + start) % keys.size()], j));
1159 stats.all_probes_histogram.resize(
1160 std::max(stats.all_probes_histogram.size(), probe_histogram.size()));
1161 std::transform(probe_histogram.begin(), probe_histogram.end(),
1162 stats.all_probes_histogram.begin(),
1163 stats.all_probes_histogram.begin(), std::plus<size_t>());
1165 size_t total_probe_seq_length = 0;
1166 for (
size_t i = 0;
i < probe_histogram.size(); ++
i) {
1167 total_probe_seq_length +=
i * probe_histogram[
i];
1169 stats.single_table_ratios.push_back(total_probe_seq_length * 1.0 /
1171 t1.erase(t1.begin(), t1.end());
1176 ExpectedStats LinearTransformExpectedStats() {
1177 constexpr
bool kRandomizesInserts =
1188 if (kRandomizesInserts) {
1192 {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}};
1197 {{0.95, 0}, {0.99, 3}, {0.999, 15}, {0.9999, 25}}};
1200 if (kRandomizesInserts) {
1204 {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}};
1209 {{0.95, 0}, {0.99, 1}, {0.999, 6}, {0.9999, 10}}};
1216 TEST(Table, DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength) {
1217 ProbeStatsPerSize stats;
1219 for (
size_t size : sizes) {
1220 stats[
size] = CollectProbeStatsOnLinearlyTransformedKeys(
1221 CollectBadMergeKeys(size), 300);
1223 auto expected = LinearTransformExpectedStats();
1224 for (
size_t size : sizes) {
1225 auto& stat = stats[
size];
1226 VerifyStats(size, expected, stat);
1230 TEST(Table, EraseCollision) {
1237 EXPECT_THAT(*t.find(1), 1);
1238 EXPECT_THAT(*t.find(2), 2);
1239 EXPECT_THAT(*t.find(3), 3);
1240 EXPECT_EQ(3, t.size());
1244 EXPECT_THAT(*t.find(1), 1);
1245 EXPECT_TRUE(t.find(2) == t.end());
1246 EXPECT_THAT(*t.find(3), 3);
1247 EXPECT_EQ(2, t.size());
1251 EXPECT_TRUE(t.find(1) == t.end());
1252 EXPECT_TRUE(t.find(2) == t.end());
1253 EXPECT_THAT(*t.find(3), 3);
1254 EXPECT_EQ(1, t.size());
1258 EXPECT_TRUE(t.find(1) == t.end());
1259 EXPECT_TRUE(t.find(2) == t.end());
1260 EXPECT_TRUE(t.find(3) == t.end());
1261 EXPECT_EQ(0, t.size());
1264 TEST(Table, EraseInsertProbing) {
1282 EXPECT_EQ(5, t.size());
1283 EXPECT_THAT(t, UnorderedElementsAre(1, 10, 3, 11, 12));
1286 TEST(Table, Clear) {
1288 EXPECT_TRUE(t.find(0) == t.end());
1290 EXPECT_TRUE(t.find(0) == t.end());
1291 auto res = t.emplace(0);
1292 EXPECT_TRUE(res.second);
1293 EXPECT_EQ(1, t.size());
1295 EXPECT_EQ(0, t.size());
1296 EXPECT_TRUE(t.find(0) == t.end());
1301 EXPECT_TRUE(t.find(0) == t.end());
1302 auto res = t.emplace(0);
1303 EXPECT_TRUE(res.second);
1304 EXPECT_EQ(1, t.size());
1307 EXPECT_EQ(0, t.size());
1308 EXPECT_EQ(1, u.size());
1309 EXPECT_TRUE(t.find(0) == t.end());
1310 EXPECT_THAT(*u.find(0), 0);
1313 TEST(Table, Rehash) {
1315 EXPECT_TRUE(t.find(0) == t.end());
1318 EXPECT_EQ(2, t.size());
1320 EXPECT_EQ(2, t.size());
1321 EXPECT_THAT(*t.find(0), 0);
1322 EXPECT_THAT(*t.find(1), 1);
1325 TEST(Table, RehashDoesNotRehashWhenNotNecessary) {
1329 auto* p = &*t.find(0);
1331 EXPECT_EQ(p, &*t.find(0));
1334 TEST(Table, RehashZeroDoesNotAllocateOnEmptyTable) {
1337 EXPECT_EQ(0, t.bucket_count());
1340 TEST(Table, RehashZeroDeallocatesEmptyTable) {
1344 EXPECT_NE(0, t.bucket_count());
1346 EXPECT_EQ(0, t.bucket_count());
1349 TEST(Table, RehashZeroForcesRehash) {
1353 auto* p = &*t.find(0);
1355 EXPECT_NE(p, &*t.find(0));
1358 TEST(Table, ConstructFromInitList) {
1359 using P = std::pair<std::string, std::string>;
1361 operator P()
const {
return {}; }
1363 StringTable t = {P(), Q(), {}, {{}, {}}};
1369 EXPECT_EQ(1, t.size());
1372 EXPECT_EQ(1, u.size());
1373 EXPECT_THAT(*u.find(0), 0);
1377 EXPECT_EQ(1, u.size());
1378 EXPECT_THAT(*u.find(0), 0);
1382 EXPECT_EQ(1, u.size());
1383 EXPECT_THAT(*u.find(0), 0);
1387 TEST(Table, CopyConstructWithAlloc) {
1389 t.emplace(
"a",
"b");
1390 EXPECT_EQ(1, t.size());
1391 StringTable u(t, Alloc<std::pair<std::string, std::string>>());
1392 EXPECT_EQ(1, u.size());
1393 EXPECT_THAT(*u.find(
"a"), Pair(
"a",
"b"));
1396 struct ExplicitAllocIntTable
1397 : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
1398 std::equal_to<int64_t>, Alloc<int64_t>> {
1399 ExplicitAllocIntTable() {}
1402 TEST(Table, AllocWithExplicitCtor) {
1403 ExplicitAllocIntTable t;
1404 EXPECT_EQ(0, t.size());
1407 TEST(Table, MoveConstruct) {
1410 t.emplace(
"a",
"b");
1411 EXPECT_EQ(1, t.size());
1414 EXPECT_EQ(1, u.size());
1415 EXPECT_THAT(*u.find(
"a"), Pair(
"a",
"b"));
1419 t.emplace(
"a",
"b");
1420 EXPECT_EQ(1, t.size());
1423 EXPECT_EQ(1, u.size());
1424 EXPECT_THAT(*u.find(
"a"), Pair(
"a",
"b"));
1428 t.emplace(
"a",
"b");
1429 EXPECT_EQ(1, t.size());
1432 EXPECT_EQ(1, u.size());
1433 EXPECT_THAT(*u.find(
"a"), Pair(
"a",
"b"));
1437 TEST(Table, MoveConstructWithAlloc) {
1439 t.emplace(
"a",
"b");
1440 EXPECT_EQ(1, t.size());
1441 StringTable u(
std::move(t), Alloc<std::pair<std::string, std::string>>());
1442 EXPECT_EQ(1, u.size());
1443 EXPECT_THAT(*u.find(
"a"), Pair(
"a",
"b"));
1446 TEST(Table, CopyAssign) {
1448 t.emplace(
"a",
"b");
1449 EXPECT_EQ(1, t.size());
1452 EXPECT_EQ(1, u.size());
1453 EXPECT_THAT(*u.find(
"a"), Pair(
"a",
"b"));
1456 TEST(Table, CopySelfAssign) {
1458 t.emplace(
"a",
"b");
1459 EXPECT_EQ(1, t.size());
1461 EXPECT_EQ(1, t.size());
1462 EXPECT_THAT(*t.find(
"a"), Pair(
"a",
"b"));
1465 TEST(Table, MoveAssign) {
1467 t.emplace(
"a",
"b");
1468 EXPECT_EQ(1, t.size());
1471 EXPECT_EQ(1, u.size());
1472 EXPECT_THAT(*u.find(
"a"), Pair(
"a",
"b"));
1475 TEST(Table, Equality) {
1477 std::vector<std::pair<std::string, std::string>> v = {{
"a",
"b"},
1484 TEST(Table, Equality2) {
1486 std::vector<std::pair<std::string, std::string>> v1 = {{
"a",
"b"},
1490 std::vector<std::pair<std::string, std::string>> v2 = {{
"a",
"a"},
1496 TEST(Table, Equality3) {
1498 std::vector<std::pair<std::string, std::string>> v1 = {{
"b",
"b"},
1502 std::vector<std::pair<std::string, std::string>> v2 = {{
"a",
"a"},
1508 TEST(Table, NumDeletedRegression) {
1517 TEST(Table, FindFullDeletedRegression) {
1519 for (
int i = 0;
i < 1000; ++
i) {
1523 EXPECT_EQ(0, t.size());
1526 TEST(Table, ReplacingDeletedSlotDoesNotRehash) {
1532 size_t c = t.bucket_count();
1533 for (n = 1; c == t.bucket_count(); ++
n) t.emplace(n);
1538 const size_t c = t.bucket_count();
1539 for (
size_t i = 0;
i !=
n; ++
i) t.emplace(
i);
1540 EXPECT_EQ(c, t.bucket_count()) <<
"rehashing threshold = " << n;
1543 EXPECT_EQ(c, t.bucket_count()) <<
"rehashing threshold = " << n;
1546 TEST(Table, NoThrowMoveConstruct) {
1549 ASSERT_TRUE(std::is_nothrow_copy_constructible<
1550 std::equal_to<absl::string_view>>::
value);
1551 ASSERT_TRUE(std::is_nothrow_copy_constructible<std::allocator<int>>::
value);
1555 TEST(Table, NoThrowMoveAssign) {
1559 std::is_nothrow_move_assignable<std::equal_to<absl::string_view>>::
value);
1560 ASSERT_TRUE(std::is_nothrow_move_assignable<std::allocator<int>>::
value);
1566 TEST(Table, NoThrowSwappable) {
1570 std::equal_to<absl::string_view>>());
1572 EXPECT_TRUE(container_internal::IsNoThrowSwappable<StringTable>());
1575 TEST(Table, HeterogeneousLookup) {
1577 size_t operator()(int64_t
i)
const {
return i; }
1578 size_t operator()(
double i)
const {
1584 bool operator()(int64_t
a, int64_t
b)
const {
return a ==
b; }
1585 bool operator()(
double a, int64_t b)
const {
1589 bool operator()(int64_t a,
double b)
const {
1593 bool operator()(
double a,
double b)
const {
1600 using is_transparent = void;
1601 size_t operator()(int64_t
i)
const {
return i; }
1602 size_t operator()(
double i)
const {
return i; }
1605 using is_transparent = void;
1606 bool operator()(int64_t
a, int64_t
b)
const {
return a ==
b; }
1607 bool operator()(
double a, int64_t b)
const {
return a ==
b; }
1608 bool operator()(int64_t a,
double b)
const {
return a ==
b; }
1609 bool operator()(
double a,
double b)
const {
return a ==
b; }
1612 raw_hash_set<IntPolicy, Hash, Eq, Alloc<int64_t>> s{0, 1, 2};
1614 EXPECT_EQ(1, *s.find(
double{1.1}));
1616 raw_hash_set<IntPolicy, THash, TEq, Alloc<int64_t>> ts{0, 1, 2};
1618 EXPECT_TRUE(ts.find(1.1) == ts.end());
1621 template <
class Table>
1622 using CallFind = decltype(std::declval<Table&>().find(17));
1624 template <
class Table>
1625 using CallErase = decltype(std::declval<Table&>().erase(17));
1627 template <
class Table>
1628 using CallExtract = decltype(std::declval<Table&>().extract(17));
1630 template <
class Table>
1631 using CallPrefetch = decltype(std::declval<Table&>().prefetch(17));
1633 template <
class Table>
1634 using CallCount = decltype(std::declval<Table&>().count(17));
1636 template <
template <
typename>
class C,
class Table,
class =
void>
1637 struct VerifyResultOf : std::false_type {};
1639 template <
template <
typename>
class C,
class Table>
1640 struct VerifyResultOf<C, Table, absl::
void_t<C<Table>>> : std::true_type {};
1642 TEST(Table, HeterogeneousLookupOverloads) {
1643 using NonTransparentTable =
1644 raw_hash_set<StringPolicy, absl::Hash<absl::string_view>,
1645 std::equal_to<absl::string_view>, std::allocator<int>>;
1647 EXPECT_FALSE((VerifyResultOf<CallFind, NonTransparentTable>()));
1648 EXPECT_FALSE((VerifyResultOf<CallErase, NonTransparentTable>()));
1649 EXPECT_FALSE((VerifyResultOf<CallExtract, NonTransparentTable>()));
1650 EXPECT_FALSE((VerifyResultOf<CallPrefetch, NonTransparentTable>()));
1651 EXPECT_FALSE((VerifyResultOf<CallCount, NonTransparentTable>()));
1653 using TransparentTable = raw_hash_set<
1657 std::allocator<int>>;
1659 EXPECT_TRUE((VerifyResultOf<CallFind, TransparentTable>()));
1660 EXPECT_TRUE((VerifyResultOf<CallErase, TransparentTable>()));
1661 EXPECT_TRUE((VerifyResultOf<CallExtract, TransparentTable>()));
1662 EXPECT_TRUE((VerifyResultOf<CallPrefetch, TransparentTable>()));
1663 EXPECT_TRUE((VerifyResultOf<CallCount, TransparentTable>()));
1667 TEST(Iterator, IsDefaultConstructible) {
1668 StringTable::iterator
i;
1669 EXPECT_TRUE(i == StringTable::iterator());
1672 TEST(ConstIterator, IsDefaultConstructible) {
1673 StringTable::const_iterator
i;
1674 EXPECT_TRUE(i == StringTable::const_iterator());
1677 TEST(Iterator, ConvertsToConstIterator) {
1678 StringTable::iterator
i;
1679 EXPECT_TRUE(i == StringTable::const_iterator());
1682 TEST(Iterator, Iterates) {
1684 for (
size_t i = 3;
i != 6; ++
i) EXPECT_TRUE(t.emplace(
i).second);
1685 EXPECT_THAT(t, UnorderedElementsAre(3, 4, 5));
1688 TEST(Table, Merge) {
1690 t1.emplace(
"0",
"-0");
1691 t1.emplace(
"1",
"-1");
1692 t2.emplace(
"0",
"~0");
1693 t2.emplace(
"2",
"~2");
1695 EXPECT_THAT(t1, UnorderedElementsAre(Pair(
"0",
"-0"), Pair(
"1",
"-1")));
1696 EXPECT_THAT(t2, UnorderedElementsAre(Pair(
"0",
"~0"), Pair(
"2",
"~2")));
1699 EXPECT_THAT(t1, UnorderedElementsAre(Pair(
"0",
"-0"), Pair(
"1",
"-1"),
1701 EXPECT_THAT(t2, UnorderedElementsAre(Pair(
"0",
"~0")));
1705 using node_type = StringTable::node_type;
1708 EXPECT_TRUE(n.empty());
1710 EXPECT_TRUE((std::is_same<node_type::allocator_type,
1711 StringTable::allocator_type>::
value));
1715 constexpr
char k0[] =
"Very long std::string zero.";
1716 constexpr
char k1[] =
"Very long std::string one.";
1717 constexpr
char k2[] =
"Very long std::string two.";
1718 StringTable t = {{
k0,
""}, {
k1,
""}, {
k2,
""}};
1720 UnorderedElementsAre(Pair(k0,
""), Pair(k1,
""), Pair(k2,
"")));
1722 auto node = t.extract(k0);
1723 EXPECT_THAT(t, UnorderedElementsAre(Pair(k1,
""), Pair(k2,
"")));
1725 EXPECT_FALSE(node.empty());
1728 StringTable::insert_return_type res = t2.insert(
std::move(node));
1729 EXPECT_TRUE(res.inserted);
1730 EXPECT_THAT(*res.position, Pair(k0,
""));
1731 EXPECT_FALSE(res.node);
1732 EXPECT_THAT(t2, UnorderedElementsAre(Pair(k0,
"")));
1735 EXPECT_THAT(t, UnorderedElementsAre(Pair(k1,
""), Pair(k2,
"")));
1736 node = t.extract(
"Not there!");
1737 EXPECT_THAT(t, UnorderedElementsAre(Pair(k1,
""), Pair(k2,
"")));
1742 EXPECT_FALSE(res.inserted);
1743 EXPECT_EQ(res.position, t2.end());
1744 EXPECT_FALSE(res.node);
1745 EXPECT_THAT(t2, UnorderedElementsAre(Pair(k0,
"")));
1748 node = t.extract(k0);
1752 EXPECT_FALSE(res.inserted);
1753 EXPECT_THAT(*res.position, Pair(k0,
""));
1754 EXPECT_TRUE(res.node);
1758 IntTable MakeSimpleTable(
size_t size) {
1760 while (t.size() <
size) t.insert(t.size());
1764 std::vector<int> OrderOfIteration(
const IntTable& t) {
1765 return {t.begin(), t.end()};
1774 TEST(Table, IterationOrderChangesByInstance) {
1775 for (
size_t size : {2, 6, 12, 20}) {
1776 const auto reference_table = MakeSimpleTable(size);
1777 const auto reference = OrderOfIteration(reference_table);
1779 std::vector<IntTable> tables;
1780 bool found_difference =
false;
1781 for (
int i = 0; !found_difference &&
i < 5000; ++
i) {
1782 tables.push_back(MakeSimpleTable(size));
1783 found_difference = OrderOfIteration(tables.back()) != reference;
1785 if (!found_difference) {
1787 <<
"Iteration order remained the same across many attempts with size " 1793 TEST(Table, IterationOrderChangesOnRehash) {
1794 std::vector<IntTable> garbage;
1795 for (
int i = 0;
i < 5000; ++
i) {
1796 auto t = MakeSimpleTable(20);
1797 const auto reference = OrderOfIteration(t);
1800 auto trial = OrderOfIteration(t);
1801 if (trial != reference) {
1807 FAIL() <<
"Iteration order remained the same across many attempts.";
1812 TEST(Table, UnstablePointers) {
1815 const auto addr = [&](
int i) {
1816 return reinterpret_cast<uintptr_t
>(&*table.find(
i));
1820 const uintptr_t old_ptr = addr(0);
1825 EXPECT_NE(old_ptr, addr(0));
1829 TEST(TableDeathTest, EraseOfEndAsserts) {
1831 bool assert_enabled =
false;
1833 assert_enabled =
true;
1836 if (!assert_enabled)
return;
1840 constexpr
char kDeathMsg[] =
"it != end";
1841 EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg);
1850 size_t start_size = 0;
1851 start_size += sampler.Iterate([&](
const HashtablezInfo&) { ++start_size; });
1853 std::vector<IntTable> tables;
1854 for (
int i = 0;
i < 1000000; ++
i) {
1855 tables.emplace_back();
1856 tables.back().insert(1);
1858 size_t end_size = 0;
1859 end_size += sampler.Iterate([&](
const HashtablezInfo&) { ++end_size; });
1861 EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
1865 TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) {
1871 size_t start_size = 0;
1872 start_size += sampler.Iterate([&](
const HashtablezInfo&) { ++start_size; });
1874 std::vector<CustomAllocIntTable> tables;
1875 for (
int i = 0;
i < 1000000; ++
i) {
1876 tables.emplace_back();
1877 tables.back().insert(1);
1879 size_t end_size = 0;
1880 end_size += sampler.Iterate([&](
const HashtablezInfo&) { ++end_size; });
1882 EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
1886 #ifdef ADDRESS_SANITIZER 1887 TEST(Sanitizer, PoisoningUnused) {
1891 int64_t& v1 = *t.insert(0).first;
1894 ASSERT_GT(t.capacity(), 1);
1897 for (
size_t i = 0;
i < t.capacity(); ++
i) {
1898 EXPECT_EQ(slots +
i != &v1, __asan_address_is_poisoned(slots +
i));
1902 TEST(Sanitizer, PoisoningOnErase) {
1904 int64_t& v = *t.insert(0).first;
1906 EXPECT_FALSE(__asan_address_is_poisoned(&v));
1908 EXPECT_TRUE(__asan_address_is_poisoned(&v));
1910 #endif // ADDRESS_SANITIZER
static std::function< Slot &(Slot *)> element
BitMask< uint64_t, kWidth, 3 > MatchEmpty() const
void SetHashtablezSampleParameter(int32_t rate)
std::vector< size_t > GetHashtableDebugNumProbesHistogram(const C &container)
#define ABSL_RAW_LOG(severity,...)
#define ABSL_ATTRIBUTE_ALWAYS_INLINE
auto keys(const Set &s) -> std::vector< typename std::decay< typename Set::key_type >::type >
void SetHashtablezEnabled(bool enabled)
TEST(NotificationTest, SanityTest)
static std::function< int(int)> apply_impl
std::ostream & operator<<(std::ostream &os, absl::LogSeverity s)
BitMask< uint64_t, kWidth, 3 > MatchEmptyOrDeleted() const
void CopyConstruct(FlagOpFn op, const void *src, void *dst)
typename container_internal::HashEq< T >::Hash hash_default_hash
HashtablezInfoHandle Sample()
std::vector< std::pair< double, double > > pecentile_probes
uint32_t CountLeadingEmptyOrDeleted() const
static std::function< void(void *, Slot *)> destroy
size_t GrowthToLowerboundCapacity(size_t growth)
void Swap(T &lhs, T &rhs) noexcept(IsNothrowSwappable< T >::value)
std::pair< std::tuple<>, std::tuple<> > PairArgs()
uint128 operator+(uint128 lhs, uint128 rhs)
hash_default_hash< typename T::first_type > hash
size_t GetHashtableDebugNumProbes(const C &c, const typename C::key_type &key)
std::pair< std::string, std::string > pair
BitMask< uint64_t, kWidth, 3 > Match(h2_t hash) const
size_t CapacityToGrowth(size_t capacity)
static std::function< void(void *, Slot *, Slot *)> transfer
static std::function< void(void *, Slot *, Slot)> construct
static auto GetSlots(const C &c) -> decltype(c.slots_)
void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t *ctrl, size_t capacity)
auto apply(Functor &&functor, Tuple &&t) -> decltype(utility_internal::apply_helper(absl::forward< Functor >(functor), absl::forward< Tuple >(t), absl::make_index_sequence< std::tuple_size< typename std::remove_reference< Tuple >::type >::value >
static constexpr size_t kWidth
constexpr bool IsNoThrowSwappable()
typename type_traits_internal::VoidTImpl< Ts... >::type void_t
typename container_internal::HashEq< T >::Eq hash_default_eq
static HashtablezSampler & Global()
std::allocator< int > alloc
std::vector< std::pair< double, double > > pecentile_ratios
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
static bool Optional(bool)
std::vector< double > single_table_ratios
std::vector< size_t > all_probes_histogram
size_t NormalizeCapacity(size_t n)