tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

flat_hash_set_test.cc (11677B)


      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/flat_hash_set.h"
     16 
     17 #include <cstddef>
     18 #include <cstdint>
     19 #include <memory>
     20 #include <string>
     21 #include <type_traits>
     22 #include <utility>
     23 #include <vector>
     24 
     25 #include "gmock/gmock.h"
     26 #include "gtest/gtest.h"
     27 #include "absl/base/config.h"
     28 #include "absl/container/hash_container_defaults.h"
     29 #include "absl/container/internal/container_memory.h"
     30 #include "absl/container/internal/hash_generator_testing.h"
     31 #include "absl/container/internal/test_allocator.h"
     32 #include "absl/container/internal/unordered_set_constructor_test.h"
     33 #include "absl/container/internal/unordered_set_lookup_test.h"
     34 #include "absl/container/internal/unordered_set_members_test.h"
     35 #include "absl/container/internal/unordered_set_modifiers_test.h"
     36 #include "absl/hash/hash.h"
     37 #include "absl/log/check.h"
     38 #include "absl/memory/memory.h"
     39 #include "absl/strings/string_view.h"
     40 
     41 namespace absl {
     42 ABSL_NAMESPACE_BEGIN
     43 namespace container_internal {
     44 namespace {
     45 
     46 using ::absl::container_internal::hash_internal::Enum;
     47 using ::absl::container_internal::hash_internal::EnumClass;
     48 using ::testing::IsEmpty;
     49 using ::testing::Pointee;
     50 using ::testing::UnorderedElementsAre;
     51 using ::testing::UnorderedElementsAreArray;
     52 
     53 // Check that absl::flat_hash_set works in a global constructor.
     54 struct BeforeMain {
     55  BeforeMain() {
     56    absl::flat_hash_set<int> x;
     57    x.insert(1);
     58    CHECK(!x.contains(0)) << "x should not contain 0";
     59    CHECK(x.contains(1)) << "x should contain 1";
     60  }
     61 };
     62 const BeforeMain before_main;
     63 
     64 template <class T>
     65 using Set =
     66    absl::flat_hash_set<T, StatefulTestingHash, StatefulTestingEqual, Alloc<T>>;
     67 
     68 using SetTypes =
     69    ::testing::Types<Set<int>, Set<std::string>, Set<Enum>, Set<EnumClass>>;
     70 
     71 INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, ConstructorTest, SetTypes);
     72 INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, LookupTest, SetTypes);
     73 INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, MembersTest, SetTypes);
     74 INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, ModifiersTest, SetTypes);
     75 
     76 TEST(FlatHashSet, EmplaceString) {
     77  std::vector<std::string> v = {"a", "b"};
     78  absl::flat_hash_set<absl::string_view> hs(v.begin(), v.end());
     79  EXPECT_THAT(hs, UnorderedElementsAreArray(v));
     80 }
     81 
     82 TEST(FlatHashSet, BitfieldArgument) {
     83  union {
     84    int n : 1;
     85  };
     86  n = 0;
     87  absl::flat_hash_set<int> s = {n};
     88  s.insert(n);
     89  s.insert(s.end(), n);
     90  s.insert({n});
     91  s.erase(n);
     92  s.count(n);
     93  s.prefetch(n);
     94  s.find(n);
     95  s.contains(n);
     96  s.equal_range(n);
     97 }
     98 
     99 TEST(FlatHashSet, MergeExtractInsert) {
    100  struct Hash {
    101    size_t operator()(const std::unique_ptr<int>& p) const { return *p; }
    102  };
    103  struct Eq {
    104    bool operator()(const std::unique_ptr<int>& a,
    105                    const std::unique_ptr<int>& b) const {
    106      return *a == *b;
    107    }
    108  };
    109  absl::flat_hash_set<std::unique_ptr<int>, Hash, Eq> set1, set2;
    110  set1.insert(absl::make_unique<int>(7));
    111  set1.insert(absl::make_unique<int>(17));
    112 
    113  set2.insert(absl::make_unique<int>(7));
    114  set2.insert(absl::make_unique<int>(19));
    115 
    116  EXPECT_THAT(set1, UnorderedElementsAre(Pointee(7), Pointee(17)));
    117  EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(19)));
    118 
    119  set1.merge(set2);
    120 
    121  EXPECT_THAT(set1, UnorderedElementsAre(Pointee(7), Pointee(17), Pointee(19)));
    122  EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7)));
    123 
    124  auto node = set1.extract(absl::make_unique<int>(7));
    125  EXPECT_TRUE(node);
    126  EXPECT_THAT(node.value(), Pointee(7));
    127  EXPECT_THAT(set1, UnorderedElementsAre(Pointee(17), Pointee(19)));
    128 
    129  auto insert_result = set2.insert(std::move(node));
    130  EXPECT_FALSE(node);
    131  EXPECT_FALSE(insert_result.inserted);
    132  EXPECT_TRUE(insert_result.node);
    133  EXPECT_THAT(insert_result.node.value(), Pointee(7));
    134  EXPECT_EQ(**insert_result.position, 7);
    135  EXPECT_NE(insert_result.position->get(), insert_result.node.value().get());
    136  EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7)));
    137 
    138  node = set1.extract(absl::make_unique<int>(17));
    139  EXPECT_TRUE(node);
    140  EXPECT_THAT(node.value(), Pointee(17));
    141  EXPECT_THAT(set1, UnorderedElementsAre(Pointee(19)));
    142 
    143  node.value() = absl::make_unique<int>(23);
    144 
    145  insert_result = set2.insert(std::move(node));
    146  EXPECT_FALSE(node);
    147  EXPECT_TRUE(insert_result.inserted);
    148  EXPECT_FALSE(insert_result.node);
    149  EXPECT_EQ(**insert_result.position, 23);
    150  EXPECT_THAT(set2, UnorderedElementsAre(Pointee(7), Pointee(23)));
    151 }
    152 
    153 bool IsEven(int k) { return k % 2 == 0; }
    154 
    155 TEST(FlatHashSet, EraseIf) {
    156  // Erase all elements.
    157  {
    158    flat_hash_set<int> s = {1, 2, 3, 4, 5};
    159    EXPECT_EQ(erase_if(s, [](int) { return true; }), 5);
    160    EXPECT_THAT(s, IsEmpty());
    161  }
    162  // Erase no elements.
    163  {
    164    flat_hash_set<int> s = {1, 2, 3, 4, 5};
    165    EXPECT_EQ(erase_if(s, [](int) { return false; }), 0);
    166    EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3, 4, 5));
    167  }
    168  // Erase specific elements.
    169  {
    170    flat_hash_set<int> s = {1, 2, 3, 4, 5};
    171    EXPECT_EQ(erase_if(s, [](int k) { return k % 2 == 1; }), 3);
    172    EXPECT_THAT(s, UnorderedElementsAre(2, 4));
    173  }
    174  // Predicate is function reference.
    175  {
    176    flat_hash_set<int> s = {1, 2, 3, 4, 5};
    177    EXPECT_EQ(erase_if(s, IsEven), 2);
    178    EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
    179  }
    180  // Predicate is function pointer.
    181  {
    182    flat_hash_set<int> s = {1, 2, 3, 4, 5};
    183    EXPECT_EQ(erase_if(s, &IsEven), 2);
    184    EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
    185  }
    186 }
    187 
    188 TEST(FlatHashSet, CForEach) {
    189  using ValueType = std::pair<int, int>;
    190  flat_hash_set<ValueType> s;
    191  std::vector<ValueType> expected;
    192  for (int i = 0; i < 100; ++i) {
    193    {
    194      SCOPED_TRACE("mutable object iteration");
    195      std::vector<ValueType> v;
    196      absl::container_internal::c_for_each_fast(
    197          s, [&v](const ValueType& p) { v.push_back(p); });
    198      ASSERT_THAT(v, UnorderedElementsAreArray(expected));
    199    }
    200    {
    201      SCOPED_TRACE("const object iteration");
    202      std::vector<ValueType> v;
    203      const flat_hash_set<ValueType>& cs = s;
    204      absl::container_internal::c_for_each_fast(
    205          cs, [&v](const ValueType& p) { v.push_back(p); });
    206      ASSERT_THAT(v, UnorderedElementsAreArray(expected));
    207    }
    208    {
    209      SCOPED_TRACE("temporary object iteration");
    210      std::vector<ValueType> v;
    211      absl::container_internal::c_for_each_fast(
    212          flat_hash_set<ValueType>(s),
    213          [&v](const ValueType& p) { v.push_back(p); });
    214      ASSERT_THAT(v, UnorderedElementsAreArray(expected));
    215    }
    216    s.emplace(i, i);
    217    expected.emplace_back(i, i);
    218  }
    219 }
    220 
    221 class PoisonSoo {
    222  int64_t data_;
    223 
    224 public:
    225  explicit PoisonSoo(int64_t d) : data_(d) { SanitizerPoisonObject(&data_); }
    226  PoisonSoo(const PoisonSoo& that) : PoisonSoo(*that) {}
    227  ~PoisonSoo() { SanitizerUnpoisonObject(&data_); }
    228 
    229  int64_t operator*() const {
    230    SanitizerUnpoisonObject(&data_);
    231    const int64_t ret = data_;
    232    SanitizerPoisonObject(&data_);
    233    return ret;
    234  }
    235  template <typename H>
    236  friend H AbslHashValue(H h, const PoisonSoo& pi) {
    237    return H::combine(std::move(h), *pi);
    238  }
    239  bool operator==(const PoisonSoo& rhs) const { return **this == *rhs; }
    240 };
    241 
    242 TEST(FlatHashSet, PoisonSooBasic) {
    243  PoisonSoo a(0), b(1);
    244  flat_hash_set<PoisonSoo> set;
    245  set.insert(a);
    246  EXPECT_THAT(set, UnorderedElementsAre(a));
    247  set.insert(b);
    248  EXPECT_THAT(set, UnorderedElementsAre(a, b));
    249  set.erase(a);
    250  EXPECT_THAT(set, UnorderedElementsAre(b));
    251  set.rehash(0);  // Shrink to SOO.
    252  EXPECT_THAT(set, UnorderedElementsAre(b));
    253 }
    254 
    255 TEST(FlatHashSet, PoisonSooMoveConstructSooToSoo) {
    256  PoisonSoo a(0);
    257  flat_hash_set<PoisonSoo> set;
    258  set.insert(a);
    259  flat_hash_set<PoisonSoo> set2(std::move(set));
    260  EXPECT_THAT(set2, UnorderedElementsAre(a));
    261 }
    262 
    263 TEST(FlatHashSet, PoisonSooAllocMoveConstructSooToSoo) {
    264  PoisonSoo a(0);
    265  flat_hash_set<PoisonSoo> set;
    266  set.insert(a);
    267  flat_hash_set<PoisonSoo> set2(std::move(set), std::allocator<PoisonSoo>());
    268  EXPECT_THAT(set2, UnorderedElementsAre(a));
    269 }
    270 
    271 TEST(FlatHashSet, PoisonSooMoveAssignFullSooToEmptySoo) {
    272  PoisonSoo a(0);
    273  flat_hash_set<PoisonSoo> set, set2;
    274  set.insert(a);
    275  set2 = std::move(set);
    276  EXPECT_THAT(set2, UnorderedElementsAre(a));
    277 }
    278 
    279 TEST(FlatHashSet, PoisonSooMoveAssignFullSooToFullSoo) {
    280  PoisonSoo a(0), b(1);
    281  flat_hash_set<PoisonSoo> set, set2;
    282  set.insert(a);
    283  set2.insert(b);
    284  set2 = std::move(set);
    285  EXPECT_THAT(set2, UnorderedElementsAre(a));
    286 }
    287 
    288 TEST(FlatHashSet, FlatHashSetPolicyDestroyReturnsTrue) {
    289  EXPECT_TRUE((decltype(FlatHashSetPolicy<int>::destroy<std::allocator<int>>(
    290      nullptr, nullptr))()));
    291  EXPECT_FALSE(
    292      (decltype(FlatHashSetPolicy<int>::destroy<CountingAllocator<int>>(
    293          nullptr, nullptr))()));
    294  EXPECT_FALSE((decltype(FlatHashSetPolicy<std::unique_ptr<int>>::destroy<
    295                         std::allocator<int>>(nullptr, nullptr))()));
    296 }
    297 
    298 struct HashEqInvalidOnMove {
    299  HashEqInvalidOnMove() = default;
    300  HashEqInvalidOnMove(const HashEqInvalidOnMove& rhs) = default;
    301  HashEqInvalidOnMove(HashEqInvalidOnMove&& rhs) { rhs.moved = true; }
    302  HashEqInvalidOnMove& operator=(const HashEqInvalidOnMove& rhs) = default;
    303  HashEqInvalidOnMove& operator=(HashEqInvalidOnMove&& rhs) {
    304    rhs.moved = true;
    305    return *this;
    306  }
    307 
    308  size_t operator()(int x) const {
    309    CHECK(!moved);
    310    return absl::HashOf(x);
    311  }
    312 
    313  bool operator()(int x, int y) const {
    314    CHECK(!moved);
    315    return x == y;
    316  }
    317 
    318  bool moved = false;
    319 };
    320 
    321 TEST(FlatHashSet, MovedFromCleared_HashMustBeValid) {
    322  flat_hash_set<int, HashEqInvalidOnMove> s1, s2;
    323  // Moving the hashtable must not move the hasher because we need to support
    324  // this behavior.
    325  s2 = std::move(s1);
    326  s1.clear();
    327  s1.insert(2);
    328  EXPECT_THAT(s1, UnorderedElementsAre(2));
    329 }
    330 
    331 TEST(FlatHashSet, MovedFromCleared_EqMustBeValid) {
    332  flat_hash_set<int, DefaultHashContainerHash<int>, HashEqInvalidOnMove> s1, s2;
    333  // Moving the hashtable must not move the equality functor because we need to
    334  // support this behavior.
    335  s2 = std::move(s1);
    336  s1.clear();
    337  s1.insert(2);
    338  EXPECT_THAT(s1, UnorderedElementsAre(2));
    339 }
    340 
    341 TEST(FlatHashSet, Equality) {
    342  {
    343    flat_hash_set<int> s1 = {1, 2, 3};
    344    flat_hash_set<int> s2 = {1, 2, 3};
    345    EXPECT_EQ(s1, s2);
    346  }
    347  {
    348    flat_hash_set<std::string> s1 = {"a", "b", "c"};
    349    flat_hash_set<std::string> s2 = {"a", "b", "c"};
    350    EXPECT_EQ(s1, s2);
    351  }
    352 }
    353 
    354 class MoveOnlyInt {
    355 public:
    356  explicit MoveOnlyInt(int value) : value_(value) {}
    357 
    358  MoveOnlyInt(const MoveOnlyInt& other) = delete;
    359  MoveOnlyInt& operator=(const MoveOnlyInt& other) = delete;
    360 
    361  MoveOnlyInt(MoveOnlyInt&& other) = default;
    362  MoveOnlyInt& operator=(MoveOnlyInt&& other) = default;
    363 
    364  bool operator==(const MoveOnlyInt& other) const {
    365    return value_ == other.value_;
    366  }
    367  bool operator==(int other) const { return value_ == other; }
    368 
    369 private:
    370  template <typename H>
    371  friend H AbslHashValue(H h, const MoveOnlyInt& m) {
    372    return H::combine(std::move(h), m.value_);
    373  }
    374 
    375  int value_;
    376 };
    377 
    378 TEST(FlatHashSet, MoveOnlyKey) {
    379  flat_hash_set<MoveOnlyInt> s;
    380  s.insert(MoveOnlyInt(1));
    381  s.insert(MoveOnlyInt(2));
    382  s.insert(MoveOnlyInt(3));
    383  EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3));
    384 }
    385 
    386 }  // namespace
    387 }  // namespace container_internal
    388 ABSL_NAMESPACE_END
    389 }  // namespace absl