Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:15

0001 // Copyright 2018 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 //
0015 // -----------------------------------------------------------------------------
0016 // File: flat_hash_set.h
0017 // -----------------------------------------------------------------------------
0018 //
0019 // An `absl::flat_hash_set<T>` is an unordered associative container designed to
0020 // be a more efficient replacement for `std::unordered_set`. Like
0021 // `unordered_set`, search, insertion, and deletion of set elements can be done
0022 // as an `O(1)` operation. However, `flat_hash_set` (and other unordered
0023 // associative containers known as the collection of Abseil "Swiss tables")
0024 // contain other optimizations that result in both memory and computation
0025 // advantages.
0026 //
0027 // In most cases, your default choice for a hash set should be a set of type
0028 // `flat_hash_set`.
0029 //
0030 // `flat_hash_set` is not exception-safe.
0031 
0032 #ifndef ABSL_CONTAINER_FLAT_HASH_SET_H_
0033 #define ABSL_CONTAINER_FLAT_HASH_SET_H_
0034 
0035 #include <cstddef>
0036 #include <memory>
0037 #include <type_traits>
0038 #include <utility>
0039 
0040 #include "absl/algorithm/container.h"
0041 #include "absl/base/attributes.h"
0042 #include "absl/base/macros.h"
0043 #include "absl/container/hash_container_defaults.h"
0044 #include "absl/container/internal/container_memory.h"
0045 #include "absl/container/internal/raw_hash_set.h"  // IWYU pragma: export
0046 #include "absl/memory/memory.h"
0047 #include "absl/meta/type_traits.h"
0048 
0049 namespace absl {
0050 ABSL_NAMESPACE_BEGIN
0051 namespace container_internal {
0052 template <typename T>
0053 struct FlatHashSetPolicy;
0054 }  // namespace container_internal
0055 
0056 // -----------------------------------------------------------------------------
0057 // absl::flat_hash_set
0058 // -----------------------------------------------------------------------------
0059 //
0060 // An `absl::flat_hash_set<T>` is an unordered associative container which has
0061 // been optimized for both speed and memory footprint in most common use cases.
0062 // Its interface is similar to that of `std::unordered_set<T>` with the
0063 // following notable differences:
0064 //
0065 // * Requires keys that are CopyConstructible
0066 // * Supports heterogeneous lookup, through `find()` and `insert()`, provided
0067 //   that the set is provided a compatible heterogeneous hashing function and
0068 //   equality operator. See below for details.
0069 // * Invalidates any references and pointers to elements within the table after
0070 //   `rehash()` and when the table is moved.
0071 // * Contains a `capacity()` member function indicating the number of element
0072 //   slots (open, deleted, and empty) within the hash set.
0073 // * Returns `void` from the `erase(iterator)` overload.
0074 //
0075 // By default, `flat_hash_set` uses the `absl::Hash` hashing framework. All
0076 // fundamental and Abseil types that support the `absl::Hash` framework have a
0077 // compatible equality operator for comparing insertions into `flat_hash_set`.
0078 // If your type is not yet supported by the `absl::Hash` framework, see
0079 // absl/hash/hash.h for information on extending Abseil hashing to user-defined
0080 // types.
0081 //
0082 // Using `absl::flat_hash_set` at interface boundaries in dynamically loaded
0083 // libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may
0084 // be randomized across dynamically loaded libraries.
0085 //
0086 // To achieve heterogeneous lookup for custom types either `Hash` and `Eq` type
0087 // parameters can be used or `T` should have public inner types
0088 // `absl_container_hash` and (optionally) `absl_container_eq`. In either case,
0089 // `typename Hash::is_transparent` and `typename Eq::is_transparent` should be
0090 // well-formed. Both types are basically functors:
0091 // * `Hash` should support `size_t operator()(U val) const` that returns a hash
0092 // for the given `val`.
0093 // * `Eq` should support `bool operator()(U lhs, V rhs) const` that returns true
0094 // if `lhs` is equal to `rhs`.
0095 //
0096 // In most cases `T` needs only to provide the `absl_container_hash`. In this
0097 // case `std::equal_to<void>` will be used instead of `eq` part.
0098 //
0099 // NOTE: A `flat_hash_set` stores its keys directly inside its implementation
0100 // array to avoid memory indirection. Because a `flat_hash_set` is designed to
0101 // move data when rehashed, set keys will not retain pointer stability. If you
0102 // require pointer stability, consider using
0103 // `absl::flat_hash_set<std::unique_ptr<T>>`. If your type is not moveable and
0104 // you require pointer stability, consider `absl::node_hash_set` instead.
0105 //
0106 // Example:
0107 //
0108 //   // Create a flat hash set of three strings
0109 //   absl::flat_hash_set<std::string> ducks =
0110 //     {"huey", "dewey", "louie"};
0111 //
0112 //  // Insert a new element into the flat hash set
0113 //  ducks.insert("donald");
0114 //
0115 //  // Force a rehash of the flat hash set
0116 //  ducks.rehash(0);
0117 //
0118 //  // See if "dewey" is present
0119 //  if (ducks.contains("dewey")) {
0120 //    std::cout << "We found dewey!" << std::endl;
0121 //  }
0122 template <class T, class Hash = DefaultHashContainerHash<T>,
0123           class Eq = DefaultHashContainerEq<T>,
0124           class Allocator = std::allocator<T>>
0125 class ABSL_INTERNAL_ATTRIBUTE_OWNER flat_hash_set
0126     : public absl::container_internal::raw_hash_set<
0127           absl::container_internal::FlatHashSetPolicy<T>, Hash, Eq, Allocator> {
0128   using Base = typename flat_hash_set::raw_hash_set;
0129 
0130  public:
0131   // Constructors and Assignment Operators
0132   //
0133   // A flat_hash_set supports the same overload set as `std::unordered_set`
0134   // for construction and assignment:
0135   //
0136   // *  Default constructor
0137   //
0138   //    // No allocation for the table's elements is made.
0139   //    absl::flat_hash_set<std::string> set1;
0140   //
0141   // * Initializer List constructor
0142   //
0143   //   absl::flat_hash_set<std::string> set2 =
0144   //       {{"huey"}, {"dewey"}, {"louie"},};
0145   //
0146   // * Copy constructor
0147   //
0148   //   absl::flat_hash_set<std::string> set3(set2);
0149   //
0150   // * Copy assignment operator
0151   //
0152   //  // Hash functor and Comparator are copied as well
0153   //  absl::flat_hash_set<std::string> set4;
0154   //  set4 = set3;
0155   //
0156   // * Move constructor
0157   //
0158   //   // Move is guaranteed efficient
0159   //   absl::flat_hash_set<std::string> set5(std::move(set4));
0160   //
0161   // * Move assignment operator
0162   //
0163   //   // May be efficient if allocators are compatible
0164   //   absl::flat_hash_set<std::string> set6;
0165   //   set6 = std::move(set5);
0166   //
0167   // * Range constructor
0168   //
0169   //   std::vector<std::string> v = {"a", "b"};
0170   //   absl::flat_hash_set<std::string> set7(v.begin(), v.end());
0171   flat_hash_set() {}
0172   using Base::Base;
0173 
0174   // flat_hash_set::begin()
0175   //
0176   // Returns an iterator to the beginning of the `flat_hash_set`.
0177   using Base::begin;
0178 
0179   // flat_hash_set::cbegin()
0180   //
0181   // Returns a const iterator to the beginning of the `flat_hash_set`.
0182   using Base::cbegin;
0183 
0184   // flat_hash_set::cend()
0185   //
0186   // Returns a const iterator to the end of the `flat_hash_set`.
0187   using Base::cend;
0188 
0189   // flat_hash_set::end()
0190   //
0191   // Returns an iterator to the end of the `flat_hash_set`.
0192   using Base::end;
0193 
0194   // flat_hash_set::capacity()
0195   //
0196   // Returns the number of element slots (assigned, deleted, and empty)
0197   // available within the `flat_hash_set`.
0198   //
0199   // NOTE: this member function is particular to `absl::flat_hash_set` and is
0200   // not provided in the `std::unordered_set` API.
0201   using Base::capacity;
0202 
0203   // flat_hash_set::empty()
0204   //
0205   // Returns whether or not the `flat_hash_set` is empty.
0206   using Base::empty;
0207 
0208   // flat_hash_set::max_size()
0209   //
0210   // Returns the largest theoretical possible number of elements within a
0211   // `flat_hash_set` under current memory constraints. This value can be thought
0212   // of the largest value of `std::distance(begin(), end())` for a
0213   // `flat_hash_set<T>`.
0214   using Base::max_size;
0215 
0216   // flat_hash_set::size()
0217   //
0218   // Returns the number of elements currently within the `flat_hash_set`.
0219   using Base::size;
0220 
0221   // flat_hash_set::clear()
0222   //
0223   // Removes all elements from the `flat_hash_set`. Invalidates any references,
0224   // pointers, or iterators referring to contained elements.
0225   //
0226   // NOTE: this operation may shrink the underlying buffer. To avoid shrinking
0227   // the underlying buffer call `erase(begin(), end())`.
0228   using Base::clear;
0229 
0230   // flat_hash_set::erase()
0231   //
0232   // Erases elements within the `flat_hash_set`. Erasing does not trigger a
0233   // rehash. Overloads are listed below.
0234   //
0235   // void erase(const_iterator pos):
0236   //
0237   //   Erases the element at `position` of the `flat_hash_set`, returning
0238   //   `void`.
0239   //
0240   //   NOTE: returning `void` in this case is different than that of STL
0241   //   containers in general and `std::unordered_set` in particular (which
0242   //   return an iterator to the element following the erased element). If that
0243   //   iterator is needed, simply post increment the iterator:
0244   //
0245   //     set.erase(it++);
0246   //
0247   // iterator erase(const_iterator first, const_iterator last):
0248   //
0249   //   Erases the elements in the open interval [`first`, `last`), returning an
0250   //   iterator pointing to `last`. The special case of calling
0251   //   `erase(begin(), end())` resets the reserved growth such that if
0252   //   `reserve(N)` has previously been called and there has been no intervening
0253   //   call to `clear()`, then after calling `erase(begin(), end())`, it is safe
0254   //   to assume that inserting N elements will not cause a rehash.
0255   //
0256   // size_type erase(const key_type& key):
0257   //
0258   //   Erases the element with the matching key, if it exists, returning the
0259   //   number of elements erased (0 or 1).
0260   using Base::erase;
0261 
0262   // flat_hash_set::insert()
0263   //
0264   // Inserts an element of the specified value into the `flat_hash_set`,
0265   // returning an iterator pointing to the newly inserted element, provided that
0266   // an element with the given key does not already exist. If rehashing occurs
0267   // due to the insertion, all iterators are invalidated. Overloads are listed
0268   // below.
0269   //
0270   // std::pair<iterator,bool> insert(const T& value):
0271   //
0272   //   Inserts a value into the `flat_hash_set`. Returns a pair consisting of an
0273   //   iterator to the inserted element (or to the element that prevented the
0274   //   insertion) and a bool denoting whether the insertion took place.
0275   //
0276   // std::pair<iterator,bool> insert(T&& value):
0277   //
0278   //   Inserts a moveable value into the `flat_hash_set`. Returns a pair
0279   //   consisting of an iterator to the inserted element (or to the element that
0280   //   prevented the insertion) and a bool denoting whether the insertion took
0281   //   place.
0282   //
0283   // iterator insert(const_iterator hint, const T& value):
0284   // iterator insert(const_iterator hint, T&& value):
0285   //
0286   //   Inserts a value, using the position of `hint` as a non-binding suggestion
0287   //   for where to begin the insertion search. Returns an iterator to the
0288   //   inserted element, or to the existing element that prevented the
0289   //   insertion.
0290   //
0291   // void insert(InputIterator first, InputIterator last):
0292   //
0293   //   Inserts a range of values [`first`, `last`).
0294   //
0295   //   NOTE: Although the STL does not specify which element may be inserted if
0296   //   multiple keys compare equivalently, for `flat_hash_set` we guarantee the
0297   //   first match is inserted.
0298   //
0299   // void insert(std::initializer_list<T> ilist):
0300   //
0301   //   Inserts the elements within the initializer list `ilist`.
0302   //
0303   //   NOTE: Although the STL does not specify which element may be inserted if
0304   //   multiple keys compare equivalently within the initializer list, for
0305   //   `flat_hash_set` we guarantee the first match is inserted.
0306   using Base::insert;
0307 
0308   // flat_hash_set::emplace()
0309   //
0310   // Inserts an element of the specified value by constructing it in-place
0311   // within the `flat_hash_set`, provided that no element with the given key
0312   // already exists.
0313   //
0314   // The element may be constructed even if there already is an element with the
0315   // key in the container, in which case the newly constructed element will be
0316   // destroyed immediately.
0317   //
0318   // If rehashing occurs due to the insertion, all iterators are invalidated.
0319   using Base::emplace;
0320 
0321   // flat_hash_set::emplace_hint()
0322   //
0323   // Inserts an element of the specified value by constructing it in-place
0324   // within the `flat_hash_set`, using the position of `hint` as a non-binding
0325   // suggestion for where to begin the insertion search, and only inserts
0326   // provided that no element with the given key already exists.
0327   //
0328   // The element may be constructed even if there already is an element with the
0329   // key in the container, in which case the newly constructed element will be
0330   // destroyed immediately.
0331   //
0332   // If rehashing occurs due to the insertion, all iterators are invalidated.
0333   using Base::emplace_hint;
0334 
0335   // flat_hash_set::extract()
0336   //
0337   // Extracts the indicated element, erasing it in the process, and returns it
0338   // as a C++17-compatible node handle. Overloads are listed below.
0339   //
0340   // node_type extract(const_iterator position):
0341   //
0342   //   Extracts the element at the indicated position and returns a node handle
0343   //   owning that extracted data.
0344   //
0345   // node_type extract(const key_type& x):
0346   //
0347   //   Extracts the element with the key matching the passed key value and
0348   //   returns a node handle owning that extracted data. If the `flat_hash_set`
0349   //   does not contain an element with a matching key, this function returns an
0350   //   empty node handle.
0351   using Base::extract;
0352 
0353   // flat_hash_set::merge()
0354   //
0355   // Extracts elements from a given `source` flat hash set into this
0356   // `flat_hash_set`. If the destination `flat_hash_set` already contains an
0357   // element with an equivalent key, that element is not extracted.
0358   using Base::merge;
0359 
0360   // flat_hash_set::swap(flat_hash_set& other)
0361   //
0362   // Exchanges the contents of this `flat_hash_set` with those of the `other`
0363   // flat hash set, avoiding invocation of any move, copy, or swap operations on
0364   // individual elements.
0365   //
0366   // All iterators and references on the `flat_hash_set` remain valid, excepting
0367   // for the past-the-end iterator, which is invalidated.
0368   //
0369   // `swap()` requires that the flat hash set's hashing and key equivalence
0370   // functions be Swappable, and are exchanged using unqualified calls to
0371   // non-member `swap()`. If the set's allocator has
0372   // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
0373   // set to `true`, the allocators are also exchanged using an unqualified call
0374   // to non-member `swap()`; otherwise, the allocators are not swapped.
0375   using Base::swap;
0376 
0377   // flat_hash_set::rehash(count)
0378   //
0379   // Rehashes the `flat_hash_set`, setting the number of slots to be at least
0380   // the passed value. If the new number of slots increases the load factor more
0381   // than the current maximum load factor
0382   // (`count` < `size()` / `max_load_factor()`), then the new number of slots
0383   // will be at least `size()` / `max_load_factor()`.
0384   //
0385   // To force a rehash, pass rehash(0).
0386   //
0387   // NOTE: unlike behavior in `std::unordered_set`, references are also
0388   // invalidated upon a `rehash()`.
0389   using Base::rehash;
0390 
0391   // flat_hash_set::reserve(count)
0392   //
0393   // Sets the number of slots in the `flat_hash_set` to the number needed to
0394   // accommodate at least `count` total elements without exceeding the current
0395   // maximum load factor, and may rehash the container if needed.
0396   using Base::reserve;
0397 
0398   // flat_hash_set::contains()
0399   //
0400   // Determines whether an element comparing equal to the given `key` exists
0401   // within the `flat_hash_set`, returning `true` if so or `false` otherwise.
0402   using Base::contains;
0403 
0404   // flat_hash_set::count(const Key& key) const
0405   //
0406   // Returns the number of elements comparing equal to the given `key` within
0407   // the `flat_hash_set`. note that this function will return either `1` or `0`
0408   // since duplicate elements are not allowed within a `flat_hash_set`.
0409   using Base::count;
0410 
0411   // flat_hash_set::equal_range()
0412   //
0413   // Returns a closed range [first, last], defined by a `std::pair` of two
0414   // iterators, containing all elements with the passed key in the
0415   // `flat_hash_set`.
0416   using Base::equal_range;
0417 
0418   // flat_hash_set::find()
0419   //
0420   // Finds an element with the passed `key` within the `flat_hash_set`.
0421   using Base::find;
0422 
0423   // flat_hash_set::bucket_count()
0424   //
0425   // Returns the number of "buckets" within the `flat_hash_set`. Note that
0426   // because a flat hash set contains all elements within its internal storage,
0427   // this value simply equals the current capacity of the `flat_hash_set`.
0428   using Base::bucket_count;
0429 
0430   // flat_hash_set::load_factor()
0431   //
0432   // Returns the current load factor of the `flat_hash_set` (the average number
0433   // of slots occupied with a value within the hash set).
0434   using Base::load_factor;
0435 
0436   // flat_hash_set::max_load_factor()
0437   //
0438   // Manages the maximum load factor of the `flat_hash_set`. Overloads are
0439   // listed below.
0440   //
0441   // float flat_hash_set::max_load_factor()
0442   //
0443   //   Returns the current maximum load factor of the `flat_hash_set`.
0444   //
0445   // void flat_hash_set::max_load_factor(float ml)
0446   //
0447   //   Sets the maximum load factor of the `flat_hash_set` to the passed value.
0448   //
0449   //   NOTE: This overload is provided only for API compatibility with the STL;
0450   //   `flat_hash_set` will ignore any set load factor and manage its rehashing
0451   //   internally as an implementation detail.
0452   using Base::max_load_factor;
0453 
0454   // flat_hash_set::get_allocator()
0455   //
0456   // Returns the allocator function associated with this `flat_hash_set`.
0457   using Base::get_allocator;
0458 
0459   // flat_hash_set::hash_function()
0460   //
0461   // Returns the hashing function used to hash the keys within this
0462   // `flat_hash_set`.
0463   using Base::hash_function;
0464 
0465   // flat_hash_set::key_eq()
0466   //
0467   // Returns the function used for comparing keys equality.
0468   using Base::key_eq;
0469 };
0470 
0471 // erase_if(flat_hash_set<>, Pred)
0472 //
0473 // Erases all elements that satisfy the predicate `pred` from the container `c`.
0474 // Returns the number of erased elements.
0475 template <typename T, typename H, typename E, typename A, typename Predicate>
0476 typename flat_hash_set<T, H, E, A>::size_type erase_if(
0477     flat_hash_set<T, H, E, A>& c, Predicate pred) {
0478   return container_internal::EraseIf(pred, &c);
0479 }
0480 
0481 namespace container_internal {
0482 
0483 // c_for_each_fast(flat_hash_set<>, Function)
0484 //
0485 // Container-based version of the <algorithm> `std::for_each()` function to
0486 // apply a function to a container's elements.
0487 // There is no guarantees on the order of the function calls.
0488 // Erasure and/or insertion of elements in the function is not allowed.
0489 template <typename T, typename H, typename E, typename A, typename Function>
0490 decay_t<Function> c_for_each_fast(const flat_hash_set<T, H, E, A>& c,
0491                                   Function&& f) {
0492   container_internal::ForEach(f, &c);
0493   return f;
0494 }
0495 template <typename T, typename H, typename E, typename A, typename Function>
0496 decay_t<Function> c_for_each_fast(flat_hash_set<T, H, E, A>& c, Function&& f) {
0497   container_internal::ForEach(f, &c);
0498   return f;
0499 }
0500 template <typename T, typename H, typename E, typename A, typename Function>
0501 decay_t<Function> c_for_each_fast(flat_hash_set<T, H, E, A>&& c, Function&& f) {
0502   container_internal::ForEach(f, &c);
0503   return f;
0504 }
0505 
0506 }  // namespace container_internal
0507 
0508 namespace container_internal {
0509 
0510 template <class T>
0511 struct FlatHashSetPolicy {
0512   using slot_type = T;
0513   using key_type = T;
0514   using init_type = T;
0515   using constant_iterators = std::true_type;
0516 
0517   template <class Allocator, class... Args>
0518   static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
0519     absl::allocator_traits<Allocator>::construct(*alloc, slot,
0520                                                  std::forward<Args>(args)...);
0521   }
0522 
0523   // Return std::true_type in case destroy is trivial.
0524   template <class Allocator>
0525   static auto destroy(Allocator* alloc, slot_type* slot) {
0526     absl::allocator_traits<Allocator>::destroy(*alloc, slot);
0527     return IsDestructionTrivial<Allocator, slot_type>();
0528   }
0529 
0530   static T& element(slot_type* slot) { return *slot; }
0531 
0532   template <class F, class... Args>
0533   static decltype(absl::container_internal::DecomposeValue(
0534       std::declval<F>(), std::declval<Args>()...))
0535   apply(F&& f, Args&&... args) {
0536     return absl::container_internal::DecomposeValue(
0537         std::forward<F>(f), std::forward<Args>(args)...);
0538   }
0539 
0540   static size_t space_used(const T*) { return 0; }
0541 
0542   template <class Hash>
0543   static constexpr HashSlotFn get_hash_slot_fn() {
0544     return &TypeErasedApplyToSlotFn<Hash, T>;
0545   }
0546 };
0547 }  // namespace container_internal
0548 
0549 namespace container_algorithm_internal {
0550 
0551 // Specialization of trait in absl/algorithm/container.h
0552 template <class Key, class Hash, class KeyEqual, class Allocator>
0553 struct IsUnorderedContainer<absl::flat_hash_set<Key, Hash, KeyEqual, Allocator>>
0554     : std::true_type {};
0555 
0556 }  // namespace container_algorithm_internal
0557 
0558 ABSL_NAMESPACE_END
0559 }  // namespace absl
0560 
0561 #endif  // ABSL_CONTAINER_FLAT_HASH_SET_H_