tor-browser

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

node_hash_map.h (27168B)


      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 // -----------------------------------------------------------------------------
     16 // File: node_hash_map.h
     17 // -----------------------------------------------------------------------------
     18 //
     19 // An `absl::node_hash_map<K, V>` is an unordered associative container of
     20 // unique keys and associated values designed to be a more efficient replacement
     21 // for `std::unordered_map`. Like `unordered_map`, search, insertion, and
     22 // deletion of map elements can be done as an `O(1)` operation. However,
     23 // `node_hash_map` (and other unordered associative containers known as the
     24 // collection of Abseil "Swiss tables") contain other optimizations that result
     25 // in both memory and computation advantages.
     26 //
     27 // In most cases, your default choice for a hash map should be a map of type
     28 // `flat_hash_map`. However, if you need pointer stability and cannot store
     29 // a `flat_hash_map` with `unique_ptr` elements, a `node_hash_map` may be a
     30 // valid alternative. As well, if you are migrating your code from using
     31 // `std::unordered_map`, a `node_hash_map` provides a more straightforward
     32 // migration, because it guarantees pointer stability. Consider migrating to
     33 // `node_hash_map` and perhaps converting to a more efficient `flat_hash_map`
     34 // upon further review.
     35 //
     36 // `node_hash_map` is not exception-safe.
     37 
     38 #ifndef ABSL_CONTAINER_NODE_HASH_MAP_H_
     39 #define ABSL_CONTAINER_NODE_HASH_MAP_H_
     40 
     41 #include <cstddef>
     42 #include <memory>
     43 #include <type_traits>
     44 #include <utility>
     45 
     46 #include "absl/algorithm/container.h"
     47 #include "absl/base/attributes.h"
     48 #include "absl/container/hash_container_defaults.h"
     49 #include "absl/container/internal/container_memory.h"
     50 #include "absl/container/internal/node_slot_policy.h"
     51 #include "absl/container/internal/raw_hash_map.h"  // IWYU pragma: export
     52 #include "absl/memory/memory.h"
     53 #include "absl/meta/type_traits.h"
     54 
     55 namespace absl {
     56 ABSL_NAMESPACE_BEGIN
     57 namespace container_internal {
     58 template <class Key, class Value>
     59 class NodeHashMapPolicy;
     60 }  // namespace container_internal
     61 
     62 // -----------------------------------------------------------------------------
     63 // absl::node_hash_map
     64 // -----------------------------------------------------------------------------
     65 //
     66 // An `absl::node_hash_map<K, V>` is an unordered associative container which
     67 // has been optimized for both speed and memory footprint in most common use
     68 // cases. Its interface is similar to that of `std::unordered_map<K, V>` with
     69 // the following notable differences:
     70 //
     71 // * Supports heterogeneous lookup, through `find()`, `operator[]()` and
     72 //   `insert()`, provided that the map is provided a compatible heterogeneous
     73 //   hashing function and equality operator. See below for details.
     74 // * Contains a `capacity()` member function indicating the number of element
     75 //   slots (open, deleted, and empty) within the hash map.
     76 // * Returns `void` from the `erase(iterator)` overload.
     77 //
     78 // By default, `node_hash_map` uses the `absl::Hash` hashing framework.
     79 // All fundamental and Abseil types that support the `absl::Hash` framework have
     80 // a compatible equality operator for comparing insertions into `node_hash_map`.
     81 // If your type is not yet supported by the `absl::Hash` framework, see
     82 // absl/hash/hash.h for information on extending Abseil hashing to user-defined
     83 // types.
     84 //
     85 // Using `absl::node_hash_map` at interface boundaries in dynamically loaded
     86 // libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may
     87 // be randomized across dynamically loaded libraries.
     88 //
     89 // To achieve heterogeneous lookup for custom types either `Hash` and `Eq` type
     90 // parameters can be used or `T` should have public inner types
     91 // `absl_container_hash` and (optionally) `absl_container_eq`. In either case,
     92 // `typename Hash::is_transparent` and `typename Eq::is_transparent` should be
     93 // well-formed. Both types are basically functors:
     94 // * `Hash` should support `size_t operator()(U val) const` that returns a hash
     95 // for the given `val`.
     96 // * `Eq` should support `bool operator()(U lhs, V rhs) const` that returns true
     97 // if `lhs` is equal to `rhs`.
     98 //
     99 // In most cases `T` needs only to provide the `absl_container_hash`. In this
    100 // case `std::equal_to<void>` will be used instead of `eq` part.
    101 //
    102 // PERFORMANCE WARNING: Erasure & sparsity can negatively affect performance:
    103 //  * Iteration takes O(capacity) time, not O(size).
    104 //  * erase() slows down begin() and ++iterator.
    105 //  * Capacity only shrinks on rehash() or clear() -- not on erase().
    106 //
    107 // Example:
    108 //
    109 //   // Create a node hash map of three strings (that map to strings)
    110 //   absl::node_hash_map<std::string, std::string> ducks =
    111 //     {{"a", "huey"}, {"b", "dewey"}, {"c", "louie"}};
    112 //
    113 //  // Insert a new element into the node hash map
    114 //  ducks.insert({"d", "donald"}};
    115 //
    116 //  // Force a rehash of the node hash map
    117 //  ducks.rehash(0);
    118 //
    119 //  // Find the element with the key "b"
    120 //  std::string search_key = "b";
    121 //  auto result = ducks.find(search_key);
    122 //  if (result != ducks.end()) {
    123 //    std::cout << "Result: " << result->second << std::endl;
    124 //  }
    125 template <class Key, class Value, class Hash = DefaultHashContainerHash<Key>,
    126          class Eq = DefaultHashContainerEq<Key>,
    127          class Alloc = std::allocator<std::pair<const Key, Value>>>
    128 class ABSL_ATTRIBUTE_OWNER node_hash_map
    129    : public absl::container_internal::raw_hash_map<
    130          absl::container_internal::NodeHashMapPolicy<Key, Value>, Hash, Eq,
    131          Alloc> {
    132  using Base = typename node_hash_map::raw_hash_map;
    133 
    134 public:
    135  // Constructors and Assignment Operators
    136  //
    137  // A node_hash_map supports the same overload set as `std::unordered_map`
    138  // for construction and assignment:
    139  //
    140  // *  Default constructor
    141  //
    142  //    // No allocation for the table's elements is made.
    143  //    absl::node_hash_map<int, std::string> map1;
    144  //
    145  // * Initializer List constructor
    146  //
    147  //   absl::node_hash_map<int, std::string> map2 =
    148  //       {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
    149  //
    150  // * Copy constructor
    151  //
    152  //   absl::node_hash_map<int, std::string> map3(map2);
    153  //
    154  // * Copy assignment operator
    155  //
    156  //  // Hash functor and Comparator are copied as well
    157  //  absl::node_hash_map<int, std::string> map4;
    158  //  map4 = map3;
    159  //
    160  // * Move constructor
    161  //
    162  //   // Move is guaranteed efficient
    163  //   absl::node_hash_map<int, std::string> map5(std::move(map4));
    164  //
    165  // * Move assignment operator
    166  //
    167  //   // May be efficient if allocators are compatible
    168  //   absl::node_hash_map<int, std::string> map6;
    169  //   map6 = std::move(map5);
    170  //
    171  // * Range constructor
    172  //
    173  //   std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
    174  //   absl::node_hash_map<int, std::string> map7(v.begin(), v.end());
    175  node_hash_map() {}
    176  using Base::Base;
    177 
    178  // node_hash_map::begin()
    179  //
    180  // Returns an iterator to the beginning of the `node_hash_map`.
    181  using Base::begin;
    182 
    183  // node_hash_map::cbegin()
    184  //
    185  // Returns a const iterator to the beginning of the `node_hash_map`.
    186  using Base::cbegin;
    187 
    188  // node_hash_map::cend()
    189  //
    190  // Returns a const iterator to the end of the `node_hash_map`.
    191  using Base::cend;
    192 
    193  // node_hash_map::end()
    194  //
    195  // Returns an iterator to the end of the `node_hash_map`.
    196  using Base::end;
    197 
    198  // node_hash_map::capacity()
    199  //
    200  // Returns the number of element slots (assigned, deleted, and empty)
    201  // available within the `node_hash_map`.
    202  //
    203  // NOTE: this member function is particular to `absl::node_hash_map` and is
    204  // not provided in the `std::unordered_map` API.
    205  using Base::capacity;
    206 
    207  // node_hash_map::empty()
    208  //
    209  // Returns whether or not the `node_hash_map` is empty.
    210  using Base::empty;
    211 
    212  // node_hash_map::max_size()
    213  //
    214  // Returns the largest theoretical possible number of elements within a
    215  // `node_hash_map` under current memory constraints. This value can be thought
    216  // of as the largest value of `std::distance(begin(), end())` for a
    217  // `node_hash_map<K, V>`.
    218  using Base::max_size;
    219 
    220  // node_hash_map::size()
    221  //
    222  // Returns the number of elements currently within the `node_hash_map`.
    223  using Base::size;
    224 
    225  // node_hash_map::clear()
    226  //
    227  // Removes all elements from the `node_hash_map`. Invalidates any references,
    228  // pointers, or iterators referring to contained elements.
    229  //
    230  // NOTE: this operation may shrink the underlying buffer. To avoid shrinking
    231  // the underlying buffer call `erase(begin(), end())`.
    232  using Base::clear;
    233 
    234  // node_hash_map::erase()
    235  //
    236  // Erases elements within the `node_hash_map`. Erasing does not trigger a
    237  // rehash. Overloads are listed below.
    238  //
    239  // void erase(const_iterator pos):
    240  //
    241  //   Erases the element at `position` of the `node_hash_map`, returning
    242  //   `void`.
    243  //
    244  //   NOTE: Returning `void` in this case is different than that of STL
    245  //   containers in general and `std::unordered_map` in particular (which
    246  //   return an iterator to the element following the erased element). If that
    247  //   iterator is needed, simply post increment the iterator:
    248  //
    249  //     map.erase(it++);
    250  //
    251  //
    252  // iterator erase(const_iterator first, const_iterator last):
    253  //
    254  //   Erases the elements in the open interval [`first`, `last`), returning an
    255  //   iterator pointing to `last`. The special case of calling
    256  //   `erase(begin(), end())` resets the reserved growth such that if
    257  //   `reserve(N)` has previously been called and there has been no intervening
    258  //   call to `clear()`, then after calling `erase(begin(), end())`, it is safe
    259  //   to assume that inserting N elements will not cause a rehash.
    260  //
    261  // size_type erase(const key_type& key):
    262  //
    263  //   Erases the element with the matching key, if it exists, returning the
    264  //   number of elements erased (0 or 1).
    265  using Base::erase;
    266 
    267  // node_hash_map::insert()
    268  //
    269  // Inserts an element of the specified value into the `node_hash_map`,
    270  // returning an iterator pointing to the newly inserted element, provided that
    271  // an element with the given key does not already exist. If rehashing occurs
    272  // due to the insertion, all iterators are invalidated. Overloads are listed
    273  // below.
    274  //
    275  // std::pair<iterator,bool> insert(const init_type& value):
    276  //
    277  //   Inserts a value into the `node_hash_map`. Returns a pair consisting of an
    278  //   iterator to the inserted element (or to the element that prevented the
    279  //   insertion) and a `bool` denoting whether the insertion took place.
    280  //
    281  // std::pair<iterator,bool> insert(T&& value):
    282  // std::pair<iterator,bool> insert(init_type&& value):
    283  //
    284  //   Inserts a moveable value into the `node_hash_map`. Returns a `std::pair`
    285  //   consisting of an iterator to the inserted element (or to the element that
    286  //   prevented the insertion) and a `bool` denoting whether the insertion took
    287  //   place.
    288  //
    289  // iterator insert(const_iterator hint, const init_type& value):
    290  // iterator insert(const_iterator hint, T&& value):
    291  // iterator insert(const_iterator hint, init_type&& value);
    292  //
    293  //   Inserts a value, using the position of `hint` as a non-binding suggestion
    294  //   for where to begin the insertion search. Returns an iterator to the
    295  //   inserted element, or to the existing element that prevented the
    296  //   insertion.
    297  //
    298  // void insert(InputIterator first, InputIterator last):
    299  //
    300  //   Inserts a range of values [`first`, `last`).
    301  //
    302  //   NOTE: Although the STL does not specify which element may be inserted if
    303  //   multiple keys compare equivalently, for `node_hash_map` we guarantee the
    304  //   first match is inserted.
    305  //
    306  // void insert(std::initializer_list<init_type> ilist):
    307  //
    308  //   Inserts the elements within the initializer list `ilist`.
    309  //
    310  //   NOTE: Although the STL does not specify which element may be inserted if
    311  //   multiple keys compare equivalently within the initializer list, for
    312  //   `node_hash_map` we guarantee the first match is inserted.
    313  using Base::insert;
    314 
    315  // node_hash_map::insert_or_assign()
    316  //
    317  // Inserts an element of the specified value into the `node_hash_map` provided
    318  // that a value with the given key does not already exist, or replaces it with
    319  // the element value if a key for that value already exists, returning an
    320  // iterator pointing to the newly inserted element. If rehashing occurs due to
    321  // the insertion, all iterators are invalidated. Overloads are listed
    322  // below.
    323  //
    324  // std::pair<iterator, bool> insert_or_assign(const init_type& k, T&& obj):
    325  // std::pair<iterator, bool> insert_or_assign(init_type&& k, T&& obj):
    326  //
    327  //   Inserts/Assigns (or moves) the element of the specified key into the
    328  //   `node_hash_map`.
    329  //
    330  // iterator insert_or_assign(const_iterator hint,
    331  //                           const init_type& k, T&& obj):
    332  // iterator insert_or_assign(const_iterator hint, init_type&& k, T&& obj):
    333  //
    334  //   Inserts/Assigns (or moves) the element of the specified key into the
    335  //   `node_hash_map` using the position of `hint` as a non-binding suggestion
    336  //   for where to begin the insertion search.
    337  using Base::insert_or_assign;
    338 
    339  // node_hash_map::emplace()
    340  //
    341  // Inserts an element of the specified value by constructing it in-place
    342  // within the `node_hash_map`, provided that no element with the given key
    343  // already exists.
    344  //
    345  // The element may be constructed even if there already is an element with the
    346  // key in the container, in which case the newly constructed element will be
    347  // destroyed immediately. Prefer `try_emplace()` unless your key is not
    348  // copyable or moveable.
    349  //
    350  // If rehashing occurs due to the insertion, all iterators are invalidated.
    351  using Base::emplace;
    352 
    353  // node_hash_map::emplace_hint()
    354  //
    355  // Inserts an element of the specified value by constructing it in-place
    356  // within the `node_hash_map`, using the position of `hint` as a non-binding
    357  // suggestion for where to begin the insertion search, and only inserts
    358  // provided that no element with the given key already exists.
    359  //
    360  // The element may be constructed even if there already is an element with the
    361  // key in the container, in which case the newly constructed element will be
    362  // destroyed immediately. Prefer `try_emplace()` unless your key is not
    363  // copyable or moveable.
    364  //
    365  // If rehashing occurs due to the insertion, all iterators are invalidated.
    366  using Base::emplace_hint;
    367 
    368  // node_hash_map::try_emplace()
    369  //
    370  // Inserts an element of the specified value by constructing it in-place
    371  // within the `node_hash_map`, provided that no element with the given key
    372  // already exists. Unlike `emplace()`, if an element with the given key
    373  // already exists, we guarantee that no element is constructed.
    374  //
    375  // If rehashing occurs due to the insertion, all iterators are invalidated.
    376  // Overloads are listed below.
    377  //
    378  //   std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
    379  //   std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
    380  //
    381  // Inserts (via copy or move) the element of the specified key into the
    382  // `node_hash_map`.
    383  //
    384  //   iterator try_emplace(const_iterator hint,
    385  //                        const key_type& k, Args&&... args):
    386  //   iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args):
    387  //
    388  // Inserts (via copy or move) the element of the specified key into the
    389  // `node_hash_map` using the position of `hint` as a non-binding suggestion
    390  // for where to begin the insertion search.
    391  //
    392  // All `try_emplace()` overloads make the same guarantees regarding rvalue
    393  // arguments as `std::unordered_map::try_emplace()`, namely that these
    394  // functions will not move from rvalue arguments if insertions do not happen.
    395  using Base::try_emplace;
    396 
    397  // node_hash_map::extract()
    398  //
    399  // Extracts the indicated element, erasing it in the process, and returns it
    400  // as a C++17-compatible node handle. Overloads are listed below.
    401  //
    402  // node_type extract(const_iterator position):
    403  //
    404  //   Extracts the key,value pair of the element at the indicated position and
    405  //   returns a node handle owning that extracted data.
    406  //
    407  // node_type extract(const key_type& x):
    408  //
    409  //   Extracts the key,value pair of the element with a key matching the passed
    410  //   key value and returns a node handle owning that extracted data. If the
    411  //   `node_hash_map` does not contain an element with a matching key, this
    412  //   function returns an empty node handle.
    413  //
    414  // NOTE: when compiled in an earlier version of C++ than C++17,
    415  // `node_type::key()` returns a const reference to the key instead of a
    416  // mutable reference. We cannot safely return a mutable reference without
    417  // std::launder (which is not available before C++17).
    418  using Base::extract;
    419 
    420  // node_hash_map::merge()
    421  //
    422  // Extracts elements from a given `source` node hash map into this
    423  // `node_hash_map`. If the destination `node_hash_map` already contains an
    424  // element with an equivalent key, that element is not extracted.
    425  using Base::merge;
    426 
    427  // node_hash_map::swap(node_hash_map& other)
    428  //
    429  // Exchanges the contents of this `node_hash_map` with those of the `other`
    430  // node hash map.
    431  //
    432  // All iterators and references on the `node_hash_map` remain valid, excepting
    433  // for the past-the-end iterator, which is invalidated.
    434  //
    435  // `swap()` requires that the node hash map's hashing and key equivalence
    436  // functions be Swappable, and are exchanged using unqualified calls to
    437  // non-member `swap()`. If the map's allocator has
    438  // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
    439  // set to `true`, the allocators are also exchanged using an unqualified call
    440  // to non-member `swap()`; otherwise, the allocators are not swapped.
    441  using Base::swap;
    442 
    443  // node_hash_map::rehash(count)
    444  //
    445  // Rehashes the `node_hash_map`, setting the number of slots to be at least
    446  // the passed value. If the new number of slots increases the load factor more
    447  // than the current maximum load factor
    448  // (`count` < `size()` / `max_load_factor()`), then the new number of slots
    449  // will be at least `size()` / `max_load_factor()`.
    450  //
    451  // To force a rehash, pass rehash(0).
    452  using Base::rehash;
    453 
    454  // node_hash_map::reserve(count)
    455  //
    456  // Sets the number of slots in the `node_hash_map` to the number needed to
    457  // accommodate at least `count` total elements without exceeding the current
    458  // maximum load factor, and may rehash the container if needed.
    459  using Base::reserve;
    460 
    461  // node_hash_map::at()
    462  //
    463  // Returns a reference to the mapped value of the element with key equivalent
    464  // to the passed key.
    465  using Base::at;
    466 
    467  // node_hash_map::contains()
    468  //
    469  // Determines whether an element with a key comparing equal to the given `key`
    470  // exists within the `node_hash_map`, returning `true` if so or `false`
    471  // otherwise.
    472  using Base::contains;
    473 
    474  // node_hash_map::count(const Key& key) const
    475  //
    476  // Returns the number of elements with a key comparing equal to the given
    477  // `key` within the `node_hash_map`. note that this function will return
    478  // either `1` or `0` since duplicate keys are not allowed within a
    479  // `node_hash_map`.
    480  using Base::count;
    481 
    482  // node_hash_map::equal_range()
    483  //
    484  // Returns a closed range [first, last], defined by a `std::pair` of two
    485  // iterators, containing all elements with the passed key in the
    486  // `node_hash_map`.
    487  using Base::equal_range;
    488 
    489  // node_hash_map::find()
    490  //
    491  // Finds an element with the passed `key` within the `node_hash_map`.
    492  using Base::find;
    493 
    494  // node_hash_map::operator[]()
    495  //
    496  // Returns a reference to the value mapped to the passed key within the
    497  // `node_hash_map`, performing an `insert()` if the key does not already
    498  // exist. If an insertion occurs and results in a rehashing of the container,
    499  // all iterators are invalidated. Otherwise iterators are not affected and
    500  // references are not invalidated. Overloads are listed below.
    501  //
    502  // T& operator[](const Key& key):
    503  //
    504  //   Inserts an init_type object constructed in-place if the element with the
    505  //   given key does not exist.
    506  //
    507  // T& operator[](Key&& key):
    508  //
    509  //   Inserts an init_type object constructed in-place provided that an element
    510  //   with the given key does not exist.
    511  using Base::operator[];
    512 
    513  // node_hash_map::bucket_count()
    514  //
    515  // Returns the number of "buckets" within the `node_hash_map`.
    516  using Base::bucket_count;
    517 
    518  // node_hash_map::load_factor()
    519  //
    520  // Returns the current load factor of the `node_hash_map` (the average number
    521  // of slots occupied with a value within the hash map).
    522  using Base::load_factor;
    523 
    524  // node_hash_map::max_load_factor()
    525  //
    526  // Manages the maximum load factor of the `node_hash_map`. Overloads are
    527  // listed below.
    528  //
    529  // float node_hash_map::max_load_factor()
    530  //
    531  //   Returns the current maximum load factor of the `node_hash_map`.
    532  //
    533  // void node_hash_map::max_load_factor(float ml)
    534  //
    535  //   Sets the maximum load factor of the `node_hash_map` to the passed value.
    536  //
    537  //   NOTE: This overload is provided only for API compatibility with the STL;
    538  //   `node_hash_map` will ignore any set load factor and manage its rehashing
    539  //   internally as an implementation detail.
    540  using Base::max_load_factor;
    541 
    542  // node_hash_map::get_allocator()
    543  //
    544  // Returns the allocator function associated with this `node_hash_map`.
    545  using Base::get_allocator;
    546 
    547  // node_hash_map::hash_function()
    548  //
    549  // Returns the hashing function used to hash the keys within this
    550  // `node_hash_map`.
    551  using Base::hash_function;
    552 
    553  // node_hash_map::key_eq()
    554  //
    555  // Returns the function used for comparing keys equality.
    556  using Base::key_eq;
    557 };
    558 
    559 // erase_if(node_hash_map<>, Pred)
    560 //
    561 // Erases all elements that satisfy the predicate `pred` from the container `c`.
    562 // Returns the number of erased elements.
    563 template <typename K, typename V, typename H, typename E, typename A,
    564          typename Predicate>
    565 typename node_hash_map<K, V, H, E, A>::size_type erase_if(
    566    node_hash_map<K, V, H, E, A>& c, Predicate pred) {
    567  return container_internal::EraseIf(pred, &c);
    568 }
    569 
    570 // swap(node_hash_map<>, node_hash_map<>)
    571 //
    572 // Swaps the contents of two `node_hash_map` containers.
    573 //
    574 // NOTE: we need to define this function template in order for
    575 // `flat_hash_set::swap` to be called instead of `std::swap`. Even though we
    576 // have `swap(raw_hash_set&, raw_hash_set&)` defined, that function requires a
    577 // derived-to-base conversion, whereas `std::swap` is a function template so
    578 // `std::swap` will be preferred by compiler.
    579 template <typename K, typename V, typename H, typename E, typename A>
    580 void swap(node_hash_map<K, V, H, E, A>& x,
    581          node_hash_map<K, V, H, E, A>& y) noexcept(noexcept(x.swap(y))) {
    582  return x.swap(y);
    583 }
    584 
    585 namespace container_internal {
    586 
    587 // c_for_each_fast(node_hash_map<>, Function)
    588 //
    589 // Container-based version of the <algorithm> `std::for_each()` function to
    590 // apply a function to a container's elements.
    591 // There is no guarantees on the order of the function calls.
    592 // Erasure and/or insertion of elements in the function is not allowed.
    593 template <typename K, typename V, typename H, typename E, typename A,
    594          typename Function>
    595 decay_t<Function> c_for_each_fast(const node_hash_map<K, V, H, E, A>& c,
    596                                  Function&& f) {
    597  container_internal::ForEach(f, &c);
    598  return f;
    599 }
    600 template <typename K, typename V, typename H, typename E, typename A,
    601          typename Function>
    602 decay_t<Function> c_for_each_fast(node_hash_map<K, V, H, E, A>& c,
    603                                  Function&& f) {
    604  container_internal::ForEach(f, &c);
    605  return f;
    606 }
    607 template <typename K, typename V, typename H, typename E, typename A,
    608          typename Function>
    609 decay_t<Function> c_for_each_fast(node_hash_map<K, V, H, E, A>&& c,
    610                                  Function&& f) {
    611  container_internal::ForEach(f, &c);
    612  return f;
    613 }
    614 
    615 }  // namespace container_internal
    616 
    617 namespace container_internal {
    618 
    619 template <class Key, class Value>
    620 class NodeHashMapPolicy
    621    : public absl::container_internal::node_slot_policy<
    622          std::pair<const Key, Value>&, NodeHashMapPolicy<Key, Value>> {
    623  using value_type = std::pair<const Key, Value>;
    624 
    625 public:
    626  using key_type = Key;
    627  using mapped_type = Value;
    628  using init_type = std::pair</*non const*/ key_type, mapped_type>;
    629 
    630  template <class Allocator, class... Args>
    631  static value_type* new_element(Allocator* alloc, Args&&... args) {
    632    using PairAlloc = typename absl::allocator_traits<
    633        Allocator>::template rebind_alloc<value_type>;
    634    PairAlloc pair_alloc(*alloc);
    635    value_type* res =
    636        absl::allocator_traits<PairAlloc>::allocate(pair_alloc, 1);
    637    absl::allocator_traits<PairAlloc>::construct(pair_alloc, res,
    638                                                 std::forward<Args>(args)...);
    639    return res;
    640  }
    641 
    642  template <class Allocator>
    643  static void delete_element(Allocator* alloc, value_type* pair) {
    644    using PairAlloc = typename absl::allocator_traits<
    645        Allocator>::template rebind_alloc<value_type>;
    646    PairAlloc pair_alloc(*alloc);
    647    absl::allocator_traits<PairAlloc>::destroy(pair_alloc, pair);
    648    absl::allocator_traits<PairAlloc>::deallocate(pair_alloc, pair, 1);
    649  }
    650 
    651  template <class F, class... Args>
    652  static decltype(absl::container_internal::DecomposePair(
    653      std::declval<F>(), std::declval<Args>()...))
    654  apply(F&& f, Args&&... args) {
    655    return absl::container_internal::DecomposePair(std::forward<F>(f),
    656                                                   std::forward<Args>(args)...);
    657  }
    658 
    659  static size_t element_space_used(const value_type*) {
    660    return sizeof(value_type);
    661  }
    662 
    663  static Value& value(value_type* elem) { return elem->second; }
    664  static const Value& value(const value_type* elem) { return elem->second; }
    665 
    666  template <class Hash>
    667  static constexpr HashSlotFn get_hash_slot_fn() {
    668    return memory_internal::IsLayoutCompatible<Key, Value>::value
    669               ? &TypeErasedDerefAndApplyToSlotFn<Hash, Key>
    670               : nullptr;
    671  }
    672 };
    673 }  // namespace container_internal
    674 
    675 namespace container_algorithm_internal {
    676 
    677 // Specialization of trait in absl/algorithm/container.h
    678 template <class Key, class T, class Hash, class KeyEqual, class Allocator>
    679 struct IsUnorderedContainer<
    680    absl::node_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
    681 
    682 }  // namespace container_algorithm_internal
    683 
    684 ABSL_NAMESPACE_END
    685 }  // namespace absl
    686 
    687 #endif  // ABSL_CONTAINER_NODE_HASH_MAP_H_