// unordered_set implementation -*- C++ -*- // Copyright (C) 2010-2024 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . /** @file bits/unordered_set.h * This is an internal header file, included by other library headers. * Do not attempt to use it directly. @headername{unordered_set} */ #ifndef _UNORDERED_SET_H #define _UNORDERED_SET_H #include #include #include // hash #include // equal_to namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Base types for unordered_set. template using __uset_traits = __detail::_Hashtable_traits<_Cache, true, true>; template, typename _Pred = std::equal_to<_Value>, typename _Alloc = std::allocator<_Value>, typename _Tr = __uset_traits<__cache_default<_Value, _Hash>::value>> using __uset_hashtable = _Hashtable<_Value, _Value, _Alloc, __detail::_Identity, _Pred, _Hash, __detail::_Mod_range_hashing, __detail::_Default_ranged_hash, __detail::_Prime_rehash_policy, _Tr>; /// Base types for unordered_multiset. template using __umset_traits = __detail::_Hashtable_traits<_Cache, true, false>; template, typename _Pred = std::equal_to<_Value>, typename _Alloc = std::allocator<_Value>, typename _Tr = __umset_traits<__cache_default<_Value, _Hash>::value>> using __umset_hashtable = _Hashtable<_Value, _Value, _Alloc, __detail::_Identity, _Pred, _Hash, __detail::_Mod_range_hashing, __detail::_Default_ranged_hash, __detail::_Prime_rehash_policy, _Tr>; template class unordered_multiset; /** * @brief A standard container composed of unique keys (containing * at most one of each key value) in which the elements' keys are * the elements themselves. * * @ingroup unordered_associative_containers * @headerfile unordered_set * @since C++11 * * @tparam _Value Type of key objects. * @tparam _Hash Hashing function object type, defaults to hash<_Value>. * @tparam _Pred Predicate function object type, defaults to * equal_to<_Value>. * * @tparam _Alloc Allocator type, defaults to allocator<_Key>. * * Meets the requirements of a container, and * unordered associative container * * Base is _Hashtable, dispatched at compile time via template * alias __uset_hashtable. */ template, typename _Pred = equal_to<_Value>, typename _Alloc = allocator<_Value>> class unordered_set { typedef __uset_hashtable<_Value, _Hash, _Pred, _Alloc> _Hashtable; _Hashtable _M_h; public: // typedefs: ///@{ /// Public typedefs. typedef typename _Hashtable::key_type key_type; typedef typename _Hashtable::value_type value_type; typedef typename _Hashtable::hasher hasher; typedef typename _Hashtable::key_equal key_equal; typedef typename _Hashtable::allocator_type allocator_type; ///@} ///@{ /// Iterator-related typedefs. typedef typename _Hashtable::pointer pointer; typedef typename _Hashtable::const_pointer const_pointer; typedef typename _Hashtable::reference reference; typedef typename _Hashtable::const_reference const_reference; typedef typename _Hashtable::iterator iterator; typedef typename _Hashtable::const_iterator const_iterator; typedef typename _Hashtable::local_iterator local_iterator; typedef typename _Hashtable::const_local_iterator const_local_iterator; typedef typename _Hashtable::size_type size_type; typedef typename _Hashtable::difference_type difference_type; ///@} #if __cplusplus > 201402L using node_type = typename _Hashtable::node_type; using insert_return_type = typename _Hashtable::insert_return_type; #endif // construct/destroy/copy /// Default constructor. unordered_set() = default; /** * @brief Default constructor creates no elements. * @param __n Minimal initial number of buckets. * @param __hf A hash functor. * @param __eql A key equality functor. * @param __a An allocator object. */ explicit unordered_set(size_type __n, const hasher& __hf = hasher(), const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _M_h(__n, __hf, __eql, __a) { } /** * @brief Builds an %unordered_set from a range. * @param __first An input iterator. * @param __last An input iterator. * @param __n Minimal initial number of buckets. * @param __hf A hash functor. * @param __eql A key equality functor. * @param __a An allocator object. * * Create an %unordered_set consisting of copies of the elements from * [__first,__last). This is linear in N (where N is * distance(__first,__last)). */ template unordered_set(_InputIterator __first, _InputIterator __last, size_type __n = 0, const hasher& __hf = hasher(), const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _M_h(__first, __last, __n, __hf, __eql, __a) { } /// Copy constructor. unordered_set(const unordered_set&) = default; /// Move constructor. unordered_set(unordered_set&&) = default; /** * @brief Creates an %unordered_set with no elements. * @param __a An allocator object. */ explicit unordered_set(const allocator_type& __a) : _M_h(__a) { } /* * @brief Copy constructor with allocator argument. * @param __uset Input %unordered_set to copy. * @param __a An allocator object. */ unordered_set(const unordered_set& __uset, const allocator_type& __a) : _M_h(__uset._M_h, __a) { } /* * @brief Move constructor with allocator argument. * @param __uset Input %unordered_set to move. * @param __a An allocator object. */ unordered_set(unordered_set&& __uset, const allocator_type& __a) noexcept( noexcept(_Hashtable(std::move(__uset._M_h), __a)) ) : _M_h(std::move(__uset._M_h), __a) { } /** * @brief Builds an %unordered_set from an initializer_list. * @param __l An initializer_list. * @param __n Minimal initial number of buckets. * @param __hf A hash functor. * @param __eql A key equality functor. * @param __a An allocator object. * * Create an %unordered_set consisting of copies of the elements in the * list. This is linear in N (where N is @a __l.size()). */ unordered_set(initializer_list __l, size_type __n = 0, const hasher& __hf = hasher(), const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _M_h(__l, __n, __hf, __eql, __a) { } unordered_set(size_type __n, const allocator_type& __a) : unordered_set(__n, hasher(), key_equal(), __a) { } unordered_set(size_type __n, const hasher& __hf, const allocator_type& __a) : unordered_set(__n, __hf, key_equal(), __a) { } template unordered_set(_InputIterator __first, _InputIterator __last, size_type __n, const allocator_type& __a) : unordered_set(__first, __last, __n, hasher(), key_equal(), __a) { } template unordered_set(_InputIterator __first, _InputIterator __last, size_type __n, const hasher& __hf, const allocator_type& __a) : unordered_set(__first, __last, __n, __hf, key_equal(), __a) { } unordered_set(initializer_list __l, size_type __n, const allocator_type& __a) : unordered_set(__l, __n, hasher(), key_equal(), __a) { } unordered_set(initializer_list __l, size_type __n, const hasher& __hf, const allocator_type& __a) : unordered_set(__l, __n, __hf, key_equal(), __a) { } /// Copy assignment operator. unordered_set& operator=(const unordered_set&) = default; /// Move assignment operator. unordered_set& operator=(unordered_set&&) = default; /** * @brief %Unordered_set list assignment operator. * @param __l An initializer_list. * * This function fills an %unordered_set with copies of the elements in * the initializer list @a __l. * * Note that the assignment completely changes the %unordered_set and * that the resulting %unordered_set's size is the same as the number * of elements assigned. */ unordered_set& operator=(initializer_list __l) { _M_h = __l; return *this; } /// Returns the allocator object used by the %unordered_set. allocator_type get_allocator() const noexcept { return _M_h.get_allocator(); } // size and capacity: /// Returns true if the %unordered_set is empty. _GLIBCXX_NODISCARD bool empty() const noexcept { return _M_h.empty(); } /// Returns the size of the %unordered_set. size_type size() const noexcept { return _M_h.size(); } /// Returns the maximum size of the %unordered_set. size_type max_size() const noexcept { return _M_h.max_size(); } // iterators. ///@{ /** * Returns a read-only (constant) iterator that points to the first * element in the %unordered_set. */ iterator begin() noexcept { return _M_h.begin(); } const_iterator begin() const noexcept { return _M_h.begin(); } ///@} ///@{ /** * Returns a read-only (constant) iterator that points one past the last * element in the %unordered_set. */ iterator end() noexcept { return _M_h.end(); } const_iterator end() const noexcept { return _M_h.end(); } ///@} /** * Returns a read-only (constant) iterator that points to the first * element in the %unordered_set. */ const_iterator cbegin() const noexcept { return _M_h.begin(); } /** * Returns a read-only (constant) iterator that points one past the last * element in the %unordered_set. */ const_iterator cend() const noexcept { return _M_h.end(); } // modifiers. /** * @brief Attempts to build and insert an element into the * %unordered_set. * @param __args Arguments used to generate an element. * @return A pair, of which the first element is an iterator that points * to the possibly inserted element, and the second is a bool * that is true if the element was actually inserted. * * This function attempts to build and insert an element into the * %unordered_set. An %unordered_set relies on unique keys and thus an * element is only inserted if it is not already present in the * %unordered_set. * * Insertion requires amortized constant time. */ template std::pair emplace(_Args&&... __args) { return _M_h.emplace(std::forward<_Args>(__args)...); } /** * @brief Attempts to insert an element into the %unordered_set. * @param __pos An iterator that serves as a hint as to where the * element should be inserted. * @param __args Arguments used to generate the element to be * inserted. * @return An iterator that points to the element with key equivalent to * the one generated from @a __args (may or may not be the * element itself). * * This function is not concerned about whether the insertion took place, * and thus does not return a boolean like the single-argument emplace() * does. Note that the first parameter is only a hint and can * potentially improve the performance of the insertion process. A bad * hint would cause no gains in efficiency. * * For more on @a hinting, see: * https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints * * Insertion requires amortized constant time. */ template iterator emplace_hint(const_iterator __pos, _Args&&... __args) { return _M_h.emplace_hint(__pos, std::forward<_Args>(__args)...); } ///@{ /** * @brief Attempts to insert an element into the %unordered_set. * @param __x Element to be inserted. * @return A pair, of which the first element is an iterator that points * to the possibly inserted element, and the second is a bool * that is true if the element was actually inserted. * * This function attempts to insert an element into the %unordered_set. * An %unordered_set relies on unique keys and thus an element is only * inserted if it is not already present in the %unordered_set. * * Insertion requires amortized constant time. */ std::pair insert(const value_type& __x) { return _M_h.insert(__x); } std::pair insert(value_type&& __x) { return _M_h.insert(std::move(__x)); } ///@} ///@{ /** * @brief Attempts to insert an element into the %unordered_set. * @param __hint An iterator that serves as a hint as to where the * element should be inserted. * @param __x Element to be inserted. * @return An iterator that points to the element with key of * @a __x (may or may not be the element passed in). * * This function is not concerned about whether the insertion took place, * and thus does not return a boolean like the single-argument insert() * does. Note that the first parameter is only a hint and can * potentially improve the performance of the insertion process. A bad * hint would cause no gains in efficiency. * * For more on @a hinting, see: * https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints * * Insertion requires amortized constant. */ iterator insert(const_iterator __hint, const value_type& __x) { return _M_h.insert(__hint, __x); } iterator insert(const_iterator __hint, value_type&& __x) { return _M_h.insert(__hint, std::move(__x)); } ///@} /** * @brief A template function that attempts to insert a range of * elements. * @param __first Iterator pointing to the start of the range to be * inserted. * @param __last Iterator pointing to the end of the range. * * Complexity similar to that of the range constructor. */ template void insert(_InputIterator __first, _InputIterator __last) { _M_h.insert(__first, __last); } /** * @brief Attempts to insert a list of elements into the %unordered_set. * @param __l A std::initializer_list of elements * to be inserted. * * Complexity similar to that of the range constructor. */ void insert(initializer_list __l) { _M_h.insert(__l); } #if __cplusplus > 201402L /// Extract a node. node_type extract(const_iterator __pos) { __glibcxx_assert(__pos != end()); return _M_h.extract(__pos); } /// Extract a node. node_type extract(const key_type& __key) { return _M_h.extract(__key); } /// Re-insert an extracted node. insert_return_type insert(node_type&& __nh) { return _M_h._M_reinsert_node(std::move(__nh)); } /// Re-insert an extracted node. iterator insert(const_iterator, node_type&& __nh) { return _M_h._M_reinsert_node(std::move(__nh)).position; } #endif // C++17 ///@{ /** * @brief Erases an element from an %unordered_set. * @param __position An iterator pointing to the element to be erased. * @return An iterator pointing to the element immediately following * @a __position prior to the element being erased. If no such * element exists, end() is returned. * * This function erases an element, pointed to by the given iterator, * from an %unordered_set. Note that this function only erases the * element, and that if the element is itself a pointer, the pointed-to * memory is not touched in any way. Managing the pointer is the user's * responsibility. */ iterator erase(const_iterator __position) { return _M_h.erase(__position); } // LWG 2059. iterator erase(iterator __position) { return _M_h.erase(__position); } ///@} /** * @brief Erases elements according to the provided key. * @param __x Key of element to be erased. * @return The number of elements erased. * * This function erases all the elements located by the given key from * an %unordered_set. For an %unordered_set the result of this function * can only be 0 (not present) or 1 (present). * Note that this function only erases the element, and that if * the element is itself a pointer, the pointed-to memory is not touched * in any way. Managing the pointer is the user's responsibility. */ size_type erase(const key_type& __x) { return _M_h.erase(__x); } /** * @brief Erases a [__first,__last) range of elements from an * %unordered_set. * @param __first Iterator pointing to the start of the range to be * erased. * @param __last Iterator pointing to the end of the range to * be erased. * @return The iterator @a __last. * * This function erases a sequence of elements from an %unordered_set. * Note that this function only erases the element, and that if * the element is itself a pointer, the pointed-to memory is not touched * in any way. Managing the pointer is the user's responsibility. */ iterator erase(const_iterator __first, const_iterator __last) { return _M_h.erase(__first, __last); } /** * Erases all elements in an %unordered_set. Note that this function only * erases the elements, and that if the elements themselves are pointers, * the pointed-to memory is not touched in any way. Managing the pointer * is the user's responsibility. */ void clear() noexcept { _M_h.clear(); } /** * @brief Swaps data with another %unordered_set. * @param __x An %unordered_set of the same element and allocator * types. * * This exchanges the elements between two sets in constant time. * Note that the global std::swap() function is specialized such that * std::swap(s1,s2) will feed to this function. */ void swap(unordered_set& __x) noexcept( noexcept(_M_h.swap(__x._M_h)) ) { _M_h.swap(__x._M_h); } #if __cplusplus > 201402L template friend class std::_Hash_merge_helper; template void merge(unordered_set<_Value, _H2, _P2, _Alloc>& __source) { using _Merge_helper = _Hash_merge_helper; _M_h._M_merge_unique(_Merge_helper::_S_get_table(__source)); } template void merge(unordered_set<_Value, _H2, _P2, _Alloc>&& __source) { merge(__source); } template void merge(unordered_multiset<_Value, _H2, _P2, _Alloc>& __source) { using _Merge_helper = _Hash_merge_helper; _M_h._M_merge_unique(_Merge_helper::_S_get_table(__source)); } template void merge(unordered_multiset<_Value, _H2, _P2, _Alloc>&& __source) { merge(__source); } #endif // C++17 // observers. /// Returns the hash functor object with which the %unordered_set was /// constructed. hasher hash_function() const { return _M_h.hash_function(); } /// Returns the key comparison object with which the %unordered_set was /// constructed. key_equal key_eq() const { return _M_h.key_eq(); } // lookup. ///@{ /** * @brief Tries to locate an element in an %unordered_set. * @param __x Element to be located. * @return Iterator pointing to sought-after element, or end() if not * found. * * This function takes a key and tries to locate the element with which * the key matches. If successful the function returns an iterator * pointing to the sought after element. If unsuccessful it returns the * past-the-end ( @c end() ) iterator. */ iterator find(const key_type& __x) { return _M_h.find(__x); } #if __cplusplus > 201703L template auto find(const _Kt& __k) -> decltype(_M_h._M_find_tr(__k)) { return _M_h._M_find_tr(__k); } #endif const_iterator find(const key_type& __x) const { return _M_h.find(__x); } #if __cplusplus > 201703L template auto find(const _Kt& __k) const -> decltype(_M_h._M_find_tr(__k)) { return _M_h._M_find_tr(__k); } #endif ///@} ///@{ /** * @brief Finds the number of elements. * @param __x Element to located. * @return Number of elements with specified key. * * This function only makes sense for unordered_multisets; for * unordered_set the result will either be 0 (not present) or 1 * (present). */ size_type count(const key_type& __x) const { return _M_h.count(__x); } #if __cplusplus > 201703L template auto count(const _Kt& __k) const -> decltype(_M_h._M_count_tr(__k)) { return _M_h._M_count_tr(__k); } #endif ///@} #if __cplusplus > 201703L ///@{ /** * @brief Finds whether an element with the given key exists. * @param __x Key of elements to be located. * @return True if there is any element with the specified key. */ bool contains(const key_type& __x) const { return _M_h.find(__x) != _M_h.end(); } template auto contains(const _Kt& __k) const -> decltype(_M_h._M_find_tr(__k), void(), true) { return _M_h._M_find_tr(__k) != _M_h.end(); } ///@} #endif ///@{ /** * @brief Finds a subsequence matching given key. * @param __x Key to be located. * @return Pair of iterators that possibly points to the subsequence * matching given key. * * This function probably only makes sense for multisets. */ std::pair equal_range(const key_type& __x) { return _M_h.equal_range(__x); } #if __cplusplus > 201703L template auto equal_range(const _Kt& __k) -> decltype(_M_h._M_equal_range_tr(__k)) { return _M_h._M_equal_range_tr(__k); } #endif std::pair equal_range(const key_type& __x) const { return _M_h.equal_range(__x); } #if __cplusplus > 201703L template auto equal_range(const _Kt& __k) const -> decltype(_M_h._M_equal_range_tr(__k)) { return _M_h._M_equal_range_tr(__k); } #endif ///@} // bucket interface. /// Returns the number of buckets of the %unordered_set. size_type bucket_count() const noexcept { return _M_h.bucket_count(); } /// Returns the maximum number of buckets of the %unordered_set. size_type max_bucket_count() const noexcept { return _M_h.max_bucket_count(); } /* * @brief Returns the number of elements in a given bucket. * @param __n A bucket index. * @return The number of elements in the bucket. */ size_type bucket_size(size_type __n) const { return _M_h.bucket_size(__n); } /* * @brief Returns the bucket index of a given element. * @param __key A key instance. * @return The key bucket index. */ size_type bucket(const key_type& __key) const { return _M_h.bucket(__key); } ///@{ /** * @brief Returns a read-only (constant) iterator pointing to the first * bucket element. * @param __n The bucket index. * @return A read-only local iterator. */ local_iterator begin(size_type __n) { return _M_h.begin(__n); } const_local_iterator begin(size_type __n) const { return _M_h.begin(__n); } const_local_iterator cbegin(size_type __n) const { return _M_h.cbegin(__n); } ///@} ///@{ /** * @brief Returns a read-only (constant) iterator pointing to one past * the last bucket elements. * @param __n The bucket index. * @return A read-only local iterator. */ local_iterator end(size_type __n) { return _M_h.end(__n); } const_local_iterator end(size_type __n) const { return _M_h.end(__n); } const_local_iterator cend(size_type __n) const { return _M_h.cend(__n); } ///@} // hash policy. /// Returns the average number of elements per bucket. float load_factor() const noexcept { return _M_h.load_factor(); } /// Returns a positive number that the %unordered_set tries to keep the /// load factor less than or equal to. float max_load_factor() const noexcept { return _M_h.max_load_factor(); } /** * @brief Change the %unordered_set maximum load factor. * @param __z The new maximum load factor. */ void max_load_factor(float __z) { _M_h.max_load_factor(__z); } /** * @brief May rehash the %unordered_set. * @param __n The new number of buckets. * * Rehash will occur only if the new number of buckets respect the * %unordered_set maximum load factor. */ void rehash(size_type __n) { _M_h.rehash(__n); } /** * @brief Prepare the %unordered_set for a specified number of * elements. * @param __n Number of elements required. * * Same as rehash(ceil(n / max_load_factor())). */ void reserve(size_type __n) { _M_h.reserve(__n); } template friend bool operator==(const unordered_set<_Value1, _Hash1, _Pred1, _Alloc1>&, const unordered_set<_Value1, _Hash1, _Pred1, _Alloc1>&); }; #if __cpp_deduction_guides >= 201606 template::value_type>, typename _Pred = equal_to::value_type>, typename _Allocator = allocator::value_type>, typename = _RequireInputIter<_InputIterator>, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireNotAllocator<_Pred>, typename = _RequireAllocator<_Allocator>> unordered_set(_InputIterator, _InputIterator, unordered_set::size_type = {}, _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator()) -> unordered_set::value_type, _Hash, _Pred, _Allocator>; template, typename _Pred = equal_to<_Tp>, typename _Allocator = allocator<_Tp>, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireNotAllocator<_Pred>, typename = _RequireAllocator<_Allocator>> unordered_set(initializer_list<_Tp>, unordered_set::size_type = {}, _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator()) -> unordered_set<_Tp, _Hash, _Pred, _Allocator>; template, typename = _RequireAllocator<_Allocator>> unordered_set(_InputIterator, _InputIterator, unordered_set::size_type, _Allocator) -> unordered_set::value_type, hash< typename iterator_traits<_InputIterator>::value_type>, equal_to< typename iterator_traits<_InputIterator>::value_type>, _Allocator>; template, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireAllocator<_Allocator>> unordered_set(_InputIterator, _InputIterator, unordered_set::size_type, _Hash, _Allocator) -> unordered_set::value_type, _Hash, equal_to< typename iterator_traits<_InputIterator>::value_type>, _Allocator>; template> unordered_set(initializer_list<_Tp>, unordered_set::size_type, _Allocator) -> unordered_set<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; template, typename = _RequireAllocator<_Allocator>> unordered_set(initializer_list<_Tp>, unordered_set::size_type, _Hash, _Allocator) -> unordered_set<_Tp, _Hash, equal_to<_Tp>, _Allocator>; #endif /** * @brief A standard container composed of equivalent keys * (possibly containing multiple of each key value) in which the * elements' keys are the elements themselves. * * @ingroup unordered_associative_containers * @headerfile unordered_set * @since C++11 * * @tparam _Value Type of key objects. * @tparam _Hash Hashing function object type, defaults to hash<_Value>. * @tparam _Pred Predicate function object type, defaults * to equal_to<_Value>. * @tparam _Alloc Allocator type, defaults to allocator<_Key>. * * Meets the requirements of a container, and * unordered associative container * * Base is _Hashtable, dispatched at compile time via template * alias __umset_hashtable. */ template, typename _Pred = equal_to<_Value>, typename _Alloc = allocator<_Value>> class unordered_multiset { typedef __umset_hashtable<_Value, _Hash, _Pred, _Alloc> _Hashtable; _Hashtable _M_h; public: // typedefs: ///@{ /// Public typedefs. typedef typename _Hashtable::key_type key_type; typedef typename _Hashtable::value_type value_type; typedef typename _Hashtable::hasher hasher; typedef typename _Hashtable::key_equal key_equal; typedef typename _Hashtable::allocator_type allocator_type; ///@} ///@{ /// Iterator-related typedefs. typedef typename _Hashtable::pointer pointer; typedef typename _Hashtable::const_pointer const_pointer; typedef typename _Hashtable::reference reference; typedef typename _Hashtable::const_reference const_reference; typedef typename _Hashtable::iterator iterator; typedef typename _Hashtable::const_iterator const_iterator; typedef typename _Hashtable::local_iterator local_iterator; typedef typename _Hashtable::const_local_iterator const_local_iterator; typedef typename _Hashtable::size_type size_type; typedef typename _Hashtable::difference_type difference_type; ///@} #if __cplusplus > 201402L using node_type = typename _Hashtable::node_type; #endif // construct/destroy/copy /// Default constructor. unordered_multiset() = default; /** * @brief Default constructor creates no elements. * @param __n Minimal initial number of buckets. * @param __hf A hash functor. * @param __eql A key equality functor. * @param __a An allocator object. */ explicit unordered_multiset(size_type __n, const hasher& __hf = hasher(), const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _M_h(__n, __hf, __eql, __a) { } /** * @brief Builds an %unordered_multiset from a range. * @param __first An input iterator. * @param __last An input iterator. * @param __n Minimal initial number of buckets. * @param __hf A hash functor. * @param __eql A key equality functor. * @param __a An allocator object. * * Create an %unordered_multiset consisting of copies of the elements * from [__first,__last). This is linear in N (where N is * distance(__first,__last)). */ template unordered_multiset(_InputIterator __first, _InputIterator __last, size_type __n = 0, const hasher& __hf = hasher(), const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _M_h(__first, __last, __n, __hf, __eql, __a) { } /// Copy constructor. unordered_multiset(const unordered_multiset&) = default; /// Move constructor. unordered_multiset(unordered_multiset&&) = default; /** * @brief Builds an %unordered_multiset from an initializer_list. * @param __l An initializer_list. * @param __n Minimal initial number of buckets. * @param __hf A hash functor. * @param __eql A key equality functor. * @param __a An allocator object. * * Create an %unordered_multiset consisting of copies of the elements in * the list. This is linear in N (where N is @a __l.size()). */ unordered_multiset(initializer_list __l, size_type __n = 0, const hasher& __hf = hasher(), const key_equal& __eql = key_equal(), const allocator_type& __a = allocator_type()) : _M_h(__l, __n, __hf, __eql, __a) { } /// Copy assignment operator. unordered_multiset& operator=(const unordered_multiset&) = default; /// Move assignment operator. unordered_multiset& operator=(unordered_multiset&&) = default; /** * @brief Creates an %unordered_multiset with no elements. * @param __a An allocator object. */ explicit unordered_multiset(const allocator_type& __a) : _M_h(__a) { } /* * @brief Copy constructor with allocator argument. * @param __uset Input %unordered_multiset to copy. * @param __a An allocator object. */ unordered_multiset(const unordered_multiset& __umset, const allocator_type& __a) : _M_h(__umset._M_h, __a) { } /* * @brief Move constructor with allocator argument. * @param __umset Input %unordered_multiset to move. * @param __a An allocator object. */ unordered_multiset(unordered_multiset&& __umset, const allocator_type& __a) noexcept( noexcept(_Hashtable(std::move(__umset._M_h), __a)) ) : _M_h(std::move(__umset._M_h), __a) { } unordered_multiset(size_type __n, const allocator_type& __a) : unordered_multiset(__n, hasher(), key_equal(), __a) { } unordered_multiset(size_type __n, const hasher& __hf, const allocator_type& __a) : unordered_multiset(__n, __hf, key_equal(), __a) { } template unordered_multiset(_InputIterator __first, _InputIterator __last, size_type __n, const allocator_type& __a) : unordered_multiset(__first, __last, __n, hasher(), key_equal(), __a) { } template unordered_multiset(_InputIterator __first, _InputIterator __last, size_type __n, const hasher& __hf, const allocator_type& __a) : unordered_multiset(__first, __last, __n, __hf, key_equal(), __a) { } unordered_multiset(initializer_list __l, size_type __n, const allocator_type& __a) : unordered_multiset(__l, __n, hasher(), key_equal(), __a) { } unordered_multiset(initializer_list __l, size_type __n, const hasher& __hf, const allocator_type& __a) : unordered_multiset(__l, __n, __hf, key_equal(), __a) { } /** * @brief %Unordered_multiset list assignment operator. * @param __l An initializer_list. * * This function fills an %unordered_multiset with copies of the elements * in the initializer list @a __l. * * Note that the assignment completely changes the %unordered_multiset * and that the resulting %unordered_multiset's size is the same as the * number of elements assigned. */ unordered_multiset& operator=(initializer_list __l) { _M_h = __l; return *this; } /// Returns the allocator object used by the %unordered_multiset. allocator_type get_allocator() const noexcept { return _M_h.get_allocator(); } // size and capacity: /// Returns true if the %unordered_multiset is empty. _GLIBCXX_NODISCARD bool empty() const noexcept { return _M_h.empty(); } /// Returns the size of the %unordered_multiset. size_type size() const noexcept { return _M_h.size(); } /// Returns the maximum size of the %unordered_multiset. size_type max_size() const noexcept { return _M_h.max_size(); } // iterators. ///@{ /** * Returns a read-only (constant) iterator that points to the first * element in the %unordered_multiset. */ iterator begin() noexcept { return _M_h.begin(); } const_iterator begin() const noexcept { return _M_h.begin(); } ///@} ///@{ /** * Returns a read-only (constant) iterator that points one past the last * element in the %unordered_multiset. */ iterator end() noexcept { return _M_h.end(); } const_iterator end() const noexcept { return _M_h.end(); } ///@} /** * Returns a read-only (constant) iterator that points to the first * element in the %unordered_multiset. */ const_iterator cbegin() const noexcept { return _M_h.begin(); } /** * Returns a read-only (constant) iterator that points one past the last * element in the %unordered_multiset. */ const_iterator cend() const noexcept { return _M_h.end(); } // modifiers. /** * @brief Builds and insert an element into the %unordered_multiset. * @param __args Arguments used to generate an element. * @return An iterator that points to the inserted element. * * Insertion requires amortized constant time. */ template iterator emplace(_Args&&... __args) { return _M_h.emplace(std::forward<_Args>(__args)...); } /** * @brief Inserts an element into the %unordered_multiset. * @param __pos An iterator that serves as a hint as to where the * element should be inserted. * @param __args Arguments used to generate the element to be * inserted. * @return An iterator that points to the inserted element. * * Note that the first parameter is only a hint and can potentially * improve the performance of the insertion process. A bad hint would * cause no gains in efficiency. * * For more on @a hinting, see: * https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints * * Insertion requires amortized constant time. */ template iterator emplace_hint(const_iterator __pos, _Args&&... __args) { return _M_h.emplace_hint(__pos, std::forward<_Args>(__args)...); } ///@{ /** * @brief Inserts an element into the %unordered_multiset. * @param __x Element to be inserted. * @return An iterator that points to the inserted element. * * Insertion requires amortized constant time. */ iterator insert(const value_type& __x) { return _M_h.insert(__x); } iterator insert(value_type&& __x) { return _M_h.insert(std::move(__x)); } ///@} ///@{ /** * @brief Inserts an element into the %unordered_multiset. * @param __hint An iterator that serves as a hint as to where the * element should be inserted. * @param __x Element to be inserted. * @return An iterator that points to the inserted element. * * Note that the first parameter is only a hint and can potentially * improve the performance of the insertion process. A bad hint would * cause no gains in efficiency. * * For more on @a hinting, see: * https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints * * Insertion requires amortized constant. */ iterator insert(const_iterator __hint, const value_type& __x) { return _M_h.insert(__hint, __x); } iterator insert(const_iterator __hint, value_type&& __x) { return _M_h.insert(__hint, std::move(__x)); } ///@} /** * @brief A template function that inserts a range of elements. * @param __first Iterator pointing to the start of the range to be * inserted. * @param __last Iterator pointing to the end of the range. * * Complexity similar to that of the range constructor. */ template void insert(_InputIterator __first, _InputIterator __last) { _M_h.insert(__first, __last); } /** * @brief Inserts a list of elements into the %unordered_multiset. * @param __l A std::initializer_list of elements to be * inserted. * * Complexity similar to that of the range constructor. */ void insert(initializer_list __l) { _M_h.insert(__l); } #if __cplusplus > 201402L /// Extract a node. node_type extract(const_iterator __pos) { __glibcxx_assert(__pos != end()); return _M_h.extract(__pos); } /// Extract a node. node_type extract(const key_type& __key) { return _M_h.extract(__key); } /// Re-insert an extracted node. iterator insert(node_type&& __nh) { return _M_h._M_reinsert_node_multi(cend(), std::move(__nh)); } /// Re-insert an extracted node. iterator insert(const_iterator __hint, node_type&& __nh) { return _M_h._M_reinsert_node_multi(__hint, std::move(__nh)); } #endif // C++17 ///@{ /** * @brief Erases an element from an %unordered_multiset. * @param __position An iterator pointing to the element to be erased. * @return An iterator pointing to the element immediately following * @a __position prior to the element being erased. If no such * element exists, end() is returned. * * This function erases an element, pointed to by the given iterator, * from an %unordered_multiset. * * Note that this function only erases the element, and that if the * element is itself a pointer, the pointed-to memory is not touched in * any way. Managing the pointer is the user's responsibility. */ iterator erase(const_iterator __position) { return _M_h.erase(__position); } // LWG 2059. iterator erase(iterator __position) { return _M_h.erase(__position); } ///@} /** * @brief Erases elements according to the provided key. * @param __x Key of element to be erased. * @return The number of elements erased. * * This function erases all the elements located by the given key from * an %unordered_multiset. * * Note that this function only erases the element, and that if the * element is itself a pointer, the pointed-to memory is not touched in * any way. Managing the pointer is the user's responsibility. */ size_type erase(const key_type& __x) { return _M_h.erase(__x); } /** * @brief Erases a [__first,__last) range of elements from an * %unordered_multiset. * @param __first Iterator pointing to the start of the range to be * erased. * @param __last Iterator pointing to the end of the range to * be erased. * @return The iterator @a __last. * * This function erases a sequence of elements from an * %unordered_multiset. * * Note that this function only erases the element, and that if * the element is itself a pointer, the pointed-to memory is not touched * in any way. Managing the pointer is the user's responsibility. */ iterator erase(const_iterator __first, const_iterator __last) { return _M_h.erase(__first, __last); } /** * Erases all elements in an %unordered_multiset. * * Note that this function only erases the elements, and that if the * elements themselves are pointers, the pointed-to memory is not touched * in any way. Managing the pointer is the user's responsibility. */ void clear() noexcept { _M_h.clear(); } /** * @brief Swaps data with another %unordered_multiset. * @param __x An %unordered_multiset of the same element and allocator * types. * * This exchanges the elements between two sets in constant time. * Note that the global std::swap() function is specialized such that * std::swap(s1,s2) will feed to this function. */ void swap(unordered_multiset& __x) noexcept( noexcept(_M_h.swap(__x._M_h)) ) { _M_h.swap(__x._M_h); } #if __cplusplus > 201402L template friend class std::_Hash_merge_helper; template void merge(unordered_multiset<_Value, _H2, _P2, _Alloc>& __source) { using _Merge_helper = _Hash_merge_helper; _M_h._M_merge_multi(_Merge_helper::_S_get_table(__source)); } template void merge(unordered_multiset<_Value, _H2, _P2, _Alloc>&& __source) { merge(__source); } template void merge(unordered_set<_Value, _H2, _P2, _Alloc>& __source) { using _Merge_helper = _Hash_merge_helper; _M_h._M_merge_multi(_Merge_helper::_S_get_table(__source)); } template void merge(unordered_set<_Value, _H2, _P2, _Alloc>&& __source) { merge(__source); } #endif // C++17 // observers. /// Returns the hash functor object with which the %unordered_multiset /// was constructed. hasher hash_function() const { return _M_h.hash_function(); } /// Returns the key comparison object with which the %unordered_multiset /// was constructed. key_equal key_eq() const { return _M_h.key_eq(); } // lookup. ///@{ /** * @brief Tries to locate an element in an %unordered_multiset. * @param __x Element to be located. * @return Iterator pointing to sought-after element, or end() if not * found. * * This function takes a key and tries to locate the element with which * the key matches. If successful the function returns an iterator * pointing to the sought after element. If unsuccessful it returns the * past-the-end ( @c end() ) iterator. */ iterator find(const key_type& __x) { return _M_h.find(__x); } #if __cplusplus > 201703L template auto find(const _Kt& __x) -> decltype(_M_h._M_find_tr(__x)) { return _M_h._M_find_tr(__x); } #endif const_iterator find(const key_type& __x) const { return _M_h.find(__x); } #if __cplusplus > 201703L template auto find(const _Kt& __x) const -> decltype(_M_h._M_find_tr(__x)) { return _M_h._M_find_tr(__x); } #endif ///@} ///@{ /** * @brief Finds the number of elements. * @param __x Element to located. * @return Number of elements with specified key. */ size_type count(const key_type& __x) const { return _M_h.count(__x); } #if __cplusplus > 201703L template auto count(const _Kt& __x) const -> decltype(_M_h._M_count_tr(__x)) { return _M_h._M_count_tr(__x); } #endif ///@} #if __cplusplus > 201703L ///@{ /** * @brief Finds whether an element with the given key exists. * @param __x Key of elements to be located. * @return True if there is any element with the specified key. */ bool contains(const key_type& __x) const { return _M_h.find(__x) != _M_h.end(); } template auto contains(const _Kt& __x) const -> decltype(_M_h._M_find_tr(__x), void(), true) { return _M_h._M_find_tr(__x) != _M_h.end(); } ///@} #endif ///@{ /** * @brief Finds a subsequence matching given key. * @param __x Key to be located. * @return Pair of iterators that possibly points to the subsequence * matching given key. */ std::pair equal_range(const key_type& __x) { return _M_h.equal_range(__x); } #if __cplusplus > 201703L template auto equal_range(const _Kt& __x) -> decltype(_M_h._M_equal_range_tr(__x)) { return _M_h._M_equal_range_tr(__x); } #endif std::pair equal_range(const key_type& __x) const { return _M_h.equal_range(__x); } #if __cplusplus > 201703L template auto equal_range(const _Kt& __x) const -> decltype(_M_h._M_equal_range_tr(__x)) { return _M_h._M_equal_range_tr(__x); } #endif ///@} // bucket interface. /// Returns the number of buckets of the %unordered_multiset. size_type bucket_count() const noexcept { return _M_h.bucket_count(); } /// Returns the maximum number of buckets of the %unordered_multiset. size_type max_bucket_count() const noexcept { return _M_h.max_bucket_count(); } /* * @brief Returns the number of elements in a given bucket. * @param __n A bucket index. * @return The number of elements in the bucket. */ size_type bucket_size(size_type __n) const { return _M_h.bucket_size(__n); } /* * @brief Returns the bucket index of a given element. * @param __key A key instance. * @return The key bucket index. */ size_type bucket(const key_type& __key) const { return _M_h.bucket(__key); } ///@{ /** * @brief Returns a read-only (constant) iterator pointing to the first * bucket element. * @param __n The bucket index. * @return A read-only local iterator. */ local_iterator begin(size_type __n) { return _M_h.begin(__n); } const_local_iterator begin(size_type __n) const { return _M_h.begin(__n); } const_local_iterator cbegin(size_type __n) const { return _M_h.cbegin(__n); } ///@} ///@{ /** * @brief Returns a read-only (constant) iterator pointing to one past * the last bucket elements. * @param __n The bucket index. * @return A read-only local iterator. */ local_iterator end(size_type __n) { return _M_h.end(__n); } const_local_iterator end(size_type __n) const { return _M_h.end(__n); } const_local_iterator cend(size_type __n) const { return _M_h.cend(__n); } ///@} // hash policy. /// Returns the average number of elements per bucket. float load_factor() const noexcept { return _M_h.load_factor(); } /// Returns a positive number that the %unordered_multiset tries to keep the /// load factor less than or equal to. float max_load_factor() const noexcept { return _M_h.max_load_factor(); } /** * @brief Change the %unordered_multiset maximum load factor. * @param __z The new maximum load factor. */ void max_load_factor(float __z) { _M_h.max_load_factor(__z); } /** * @brief May rehash the %unordered_multiset. * @param __n The new number of buckets. * * Rehash will occur only if the new number of buckets respect the * %unordered_multiset maximum load factor. */ void rehash(size_type __n) { _M_h.rehash(__n); } /** * @brief Prepare the %unordered_multiset for a specified number of * elements. * @param __n Number of elements required. * * Same as rehash(ceil(n / max_load_factor())). */ void reserve(size_type __n) { _M_h.reserve(__n); } template friend bool operator==(const unordered_multiset<_Value1, _Hash1, _Pred1, _Alloc1>&, const unordered_multiset<_Value1, _Hash1, _Pred1, _Alloc1>&); }; #if __cpp_deduction_guides >= 201606 template::value_type>, typename _Pred = equal_to::value_type>, typename _Allocator = allocator::value_type>, typename = _RequireInputIter<_InputIterator>, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireNotAllocator<_Pred>, typename = _RequireAllocator<_Allocator>> unordered_multiset(_InputIterator, _InputIterator, unordered_multiset::size_type = {}, _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator()) -> unordered_multiset::value_type, _Hash, _Pred, _Allocator>; template, typename _Pred = equal_to<_Tp>, typename _Allocator = allocator<_Tp>, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireNotAllocator<_Pred>, typename = _RequireAllocator<_Allocator>> unordered_multiset(initializer_list<_Tp>, unordered_multiset::size_type = {}, _Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator()) -> unordered_multiset<_Tp, _Hash, _Pred, _Allocator>; template, typename = _RequireAllocator<_Allocator>> unordered_multiset(_InputIterator, _InputIterator, unordered_multiset::size_type, _Allocator) -> unordered_multiset::value_type, hash::value_type>, equal_to::value_type>, _Allocator>; template, typename = _RequireNotAllocatorOrIntegral<_Hash>, typename = _RequireAllocator<_Allocator>> unordered_multiset(_InputIterator, _InputIterator, unordered_multiset::size_type, _Hash, _Allocator) -> unordered_multiset::value_type, _Hash, equal_to< typename iterator_traits<_InputIterator>::value_type>, _Allocator>; template> unordered_multiset(initializer_list<_Tp>, unordered_multiset::size_type, _Allocator) -> unordered_multiset<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; template, typename = _RequireAllocator<_Allocator>> unordered_multiset(initializer_list<_Tp>, unordered_multiset::size_type, _Hash, _Allocator) -> unordered_multiset<_Tp, _Hash, equal_to<_Tp>, _Allocator>; #endif template inline void swap(unordered_set<_Value, _Hash, _Pred, _Alloc>& __x, unordered_set<_Value, _Hash, _Pred, _Alloc>& __y) noexcept(noexcept(__x.swap(__y))) { __x.swap(__y); } template inline void swap(unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x, unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y) noexcept(noexcept(__x.swap(__y))) { __x.swap(__y); } template inline bool operator==(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x, const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y) { return __x._M_h._M_equal(__y._M_h); } #if __cpp_impl_three_way_comparison < 201907L template inline bool operator!=(const unordered_set<_Value, _Hash, _Pred, _Alloc>& __x, const unordered_set<_Value, _Hash, _Pred, _Alloc>& __y) { return !(__x == __y); } #endif template inline bool operator==(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x, const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y) { return __x._M_h._M_equal(__y._M_h); } #if __cpp_impl_three_way_comparison < 201907L template inline bool operator!=(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x, const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y) { return !(__x == __y); } #endif _GLIBCXX_END_NAMESPACE_CONTAINER #if __cplusplus > 201402L // Allow std::unordered_set access to internals of compatible sets. template struct _Hash_merge_helper< _GLIBCXX_STD_C::unordered_set<_Val, _Hash1, _Eq1, _Alloc>, _Hash2, _Eq2> { private: template using unordered_set = _GLIBCXX_STD_C::unordered_set<_Tp...>; template using unordered_multiset = _GLIBCXX_STD_C::unordered_multiset<_Tp...>; friend unordered_set<_Val, _Hash1, _Eq1, _Alloc>; static auto& _S_get_table(unordered_set<_Val, _Hash2, _Eq2, _Alloc>& __set) { return __set._M_h; } static auto& _S_get_table(unordered_multiset<_Val, _Hash2, _Eq2, _Alloc>& __set) { return __set._M_h; } }; // Allow std::unordered_multiset access to internals of compatible sets. template struct _Hash_merge_helper< _GLIBCXX_STD_C::unordered_multiset<_Val, _Hash1, _Eq1, _Alloc>, _Hash2, _Eq2> { private: template using unordered_set = _GLIBCXX_STD_C::unordered_set<_Tp...>; template using unordered_multiset = _GLIBCXX_STD_C::unordered_multiset<_Tp...>; friend unordered_multiset<_Val, _Hash1, _Eq1, _Alloc>; static auto& _S_get_table(unordered_set<_Val, _Hash2, _Eq2, _Alloc>& __set) { return __set._M_h; } static auto& _S_get_table(unordered_multiset<_Val, _Hash2, _Eq2, _Alloc>& __set) { return __set._M_h; } }; #endif // C++17 _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif /* _UNORDERED_SET_H */