• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/container/internal/raw_hash_set.h"
16 
17 #include <algorithm>
18 #include <atomic>
19 #include <cmath>
20 #include <cstddef>
21 #include <cstdint>
22 #include <deque>
23 #include <functional>
24 #include <iostream>
25 #include <iterator>
26 #include <list>
27 #include <map>
28 #include <memory>
29 #include <numeric>
30 #include <ostream>
31 #include <random>
32 #include <string>
33 #include <type_traits>
34 #include <unordered_map>
35 #include <unordered_set>
36 #include <utility>
37 #include <vector>
38 
39 #include "gmock/gmock.h"
40 #include "gtest/gtest.h"
41 #include "absl/base/attributes.h"
42 #include "absl/base/config.h"
43 #include "absl/base/internal/cycleclock.h"
44 #include "absl/base/prefetch.h"
45 #include "absl/container/flat_hash_map.h"
46 #include "absl/container/flat_hash_set.h"
47 #include "absl/container/internal/container_memory.h"
48 #include "absl/container/internal/hash_function_defaults.h"
49 #include "absl/container/internal/hash_policy_testing.h"
50 #include "absl/container/internal/hashtable_debug.h"
51 #include "absl/log/log.h"
52 #include "absl/strings/string_view.h"
53 
54 namespace absl {
55 ABSL_NAMESPACE_BEGIN
56 namespace container_internal {
57 
58 struct RawHashSetTestOnlyAccess {
59   template <typename C>
GetSlotsabsl::container_internal::RawHashSetTestOnlyAccess60   static auto GetSlots(const C& c) -> decltype(c.slot_array()) {
61     return c.slot_array();
62   }
63   template <typename C>
CountTombstonesabsl::container_internal::RawHashSetTestOnlyAccess64   static size_t CountTombstones(const C& c) {
65     return c.common().TombstonesCount();
66   }
67 };
68 
69 namespace {
70 
71 using ::testing::ElementsAre;
72 using ::testing::Eq;
73 using ::testing::Ge;
74 using ::testing::Lt;
75 using ::testing::Pair;
76 using ::testing::UnorderedElementsAre;
77 
78 // Convenience function to static cast to ctrl_t.
CtrlT(int i)79 ctrl_t CtrlT(int i) { return static_cast<ctrl_t>(i); }
80 
TEST(Util,NormalizeCapacity)81 TEST(Util, NormalizeCapacity) {
82   EXPECT_EQ(1, NormalizeCapacity(0));
83   EXPECT_EQ(1, NormalizeCapacity(1));
84   EXPECT_EQ(3, NormalizeCapacity(2));
85   EXPECT_EQ(3, NormalizeCapacity(3));
86   EXPECT_EQ(7, NormalizeCapacity(4));
87   EXPECT_EQ(7, NormalizeCapacity(7));
88   EXPECT_EQ(15, NormalizeCapacity(8));
89   EXPECT_EQ(15, NormalizeCapacity(15));
90   EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 1));
91   EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 2));
92 }
93 
TEST(Util,GrowthAndCapacity)94 TEST(Util, GrowthAndCapacity) {
95   // Verify that GrowthToCapacity gives the minimum capacity that has enough
96   // growth.
97   for (size_t growth = 0; growth < 10000; ++growth) {
98     SCOPED_TRACE(growth);
99     size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth));
100     // The capacity is large enough for `growth`.
101     EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth));
102     // For (capacity+1) < kWidth, growth should equal capacity.
103     if (capacity + 1 < Group::kWidth) {
104       EXPECT_THAT(CapacityToGrowth(capacity), Eq(capacity));
105     } else {
106       EXPECT_THAT(CapacityToGrowth(capacity), Lt(capacity));
107     }
108     if (growth != 0 && capacity > 1) {
109       // There is no smaller capacity that works.
110       EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth));
111     }
112   }
113 
114   for (size_t capacity = Group::kWidth - 1; capacity < 10000;
115        capacity = 2 * capacity + 1) {
116     SCOPED_TRACE(capacity);
117     size_t growth = CapacityToGrowth(capacity);
118     EXPECT_THAT(growth, Lt(capacity));
119     EXPECT_LE(GrowthToLowerboundCapacity(growth), capacity);
120     EXPECT_EQ(NormalizeCapacity(GrowthToLowerboundCapacity(growth)), capacity);
121   }
122 }
123 
TEST(Util,probe_seq)124 TEST(Util, probe_seq) {
125   probe_seq<16> seq(0, 127);
126   auto gen = [&]() {
127     size_t res = seq.offset();
128     seq.next();
129     return res;
130   };
131   std::vector<size_t> offsets(8);
132   std::generate_n(offsets.begin(), 8, gen);
133   EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64));
134   seq = probe_seq<16>(128, 127);
135   std::generate_n(offsets.begin(), 8, gen);
136   EXPECT_THAT(offsets, ElementsAre(0, 16, 48, 96, 32, 112, 80, 64));
137 }
138 
TEST(BitMask,Smoke)139 TEST(BitMask, Smoke) {
140   EXPECT_FALSE((BitMask<uint8_t, 8>(0)));
141   EXPECT_TRUE((BitMask<uint8_t, 8>(5)));
142 
143   EXPECT_THAT((BitMask<uint8_t, 8>(0)), ElementsAre());
144   EXPECT_THAT((BitMask<uint8_t, 8>(0x1)), ElementsAre(0));
145   EXPECT_THAT((BitMask<uint8_t, 8>(0x2)), ElementsAre(1));
146   EXPECT_THAT((BitMask<uint8_t, 8>(0x3)), ElementsAre(0, 1));
147   EXPECT_THAT((BitMask<uint8_t, 8>(0x4)), ElementsAre(2));
148   EXPECT_THAT((BitMask<uint8_t, 8>(0x5)), ElementsAre(0, 2));
149   EXPECT_THAT((BitMask<uint8_t, 8>(0x55)), ElementsAre(0, 2, 4, 6));
150   EXPECT_THAT((BitMask<uint8_t, 8>(0xAA)), ElementsAre(1, 3, 5, 7));
151 }
152 
TEST(BitMask,WithShift)153 TEST(BitMask, WithShift) {
154   // See the non-SSE version of Group for details on what this math is for.
155   uint64_t ctrl = 0x1716151413121110;
156   uint64_t hash = 0x12;
157   constexpr uint64_t msbs = 0x8080808080808080ULL;
158   constexpr uint64_t lsbs = 0x0101010101010101ULL;
159   auto x = ctrl ^ (lsbs * hash);
160   uint64_t mask = (x - lsbs) & ~x & msbs;
161   EXPECT_EQ(0x0000000080800000, mask);
162 
163   BitMask<uint64_t, 8, 3> b(mask);
164   EXPECT_EQ(*b, 2);
165 }
166 
TEST(BitMask,LeadingTrailing)167 TEST(BitMask, LeadingTrailing) {
168   EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).LeadingZeros()), 3);
169   EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).TrailingZeros()), 6);
170 
171   EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).LeadingZeros()), 15);
172   EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).TrailingZeros()), 0);
173 
174   EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).LeadingZeros()), 0);
175   EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).TrailingZeros()), 15);
176 
177   EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).LeadingZeros()), 3);
178   EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).TrailingZeros()), 1);
179 
180   EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000000000000080).LeadingZeros()), 7);
181   EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000000000000080).TrailingZeros()), 0);
182 
183   EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x8000000000000000).LeadingZeros()), 0);
184   EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x8000000000000000).TrailingZeros()), 7);
185 }
186 
TEST(Group,EmptyGroup)187 TEST(Group, EmptyGroup) {
188   for (h2_t h = 0; h != 128; ++h) EXPECT_FALSE(Group{EmptyGroup()}.Match(h));
189 }
190 
TEST(Group,Match)191 TEST(Group, Match) {
192   if (Group::kWidth == 16) {
193     ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted,  CtrlT(3),
194                       ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
195                       CtrlT(7),       CtrlT(5), CtrlT(3),          CtrlT(1),
196                       CtrlT(1),       CtrlT(1), CtrlT(1),          CtrlT(1)};
197     EXPECT_THAT(Group{group}.Match(0), ElementsAre());
198     EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 11, 12, 13, 14, 15));
199     EXPECT_THAT(Group{group}.Match(3), ElementsAre(3, 10));
200     EXPECT_THAT(Group{group}.Match(5), ElementsAre(5, 9));
201     EXPECT_THAT(Group{group}.Match(7), ElementsAre(7, 8));
202   } else if (Group::kWidth == 8) {
203     ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), CtrlT(2),
204                       ctrl_t::kDeleted,  CtrlT(2), CtrlT(1),
205                       ctrl_t::kSentinel, CtrlT(1)};
206     EXPECT_THAT(Group{group}.Match(0), ElementsAre());
207     EXPECT_THAT(Group{group}.Match(1), ElementsAre(1, 5, 7));
208     EXPECT_THAT(Group{group}.Match(2), ElementsAre(2, 4));
209   } else {
210     FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
211   }
212 }
213 
TEST(Group,MaskEmpty)214 TEST(Group, MaskEmpty) {
215   if (Group::kWidth == 16) {
216     ctrl_t group[] = {ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted,  CtrlT(3),
217                       ctrl_t::kEmpty, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
218                       CtrlT(7),       CtrlT(5), CtrlT(3),          CtrlT(1),
219                       CtrlT(1),       CtrlT(1), CtrlT(1),          CtrlT(1)};
220     EXPECT_THAT(Group{group}.MaskEmpty().LowestBitSet(), 0);
221     EXPECT_THAT(Group{group}.MaskEmpty().HighestBitSet(), 4);
222   } else if (Group::kWidth == 8) {
223     ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), CtrlT(2),
224                       ctrl_t::kDeleted,  CtrlT(2), CtrlT(1),
225                       ctrl_t::kSentinel, CtrlT(1)};
226     EXPECT_THAT(Group{group}.MaskEmpty().LowestBitSet(), 0);
227     EXPECT_THAT(Group{group}.MaskEmpty().HighestBitSet(), 0);
228   } else {
229     FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
230   }
231 }
232 
TEST(Group,MaskEmptyOrDeleted)233 TEST(Group, MaskEmptyOrDeleted) {
234   if (Group::kWidth == 16) {
235     ctrl_t group[] = {ctrl_t::kEmpty,   CtrlT(1), ctrl_t::kEmpty,    CtrlT(3),
236                       ctrl_t::kDeleted, CtrlT(5), ctrl_t::kSentinel, CtrlT(7),
237                       CtrlT(7),         CtrlT(5), CtrlT(3),          CtrlT(1),
238                       CtrlT(1),         CtrlT(1), CtrlT(1),          CtrlT(1)};
239     EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
240     EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().HighestBitSet(), 4);
241   } else if (Group::kWidth == 8) {
242     ctrl_t group[] = {ctrl_t::kEmpty,    CtrlT(1), CtrlT(2),
243                       ctrl_t::kDeleted,  CtrlT(2), CtrlT(1),
244                       ctrl_t::kSentinel, CtrlT(1)};
245     EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().LowestBitSet(), 0);
246     EXPECT_THAT(Group{group}.MaskEmptyOrDeleted().HighestBitSet(), 3);
247   } else {
248     FAIL() << "No test coverage for Group::kWidth==" << Group::kWidth;
249   }
250 }
251 
TEST(Batch,DropDeletes)252 TEST(Batch, DropDeletes) {
253   constexpr size_t kCapacity = 63;
254   constexpr size_t kGroupWidth = container_internal::Group::kWidth;
255   std::vector<ctrl_t> ctrl(kCapacity + 1 + kGroupWidth);
256   ctrl[kCapacity] = ctrl_t::kSentinel;
257   std::vector<ctrl_t> pattern = {
258       ctrl_t::kEmpty, CtrlT(2), ctrl_t::kDeleted, CtrlT(2),
259       ctrl_t::kEmpty, CtrlT(1), ctrl_t::kDeleted};
260   for (size_t i = 0; i != kCapacity; ++i) {
261     ctrl[i] = pattern[i % pattern.size()];
262     if (i < kGroupWidth - 1)
263       ctrl[i + kCapacity + 1] = pattern[i % pattern.size()];
264   }
265   ConvertDeletedToEmptyAndFullToDeleted(ctrl.data(), kCapacity);
266   ASSERT_EQ(ctrl[kCapacity], ctrl_t::kSentinel);
267   for (size_t i = 0; i < kCapacity + kGroupWidth; ++i) {
268     ctrl_t expected = pattern[i % (kCapacity + 1) % pattern.size()];
269     if (i == kCapacity) expected = ctrl_t::kSentinel;
270     if (expected == ctrl_t::kDeleted) expected = ctrl_t::kEmpty;
271     if (IsFull(expected)) expected = ctrl_t::kDeleted;
272     EXPECT_EQ(ctrl[i], expected)
273         << i << " " << static_cast<int>(pattern[i % pattern.size()]);
274   }
275 }
276 
TEST(Group,CountLeadingEmptyOrDeleted)277 TEST(Group, CountLeadingEmptyOrDeleted) {
278   const std::vector<ctrl_t> empty_examples = {ctrl_t::kEmpty, ctrl_t::kDeleted};
279   const std::vector<ctrl_t> full_examples = {
280       CtrlT(0), CtrlT(1), CtrlT(2),   CtrlT(3),
281       CtrlT(5), CtrlT(9), CtrlT(127), ctrl_t::kSentinel};
282 
283   for (ctrl_t empty : empty_examples) {
284     std::vector<ctrl_t> e(Group::kWidth, empty);
285     EXPECT_EQ(Group::kWidth, Group{e.data()}.CountLeadingEmptyOrDeleted());
286     for (ctrl_t full : full_examples) {
287       for (size_t i = 0; i != Group::kWidth; ++i) {
288         std::vector<ctrl_t> f(Group::kWidth, empty);
289         f[i] = full;
290         EXPECT_EQ(i, Group{f.data()}.CountLeadingEmptyOrDeleted());
291       }
292       std::vector<ctrl_t> f(Group::kWidth, empty);
293       f[Group::kWidth * 2 / 3] = full;
294       f[Group::kWidth / 2] = full;
295       EXPECT_EQ(
296           Group::kWidth / 2, Group{f.data()}.CountLeadingEmptyOrDeleted());
297     }
298   }
299 }
300 
301 template <class T>
302 struct ValuePolicy {
303   using slot_type = T;
304   using key_type = T;
305   using init_type = T;
306 
307   template <class Allocator, class... Args>
constructabsl::container_internal::__anon0a0f3e1e0111::ValuePolicy308   static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
309     absl::allocator_traits<Allocator>::construct(*alloc, slot,
310                                                  std::forward<Args>(args)...);
311   }
312 
313   template <class Allocator>
destroyabsl::container_internal::__anon0a0f3e1e0111::ValuePolicy314   static void destroy(Allocator* alloc, slot_type* slot) {
315     absl::allocator_traits<Allocator>::destroy(*alloc, slot);
316   }
317 
318   template <class Allocator>
transferabsl::container_internal::__anon0a0f3e1e0111::ValuePolicy319   static void transfer(Allocator* alloc, slot_type* new_slot,
320                        slot_type* old_slot) {
321     construct(alloc, new_slot, std::move(*old_slot));
322     destroy(alloc, old_slot);
323   }
324 
elementabsl::container_internal::__anon0a0f3e1e0111::ValuePolicy325   static T& element(slot_type* slot) { return *slot; }
326 
327   template <class F, class... Args>
328   static decltype(absl::container_internal::DecomposeValue(
329       std::declval<F>(), std::declval<Args>()...))
applyabsl::container_internal::__anon0a0f3e1e0111::ValuePolicy330   apply(F&& f, Args&&... args) {
331     return absl::container_internal::DecomposeValue(
332         std::forward<F>(f), std::forward<Args>(args)...);
333   }
334 };
335 
336 using IntPolicy = ValuePolicy<int64_t>;
337 using Uint8Policy = ValuePolicy<uint8_t>;
338 
339 class StringPolicy {
340   template <class F, class K, class V,
341             class = typename std::enable_if<
342                 std::is_convertible<const K&, absl::string_view>::value>::type>
343   decltype(std::declval<F>()(
344       std::declval<const absl::string_view&>(), std::piecewise_construct,
345       std::declval<std::tuple<K>>(),
apply_impl(F && f,std::pair<std::tuple<K>,V> p)346       std::declval<V>())) static apply_impl(F&& f,
347                                             std::pair<std::tuple<K>, V> p) {
348     const absl::string_view& key = std::get<0>(p.first);
349     return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
350                               std::move(p.second));
351   }
352 
353  public:
354   struct slot_type {
355     struct ctor {};
356 
357     template <class... Ts>
slot_typeabsl::container_internal::__anon0a0f3e1e0111::StringPolicy::slot_type358     explicit slot_type(ctor, Ts&&... ts) : pair(std::forward<Ts>(ts)...) {}
359 
360     std::pair<std::string, std::string> pair;
361   };
362 
363   using key_type = std::string;
364   using init_type = std::pair<std::string, std::string>;
365 
366   template <class allocator_type, class... Args>
construct(allocator_type * alloc,slot_type * slot,Args...args)367   static void construct(allocator_type* alloc, slot_type* slot, Args... args) {
368     std::allocator_traits<allocator_type>::construct(
369         *alloc, slot, typename slot_type::ctor(), std::forward<Args>(args)...);
370   }
371 
372   template <class allocator_type>
destroy(allocator_type * alloc,slot_type * slot)373   static void destroy(allocator_type* alloc, slot_type* slot) {
374     std::allocator_traits<allocator_type>::destroy(*alloc, slot);
375   }
376 
377   template <class allocator_type>
transfer(allocator_type * alloc,slot_type * new_slot,slot_type * old_slot)378   static void transfer(allocator_type* alloc, slot_type* new_slot,
379                        slot_type* old_slot) {
380     construct(alloc, new_slot, std::move(old_slot->pair));
381     destroy(alloc, old_slot);
382   }
383 
element(slot_type * slot)384   static std::pair<std::string, std::string>& element(slot_type* slot) {
385     return slot->pair;
386   }
387 
388   template <class F, class... Args>
apply(F && f,Args &&...args)389   static auto apply(F&& f, Args&&... args)
390       -> decltype(apply_impl(std::forward<F>(f),
391                              PairArgs(std::forward<Args>(args)...))) {
392     return apply_impl(std::forward<F>(f),
393                       PairArgs(std::forward<Args>(args)...));
394   }
395 };
396 
397 struct StringHash : absl::Hash<absl::string_view> {
398   using is_transparent = void;
399 };
400 struct StringEq : std::equal_to<absl::string_view> {
401   using is_transparent = void;
402 };
403 
404 struct StringTable
405     : raw_hash_set<StringPolicy, StringHash, StringEq, std::allocator<int>> {
406   using Base = typename StringTable::raw_hash_set;
407   StringTable() = default;
408   using Base::Base;
409 };
410 
411 struct IntTable
412     : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
413                    std::equal_to<int64_t>, std::allocator<int64_t>> {
414   using Base = typename IntTable::raw_hash_set;
415   using Base::Base;
416 };
417 
418 struct Uint8Table
419     : raw_hash_set<Uint8Policy, container_internal::hash_default_hash<uint8_t>,
420                    std::equal_to<uint8_t>, std::allocator<uint8_t>> {
421   using Base = typename Uint8Table::raw_hash_set;
422   using Base::Base;
423 };
424 
425 template <typename T>
426 struct CustomAlloc : std::allocator<T> {
427   CustomAlloc() = default;
428 
429   template <typename U>
CustomAllocabsl::container_internal::__anon0a0f3e1e0111::CustomAlloc430   explicit CustomAlloc(const CustomAlloc<U>& /*other*/) {}
431 
432   template<class U> struct rebind {
433     using other = CustomAlloc<U>;
434   };
435 };
436 
437 struct CustomAllocIntTable
438     : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
439                    std::equal_to<int64_t>, CustomAlloc<int64_t>> {
440   using Base = typename CustomAllocIntTable::raw_hash_set;
441   using Base::Base;
442 };
443 
444 // Tries to allocate memory at the minimum alignment even when the default
445 // allocator uses a higher alignment.
446 template <typename T>
447 struct MinimumAlignmentAlloc : std::allocator<T> {
448   MinimumAlignmentAlloc() = default;
449 
450   template <typename U>
MinimumAlignmentAllocabsl::container_internal::__anon0a0f3e1e0111::MinimumAlignmentAlloc451   explicit MinimumAlignmentAlloc(const MinimumAlignmentAlloc<U>& /*other*/) {}
452 
453   template <class U>
454   struct rebind {
455     using other = MinimumAlignmentAlloc<U>;
456   };
457 
allocateabsl::container_internal::__anon0a0f3e1e0111::MinimumAlignmentAlloc458   T* allocate(size_t n) {
459     T* ptr = std::allocator<T>::allocate(n + 1);
460     char* cptr = reinterpret_cast<char*>(ptr);
461     cptr += alignof(T);
462     return reinterpret_cast<T*>(cptr);
463   }
464 
deallocateabsl::container_internal::__anon0a0f3e1e0111::MinimumAlignmentAlloc465   void deallocate(T* ptr, size_t n) {
466     char* cptr = reinterpret_cast<char*>(ptr);
467     cptr -= alignof(T);
468     std::allocator<T>::deallocate(reinterpret_cast<T*>(cptr), n + 1);
469   }
470 };
471 
472 struct MinimumAlignmentUint8Table
473     : raw_hash_set<Uint8Policy, container_internal::hash_default_hash<uint8_t>,
474                    std::equal_to<uint8_t>, MinimumAlignmentAlloc<uint8_t>> {
475   using Base = typename MinimumAlignmentUint8Table::raw_hash_set;
476   using Base::Base;
477 };
478 
479 // Allows for freezing the allocator to expect no further allocations.
480 template <typename T>
481 struct FreezableAlloc : std::allocator<T> {
FreezableAllocabsl::container_internal::__anon0a0f3e1e0111::FreezableAlloc482   explicit FreezableAlloc(bool* f) : frozen(f) {}
483 
484   template <typename U>
FreezableAllocabsl::container_internal::__anon0a0f3e1e0111::FreezableAlloc485   explicit FreezableAlloc(const FreezableAlloc<U>& other)
486       : frozen(other.frozen) {}
487 
488   template <class U>
489   struct rebind {
490     using other = FreezableAlloc<U>;
491   };
492 
allocateabsl::container_internal::__anon0a0f3e1e0111::FreezableAlloc493   T* allocate(size_t n) {
494     EXPECT_FALSE(*frozen);
495     return std::allocator<T>::allocate(n);
496   }
497 
498   bool* frozen;
499 };
500 
501 struct BadFastHash {
502   template <class T>
operator ()absl::container_internal::__anon0a0f3e1e0111::BadFastHash503   size_t operator()(const T&) const {
504     return 0;
505   }
506 };
507 
508 struct BadHashFreezableIntTable
509     : raw_hash_set<IntPolicy, BadFastHash, std::equal_to<int64_t>,
510                    FreezableAlloc<int64_t>> {
511   using Base = typename BadHashFreezableIntTable::raw_hash_set;
512   using Base::Base;
513 };
514 
515 struct BadTable : raw_hash_set<IntPolicy, BadFastHash, std::equal_to<int>,
516                                std::allocator<int>> {
517   using Base = typename BadTable::raw_hash_set;
518   BadTable() = default;
519   using Base::Base;
520 };
521 
TEST(Table,EmptyFunctorOptimization)522 TEST(Table, EmptyFunctorOptimization) {
523   static_assert(std::is_empty<std::equal_to<absl::string_view>>::value, "");
524   static_assert(std::is_empty<std::allocator<int>>::value, "");
525 
526   struct MockTable {
527     void* infoz;
528     void* ctrl;
529     void* slots;
530     size_t size;
531     size_t capacity;
532   };
533   struct MockTableInfozDisabled {
534     void* ctrl;
535     void* slots;
536     size_t size;
537     size_t capacity;
538   };
539   struct StatelessHash {
540     size_t operator()(absl::string_view) const { return 0; }
541   };
542   struct StatefulHash : StatelessHash {
543     size_t dummy;
544   };
545 
546   struct GenerationData {
547     size_t reserved_growth;
548     size_t reservation_size;
549     GenerationType* generation;
550   };
551 
552 // Ignore unreachable-code warning. Compiler thinks one branch of each ternary
553 // conditional is unreachable.
554 #if defined(__clang__)
555 #pragma clang diagnostic push
556 #pragma clang diagnostic ignored "-Wunreachable-code"
557 #endif
558   constexpr size_t mock_size = std::is_empty<HashtablezInfoHandle>()
559                                    ? sizeof(MockTableInfozDisabled)
560                                    : sizeof(MockTable);
561   constexpr size_t generation_size =
562       SwisstableGenerationsEnabled() ? sizeof(GenerationData) : 0;
563 #if defined(__clang__)
564 #pragma clang diagnostic pop
565 #endif
566 
567   EXPECT_EQ(
568       mock_size + generation_size,
569       sizeof(
570           raw_hash_set<StringPolicy, StatelessHash,
571                        std::equal_to<absl::string_view>, std::allocator<int>>));
572 
573   EXPECT_EQ(
574       mock_size + sizeof(StatefulHash) + generation_size,
575       sizeof(
576           raw_hash_set<StringPolicy, StatefulHash,
577                        std::equal_to<absl::string_view>, std::allocator<int>>));
578 }
579 
TEST(Table,Empty)580 TEST(Table, Empty) {
581   IntTable t;
582   EXPECT_EQ(0, t.size());
583   EXPECT_TRUE(t.empty());
584 }
585 
TEST(Table,LookupEmpty)586 TEST(Table, LookupEmpty) {
587   IntTable t;
588   auto it = t.find(0);
589   EXPECT_TRUE(it == t.end());
590 }
591 
TEST(Table,Insert1)592 TEST(Table, Insert1) {
593   IntTable t;
594   EXPECT_TRUE(t.find(0) == t.end());
595   auto res = t.emplace(0);
596   EXPECT_TRUE(res.second);
597   EXPECT_THAT(*res.first, 0);
598   EXPECT_EQ(1, t.size());
599   EXPECT_THAT(*t.find(0), 0);
600 }
601 
TEST(Table,Insert2)602 TEST(Table, Insert2) {
603   IntTable t;
604   EXPECT_TRUE(t.find(0) == t.end());
605   auto res = t.emplace(0);
606   EXPECT_TRUE(res.second);
607   EXPECT_THAT(*res.first, 0);
608   EXPECT_EQ(1, t.size());
609   EXPECT_TRUE(t.find(1) == t.end());
610   res = t.emplace(1);
611   EXPECT_TRUE(res.second);
612   EXPECT_THAT(*res.first, 1);
613   EXPECT_EQ(2, t.size());
614   EXPECT_THAT(*t.find(0), 0);
615   EXPECT_THAT(*t.find(1), 1);
616 }
617 
TEST(Table,InsertCollision)618 TEST(Table, InsertCollision) {
619   BadTable t;
620   EXPECT_TRUE(t.find(1) == t.end());
621   auto res = t.emplace(1);
622   EXPECT_TRUE(res.second);
623   EXPECT_THAT(*res.first, 1);
624   EXPECT_EQ(1, t.size());
625 
626   EXPECT_TRUE(t.find(2) == t.end());
627   res = t.emplace(2);
628   EXPECT_THAT(*res.first, 2);
629   EXPECT_TRUE(res.second);
630   EXPECT_EQ(2, t.size());
631 
632   EXPECT_THAT(*t.find(1), 1);
633   EXPECT_THAT(*t.find(2), 2);
634 }
635 
636 // Test that we do not add existent element in case we need to search through
637 // many groups with deleted elements
TEST(Table,InsertCollisionAndFindAfterDelete)638 TEST(Table, InsertCollisionAndFindAfterDelete) {
639   BadTable t;  // all elements go to the same group.
640   // Have at least 2 groups with Group::kWidth collisions
641   // plus some extra collisions in the last group.
642   constexpr size_t kNumInserts = Group::kWidth * 2 + 5;
643   for (size_t i = 0; i < kNumInserts; ++i) {
644     auto res = t.emplace(i);
645     EXPECT_TRUE(res.second);
646     EXPECT_THAT(*res.first, i);
647     EXPECT_EQ(i + 1, t.size());
648   }
649 
650   // Remove elements one by one and check
651   // that we still can find all other elements.
652   for (size_t i = 0; i < kNumInserts; ++i) {
653     EXPECT_EQ(1, t.erase(i)) << i;
654     for (size_t j = i + 1; j < kNumInserts; ++j) {
655       EXPECT_THAT(*t.find(j), j);
656       auto res = t.emplace(j);
657       EXPECT_FALSE(res.second) << i << " " << j;
658       EXPECT_THAT(*res.first, j);
659       EXPECT_EQ(kNumInserts - i - 1, t.size());
660     }
661   }
662   EXPECT_TRUE(t.empty());
663 }
664 
TEST(Table,InsertWithinCapacity)665 TEST(Table, InsertWithinCapacity) {
666   IntTable t;
667   t.reserve(10);
668   const size_t original_capacity = t.capacity();
669   const auto addr = [&](int i) {
670     return reinterpret_cast<uintptr_t>(&*t.find(i));
671   };
672   // Inserting an element does not change capacity.
673   t.insert(0);
674   EXPECT_THAT(t.capacity(), original_capacity);
675   const uintptr_t original_addr_0 = addr(0);
676   // Inserting another element does not rehash.
677   t.insert(1);
678   EXPECT_THAT(t.capacity(), original_capacity);
679   EXPECT_THAT(addr(0), original_addr_0);
680   // Inserting lots of duplicate elements does not rehash.
681   for (int i = 0; i < 100; ++i) {
682     t.insert(i % 10);
683   }
684   EXPECT_THAT(t.capacity(), original_capacity);
685   EXPECT_THAT(addr(0), original_addr_0);
686   // Inserting a range of duplicate elements does not rehash.
687   std::vector<int> dup_range;
688   for (int i = 0; i < 100; ++i) {
689     dup_range.push_back(i % 10);
690   }
691   t.insert(dup_range.begin(), dup_range.end());
692   EXPECT_THAT(t.capacity(), original_capacity);
693   EXPECT_THAT(addr(0), original_addr_0);
694 }
695 
TEST(Table,LazyEmplace)696 TEST(Table, LazyEmplace) {
697   StringTable t;
698   bool called = false;
699   auto it = t.lazy_emplace("abc", [&](const StringTable::constructor& f) {
700     called = true;
701     f("abc", "ABC");
702   });
703   EXPECT_TRUE(called);
704   EXPECT_THAT(*it, Pair("abc", "ABC"));
705   called = false;
706   it = t.lazy_emplace("abc", [&](const StringTable::constructor& f) {
707     called = true;
708     f("abc", "DEF");
709   });
710   EXPECT_FALSE(called);
711   EXPECT_THAT(*it, Pair("abc", "ABC"));
712 }
713 
TEST(Table,ContainsEmpty)714 TEST(Table, ContainsEmpty) {
715   IntTable t;
716 
717   EXPECT_FALSE(t.contains(0));
718 }
719 
TEST(Table,Contains1)720 TEST(Table, Contains1) {
721   IntTable t;
722 
723   EXPECT_TRUE(t.insert(0).second);
724   EXPECT_TRUE(t.contains(0));
725   EXPECT_FALSE(t.contains(1));
726 
727   EXPECT_EQ(1, t.erase(0));
728   EXPECT_FALSE(t.contains(0));
729 }
730 
TEST(Table,Contains2)731 TEST(Table, Contains2) {
732   IntTable t;
733 
734   EXPECT_TRUE(t.insert(0).second);
735   EXPECT_TRUE(t.contains(0));
736   EXPECT_FALSE(t.contains(1));
737 
738   t.clear();
739   EXPECT_FALSE(t.contains(0));
740 }
741 
742 int decompose_constructed;
743 int decompose_copy_constructed;
744 int decompose_copy_assigned;
745 int decompose_move_constructed;
746 int decompose_move_assigned;
747 struct DecomposeType {
DecomposeTypeabsl::container_internal::__anon0a0f3e1e0111::DecomposeType748   DecomposeType(int i = 0) : i(i) {  // NOLINT
749     ++decompose_constructed;
750   }
751 
DecomposeTypeabsl::container_internal::__anon0a0f3e1e0111::DecomposeType752   explicit DecomposeType(const char* d) : DecomposeType(*d) {}
753 
DecomposeTypeabsl::container_internal::__anon0a0f3e1e0111::DecomposeType754   DecomposeType(const DecomposeType& other) : i(other.i) {
755     ++decompose_copy_constructed;
756   }
operator =absl::container_internal::__anon0a0f3e1e0111::DecomposeType757   DecomposeType& operator=(const DecomposeType& other) {
758     ++decompose_copy_assigned;
759     i = other.i;
760     return *this;
761   }
DecomposeTypeabsl::container_internal::__anon0a0f3e1e0111::DecomposeType762   DecomposeType(DecomposeType&& other) : i(other.i) {
763     ++decompose_move_constructed;
764   }
operator =absl::container_internal::__anon0a0f3e1e0111::DecomposeType765   DecomposeType& operator=(DecomposeType&& other) {
766     ++decompose_move_assigned;
767     i = other.i;
768     return *this;
769   }
770 
771   int i;
772 };
773 
774 struct DecomposeHash {
775   using is_transparent = void;
operator ()absl::container_internal::__anon0a0f3e1e0111::DecomposeHash776   size_t operator()(const DecomposeType& a) const { return a.i; }
operator ()absl::container_internal::__anon0a0f3e1e0111::DecomposeHash777   size_t operator()(int a) const { return a; }
operator ()absl::container_internal::__anon0a0f3e1e0111::DecomposeHash778   size_t operator()(const char* a) const { return *a; }
779 };
780 
781 struct DecomposeEq {
782   using is_transparent = void;
operator ()absl::container_internal::__anon0a0f3e1e0111::DecomposeEq783   bool operator()(const DecomposeType& a, const DecomposeType& b) const {
784     return a.i == b.i;
785   }
operator ()absl::container_internal::__anon0a0f3e1e0111::DecomposeEq786   bool operator()(const DecomposeType& a, int b) const { return a.i == b; }
operator ()absl::container_internal::__anon0a0f3e1e0111::DecomposeEq787   bool operator()(const DecomposeType& a, const char* b) const {
788     return a.i == *b;
789   }
790 };
791 
792 struct DecomposePolicy {
793   using slot_type = DecomposeType;
794   using key_type = DecomposeType;
795   using init_type = DecomposeType;
796 
797   template <typename T>
constructabsl::container_internal::__anon0a0f3e1e0111::DecomposePolicy798   static void construct(void*, DecomposeType* slot, T&& v) {
799     ::new (slot) DecomposeType(std::forward<T>(v));
800   }
destroyabsl::container_internal::__anon0a0f3e1e0111::DecomposePolicy801   static void destroy(void*, DecomposeType* slot) { slot->~DecomposeType(); }
elementabsl::container_internal::__anon0a0f3e1e0111::DecomposePolicy802   static DecomposeType& element(slot_type* slot) { return *slot; }
803 
804   template <class F, class T>
applyabsl::container_internal::__anon0a0f3e1e0111::DecomposePolicy805   static auto apply(F&& f, const T& x) -> decltype(std::forward<F>(f)(x, x)) {
806     return std::forward<F>(f)(x, x);
807   }
808 };
809 
810 template <typename Hash, typename Eq>
TestDecompose(bool construct_three)811 void TestDecompose(bool construct_three) {
812   DecomposeType elem{0};
813   const int one = 1;
814   const char* three_p = "3";
815   const auto& three = three_p;
816   const int elem_vector_count = 256;
817   std::vector<DecomposeType> elem_vector(elem_vector_count, DecomposeType{0});
818   std::iota(elem_vector.begin(), elem_vector.end(), 0);
819 
820   using DecomposeSet =
821       raw_hash_set<DecomposePolicy, Hash, Eq, std::allocator<int>>;
822   DecomposeSet set1;
823 
824   decompose_constructed = 0;
825   int expected_constructed = 0;
826   EXPECT_EQ(expected_constructed, decompose_constructed);
827   set1.insert(elem);
828   EXPECT_EQ(expected_constructed, decompose_constructed);
829   set1.insert(1);
830   EXPECT_EQ(++expected_constructed, decompose_constructed);
831   set1.emplace("3");
832   EXPECT_EQ(++expected_constructed, decompose_constructed);
833   EXPECT_EQ(expected_constructed, decompose_constructed);
834 
835   {  // insert(T&&)
836     set1.insert(1);
837     EXPECT_EQ(expected_constructed, decompose_constructed);
838   }
839 
840   {  // insert(const T&)
841     set1.insert(one);
842     EXPECT_EQ(expected_constructed, decompose_constructed);
843   }
844 
845   {  // insert(hint, T&&)
846     set1.insert(set1.begin(), 1);
847     EXPECT_EQ(expected_constructed, decompose_constructed);
848   }
849 
850   {  // insert(hint, const T&)
851     set1.insert(set1.begin(), one);
852     EXPECT_EQ(expected_constructed, decompose_constructed);
853   }
854 
855   {  // emplace(...)
856     set1.emplace(1);
857     EXPECT_EQ(expected_constructed, decompose_constructed);
858     set1.emplace("3");
859     expected_constructed += construct_three;
860     EXPECT_EQ(expected_constructed, decompose_constructed);
861     set1.emplace(one);
862     EXPECT_EQ(expected_constructed, decompose_constructed);
863     set1.emplace(three);
864     expected_constructed += construct_three;
865     EXPECT_EQ(expected_constructed, decompose_constructed);
866   }
867 
868   {  // emplace_hint(...)
869     set1.emplace_hint(set1.begin(), 1);
870     EXPECT_EQ(expected_constructed, decompose_constructed);
871     set1.emplace_hint(set1.begin(), "3");
872     expected_constructed += construct_three;
873     EXPECT_EQ(expected_constructed, decompose_constructed);
874     set1.emplace_hint(set1.begin(), one);
875     EXPECT_EQ(expected_constructed, decompose_constructed);
876     set1.emplace_hint(set1.begin(), three);
877     expected_constructed += construct_three;
878     EXPECT_EQ(expected_constructed, decompose_constructed);
879   }
880 
881   decompose_copy_constructed = 0;
882   decompose_copy_assigned = 0;
883   decompose_move_constructed = 0;
884   decompose_move_assigned = 0;
885   int expected_copy_constructed = 0;
886   int expected_move_constructed = 0;
887   {  // raw_hash_set(first, last) with random-access iterators
888     DecomposeSet set2(elem_vector.begin(), elem_vector.end());
889     // Expect exactly one copy-constructor call for each element if no
890     // rehashing is done.
891     expected_copy_constructed += elem_vector_count;
892     EXPECT_EQ(expected_copy_constructed, decompose_copy_constructed);
893     EXPECT_EQ(expected_move_constructed, decompose_move_constructed);
894     EXPECT_EQ(0, decompose_move_assigned);
895     EXPECT_EQ(0, decompose_copy_assigned);
896   }
897 
898   {  // raw_hash_set(first, last) with forward iterators
899     std::list<DecomposeType> elem_list(elem_vector.begin(), elem_vector.end());
900     expected_copy_constructed = decompose_copy_constructed;
901     DecomposeSet set2(elem_list.begin(), elem_list.end());
902     // Expect exactly N elements copied into set, expect at most 2*N elements
903     // moving internally for all resizing needed (for a growth factor of 2).
904     expected_copy_constructed += elem_vector_count;
905     EXPECT_EQ(expected_copy_constructed, decompose_copy_constructed);
906     expected_move_constructed += elem_vector_count;
907     EXPECT_LT(expected_move_constructed, decompose_move_constructed);
908     expected_move_constructed += elem_vector_count;
909     EXPECT_GE(expected_move_constructed, decompose_move_constructed);
910     EXPECT_EQ(0, decompose_move_assigned);
911     EXPECT_EQ(0, decompose_copy_assigned);
912     expected_copy_constructed = decompose_copy_constructed;
913     expected_move_constructed = decompose_move_constructed;
914   }
915 
916   {  // insert(first, last)
917     DecomposeSet set2;
918     set2.insert(elem_vector.begin(), elem_vector.end());
919     // Expect exactly N elements copied into set, expect at most 2*N elements
920     // moving internally for all resizing needed (for a growth factor of 2).
921     const int expected_new_elements = elem_vector_count;
922     const int expected_max_element_moves = 2 * elem_vector_count;
923     expected_copy_constructed += expected_new_elements;
924     EXPECT_EQ(expected_copy_constructed, decompose_copy_constructed);
925     expected_move_constructed += expected_max_element_moves;
926     EXPECT_GE(expected_move_constructed, decompose_move_constructed);
927     EXPECT_EQ(0, decompose_move_assigned);
928     EXPECT_EQ(0, decompose_copy_assigned);
929     expected_copy_constructed = decompose_copy_constructed;
930     expected_move_constructed = decompose_move_constructed;
931   }
932 }
933 
TEST(Table,Decompose)934 TEST(Table, Decompose) {
935   if (SwisstableGenerationsEnabled()) {
936     GTEST_SKIP() << "Generations being enabled causes extra rehashes.";
937   }
938 
939   TestDecompose<DecomposeHash, DecomposeEq>(false);
940 
941   struct TransparentHashIntOverload {
942     size_t operator()(const DecomposeType& a) const { return a.i; }
943     size_t operator()(int a) const { return a; }
944   };
945   struct TransparentEqIntOverload {
946     bool operator()(const DecomposeType& a, const DecomposeType& b) const {
947       return a.i == b.i;
948     }
949     bool operator()(const DecomposeType& a, int b) const { return a.i == b; }
950   };
951   TestDecompose<TransparentHashIntOverload, DecomposeEq>(true);
952   TestDecompose<TransparentHashIntOverload, TransparentEqIntOverload>(true);
953   TestDecompose<DecomposeHash, TransparentEqIntOverload>(true);
954 }
955 
956 // Returns the largest m such that a table with m elements has the same number
957 // of buckets as a table with n elements.
MaxDensitySize(size_t n)958 size_t MaxDensitySize(size_t n) {
959   IntTable t;
960   t.reserve(n);
961   for (size_t i = 0; i != n; ++i) t.emplace(i);
962   const size_t c = t.bucket_count();
963   while (c == t.bucket_count()) t.emplace(n++);
964   return t.size() - 1;
965 }
966 
967 struct Modulo1000Hash {
operator ()absl::container_internal::__anon0a0f3e1e0111::Modulo1000Hash968   size_t operator()(int x) const { return x % 1000; }
969 };
970 
971 struct Modulo1000HashTable
972     : public raw_hash_set<IntPolicy, Modulo1000Hash, std::equal_to<int>,
973                           std::allocator<int>> {};
974 
975 // Test that rehash with no resize happen in case of many deleted slots.
TEST(Table,RehashWithNoResize)976 TEST(Table, RehashWithNoResize) {
977   if (SwisstableGenerationsEnabled()) {
978     GTEST_SKIP() << "Generations being enabled causes extra rehashes.";
979   }
980 
981   Modulo1000HashTable t;
982   // Adding the same length (and the same hash) strings
983   // to have at least kMinFullGroups groups
984   // with Group::kWidth collisions. Then fill up to MaxDensitySize;
985   const size_t kMinFullGroups = 7;
986   std::vector<int> keys;
987   for (size_t i = 0; i < MaxDensitySize(Group::kWidth * kMinFullGroups); ++i) {
988     int k = i * 1000;
989     t.emplace(k);
990     keys.push_back(k);
991   }
992   const size_t capacity = t.capacity();
993 
994   // Remove elements from all groups except the first and the last one.
995   // All elements removed from full groups will be marked as ctrl_t::kDeleted.
996   const size_t erase_begin = Group::kWidth / 2;
997   const size_t erase_end = (t.size() / Group::kWidth - 1) * Group::kWidth;
998   for (size_t i = erase_begin; i < erase_end; ++i) {
999     EXPECT_EQ(1, t.erase(keys[i])) << i;
1000   }
1001   keys.erase(keys.begin() + erase_begin, keys.begin() + erase_end);
1002 
1003   auto last_key = keys.back();
1004   size_t last_key_num_probes = GetHashtableDebugNumProbes(t, last_key);
1005 
1006   // Make sure that we have to make a lot of probes for last key.
1007   ASSERT_GT(last_key_num_probes, kMinFullGroups);
1008 
1009   int x = 1;
1010   // Insert and erase one element, before inplace rehash happen.
1011   while (last_key_num_probes == GetHashtableDebugNumProbes(t, last_key)) {
1012     t.emplace(x);
1013     ASSERT_EQ(capacity, t.capacity());
1014     // All elements should be there.
1015     ASSERT_TRUE(t.find(x) != t.end()) << x;
1016     for (const auto& k : keys) {
1017       ASSERT_TRUE(t.find(k) != t.end()) << k;
1018     }
1019     t.erase(x);
1020     ++x;
1021   }
1022 }
1023 
TEST(Table,InsertEraseStressTest)1024 TEST(Table, InsertEraseStressTest) {
1025   IntTable t;
1026   const size_t kMinElementCount = 250;
1027   std::deque<int> keys;
1028   size_t i = 0;
1029   for (; i < MaxDensitySize(kMinElementCount); ++i) {
1030     t.emplace(i);
1031     keys.push_back(i);
1032   }
1033   const size_t kNumIterations = 1000000;
1034   for (; i < kNumIterations; ++i) {
1035     ASSERT_EQ(1, t.erase(keys.front()));
1036     keys.pop_front();
1037     t.emplace(i);
1038     keys.push_back(i);
1039   }
1040 }
1041 
TEST(Table,InsertOverloads)1042 TEST(Table, InsertOverloads) {
1043   StringTable t;
1044   // These should all trigger the insert(init_type) overload.
1045   t.insert({{}, {}});
1046   t.insert({"ABC", {}});
1047   t.insert({"DEF", "!!!"});
1048 
1049   EXPECT_THAT(t, UnorderedElementsAre(Pair("", ""), Pair("ABC", ""),
1050                                       Pair("DEF", "!!!")));
1051 }
1052 
TEST(Table,LargeTable)1053 TEST(Table, LargeTable) {
1054   IntTable t;
1055   for (int64_t i = 0; i != 100000; ++i) t.emplace(i << 40);
1056   for (int64_t i = 0; i != 100000; ++i) ASSERT_EQ(i << 40, *t.find(i << 40));
1057 }
1058 
1059 // Timeout if copy is quadratic as it was in Rust.
TEST(Table,EnsureNonQuadraticAsInRust)1060 TEST(Table, EnsureNonQuadraticAsInRust) {
1061   static const size_t kLargeSize = 1 << 15;
1062 
1063   IntTable t;
1064   for (size_t i = 0; i != kLargeSize; ++i) {
1065     t.insert(i);
1066   }
1067 
1068   // If this is quadratic, the test will timeout.
1069   IntTable t2;
1070   for (const auto& entry : t) t2.insert(entry);
1071 }
1072 
TEST(Table,ClearBug)1073 TEST(Table, ClearBug) {
1074   if (SwisstableGenerationsEnabled()) {
1075     GTEST_SKIP() << "Generations being enabled causes extra rehashes.";
1076   }
1077 
1078   IntTable t;
1079   constexpr size_t capacity = container_internal::Group::kWidth - 1;
1080   constexpr size_t max_size = capacity / 2 + 1;
1081   for (size_t i = 0; i < max_size; ++i) {
1082     t.insert(i);
1083   }
1084   ASSERT_EQ(capacity, t.capacity());
1085   intptr_t original = reinterpret_cast<intptr_t>(&*t.find(2));
1086   t.clear();
1087   ASSERT_EQ(capacity, t.capacity());
1088   for (size_t i = 0; i < max_size; ++i) {
1089     t.insert(i);
1090   }
1091   ASSERT_EQ(capacity, t.capacity());
1092   intptr_t second = reinterpret_cast<intptr_t>(&*t.find(2));
1093   // We are checking that original and second are close enough to each other
1094   // that they are probably still in the same group.  This is not strictly
1095   // guaranteed.
1096   EXPECT_LT(static_cast<size_t>(std::abs(original - second)),
1097             capacity * sizeof(IntTable::value_type));
1098 }
1099 
TEST(Table,Erase)1100 TEST(Table, Erase) {
1101   IntTable t;
1102   EXPECT_TRUE(t.find(0) == t.end());
1103   auto res = t.emplace(0);
1104   EXPECT_TRUE(res.second);
1105   EXPECT_EQ(1, t.size());
1106   t.erase(res.first);
1107   EXPECT_EQ(0, t.size());
1108   EXPECT_TRUE(t.find(0) == t.end());
1109 }
1110 
TEST(Table,EraseMaintainsValidIterator)1111 TEST(Table, EraseMaintainsValidIterator) {
1112   IntTable t;
1113   const int kNumElements = 100;
1114   for (int i = 0; i < kNumElements; i ++) {
1115     EXPECT_TRUE(t.emplace(i).second);
1116   }
1117   EXPECT_EQ(t.size(), kNumElements);
1118 
1119   int num_erase_calls = 0;
1120   auto it = t.begin();
1121   while (it != t.end()) {
1122     t.erase(it++);
1123     num_erase_calls++;
1124   }
1125 
1126   EXPECT_TRUE(t.empty());
1127   EXPECT_EQ(num_erase_calls, kNumElements);
1128 }
1129 
TEST(Table,EraseBeginEnd)1130 TEST(Table, EraseBeginEnd) {
1131   IntTable t;
1132   for (int i = 0; i < 10; ++i) t.insert(i);
1133   EXPECT_EQ(t.size(), 10);
1134   t.erase(t.begin(), t.end());
1135   EXPECT_EQ(t.size(), 0);
1136 }
1137 
1138 // Collect N bad keys by following algorithm:
1139 // 1. Create an empty table and reserve it to 2 * N.
1140 // 2. Insert N random elements.
1141 // 3. Take first Group::kWidth - 1 to bad_keys array.
1142 // 4. Clear the table without resize.
1143 // 5. Go to point 2 while N keys not collected
CollectBadMergeKeys(size_t N)1144 std::vector<int64_t> CollectBadMergeKeys(size_t N) {
1145   static constexpr int kGroupSize = Group::kWidth - 1;
1146 
1147   auto topk_range = [](size_t b, size_t e,
1148                        IntTable* t) -> std::vector<int64_t> {
1149     for (size_t i = b; i != e; ++i) {
1150       t->emplace(i);
1151     }
1152     std::vector<int64_t> res;
1153     res.reserve(kGroupSize);
1154     auto it = t->begin();
1155     for (size_t i = b; i != e && i != b + kGroupSize; ++i, ++it) {
1156       res.push_back(*it);
1157     }
1158     return res;
1159   };
1160 
1161   std::vector<int64_t> bad_keys;
1162   bad_keys.reserve(N);
1163   IntTable t;
1164   t.reserve(N * 2);
1165 
1166   for (size_t b = 0; bad_keys.size() < N; b += N) {
1167     auto keys = topk_range(b, b + N, &t);
1168     bad_keys.insert(bad_keys.end(), keys.begin(), keys.end());
1169     t.erase(t.begin(), t.end());
1170     EXPECT_TRUE(t.empty());
1171   }
1172   return bad_keys;
1173 }
1174 
1175 struct ProbeStats {
1176   // Number of elements with specific probe length over all tested tables.
1177   std::vector<size_t> all_probes_histogram;
1178   // Ratios total_probe_length/size for every tested table.
1179   std::vector<double> single_table_ratios;
1180 
1181   // Average ratio total_probe_length/size over tables.
AvgRatioabsl::container_internal::__anon0a0f3e1e0111::ProbeStats1182   double AvgRatio() const {
1183     return std::accumulate(single_table_ratios.begin(),
1184                            single_table_ratios.end(), 0.0) /
1185            single_table_ratios.size();
1186   }
1187 
1188   // Maximum ratio total_probe_length/size over tables.
MaxRatioabsl::container_internal::__anon0a0f3e1e0111::ProbeStats1189   double MaxRatio() const {
1190     return *std::max_element(single_table_ratios.begin(),
1191                              single_table_ratios.end());
1192   }
1193 
1194   // Percentile ratio total_probe_length/size over tables.
PercentileRatioabsl::container_internal::__anon0a0f3e1e0111::ProbeStats1195   double PercentileRatio(double Percentile = 0.95) const {
1196     auto r = single_table_ratios;
1197     auto mid = r.begin() + static_cast<size_t>(r.size() * Percentile);
1198     if (mid != r.end()) {
1199       std::nth_element(r.begin(), mid, r.end());
1200       return *mid;
1201     } else {
1202       return MaxRatio();
1203     }
1204   }
1205 
1206   // Maximum probe length over all elements and all tables.
MaxProbeabsl::container_internal::__anon0a0f3e1e0111::ProbeStats1207   size_t MaxProbe() const { return all_probes_histogram.size(); }
1208 
1209   // Fraction of elements with specified probe length.
ProbeNormalizedHistogramabsl::container_internal::__anon0a0f3e1e0111::ProbeStats1210   std::vector<double> ProbeNormalizedHistogram() const {
1211     double total_elements = std::accumulate(all_probes_histogram.begin(),
1212                                             all_probes_histogram.end(), 0ull);
1213     std::vector<double> res;
1214     for (size_t p : all_probes_histogram) {
1215       res.push_back(p / total_elements);
1216     }
1217     return res;
1218   }
1219 
PercentileProbeabsl::container_internal::__anon0a0f3e1e0111::ProbeStats1220   size_t PercentileProbe(double Percentile = 0.99) const {
1221     size_t idx = 0;
1222     for (double p : ProbeNormalizedHistogram()) {
1223       if (Percentile > p) {
1224         Percentile -= p;
1225         ++idx;
1226       } else {
1227         return idx;
1228       }
1229     }
1230     return idx;
1231   }
1232 
operator <<(std::ostream & out,const ProbeStats & s)1233   friend std::ostream& operator<<(std::ostream& out, const ProbeStats& s) {
1234     out << "{AvgRatio:" << s.AvgRatio() << ", MaxRatio:" << s.MaxRatio()
1235         << ", PercentileRatio:" << s.PercentileRatio()
1236         << ", MaxProbe:" << s.MaxProbe() << ", Probes=[";
1237     for (double p : s.ProbeNormalizedHistogram()) {
1238       out << p << ",";
1239     }
1240     out << "]}";
1241 
1242     return out;
1243   }
1244 };
1245 
1246 struct ExpectedStats {
1247   double avg_ratio;
1248   double max_ratio;
1249   std::vector<std::pair<double, double>> pecentile_ratios;
1250   std::vector<std::pair<double, double>> pecentile_probes;
1251 
operator <<(std::ostream & out,const ExpectedStats & s)1252   friend std::ostream& operator<<(std::ostream& out, const ExpectedStats& s) {
1253     out << "{AvgRatio:" << s.avg_ratio << ", MaxRatio:" << s.max_ratio
1254         << ", PercentileRatios: [";
1255     for (auto el : s.pecentile_ratios) {
1256       out << el.first << ":" << el.second << ", ";
1257     }
1258     out << "], PercentileProbes: [";
1259     for (auto el : s.pecentile_probes) {
1260       out << el.first << ":" << el.second << ", ";
1261     }
1262     out << "]}";
1263 
1264     return out;
1265   }
1266 };
1267 
VerifyStats(size_t size,const ExpectedStats & exp,const ProbeStats & stats)1268 void VerifyStats(size_t size, const ExpectedStats& exp,
1269                  const ProbeStats& stats) {
1270   EXPECT_LT(stats.AvgRatio(), exp.avg_ratio) << size << " " << stats;
1271   EXPECT_LT(stats.MaxRatio(), exp.max_ratio) << size << " " << stats;
1272   for (auto pr : exp.pecentile_ratios) {
1273     EXPECT_LE(stats.PercentileRatio(pr.first), pr.second)
1274         << size << " " << pr.first << " " << stats;
1275   }
1276 
1277   for (auto pr : exp.pecentile_probes) {
1278     EXPECT_LE(stats.PercentileProbe(pr.first), pr.second)
1279         << size << " " << pr.first << " " << stats;
1280   }
1281 }
1282 
1283 using ProbeStatsPerSize = std::map<size_t, ProbeStats>;
1284 
1285 // Collect total ProbeStats on num_iters iterations of the following algorithm:
1286 // 1. Create new table and reserve it to keys.size() * 2
1287 // 2. Insert all keys xored with seed
1288 // 3. Collect ProbeStats from final table.
CollectProbeStatsOnKeysXoredWithSeed(const std::vector<int64_t> & keys,size_t num_iters)1289 ProbeStats CollectProbeStatsOnKeysXoredWithSeed(
1290     const std::vector<int64_t>& keys, size_t num_iters) {
1291   const size_t reserve_size = keys.size() * 2;
1292 
1293   ProbeStats stats;
1294 
1295   int64_t seed = 0x71b1a19b907d6e33;
1296   while (num_iters--) {
1297     seed = static_cast<int64_t>(static_cast<uint64_t>(seed) * 17 + 13);
1298     IntTable t1;
1299     t1.reserve(reserve_size);
1300     for (const auto& key : keys) {
1301       t1.emplace(key ^ seed);
1302     }
1303 
1304     auto probe_histogram = GetHashtableDebugNumProbesHistogram(t1);
1305     stats.all_probes_histogram.resize(
1306         std::max(stats.all_probes_histogram.size(), probe_histogram.size()));
1307     std::transform(probe_histogram.begin(), probe_histogram.end(),
1308                    stats.all_probes_histogram.begin(),
1309                    stats.all_probes_histogram.begin(), std::plus<size_t>());
1310 
1311     size_t total_probe_seq_length = 0;
1312     for (size_t i = 0; i < probe_histogram.size(); ++i) {
1313       total_probe_seq_length += i * probe_histogram[i];
1314     }
1315     stats.single_table_ratios.push_back(total_probe_seq_length * 1.0 /
1316                                         keys.size());
1317     t1.erase(t1.begin(), t1.end());
1318   }
1319   return stats;
1320 }
1321 
XorSeedExpectedStats()1322 ExpectedStats XorSeedExpectedStats() {
1323   constexpr bool kRandomizesInserts =
1324 #ifdef NDEBUG
1325       false;
1326 #else   // NDEBUG
1327       true;
1328 #endif  // NDEBUG
1329 
1330   // The effective load factor is larger in non-opt mode because we insert
1331   // elements out of order.
1332   switch (container_internal::Group::kWidth) {
1333     case 8:
1334       if (kRandomizesInserts) {
1335   return {0.05,
1336           1.0,
1337           {{0.95, 0.5}},
1338           {{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}};
1339       } else {
1340   return {0.05,
1341           2.0,
1342           {{0.95, 0.1}},
1343           {{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}};
1344       }
1345     case 16:
1346       if (kRandomizesInserts) {
1347         return {0.1,
1348                 2.0,
1349                 {{0.95, 0.1}},
1350                 {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}};
1351       } else {
1352         return {0.05,
1353                 1.0,
1354                 {{0.95, 0.05}},
1355                 {{0.95, 0}, {0.99, 1}, {0.999, 4}, {0.9999, 10}}};
1356       }
1357   }
1358   LOG(FATAL) << "Unknown Group width";
1359   return {};
1360 }
1361 
1362 // TODO(b/80415403): Figure out why this test is so flaky, esp. on MSVC
TEST(Table,DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength)1363 TEST(Table, DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength) {
1364   ProbeStatsPerSize stats;
1365   std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10};
1366   for (size_t size : sizes) {
1367     stats[size] =
1368         CollectProbeStatsOnKeysXoredWithSeed(CollectBadMergeKeys(size), 200);
1369   }
1370   auto expected = XorSeedExpectedStats();
1371   for (size_t size : sizes) {
1372     auto& stat = stats[size];
1373     VerifyStats(size, expected, stat);
1374     LOG(INFO) << size << " " << stat;
1375   }
1376 }
1377 
1378 // Collect total ProbeStats on num_iters iterations of the following algorithm:
1379 // 1. Create new table
1380 // 2. Select 10% of keys and insert 10 elements key * 17 + j * 13
1381 // 3. Collect ProbeStats from final table
CollectProbeStatsOnLinearlyTransformedKeys(const std::vector<int64_t> & keys,size_t num_iters)1382 ProbeStats CollectProbeStatsOnLinearlyTransformedKeys(
1383     const std::vector<int64_t>& keys, size_t num_iters) {
1384   ProbeStats stats;
1385 
1386   std::random_device rd;
1387   std::mt19937 rng(rd());
1388   auto linear_transform = [](size_t x, size_t y) { return x * 17 + y * 13; };
1389   std::uniform_int_distribution<size_t> dist(0, keys.size()-1);
1390   while (num_iters--) {
1391     IntTable t1;
1392     size_t num_keys = keys.size() / 10;
1393     size_t start = dist(rng);
1394     for (size_t i = 0; i != num_keys; ++i) {
1395       for (size_t j = 0; j != 10; ++j) {
1396         t1.emplace(linear_transform(keys[(i + start) % keys.size()], j));
1397       }
1398     }
1399 
1400     auto probe_histogram = GetHashtableDebugNumProbesHistogram(t1);
1401     stats.all_probes_histogram.resize(
1402         std::max(stats.all_probes_histogram.size(), probe_histogram.size()));
1403     std::transform(probe_histogram.begin(), probe_histogram.end(),
1404                    stats.all_probes_histogram.begin(),
1405                    stats.all_probes_histogram.begin(), std::plus<size_t>());
1406 
1407     size_t total_probe_seq_length = 0;
1408     for (size_t i = 0; i < probe_histogram.size(); ++i) {
1409       total_probe_seq_length += i * probe_histogram[i];
1410     }
1411     stats.single_table_ratios.push_back(total_probe_seq_length * 1.0 /
1412                                         t1.size());
1413     t1.erase(t1.begin(), t1.end());
1414   }
1415   return stats;
1416 }
1417 
LinearTransformExpectedStats()1418 ExpectedStats LinearTransformExpectedStats() {
1419   constexpr bool kRandomizesInserts =
1420 #ifdef NDEBUG
1421       false;
1422 #else   // NDEBUG
1423       true;
1424 #endif  // NDEBUG
1425 
1426   // The effective load factor is larger in non-opt mode because we insert
1427   // elements out of order.
1428   switch (container_internal::Group::kWidth) {
1429     case 8:
1430       if (kRandomizesInserts) {
1431         return {0.1,
1432                 0.5,
1433                 {{0.95, 0.3}},
1434                 {{0.95, 0}, {0.99, 1}, {0.999, 8}, {0.9999, 15}}};
1435       } else {
1436         return {0.4,
1437                 0.6,
1438                 {{0.95, 0.5}},
1439                 {{0.95, 1}, {0.99, 14}, {0.999, 23}, {0.9999, 26}}};
1440       }
1441     case 16:
1442       if (kRandomizesInserts) {
1443         return {0.1,
1444                 0.4,
1445                 {{0.95, 0.3}},
1446                 {{0.95, 1}, {0.99, 2}, {0.999, 9}, {0.9999, 15}}};
1447       } else {
1448         return {0.05,
1449                 0.2,
1450                 {{0.95, 0.1}},
1451                 {{0.95, 0}, {0.99, 1}, {0.999, 6}, {0.9999, 10}}};
1452       }
1453   }
1454   LOG(FATAL) << "Unknown Group width";
1455   return {};
1456 }
1457 
1458 // TODO(b/80415403): Figure out why this test is so flaky.
TEST(Table,DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength)1459 TEST(Table, DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength) {
1460   ProbeStatsPerSize stats;
1461   std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10};
1462   for (size_t size : sizes) {
1463     stats[size] = CollectProbeStatsOnLinearlyTransformedKeys(
1464         CollectBadMergeKeys(size), 300);
1465   }
1466   auto expected = LinearTransformExpectedStats();
1467   for (size_t size : sizes) {
1468     auto& stat = stats[size];
1469     VerifyStats(size, expected, stat);
1470     LOG(INFO) << size << " " << stat;
1471   }
1472 }
1473 
TEST(Table,EraseCollision)1474 TEST(Table, EraseCollision) {
1475   BadTable t;
1476 
1477   // 1 2 3
1478   t.emplace(1);
1479   t.emplace(2);
1480   t.emplace(3);
1481   EXPECT_THAT(*t.find(1), 1);
1482   EXPECT_THAT(*t.find(2), 2);
1483   EXPECT_THAT(*t.find(3), 3);
1484   EXPECT_EQ(3, t.size());
1485 
1486   // 1 DELETED 3
1487   t.erase(t.find(2));
1488   EXPECT_THAT(*t.find(1), 1);
1489   EXPECT_TRUE(t.find(2) == t.end());
1490   EXPECT_THAT(*t.find(3), 3);
1491   EXPECT_EQ(2, t.size());
1492 
1493   // DELETED DELETED 3
1494   t.erase(t.find(1));
1495   EXPECT_TRUE(t.find(1) == t.end());
1496   EXPECT_TRUE(t.find(2) == t.end());
1497   EXPECT_THAT(*t.find(3), 3);
1498   EXPECT_EQ(1, t.size());
1499 
1500   // DELETED DELETED DELETED
1501   t.erase(t.find(3));
1502   EXPECT_TRUE(t.find(1) == t.end());
1503   EXPECT_TRUE(t.find(2) == t.end());
1504   EXPECT_TRUE(t.find(3) == t.end());
1505   EXPECT_EQ(0, t.size());
1506 }
1507 
TEST(Table,EraseInsertProbing)1508 TEST(Table, EraseInsertProbing) {
1509   BadTable t(100);
1510 
1511   // 1 2 3 4
1512   t.emplace(1);
1513   t.emplace(2);
1514   t.emplace(3);
1515   t.emplace(4);
1516 
1517   // 1 DELETED 3 DELETED
1518   t.erase(t.find(2));
1519   t.erase(t.find(4));
1520 
1521   // 1 10 3 11 12
1522   t.emplace(10);
1523   t.emplace(11);
1524   t.emplace(12);
1525 
1526   EXPECT_EQ(5, t.size());
1527   EXPECT_THAT(t, UnorderedElementsAre(1, 10, 3, 11, 12));
1528 }
1529 
TEST(Table,Clear)1530 TEST(Table, Clear) {
1531   IntTable t;
1532   EXPECT_TRUE(t.find(0) == t.end());
1533   t.clear();
1534   EXPECT_TRUE(t.find(0) == t.end());
1535   auto res = t.emplace(0);
1536   EXPECT_TRUE(res.second);
1537   EXPECT_EQ(1, t.size());
1538   t.clear();
1539   EXPECT_EQ(0, t.size());
1540   EXPECT_TRUE(t.find(0) == t.end());
1541 }
1542 
TEST(Table,Swap)1543 TEST(Table, Swap) {
1544   IntTable t;
1545   EXPECT_TRUE(t.find(0) == t.end());
1546   auto res = t.emplace(0);
1547   EXPECT_TRUE(res.second);
1548   EXPECT_EQ(1, t.size());
1549   IntTable u;
1550   t.swap(u);
1551   EXPECT_EQ(0, t.size());
1552   EXPECT_EQ(1, u.size());
1553   EXPECT_TRUE(t.find(0) == t.end());
1554   EXPECT_THAT(*u.find(0), 0);
1555 }
1556 
TEST(Table,Rehash)1557 TEST(Table, Rehash) {
1558   IntTable t;
1559   EXPECT_TRUE(t.find(0) == t.end());
1560   t.emplace(0);
1561   t.emplace(1);
1562   EXPECT_EQ(2, t.size());
1563   t.rehash(128);
1564   EXPECT_EQ(2, t.size());
1565   EXPECT_THAT(*t.find(0), 0);
1566   EXPECT_THAT(*t.find(1), 1);
1567 }
1568 
TEST(Table,RehashDoesNotRehashWhenNotNecessary)1569 TEST(Table, RehashDoesNotRehashWhenNotNecessary) {
1570   IntTable t;
1571   t.emplace(0);
1572   t.emplace(1);
1573   auto* p = &*t.find(0);
1574   t.rehash(1);
1575   EXPECT_EQ(p, &*t.find(0));
1576 }
1577 
TEST(Table,RehashZeroDoesNotAllocateOnEmptyTable)1578 TEST(Table, RehashZeroDoesNotAllocateOnEmptyTable) {
1579   IntTable t;
1580   t.rehash(0);
1581   EXPECT_EQ(0, t.bucket_count());
1582 }
1583 
TEST(Table,RehashZeroDeallocatesEmptyTable)1584 TEST(Table, RehashZeroDeallocatesEmptyTable) {
1585   IntTable t;
1586   t.emplace(0);
1587   t.clear();
1588   EXPECT_NE(0, t.bucket_count());
1589   t.rehash(0);
1590   EXPECT_EQ(0, t.bucket_count());
1591 }
1592 
TEST(Table,RehashZeroForcesRehash)1593 TEST(Table, RehashZeroForcesRehash) {
1594   IntTable t;
1595   t.emplace(0);
1596   t.emplace(1);
1597   auto* p = &*t.find(0);
1598   t.rehash(0);
1599   EXPECT_NE(p, &*t.find(0));
1600 }
1601 
TEST(Table,ConstructFromInitList)1602 TEST(Table, ConstructFromInitList) {
1603   using P = std::pair<std::string, std::string>;
1604   struct Q {
1605     operator P() const { return {}; }  // NOLINT
1606   };
1607   StringTable t = {P(), Q(), {}, {{}, {}}};
1608 }
1609 
TEST(Table,CopyConstruct)1610 TEST(Table, CopyConstruct) {
1611   IntTable t;
1612   t.emplace(0);
1613   EXPECT_EQ(1, t.size());
1614   {
1615     IntTable u(t);
1616     EXPECT_EQ(1, u.size());
1617     EXPECT_THAT(*u.find(0), 0);
1618   }
1619   {
1620     IntTable u{t};
1621     EXPECT_EQ(1, u.size());
1622     EXPECT_THAT(*u.find(0), 0);
1623   }
1624   {
1625     IntTable u = t;
1626     EXPECT_EQ(1, u.size());
1627     EXPECT_THAT(*u.find(0), 0);
1628   }
1629 }
1630 
TEST(Table,CopyConstructWithAlloc)1631 TEST(Table, CopyConstructWithAlloc) {
1632   StringTable t;
1633   t.emplace("a", "b");
1634   EXPECT_EQ(1, t.size());
1635   StringTable u(t, Alloc<std::pair<std::string, std::string>>());
1636   EXPECT_EQ(1, u.size());
1637   EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1638 }
1639 
1640 struct ExplicitAllocIntTable
1641     : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
1642                    std::equal_to<int64_t>, Alloc<int64_t>> {
1643   ExplicitAllocIntTable() = default;
1644 };
1645 
TEST(Table,AllocWithExplicitCtor)1646 TEST(Table, AllocWithExplicitCtor) {
1647   ExplicitAllocIntTable t;
1648   EXPECT_EQ(0, t.size());
1649 }
1650 
TEST(Table,MoveConstruct)1651 TEST(Table, MoveConstruct) {
1652   {
1653     StringTable t;
1654     t.emplace("a", "b");
1655     EXPECT_EQ(1, t.size());
1656 
1657     StringTable u(std::move(t));
1658     EXPECT_EQ(1, u.size());
1659     EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1660   }
1661   {
1662     StringTable t;
1663     t.emplace("a", "b");
1664     EXPECT_EQ(1, t.size());
1665 
1666     StringTable u{std::move(t)};
1667     EXPECT_EQ(1, u.size());
1668     EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1669   }
1670   {
1671     StringTable t;
1672     t.emplace("a", "b");
1673     EXPECT_EQ(1, t.size());
1674 
1675     StringTable u = std::move(t);
1676     EXPECT_EQ(1, u.size());
1677     EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1678   }
1679 }
1680 
TEST(Table,MoveConstructWithAlloc)1681 TEST(Table, MoveConstructWithAlloc) {
1682   StringTable t;
1683   t.emplace("a", "b");
1684   EXPECT_EQ(1, t.size());
1685   StringTable u(std::move(t), Alloc<std::pair<std::string, std::string>>());
1686   EXPECT_EQ(1, u.size());
1687   EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1688 }
1689 
TEST(Table,CopyAssign)1690 TEST(Table, CopyAssign) {
1691   StringTable t;
1692   t.emplace("a", "b");
1693   EXPECT_EQ(1, t.size());
1694   StringTable u;
1695   u = t;
1696   EXPECT_EQ(1, u.size());
1697   EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1698 }
1699 
TEST(Table,CopySelfAssign)1700 TEST(Table, CopySelfAssign) {
1701   StringTable t;
1702   t.emplace("a", "b");
1703   EXPECT_EQ(1, t.size());
1704   t = *&t;
1705   EXPECT_EQ(1, t.size());
1706   EXPECT_THAT(*t.find("a"), Pair("a", "b"));
1707 }
1708 
TEST(Table,MoveAssign)1709 TEST(Table, MoveAssign) {
1710   StringTable t;
1711   t.emplace("a", "b");
1712   EXPECT_EQ(1, t.size());
1713   StringTable u;
1714   u = std::move(t);
1715   EXPECT_EQ(1, u.size());
1716   EXPECT_THAT(*u.find("a"), Pair("a", "b"));
1717 }
1718 
TEST(Table,Equality)1719 TEST(Table, Equality) {
1720   StringTable t;
1721   std::vector<std::pair<std::string, std::string>> v = {{"a", "b"},
1722                                                         {"aa", "bb"}};
1723   t.insert(std::begin(v), std::end(v));
1724   StringTable u = t;
1725   EXPECT_EQ(u, t);
1726 }
1727 
TEST(Table,Equality2)1728 TEST(Table, Equality2) {
1729   StringTable t;
1730   std::vector<std::pair<std::string, std::string>> v1 = {{"a", "b"},
1731                                                          {"aa", "bb"}};
1732   t.insert(std::begin(v1), std::end(v1));
1733   StringTable u;
1734   std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"},
1735                                                          {"aa", "aa"}};
1736   u.insert(std::begin(v2), std::end(v2));
1737   EXPECT_NE(u, t);
1738 }
1739 
TEST(Table,Equality3)1740 TEST(Table, Equality3) {
1741   StringTable t;
1742   std::vector<std::pair<std::string, std::string>> v1 = {{"b", "b"},
1743                                                          {"bb", "bb"}};
1744   t.insert(std::begin(v1), std::end(v1));
1745   StringTable u;
1746   std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"},
1747                                                          {"aa", "aa"}};
1748   u.insert(std::begin(v2), std::end(v2));
1749   EXPECT_NE(u, t);
1750 }
1751 
TEST(Table,NumDeletedRegression)1752 TEST(Table, NumDeletedRegression) {
1753   IntTable t;
1754   t.emplace(0);
1755   t.erase(t.find(0));
1756   // construct over a deleted slot.
1757   t.emplace(0);
1758   t.clear();
1759 }
1760 
TEST(Table,FindFullDeletedRegression)1761 TEST(Table, FindFullDeletedRegression) {
1762   IntTable t;
1763   for (int i = 0; i < 1000; ++i) {
1764     t.emplace(i);
1765     t.erase(t.find(i));
1766   }
1767   EXPECT_EQ(0, t.size());
1768 }
1769 
TEST(Table,ReplacingDeletedSlotDoesNotRehash)1770 TEST(Table, ReplacingDeletedSlotDoesNotRehash) {
1771   size_t n;
1772   {
1773     // Compute n such that n is the maximum number of elements before rehash.
1774     IntTable t;
1775     t.emplace(0);
1776     size_t c = t.bucket_count();
1777     for (n = 1; c == t.bucket_count(); ++n) t.emplace(n);
1778     --n;
1779   }
1780   IntTable t;
1781   t.rehash(n);
1782   const size_t c = t.bucket_count();
1783   for (size_t i = 0; i != n; ++i) t.emplace(i);
1784   EXPECT_EQ(c, t.bucket_count()) << "rehashing threshold = " << n;
1785   t.erase(0);
1786   t.emplace(0);
1787   EXPECT_EQ(c, t.bucket_count()) << "rehashing threshold = " << n;
1788 }
1789 
TEST(Table,NoThrowMoveConstruct)1790 TEST(Table, NoThrowMoveConstruct) {
1791   ASSERT_TRUE(
1792       std::is_nothrow_copy_constructible<absl::Hash<absl::string_view>>::value);
1793   ASSERT_TRUE(std::is_nothrow_copy_constructible<
1794               std::equal_to<absl::string_view>>::value);
1795   ASSERT_TRUE(std::is_nothrow_copy_constructible<std::allocator<int>>::value);
1796   EXPECT_TRUE(std::is_nothrow_move_constructible<StringTable>::value);
1797 }
1798 
TEST(Table,NoThrowMoveAssign)1799 TEST(Table, NoThrowMoveAssign) {
1800   ASSERT_TRUE(
1801       std::is_nothrow_move_assignable<absl::Hash<absl::string_view>>::value);
1802   ASSERT_TRUE(
1803       std::is_nothrow_move_assignable<std::equal_to<absl::string_view>>::value);
1804   ASSERT_TRUE(std::is_nothrow_move_assignable<std::allocator<int>>::value);
1805   ASSERT_TRUE(
1806       absl::allocator_traits<std::allocator<int>>::is_always_equal::value);
1807   EXPECT_TRUE(std::is_nothrow_move_assignable<StringTable>::value);
1808 }
1809 
TEST(Table,NoThrowSwappable)1810 TEST(Table, NoThrowSwappable) {
1811   ASSERT_TRUE(
1812       container_internal::IsNoThrowSwappable<absl::Hash<absl::string_view>>());
1813   ASSERT_TRUE(container_internal::IsNoThrowSwappable<
1814               std::equal_to<absl::string_view>>());
1815   ASSERT_TRUE(container_internal::IsNoThrowSwappable<std::allocator<int>>());
1816   EXPECT_TRUE(container_internal::IsNoThrowSwappable<StringTable>());
1817 }
1818 
TEST(Table,HeterogeneousLookup)1819 TEST(Table, HeterogeneousLookup) {
1820   struct Hash {
1821     size_t operator()(int64_t i) const { return i; }
1822     size_t operator()(double i) const {
1823       ADD_FAILURE();
1824       return i;
1825     }
1826   };
1827   struct Eq {
1828     bool operator()(int64_t a, int64_t b) const { return a == b; }
1829     bool operator()(double a, int64_t b) const {
1830       ADD_FAILURE();
1831       return a == b;
1832     }
1833     bool operator()(int64_t a, double b) const {
1834       ADD_FAILURE();
1835       return a == b;
1836     }
1837     bool operator()(double a, double b) const {
1838       ADD_FAILURE();
1839       return a == b;
1840     }
1841   };
1842 
1843   struct THash {
1844     using is_transparent = void;
1845     size_t operator()(int64_t i) const { return i; }
1846     size_t operator()(double i) const { return i; }
1847   };
1848   struct TEq {
1849     using is_transparent = void;
1850     bool operator()(int64_t a, int64_t b) const { return a == b; }
1851     bool operator()(double a, int64_t b) const { return a == b; }
1852     bool operator()(int64_t a, double b) const { return a == b; }
1853     bool operator()(double a, double b) const { return a == b; }
1854   };
1855 
1856   raw_hash_set<IntPolicy, Hash, Eq, Alloc<int64_t>> s{0, 1, 2};
1857   // It will convert to int64_t before the query.
1858   EXPECT_EQ(1, *s.find(double{1.1}));
1859 
1860   raw_hash_set<IntPolicy, THash, TEq, Alloc<int64_t>> ts{0, 1, 2};
1861   // It will try to use the double, and fail to find the object.
1862   EXPECT_TRUE(ts.find(1.1) == ts.end());
1863 }
1864 
1865 template <class Table>
1866 using CallFind = decltype(std::declval<Table&>().find(17));
1867 
1868 template <class Table>
1869 using CallErase = decltype(std::declval<Table&>().erase(17));
1870 
1871 template <class Table>
1872 using CallExtract = decltype(std::declval<Table&>().extract(17));
1873 
1874 template <class Table>
1875 using CallPrefetch = decltype(std::declval<Table&>().prefetch(17));
1876 
1877 template <class Table>
1878 using CallCount = decltype(std::declval<Table&>().count(17));
1879 
1880 template <template <typename> class C, class Table, class = void>
1881 struct VerifyResultOf : std::false_type {};
1882 
1883 template <template <typename> class C, class Table>
1884 struct VerifyResultOf<C, Table, absl::void_t<C<Table>>> : std::true_type {};
1885 
TEST(Table,HeterogeneousLookupOverloads)1886 TEST(Table, HeterogeneousLookupOverloads) {
1887   using NonTransparentTable =
1888       raw_hash_set<StringPolicy, absl::Hash<absl::string_view>,
1889                    std::equal_to<absl::string_view>, std::allocator<int>>;
1890 
1891   EXPECT_FALSE((VerifyResultOf<CallFind, NonTransparentTable>()));
1892   EXPECT_FALSE((VerifyResultOf<CallErase, NonTransparentTable>()));
1893   EXPECT_FALSE((VerifyResultOf<CallExtract, NonTransparentTable>()));
1894   EXPECT_FALSE((VerifyResultOf<CallPrefetch, NonTransparentTable>()));
1895   EXPECT_FALSE((VerifyResultOf<CallCount, NonTransparentTable>()));
1896 
1897   using TransparentTable = raw_hash_set<
1898       StringPolicy,
1899       absl::container_internal::hash_default_hash<absl::string_view>,
1900       absl::container_internal::hash_default_eq<absl::string_view>,
1901       std::allocator<int>>;
1902 
1903   EXPECT_TRUE((VerifyResultOf<CallFind, TransparentTable>()));
1904   EXPECT_TRUE((VerifyResultOf<CallErase, TransparentTable>()));
1905   EXPECT_TRUE((VerifyResultOf<CallExtract, TransparentTable>()));
1906   EXPECT_TRUE((VerifyResultOf<CallPrefetch, TransparentTable>()));
1907   EXPECT_TRUE((VerifyResultOf<CallCount, TransparentTable>()));
1908 }
1909 
TEST(Iterator,IsDefaultConstructible)1910 TEST(Iterator, IsDefaultConstructible) {
1911   StringTable::iterator i;
1912   EXPECT_TRUE(i == StringTable::iterator());
1913 }
1914 
TEST(ConstIterator,IsDefaultConstructible)1915 TEST(ConstIterator, IsDefaultConstructible) {
1916   StringTable::const_iterator i;
1917   EXPECT_TRUE(i == StringTable::const_iterator());
1918 }
1919 
TEST(Iterator,ConvertsToConstIterator)1920 TEST(Iterator, ConvertsToConstIterator) {
1921   StringTable::iterator i;
1922   EXPECT_TRUE(i == StringTable::const_iterator());
1923 }
1924 
TEST(Iterator,Iterates)1925 TEST(Iterator, Iterates) {
1926   IntTable t;
1927   for (size_t i = 3; i != 6; ++i) EXPECT_TRUE(t.emplace(i).second);
1928   EXPECT_THAT(t, UnorderedElementsAre(3, 4, 5));
1929 }
1930 
TEST(Table,Merge)1931 TEST(Table, Merge) {
1932   StringTable t1, t2;
1933   t1.emplace("0", "-0");
1934   t1.emplace("1", "-1");
1935   t2.emplace("0", "~0");
1936   t2.emplace("2", "~2");
1937 
1938   EXPECT_THAT(t1, UnorderedElementsAre(Pair("0", "-0"), Pair("1", "-1")));
1939   EXPECT_THAT(t2, UnorderedElementsAre(Pair("0", "~0"), Pair("2", "~2")));
1940 
1941   t1.merge(t2);
1942   EXPECT_THAT(t1, UnorderedElementsAre(Pair("0", "-0"), Pair("1", "-1"),
1943                                        Pair("2", "~2")));
1944   EXPECT_THAT(t2, UnorderedElementsAre(Pair("0", "~0")));
1945 }
1946 
TEST(Table,IteratorEmplaceConstructibleRequirement)1947 TEST(Table, IteratorEmplaceConstructibleRequirement) {
1948   struct Value {
1949     explicit Value(absl::string_view view) : value(view) {}
1950     std::string value;
1951 
1952     bool operator==(const Value& other) const { return value == other.value; }
1953   };
1954   struct H {
1955     size_t operator()(const Value& v) const {
1956       return absl::Hash<std::string>{}(v.value);
1957     }
1958   };
1959 
1960   struct Table : raw_hash_set<ValuePolicy<Value>, H, std::equal_to<Value>,
1961                               std::allocator<Value>> {
1962     using Base = typename Table::raw_hash_set;
1963     using Base::Base;
1964   };
1965 
1966   std::string input[3]{"A", "B", "C"};
1967 
1968   Table t(std::begin(input), std::end(input));
1969   EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"}));
1970 
1971   input[0] = "D";
1972   input[1] = "E";
1973   input[2] = "F";
1974   t.insert(std::begin(input), std::end(input));
1975   EXPECT_THAT(t, UnorderedElementsAre(Value{"A"}, Value{"B"}, Value{"C"},
1976                                       Value{"D"}, Value{"E"}, Value{"F"}));
1977 }
1978 
TEST(Nodes,EmptyNodeType)1979 TEST(Nodes, EmptyNodeType) {
1980   using node_type = StringTable::node_type;
1981   node_type n;
1982   EXPECT_FALSE(n);
1983   EXPECT_TRUE(n.empty());
1984 
1985   EXPECT_TRUE((std::is_same<node_type::allocator_type,
1986                             StringTable::allocator_type>::value));
1987 }
1988 
TEST(Nodes,ExtractInsert)1989 TEST(Nodes, ExtractInsert) {
1990   constexpr char k0[] = "Very long string zero.";
1991   constexpr char k1[] = "Very long string one.";
1992   constexpr char k2[] = "Very long string two.";
1993   StringTable t = {{k0, ""}, {k1, ""}, {k2, ""}};
1994   EXPECT_THAT(t,
1995               UnorderedElementsAre(Pair(k0, ""), Pair(k1, ""), Pair(k2, "")));
1996 
1997   auto node = t.extract(k0);
1998   EXPECT_THAT(t, UnorderedElementsAre(Pair(k1, ""), Pair(k2, "")));
1999   EXPECT_TRUE(node);
2000   EXPECT_FALSE(node.empty());
2001 
2002   StringTable t2;
2003   StringTable::insert_return_type res = t2.insert(std::move(node));
2004   EXPECT_TRUE(res.inserted);
2005   EXPECT_THAT(*res.position, Pair(k0, ""));
2006   EXPECT_FALSE(res.node);
2007   EXPECT_THAT(t2, UnorderedElementsAre(Pair(k0, "")));
2008 
2009   // Not there.
2010   EXPECT_THAT(t, UnorderedElementsAre(Pair(k1, ""), Pair(k2, "")));
2011   node = t.extract("Not there!");
2012   EXPECT_THAT(t, UnorderedElementsAre(Pair(k1, ""), Pair(k2, "")));
2013   EXPECT_FALSE(node);
2014 
2015   // Inserting nothing.
2016   res = t2.insert(std::move(node));
2017   EXPECT_FALSE(res.inserted);
2018   EXPECT_EQ(res.position, t2.end());
2019   EXPECT_FALSE(res.node);
2020   EXPECT_THAT(t2, UnorderedElementsAre(Pair(k0, "")));
2021 
2022   t.emplace(k0, "1");
2023   node = t.extract(k0);
2024 
2025   // Insert duplicate.
2026   res = t2.insert(std::move(node));
2027   EXPECT_FALSE(res.inserted);
2028   EXPECT_THAT(*res.position, Pair(k0, ""));
2029   EXPECT_TRUE(res.node);
2030   EXPECT_FALSE(node);  // NOLINT(bugprone-use-after-move)
2031 }
2032 
TEST(Nodes,HintInsert)2033 TEST(Nodes, HintInsert) {
2034   IntTable t = {1, 2, 3};
2035   auto node = t.extract(1);
2036   EXPECT_THAT(t, UnorderedElementsAre(2, 3));
2037   auto it = t.insert(t.begin(), std::move(node));
2038   EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
2039   EXPECT_EQ(*it, 1);
2040   EXPECT_FALSE(node);  // NOLINT(bugprone-use-after-move)
2041 
2042   node = t.extract(2);
2043   EXPECT_THAT(t, UnorderedElementsAre(1, 3));
2044   // reinsert 2 to make the next insert fail.
2045   t.insert(2);
2046   EXPECT_THAT(t, UnorderedElementsAre(1, 2, 3));
2047   it = t.insert(t.begin(), std::move(node));
2048   EXPECT_EQ(*it, 2);
2049   // The node was not emptied by the insert call.
2050   EXPECT_TRUE(node);  // NOLINT(bugprone-use-after-move)
2051 }
2052 
MakeSimpleTable(size_t size)2053 IntTable MakeSimpleTable(size_t size) {
2054   IntTable t;
2055   while (t.size() < size) t.insert(t.size());
2056   return t;
2057 }
2058 
OrderOfIteration(const IntTable & t)2059 std::vector<int> OrderOfIteration(const IntTable& t) {
2060   return {t.begin(), t.end()};
2061 }
2062 
2063 // These IterationOrderChanges tests depend on non-deterministic behavior.
2064 // We are injecting non-determinism from the pointer of the table, but do so in
2065 // a way that only the page matters. We have to retry enough times to make sure
2066 // we are touching different memory pages to cause the ordering to change.
2067 // We also need to keep the old tables around to avoid getting the same memory
2068 // blocks over and over.
TEST(Table,IterationOrderChangesByInstance)2069 TEST(Table, IterationOrderChangesByInstance) {
2070   for (size_t size : {2, 6, 12, 20}) {
2071     const auto reference_table = MakeSimpleTable(size);
2072     const auto reference = OrderOfIteration(reference_table);
2073 
2074     std::vector<IntTable> tables;
2075     bool found_difference = false;
2076     for (int i = 0; !found_difference && i < 5000; ++i) {
2077       tables.push_back(MakeSimpleTable(size));
2078       found_difference = OrderOfIteration(tables.back()) != reference;
2079     }
2080     if (!found_difference) {
2081       FAIL()
2082           << "Iteration order remained the same across many attempts with size "
2083           << size;
2084     }
2085   }
2086 }
2087 
TEST(Table,IterationOrderChangesOnRehash)2088 TEST(Table, IterationOrderChangesOnRehash) {
2089   std::vector<IntTable> garbage;
2090   for (int i = 0; i < 5000; ++i) {
2091     auto t = MakeSimpleTable(20);
2092     const auto reference = OrderOfIteration(t);
2093     // Force rehash to the same size.
2094     t.rehash(0);
2095     auto trial = OrderOfIteration(t);
2096     if (trial != reference) {
2097       // We are done.
2098       return;
2099     }
2100     garbage.push_back(std::move(t));
2101   }
2102   FAIL() << "Iteration order remained the same across many attempts.";
2103 }
2104 
2105 // Verify that pointers are invalidated as soon as a second element is inserted.
2106 // This prevents dependency on pointer stability on small tables.
TEST(Table,UnstablePointers)2107 TEST(Table, UnstablePointers) {
2108   IntTable table;
2109 
2110   const auto addr = [&](int i) {
2111     return reinterpret_cast<uintptr_t>(&*table.find(i));
2112   };
2113 
2114   table.insert(0);
2115   const uintptr_t old_ptr = addr(0);
2116 
2117   // This causes a rehash.
2118   table.insert(1);
2119 
2120   EXPECT_NE(old_ptr, addr(0));
2121 }
2122 
IsAssertEnabled()2123 bool IsAssertEnabled() {
2124   // Use an assert with side-effects to figure out if they are actually enabled.
2125   bool assert_enabled = false;
2126   assert([&]() {  // NOLINT
2127     assert_enabled = true;
2128     return true;
2129   }());
2130   return assert_enabled;
2131 }
2132 
TEST(TableDeathTest,InvalidIteratorAsserts)2133 TEST(TableDeathTest, InvalidIteratorAsserts) {
2134   if (!IsAssertEnabled() && !SwisstableGenerationsEnabled())
2135     GTEST_SKIP() << "Assertions not enabled.";
2136 
2137   IntTable t;
2138   // Extra simple "regexp" as regexp support is highly varied across platforms.
2139   EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()),
2140                             "erase.* called on end.. iterator.");
2141   typename IntTable::iterator iter;
2142   EXPECT_DEATH_IF_SUPPORTED(
2143       ++iter, "operator.* called on default-constructed iterator.");
2144   t.insert(0);
2145   iter = t.begin();
2146   t.erase(iter);
2147   const char* const kErasedDeathMessage =
2148       SwisstableGenerationsEnabled()
2149           ? "operator.* called on invalid iterator.*was likely erased"
2150           : "operator.* called on invalid iterator.*might have been "
2151             "erased.*config=asan";
2152   EXPECT_DEATH_IF_SUPPORTED(++iter, kErasedDeathMessage);
2153 }
2154 
2155 // Invalid iterator use can trigger heap-use-after-free in asan,
2156 // use-of-uninitialized-value in msan, or invalidated iterator assertions.
2157 constexpr const char* kInvalidIteratorDeathMessage =
2158     "heap-use-after-free|use-of-uninitialized-value|invalidated "
2159     "iterator|Invalid iterator|invalid iterator";
2160 
2161 // MSVC doesn't support | in regex.
2162 #if defined(_MSC_VER)
2163 constexpr bool kMsvc = true;
2164 #else
2165 constexpr bool kMsvc = false;
2166 #endif
2167 
TEST(TableDeathTest,IteratorInvalidAssertsEqualityOperator)2168 TEST(TableDeathTest, IteratorInvalidAssertsEqualityOperator) {
2169   if (!IsAssertEnabled() && !SwisstableGenerationsEnabled())
2170     GTEST_SKIP() << "Assertions not enabled.";
2171 
2172   IntTable t;
2173   t.insert(1);
2174   t.insert(2);
2175   t.insert(3);
2176   auto iter1 = t.begin();
2177   auto iter2 = std::next(iter1);
2178   ASSERT_NE(iter1, t.end());
2179   ASSERT_NE(iter2, t.end());
2180   t.erase(iter1);
2181   // Extra simple "regexp" as regexp support is highly varied across platforms.
2182   const char* const kErasedDeathMessage =
2183       SwisstableGenerationsEnabled()
2184           ? "Invalid iterator comparison.*was likely erased"
2185           : "Invalid iterator comparison.*might have been erased.*config=asan";
2186   EXPECT_DEATH_IF_SUPPORTED(void(iter1 == iter2), kErasedDeathMessage);
2187   EXPECT_DEATH_IF_SUPPORTED(void(iter2 != iter1), kErasedDeathMessage);
2188   t.erase(iter2);
2189   EXPECT_DEATH_IF_SUPPORTED(void(iter1 == iter2), kErasedDeathMessage);
2190 
2191   IntTable t1, t2;
2192   t1.insert(0);
2193   t2.insert(0);
2194   iter1 = t1.begin();
2195   iter2 = t2.begin();
2196   const char* const kContainerDiffDeathMessage =
2197       SwisstableGenerationsEnabled()
2198           ? "Invalid iterator comparison.*iterators from different hashtables"
2199           : "Invalid iterator comparison.*may be from different "
2200             ".*containers.*config=asan";
2201   EXPECT_DEATH_IF_SUPPORTED(void(iter1 == iter2), kContainerDiffDeathMessage);
2202   EXPECT_DEATH_IF_SUPPORTED(void(iter2 == iter1), kContainerDiffDeathMessage);
2203 
2204   for (int i = 0; i < 10; ++i) t1.insert(i);
2205   // There should have been a rehash in t1.
2206   if (kMsvc) return;  // MSVC doesn't support | in regex.
2207 
2208   // NOTE(b/293887834): After rehashing, iterators will contain pointers to
2209   // freed memory, which may be detected by ThreadSanitizer.
2210   const char* const kRehashedDeathMessage =
2211       SwisstableGenerationsEnabled()
2212           ? kInvalidIteratorDeathMessage
2213           : "Invalid iterator comparison.*might have rehashed.*config=asan"
2214             "|ThreadSanitizer: heap-use-after-free";
2215   EXPECT_DEATH_IF_SUPPORTED(void(iter1 == t1.begin()), kRehashedDeathMessage);
2216 }
2217 
2218 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
TEST(RawHashSamplerTest,Sample)2219 TEST(RawHashSamplerTest, Sample) {
2220   // Enable the feature even if the prod default is off.
2221   SetHashtablezEnabled(true);
2222   SetHashtablezSampleParameter(100);
2223 
2224   auto& sampler = GlobalHashtablezSampler();
2225   size_t start_size = 0;
2226   absl::flat_hash_set<const HashtablezInfo*> preexisting_info;
2227   start_size += sampler.Iterate([&](const HashtablezInfo& info) {
2228     preexisting_info.insert(&info);
2229     ++start_size;
2230   });
2231 
2232   std::vector<IntTable> tables;
2233   for (int i = 0; i < 1000000; ++i) {
2234     tables.emplace_back();
2235 
2236     const bool do_reserve = (i % 10 > 5);
2237     const bool do_rehash = !do_reserve && (i % 10 > 0);
2238 
2239     if (do_reserve) {
2240       // Don't reserve on all tables.
2241       tables.back().reserve(10 * (i % 10));
2242     }
2243 
2244     tables.back().insert(1);
2245     tables.back().insert(i % 5);
2246 
2247     if (do_rehash) {
2248       // Rehash some other tables.
2249       tables.back().rehash(10 * (i % 10));
2250     }
2251   }
2252   size_t end_size = 0;
2253   absl::flat_hash_map<size_t, int> observed_checksums;
2254   absl::flat_hash_map<ssize_t, int> reservations;
2255   end_size += sampler.Iterate([&](const HashtablezInfo& info) {
2256     if (preexisting_info.count(&info) == 0) {
2257       observed_checksums[info.hashes_bitwise_xor.load(
2258           std::memory_order_relaxed)]++;
2259       reservations[info.max_reserve.load(std::memory_order_relaxed)]++;
2260     }
2261     EXPECT_EQ(info.inline_element_size, sizeof(int64_t));
2262     ++end_size;
2263   });
2264 
2265   EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
2266               0.01, 0.005);
2267   EXPECT_EQ(observed_checksums.size(), 5);
2268   for (const auto& [_, count] : observed_checksums) {
2269     EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.2, 0.05);
2270   }
2271 
2272   EXPECT_EQ(reservations.size(), 10);
2273   for (const auto& [reservation, count] : reservations) {
2274     EXPECT_GE(reservation, 0);
2275     EXPECT_LT(reservation, 100);
2276 
2277     EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.1, 0.05)
2278         << reservation;
2279   }
2280 }
2281 #endif  // ABSL_INTERNAL_HASHTABLEZ_SAMPLE
2282 
TEST(RawHashSamplerTest,DoNotSampleCustomAllocators)2283 TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) {
2284   // Enable the feature even if the prod default is off.
2285   SetHashtablezEnabled(true);
2286   SetHashtablezSampleParameter(100);
2287 
2288   auto& sampler = GlobalHashtablezSampler();
2289   size_t start_size = 0;
2290   start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; });
2291 
2292   std::vector<CustomAllocIntTable> tables;
2293   for (int i = 0; i < 1000000; ++i) {
2294     tables.emplace_back();
2295     tables.back().insert(1);
2296   }
2297   size_t end_size = 0;
2298   end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; });
2299 
2300   EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
2301               0.00, 0.001);
2302 }
2303 
2304 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
TEST(Sanitizer,PoisoningUnused)2305 TEST(Sanitizer, PoisoningUnused) {
2306   IntTable t;
2307   t.reserve(5);
2308   // Insert something to force an allocation.
2309   int64_t& v1 = *t.insert(0).first;
2310 
2311   // Make sure there is something to test.
2312   ASSERT_GT(t.capacity(), 1);
2313 
2314   int64_t* slots = RawHashSetTestOnlyAccess::GetSlots(t);
2315   for (size_t i = 0; i < t.capacity(); ++i) {
2316     EXPECT_EQ(slots + i != &v1, __asan_address_is_poisoned(slots + i));
2317   }
2318 }
2319 
TEST(Sanitizer,PoisoningOnErase)2320 TEST(Sanitizer, PoisoningOnErase) {
2321   IntTable t;
2322   int64_t& v = *t.insert(0).first;
2323 
2324   EXPECT_FALSE(__asan_address_is_poisoned(&v));
2325   t.erase(0);
2326   EXPECT_TRUE(__asan_address_is_poisoned(&v));
2327 }
2328 #endif  // ABSL_HAVE_ADDRESS_SANITIZER
2329 
2330 template <typename T>
2331 class AlignOneTest : public ::testing::Test {};
2332 using AlignOneTestTypes =
2333     ::testing::Types<Uint8Table, MinimumAlignmentUint8Table>;
2334 TYPED_TEST_SUITE(AlignOneTest, AlignOneTestTypes);
2335 
TYPED_TEST(AlignOneTest,AlignOne)2336 TYPED_TEST(AlignOneTest, AlignOne) {
2337   // We previously had a bug in which we were copying a control byte over the
2338   // first slot when alignof(value_type) is 1. We test repeated
2339   // insertions/erases and verify that the behavior is correct.
2340   TypeParam t;
2341   std::unordered_set<uint8_t> verifier;  // NOLINT
2342 
2343   // Do repeated insertions/erases from the table.
2344   for (int64_t i = 0; i < 100000; ++i) {
2345     SCOPED_TRACE(i);
2346     const uint8_t u = (i * -i) & 0xFF;
2347     auto it = t.find(u);
2348     auto verifier_it = verifier.find(u);
2349     if (it == t.end()) {
2350       ASSERT_EQ(verifier_it, verifier.end());
2351       t.insert(u);
2352       verifier.insert(u);
2353     } else {
2354       ASSERT_NE(verifier_it, verifier.end());
2355       t.erase(it);
2356       verifier.erase(verifier_it);
2357     }
2358   }
2359 
2360   EXPECT_EQ(t.size(), verifier.size());
2361   for (uint8_t u : t) {
2362     EXPECT_EQ(verifier.count(u), 1);
2363   }
2364 }
2365 
TEST(Iterator,InvalidUseCrashesWithSanitizers)2366 TEST(Iterator, InvalidUseCrashesWithSanitizers) {
2367   if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2368   if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
2369 
2370   IntTable t;
2371   // Start with 1 element so that `it` is never an end iterator.
2372   t.insert(-1);
2373   for (int i = 0; i < 10; ++i) {
2374     auto it = t.begin();
2375     t.insert(i);
2376     EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
2377     EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()),
2378                               kInvalidIteratorDeathMessage);
2379   }
2380 }
2381 
TEST(Iterator,InvalidUseWithReserveCrashesWithSanitizers)2382 TEST(Iterator, InvalidUseWithReserveCrashesWithSanitizers) {
2383   if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2384   if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
2385 
2386   IntTable t;
2387   t.reserve(10);
2388   t.insert(0);
2389   auto it = t.begin();
2390   // Reserved growth can't rehash.
2391   for (int i = 1; i < 10; ++i) {
2392     t.insert(i);
2393     EXPECT_EQ(*it, 0);
2394   }
2395   // ptr will become invalidated on rehash.
2396   const int64_t* ptr = &*it;
2397   (void)ptr;
2398 
2399   // erase decreases size but does not decrease reserved growth so the next
2400   // insertion still invalidates iterators.
2401   t.erase(0);
2402   // The first insert after reserved growth is 0 is guaranteed to rehash when
2403   // generations are enabled.
2404   t.insert(10);
2405   EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
2406   EXPECT_DEATH_IF_SUPPORTED(void(it == t.begin()),
2407                             kInvalidIteratorDeathMessage);
2408 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
2409   EXPECT_DEATH_IF_SUPPORTED(std::cout << *ptr, "heap-use-after-free");
2410 #endif
2411 }
2412 
TEST(Table,ReservedGrowthUpdatesWhenTableDoesntGrow)2413 TEST(Table, ReservedGrowthUpdatesWhenTableDoesntGrow) {
2414   IntTable t;
2415   for (int i = 0; i < 8; ++i) t.insert(i);
2416   // Want to insert twice without invalidating iterators so reserve.
2417   const size_t cap = t.capacity();
2418   t.reserve(t.size() + 2);
2419   // We want to be testing the case in which the reserve doesn't grow the table.
2420   ASSERT_EQ(cap, t.capacity());
2421   auto it = t.find(0);
2422   t.insert(100);
2423   t.insert(200);
2424   // `it` shouldn't have been invalidated.
2425   EXPECT_EQ(*it, 0);
2426 }
2427 
TEST(Table,EraseBeginEndResetsReservedGrowth)2428 TEST(Table, EraseBeginEndResetsReservedGrowth) {
2429   bool frozen = false;
2430   BadHashFreezableIntTable t{FreezableAlloc<int64_t>(&frozen)};
2431   t.reserve(100);
2432   const size_t cap = t.capacity();
2433   frozen = true;  // no further allocs allowed
2434 
2435   for (int i = 0; i < 10; ++i) {
2436     // Create a long run (hash function returns constant).
2437     for (int j = 0; j < 100; ++j) t.insert(j);
2438     // Erase elements from the middle of the long run, which creates tombstones.
2439     for (int j = 30; j < 60; ++j) t.erase(j);
2440     EXPECT_EQ(t.size(), 70);
2441     EXPECT_EQ(t.capacity(), cap);
2442     ASSERT_EQ(RawHashSetTestOnlyAccess::CountTombstones(t), 30);
2443 
2444     t.erase(t.begin(), t.end());
2445 
2446     EXPECT_EQ(t.size(), 0);
2447     EXPECT_EQ(t.capacity(), cap);
2448     ASSERT_EQ(RawHashSetTestOnlyAccess::CountTombstones(t), 0);
2449   }
2450 }
2451 
TEST(Table,GenerationInfoResetsOnClear)2452 TEST(Table, GenerationInfoResetsOnClear) {
2453   if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2454   if (kMsvc) GTEST_SKIP() << "MSVC doesn't support | in regexp.";
2455 
2456   IntTable t;
2457   for (int i = 0; i < 1000; ++i) t.insert(i);
2458   t.reserve(t.size() + 100);
2459 
2460   t.clear();
2461 
2462   t.insert(0);
2463   auto it = t.begin();
2464   t.insert(1);
2465   EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
2466 }
2467 
TEST(Table,InvalidReferenceUseCrashesWithSanitizers)2468 TEST(Table, InvalidReferenceUseCrashesWithSanitizers) {
2469   if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2470 #ifdef ABSL_HAVE_MEMORY_SANITIZER
2471   GTEST_SKIP() << "MSan fails to detect some of these rehashes.";
2472 #endif
2473 
2474   IntTable t;
2475   t.insert(0);
2476   // Rehashing is guaranteed on every insertion while capacity is less than
2477   // RehashProbabilityConstant().
2478   int64_t i = 0;
2479   while (t.capacity() <= RehashProbabilityConstant()) {
2480     // ptr will become invalidated on rehash.
2481     const int64_t* ptr = &*t.begin();
2482     t.insert(++i);
2483     EXPECT_DEATH_IF_SUPPORTED(std::cout << *ptr, "heap-use-after-free") << i;
2484   }
2485 }
2486 
TEST(Iterator,InvalidComparisonDifferentTables)2487 TEST(Iterator, InvalidComparisonDifferentTables) {
2488   if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
2489 
2490   IntTable t1, t2;
2491   IntTable::iterator default_constructed_iter;
2492   // We randomly use one of N empty generations for generations from empty
2493   // hashtables. In general, we won't always detect when iterators from
2494   // different empty hashtables are compared, but in this test case, we
2495   // should deterministically detect the error due to our randomness yielding
2496   // consecutive random generations.
2497   EXPECT_DEATH_IF_SUPPORTED(void(t1.end() == t2.end()),
2498                             "Invalid iterator comparison.*empty hashtables");
2499   EXPECT_DEATH_IF_SUPPORTED(void(t1.end() == default_constructed_iter),
2500                             "Invalid iterator comparison.*default-constructed");
2501   t1.insert(0);
2502   EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == t2.end()),
2503                             "Invalid iterator comparison.*empty hashtable");
2504   EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == default_constructed_iter),
2505                             "Invalid iterator comparison.*default-constructed");
2506   t2.insert(0);
2507   EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == t2.end()),
2508                             "Invalid iterator comparison.*end.. iterator");
2509   EXPECT_DEATH_IF_SUPPORTED(void(t1.begin() == t2.begin()),
2510                             "Invalid iterator comparison.*non-end");
2511 }
2512 
2513 }  // namespace
2514 }  // namespace container_internal
2515 ABSL_NAMESPACE_END
2516 }  // namespace absl
2517