Add unordered containers heterogeneous lookup member functions find, count, contains and
equal_range in C++20. Those members are considered for overload resolution only if hash and
equal functors used to instantiate the container have a nested is_transparent type.
libstdc++-v3/ChangeLog:
* include/bits/stl_tree.h
(__has_is_transparent, __has_is_transparent_t): Move...
* include/bits/stl_function.h: ...here.
* include/bits/hashtable_policy.h (_Hash_code_base<>::_M_hash_code_tr): New..
(_Hashtable_base<>::_M_equals_tr): New.
* include/bits/hashtable.h (_Hashtable<>::_M_find_tr, _Hashtable<>::_M_count_tr,
_Hashtable<>::_M_equal_range_tr): New member function templates to perform
heterogeneous lookup.
(_Hashtable<>::_M_find_before_node_tr): New.
(_Hashtable<>::_M_find_node_tr): New.
* include/bits/unordered_map.h (unordered_map::find<>, unordered_map::count<>,
unordered_map::contains<>, unordered_map::equal_range<>): New member function
templates to perform heterogeneous lookup.
(unordered_multimap::find<>, unordered_multimap::count<>,
unordered_multimap::contains<>, unordered_multimap::equal_range<>): Likewise.
* include/bits/unordered_set.h (unordered_set::find<>, unordered_set::count<>,
unordered_set::contains<>, unordered_set::equal_range<>): Likewise.
(unordered_multiset::find<>, unordered_multiset::count<>,
unordered_multiset::contains<>, unordered_multiset::equal_range<>): Likewise.
* include/debug/unordered_map
(unordered_map::find<>, unordered_map::equal_range<>): Likewise.
(unordered_multimap::find<>, unordered_multimap::equal_range<>): Likewise.
* include/debug/unordered_set
(unordered_set::find<>, unordered_set::equal_range<>): Likewise.
(unordered_multiset::find<>, unordered_multiset::equal_range<>): Likewise.
* testsuite/23_containers/unordered_map/operations/1.cc: New test.
* testsuite/23_containers/unordered_multimap/operations/1.cc: New test.
* testsuite/23_containers/unordered_multiset/operations/1.cc: New test.
* testsuite/23_containers/unordered_set/operations/1.cc: New test.
std::pair<const_iterator, const_iterator>
equal_range(const key_type& __k) const;
+#if __cplusplus > 201702L
+ template<typename _Kt,
+ typename = __has_is_transparent_t<_Hash, _Kt>,
+ typename = __has_is_transparent_t<_Equal, _Kt>>
+ iterator
+ _M_find_tr(const _Kt& __k);
+
+ template<typename _Kt,
+ typename = __has_is_transparent_t<_Hash, _Kt>,
+ typename = __has_is_transparent_t<_Equal, _Kt>>
+ const_iterator
+ _M_find_tr(const _Kt& __k) const;
+
+ template<typename _Kt,
+ typename = __has_is_transparent_t<_Hash, _Kt>,
+ typename = __has_is_transparent_t<_Equal, _Kt>>
+ size_type
+ _M_count_tr(const _Kt& __k) const;
+
+ template<typename _Kt,
+ typename = __has_is_transparent_t<_Hash, _Kt>,
+ typename = __has_is_transparent_t<_Equal, _Kt>>
+ pair<iterator, iterator>
+ _M_equal_range_tr(const _Kt& __k);
+
+ template<typename _Kt,
+ typename = __has_is_transparent_t<_Hash, _Kt>,
+ typename = __has_is_transparent_t<_Equal, _Kt>>
+ pair<const_iterator, const_iterator>
+ _M_equal_range_tr(const _Kt& __k) const;
+#endif
+
private:
// Bucket index computation helpers.
size_type
__node_base_ptr
_M_find_before_node(size_type, const key_type&, __hash_code) const;
+ template<typename _Kt>
+ __node_base_ptr
+ _M_find_before_node_tr(size_type, const _Kt&, __hash_code) const;
+
__node_ptr
_M_find_node(size_type __bkt, const key_type& __key,
__hash_code __c) const
return nullptr;
}
+ template<typename _Kt>
+ __node_ptr
+ _M_find_node_tr(size_type __bkt, const _Kt& __key,
+ __hash_code __c) const
+ {
+ auto __before_n = _M_find_before_node_tr(__bkt, __key, __c);
+ if (__before_n)
+ return static_cast<__node_ptr>(__before_n->_M_nxt);
+ return nullptr;
+ }
+
// Insert a node at the beginning of a bucket.
void
_M_insert_bucket_begin(size_type, __node_ptr);
return const_iterator(_M_find_node(__bkt, __k, __code));
}
+#if __cplusplus > 201703L
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _Hash, typename _RangeHash, typename _Unused,
+ typename _RehashPolicy, typename _Traits>
+ template<typename _Kt, typename, typename>
+ auto
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
+ _M_find_tr(const _Kt& __k)
+ -> iterator
+ {
+ __hash_code __code = this->_M_hash_code_tr(__k);
+ std::size_t __bkt = _M_bucket_index(__code);
+ return iterator(_M_find_node_tr(__bkt, __k, __code));
+ }
+
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _Hash, typename _RangeHash, typename _Unused,
+ typename _RehashPolicy, typename _Traits>
+ template<typename _Kt, typename, typename>
+ auto
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
+ _M_find_tr(const _Kt& __k) const
+ -> const_iterator
+ {
+ __hash_code __code = this->_M_hash_code_tr(__k);
+ std::size_t __bkt = _M_bucket_index(__code);
+ return const_iterator(_M_find_node_tr(__bkt, __k, __code));
+ }
+#endif
+
template<typename _Key, typename _Value, typename _Alloc,
typename _ExtractKey, typename _Equal,
typename _Hash, typename _RangeHash, typename _Unused,
return __result;
}
+#if __cplusplus > 201703L
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _Hash, typename _RangeHash, typename _Unused,
+ typename _RehashPolicy, typename _Traits>
+ template<typename _Kt, typename, typename>
+ auto
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
+ _M_count_tr(const _Kt& __k) const
+ -> size_type
+ {
+ __hash_code __code = this->_M_hash_code_tr(__k);
+ std::size_t __bkt = _M_bucket_index(__code);
+ auto __n = _M_find_node_tr(__bkt, __k, __code);
+ if (!__n)
+ return 0;
+
+ // All equivalent values are next to each other, if we find a
+ // non-equivalent value after an equivalent one it means that we won't
+ // find any new equivalent value.
+ iterator __it(__n);
+ size_type __result = 1;
+ for (++__it;
+ __it._M_cur && this->_M_equals_tr(__k, __code, *__it._M_cur);
+ ++__it)
+ ++__result;
+
+ return __result;
+ }
+#endif
+
template<typename _Key, typename _Value, typename _Alloc,
typename _ExtractKey, typename _Equal,
typename _Hash, typename _RangeHash, typename _Unused,
return { __beg, __ite };
}
+#if __cplusplus > 201703L
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _Hash, typename _RangeHash, typename _Unused,
+ typename _RehashPolicy, typename _Traits>
+ template<typename _Kt, typename, typename>
+ auto
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
+ _M_equal_range_tr(const _Kt& __k)
+ -> pair<iterator, iterator>
+ {
+ __hash_code __code = this->_M_hash_code_tr(__k);
+ std::size_t __bkt = _M_bucket_index(__code);
+ auto __n = _M_find_node_tr(__bkt, __k, __code);
+ iterator __ite(__n);
+ if (!__n)
+ return { __ite, __ite };
+
+ // All equivalent values are next to each other, if we find a
+ // non-equivalent value after an equivalent one it means that we won't
+ // find any new equivalent value.
+ auto __beg = __ite++;
+ while (__ite._M_cur && this->_M_equals_tr(__k, __code, *__ite._M_cur))
+ ++__ite;
+
+ return { __beg, __ite };
+ }
+
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _Hash, typename _RangeHash, typename _Unused,
+ typename _RehashPolicy, typename _Traits>
+ template<typename _Kt, typename, typename>
+ auto
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
+ _M_equal_range_tr(const _Kt& __k) const
+ -> pair<const_iterator, const_iterator>
+ {
+ __hash_code __code = this->_M_hash_code_tr(__k);
+ std::size_t __bkt = _M_bucket_index(__code);
+ auto __n = _M_find_node_tr(__bkt, __k, __code);
+ const_iterator __ite(__n);
+ if (!__n)
+ return { __ite, __ite };
+
+ // All equivalent values are next to each other, if we find a
+ // non-equivalent value after an equivalent one it means that we won't
+ // find any new equivalent value.
+ auto __beg = __ite++;
+ while (__ite._M_cur && this->_M_equals_tr(__k, __code, *__ite._M_cur))
+ ++__ite;
+
+ return { __beg, __ite };
+ }
+#endif
+
// Find the node before the one whose key compares equal to k in the bucket
// bkt. Return nullptr if no node is found.
template<typename _Key, typename _Value, typename _Alloc,
typename _ExtractKey, typename _Equal,
typename _Hash, typename _RangeHash, typename _Unused,
typename _RehashPolicy, typename _Traits>
+ template<typename _Kt>
+ auto
+ _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
+ _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
+ _M_find_before_node_tr(size_type __bkt, const _Kt& __k,
+ __hash_code __code) const
+ -> __node_base_ptr
+ {
+ __node_base_ptr __prev_p = _M_buckets[__bkt];
+ if (!__prev_p)
+ return nullptr;
+
+ for (__node_ptr __p = static_cast<__node_ptr>(__prev_p->_M_nxt);;
+ __p = __p->_M_next())
+ {
+ if (this->_M_equals_tr(__k, __code, *__p))
+ return __prev_p;
+
+ if (!__p->_M_nxt || _M_bucket_index(*__p->_M_next()) != __bkt)
+ break;
+ __prev_p = __p;
+ }
+
+ return nullptr;
+ }
+
+ template<typename _Key, typename _Value, typename _Alloc,
+ typename _ExtractKey, typename _Equal,
+ typename _Hash, typename _RangeHash, typename _Unused,
+ typename _RehashPolicy, typename _Traits>
void
_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
_Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
return _M_hash()(__k);
}
+ template<typename _Kt>
+ __hash_code
+ _M_hash_code_tr(const _Kt& __k) const
+ {
+ static_assert(__is_invocable<const _Hash&, const _Kt&>{},
+ "hash function must be invocable with an argument of key type");
+ return _M_hash()(__k);
+ }
+
std::size_t
_M_bucket_index(__hash_code __c, std::size_t __bkt_count) const
{ return _RangeHash{}(__c, __bkt_count); }
return _S_equals(__c, __n) && _M_eq()(__k, _ExtractKey{}(__n._M_v()));
}
+ template<typename _Kt>
+ bool
+ _M_equals_tr(const _Kt& __k, __hash_code __c,
+ const _Hash_node_value<_Value,
+ __hash_cached::value>& __n) const
+ {
+ static_assert(
+ __is_invocable<const _Equal&, const _Kt&, const _Key&>{},
+ "key equality predicate must be invocable with two arguments of "
+ "key type");
+ return _S_equals(__c, __n) && _M_eq()(__k, _ExtractKey{}(__n._M_v()));
+ }
+
bool
_M_node_equals(
const _Hash_node_value<_Value, __hash_cached::value>& __lhn,
/** @} */
+#if __cplusplus >= 201402L
+ template<typename _Func, typename _SfinaeType, typename = __void_t<>>
+ struct __has_is_transparent
+ { };
+
+ template<typename _Func, typename _SfinaeType>
+ struct __has_is_transparent<_Func, _SfinaeType,
+ __void_t<typename _Func::is_transparent>>
+ { typedef void type; };
+
+ template<typename _Func, typename _SfinaeType>
+ using __has_is_transparent_t
+ = typename __has_is_transparent<_Func, _SfinaeType>::type;
+#endif
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
_Rb_tree_rebalance_for_erase(_Rb_tree_node_base* const __z,
_Rb_tree_node_base& __header) throw ();
-#if __cplusplus >= 201402L
- template<typename _Cmp, typename _SfinaeType, typename = __void_t<>>
- struct __has_is_transparent
- { };
-
- template<typename _Cmp, typename _SfinaeType>
- struct __has_is_transparent<_Cmp, _SfinaeType,
- __void_t<typename _Cmp::is_transparent>>
- { typedef void type; };
-
- template<typename _Cmp, typename _SfinaeType>
- using __has_is_transparent_t
- = typename __has_is_transparent<_Cmp, _SfinaeType>::type;
-#endif
-
#if __cplusplus > 201402L
template<typename _Tree1, typename _Cmp2>
struct _Rb_tree_merge_helper { };
find(const key_type& __x)
{ return _M_h.find(__x); }
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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<typename _Kt>
+ 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 Key to count.
{ return _M_h.count(__x); }
#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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.
bool
contains(const key_type& __x) const
{ return _M_h.find(__x) != _M_h.end(); }
+
+ template<typename _Kt>
+ 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
//@{
equal_range(const key_type& __x)
{ return _M_h.equal_range(__x); }
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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<const_iterator, const_iterator>
equal_range(const key_type& __x) const
{ return _M_h.equal_range(__x); }
+
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ auto
+ equal_range(const _Kt& __x) const
+ -> decltype(_M_h._M_equal_range_tr(__x))
+ { return _M_h._M_equal_range_tr(__x); }
+#endif
//@}
//@{
find(const key_type& __x)
{ return _M_h.find(__x); }
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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<typename _Kt>
+ 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 Key to count.
{ return _M_h.count(__x); }
#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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.
bool
contains(const key_type& __x) const
{ return _M_h.find(__x) != _M_h.end(); }
+
+ template<typename _Kt>
+ 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
//@{
equal_range(const key_type& __x)
{ return _M_h.equal_range(__x); }
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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<const_iterator, const_iterator>
equal_range(const key_type& __x) const
{ return _M_h.equal_range(__x); }
+
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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.
find(const key_type& __x)
{ return _M_h.find(__x); }
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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<typename _Kt>
+ 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 _M_h.count(__x); }
#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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.
bool
contains(const key_type& __x) const
{ return _M_h.find(__x) != _M_h.end(); }
+
+ template<typename _Kt>
+ 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
//@{
equal_range(const key_type& __x)
{ return _M_h.equal_range(__x); }
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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<const_iterator, const_iterator>
equal_range(const key_type& __x) const
{ return _M_h.equal_range(__x); }
+
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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.
find(const key_type& __x)
{ return _M_h.find(__x); }
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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<typename _Kt>
+ 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 _M_h.count(__x); }
#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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.
bool
contains(const key_type& __x) const
{ return _M_h.find(__x) != _M_h.end(); }
+
+ template<typename _Kt>
+ 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
//@{
equal_range(const key_type& __x)
{ return _M_h.equal_range(__x); }
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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<const_iterator, const_iterator>
equal_range(const key_type& __x) const
{ return _M_h.equal_range(__x); }
+
+#if __cplusplus > 201703L
+ template<typename _Kt>
+ 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.
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ iterator
+ find(const _Kt& __k)
+ { return { _Base::find(__k), this }; }
+#endif
+
const_iterator
find(const key_type& __key) const
{ return { _Base::find(__key), this }; }
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ const_iterator
+ find(const _Kt& __k) const
+ { return { _Base::find(__k), this }; }
+#endif
+
std::pair<iterator, iterator>
equal_range(const key_type& __key)
{
return { { __res.first, this }, { __res.second, this } };
}
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ std::pair<iterator, iterator>
+ equal_range(const _Kt& __k)
+ {
+ auto __res = _Base::equal_range(__k);
+ return { { __res.first, this }, { __res.second, this } };
+ }
+#endif
+
std::pair<const_iterator, const_iterator>
equal_range(const key_type& __key) const
{
return { { __res.first, this }, { __res.second, this } };
}
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ std::pair<const_iterator, const_iterator>
+ equal_range(const _Kt& __k) const
+ {
+ auto __res = _Base::equal_range(__k);
+ return { { __res.first, this }, { __res.second, this } };
+ }
+#endif
+
size_type
erase(const key_type& __key)
{
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ iterator
+ find(const _Kt& __k)
+ { return { _Base::find(__k), this }; }
+#endif
+
const_iterator
find(const key_type& __key) const
{ return { _Base::find(__key), this }; }
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ const_iterator
+ find(const _Kt& __k) const
+ { return { _Base::find(__k), this }; }
+#endif
+
std::pair<iterator, iterator>
equal_range(const key_type& __key)
{
return { { __res.first, this }, { __res.second, this } };
}
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ std::pair<iterator, iterator>
+ equal_range(const _Kt& __k)
+ {
+ auto __res = _Base::equal_range(__k);
+ return { { __res.first, this }, { __res.second, this } };
+ }
+#endif
+
std::pair<const_iterator, const_iterator>
equal_range(const key_type& __key) const
{
return { { __res.first, this }, { __res.second, this } };
}
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ std::pair<const_iterator, const_iterator>
+ equal_range(const _Kt& __k) const
+ {
+ auto __res = _Base::equal_range(__k);
+ return { { __res.first, this }, { __res.second, this } };
+ }
+#endif
+
size_type
erase(const key_type& __key)
{
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ iterator
+ find(const _Kt& __k)
+ { return { _Base::find(__k), this }; }
+#endif
+
const_iterator
find(const key_type& __key) const
{ return { _Base::find(__key), this }; }
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ const_iterator
+ find(const _Kt& __k) const
+ { return { _Base::find(__k), this }; }
+#endif
+
std::pair<iterator, iterator>
equal_range(const key_type& __key)
{
return { { __res.first, this }, { __res.second, this } };
}
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ std::pair<iterator, iterator>
+ equal_range(const _Kt& __k)
+ {
+ auto __res = _Base::equal_range(__k);
+ return { { __res.first, this }, { __res.second, this } };
+ }
+#endif
+
std::pair<const_iterator, const_iterator>
equal_range(const key_type& __key) const
{
return { { __res.first, this }, { __res.second, this } };
}
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ std::pair<const_iterator, const_iterator>
+ equal_range(const _Kt& __k) const
+ {
+ auto __res = _Base::equal_range(__k);
+ return { { __res.first, this }, { __res.second, this } };
+ }
+#endif
+
size_type
erase(const key_type& __key)
{
find(const key_type& __key)
{ return { _Base::find(__key), this }; }
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ iterator
+ find(const _Kt& __k)
+ { return { _Base::find(__k), this }; }
+#endif
+
const_iterator
find(const key_type& __key) const
{ return { _Base::find(__key), this }; }
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ const_iterator
+ find(const _Kt& __k) const
+ { return { _Base::find(__k), this }; }
+#endif
+
std::pair<iterator, iterator>
equal_range(const key_type& __key)
{
return { { __res.first, this }, { __res.second, this } };
}
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ std::pair<iterator, iterator>
+ equal_range(const _Kt& __k)
+ {
+ auto __res = _Base::equal_range(__k);
+ return { { __res.first, this }, { __res.second, this } };
+ }
+#endif
+
std::pair<const_iterator, const_iterator>
equal_range(const key_type& __key) const
{
return { { __res.first, this }, { __res.second, this } };
}
+#if __cplusplus > 201703L
+ template<typename _Kt,
+ typename = std::__has_is_transparent_t<_Hash, _Kt>,
+ typename = std::__has_is_transparent_t<_Pred, _Kt>>
+ std::pair<const_iterator, const_iterator>
+ equal_range(const _Kt& __k) const
+ {
+ auto __res = _Base::equal_range(__k);
+ return { { __res.first, this }, { __res.second, this } };
+ }
+#endif
+
size_type
erase(const key_type& __key)
{
--- /dev/null
+// Copyright (C) 2021 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++20 } }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+struct Equal
+{
+ typedef void is_transparent;
+
+ bool operator()(int i, long l) const { return i == l; }
+ bool operator()(long l, int i) const { return l == i; }
+ bool operator()(int i, int j) const { ++count; return i == j; }
+
+ static int count;
+};
+
+int Equal::count = 0;
+
+struct Hash
+{
+ typedef void is_transparent;
+
+ std::size_t operator()(int i) const { ++count; return i; }
+ std::size_t operator()(long l) const { return l; }
+
+ static int count;
+};
+
+int Hash::count = 0;
+
+using test_type = std::unordered_map<int, char, Hash, Equal>;
+
+test_type x{ { 1, '2' }, { 3, '4' } };
+const test_type& cx = x;
+
+void
+test01()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ VERIFY( x.contains(1L) );
+
+ auto it = x.find(1L);
+ VERIFY( it != x.end() && it->second == '2' );
+ it = x.find(2L);
+ VERIFY( it == x.end() );
+
+ auto cit = cx.find(3L);
+ VERIFY( cit != cx.end() && cit->second == '4' );
+ cit = cx.find(2L);
+ VERIFY( cit == cx.end() );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+
+ static_assert(std::is_same<decltype(it), test_type::iterator>::value,
+ "find returns iterator");
+ static_assert(std::is_same<decltype(cit), test_type::const_iterator>::value,
+ "const find returns const_iterator");
+}
+
+void
+test02()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ auto n = x.count(1L);
+ VERIFY( n == 1 );
+ n = x.count(2L);
+ VERIFY( n == 0 );
+
+ auto cn = cx.count(3L);
+ VERIFY( cn == 1 );
+ cn = cx.count(2L);
+ VERIFY( cn == 0 );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+}
+
+void
+test03()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ auto it = x.equal_range(1L);
+ VERIFY( it.first != it.second && it.first->second == '2' );
+ it = x.equal_range(2L);
+ VERIFY( it.first == it.second && it.first == x.end() );
+
+ auto cit = cx.equal_range(1L);
+ VERIFY( cit.first != cit.second && cit.first->second == '2' );
+ cit = cx.equal_range(2L);
+ VERIFY( cit.first == cit.second && cit.first == cx.end() );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+
+ using pair = std::pair<test_type::iterator, test_type::iterator>;
+ static_assert(std::is_same<decltype(it), pair>::value,
+ "equal_range returns pair<iterator, iterator>");
+ using cpair = std::pair<test_type::const_iterator, test_type::const_iterator>;
+ static_assert(std::is_same<decltype(cit), cpair>::value,
+ "const equal_range returns pair<const_iterator, const_iterator>");
+}
+
+void
+test04()
+{
+ struct E
+ {
+ bool operator()(int l, int r) const { return l == r; }
+
+ struct Partition { };
+
+ bool operator()(int l, Partition) const { return l < 6; }
+ bool operator()(Partition, int r) const { return 3 < r; }
+
+ using is_transparent = void;
+ };
+
+ struct H
+ {
+ size_t
+ operator()(int x) const
+ { return 0; }
+
+ size_t
+ operator()(E::Partition) const
+ { return 0; }
+
+ using is_transparent = void;
+ };
+
+ std::unordered_map<int, int, H, E> m{ {1,0}, {2,0}, {3,0}, {4, 0}, {5, 0} };
+
+ auto n = m.count(E::Partition{});
+ VERIFY( n == 2 );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
--- /dev/null
+// Copyright (C) 2021 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++20 } }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+struct Equal
+{
+ typedef void is_transparent;
+
+ bool operator()(int i, long l) const { return i == l; }
+ bool operator()(long l, int i) const { return l == i; }
+ bool operator()(int i, int j) const { ++count; return i == j; }
+
+ static int count;
+};
+
+int Equal::count = 0;
+
+struct Hash
+{
+ typedef void is_transparent;
+
+ std::size_t operator()(int i) const { ++count; return i; }
+ std::size_t operator()(long l) const { return l; }
+
+ static int count;
+};
+
+int Hash::count = 0;
+
+using test_type = std::unordered_multimap<int, char, Hash, Equal>;
+
+test_type x{ { 1, '2' }, { 3, '4' }, { 3, '5' } };
+const test_type& cx = x;
+
+void
+test01()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ VERIFY( x.contains(1L) );
+
+ auto it = x.find(1L);
+ VERIFY( it != x.end() && it->second == '2' );
+ it = x.find(2L);
+ VERIFY( it == x.end() );
+
+ auto cit = cx.find(3L);
+ VERIFY( cit != cx.end() && cit->second == '5' );
+ cit = cx.find(2L);
+ VERIFY( cit == cx.end() );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+
+ static_assert(std::is_same<decltype(it), test_type::iterator>::value,
+ "find returns iterator");
+ static_assert(std::is_same<decltype(cit), test_type::const_iterator>::value,
+ "const find returns const_iterator");
+}
+
+void
+test02()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ auto n = x.count(1L);
+ VERIFY( n == 1 );
+ n = x.count(2L);
+ VERIFY( n == 0 );
+
+ auto cn = cx.count(3L);
+ VERIFY( cn == 2 );
+ cn = cx.count(2L);
+ VERIFY( cn == 0 );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+}
+
+void
+test03()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ auto it = x.equal_range(1L);
+ VERIFY( it.first != it.second && it.first->second == '2' );
+ it = x.equal_range(2L);
+ VERIFY( it.first == it.second && it.first == x.end() );
+
+ auto cit = cx.equal_range(3L);
+ VERIFY( cit.first != cit.second && cit.first->second == '5' );
+ VERIFY( std::distance(cit.first, cit.second) == 2 );
+ cit = cx.equal_range(2L);
+ VERIFY( cit.first == cit.second && cit.first == cx.end() );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+
+ using pair = std::pair<test_type::iterator, test_type::iterator>;
+ static_assert(std::is_same<decltype(it), pair>::value,
+ "equal_range returns pair<iterator, iterator>");
+ using cpair = std::pair<test_type::const_iterator, test_type::const_iterator>;
+ static_assert(std::is_same<decltype(cit), cpair>::value,
+ "const equal_range returns pair<const_iterator, const_iterator>");
+}
+
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+}
--- /dev/null
+// Copyright (C) 2021 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++20 } }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+struct Equal
+{
+ typedef void is_transparent;
+
+ bool operator()(int i, long l) const { return i == l; }
+ bool operator()(long l, int i) const { return l == i; }
+ bool operator()(int i, int j) const { ++count; return i == j; }
+
+ static int count;
+};
+
+int Equal::count = 0;
+
+struct Hash
+{
+ typedef void is_transparent;
+
+ std::size_t operator()(int i) const { ++count; return i; }
+ std::size_t operator()(long l) const { return l; }
+
+ static int count;
+};
+
+int Hash::count = 0;
+
+using test_type = std::unordered_multiset<int, Hash, Equal>;
+
+test_type x{ 1, 3, 3, 5 };
+const test_type& cx = x;
+
+void
+test01()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ VERIFY( x.contains(1L) );
+
+ auto it = x.find(1L);
+ VERIFY( it != x.end() && *it == 1 );
+ it = x.find(2L);
+ VERIFY( it == x.end() );
+
+ auto cit = cx.find(3L);
+ VERIFY( cit != cx.end() && *cit == 3 );
+ cit = cx.find(2L);
+ VERIFY( cit == cx.end() );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+
+ static_assert(std::is_same<decltype(it), test_type::iterator>::value,
+ "find returns iterator");
+ static_assert(std::is_same<decltype(cit), test_type::const_iterator>::value,
+ "const find returns const_iterator");
+}
+
+void
+test02()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ auto n = x.count(1L);
+ VERIFY( n == 1 );
+ n = x.count(2L);
+ VERIFY( n == 0 );
+
+ auto cn = cx.count(3L);
+ VERIFY( cn == 2 );
+ cn = cx.count(2L);
+ VERIFY( cn == 0 );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+}
+
+void
+test03()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ auto it = x.equal_range(1L);
+ VERIFY( it.first != it.second && *it.first == 1 );
+ it = x.equal_range(2L);
+ VERIFY( it.first == it.second && it.first == x.end() );
+
+ auto cit = cx.equal_range(3L);
+ VERIFY( cit.first != cit.second && *cit.first == 3 );
+ VERIFY( std::distance(cit.first, cit.second) == 2 );
+ cit = cx.equal_range(2L);
+ VERIFY( cit.first == cit.second && cit.first == cx.end() );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+
+ using pair = std::pair<test_type::iterator, test_type::iterator>;
+ static_assert(std::is_same<decltype(it), pair>::value,
+ "equal_range returns pair<iterator, iterator>");
+ using cpair = std::pair<test_type::const_iterator, test_type::const_iterator>;
+ static_assert(std::is_same<decltype(cit), cpair>::value,
+ "const equal_range returns pair<const_iterator, const_iterator>");
+}
+
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+}
--- /dev/null
+// Copyright (C) 2021 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++20 } }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+struct Equal
+{
+ typedef void is_transparent;
+
+ bool operator()(int i, long l) const { return i == l; }
+ bool operator()(long l, int i) const { return l == i; }
+ bool operator()(int i, int j) const { ++count; return i == j; }
+
+ static int count;
+};
+
+int Equal::count = 0;
+
+struct Hash
+{
+ typedef void is_transparent;
+
+ std::size_t operator()(int i) const { ++count; return i; }
+ std::size_t operator()(long l) const { return l; }
+
+ static int count;
+};
+
+int Hash::count = 0;
+
+using test_type = std::unordered_set<int, Hash, Equal>;
+
+test_type x{ 1, 3, 5 };
+const test_type& cx = x;
+
+void
+test01()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ VERIFY( x.contains(1L) );
+
+ auto it = x.find(1L);
+ VERIFY( it != x.end() && *it == 1 );
+ it = x.find(2L);
+ VERIFY( it == x.end() );
+
+ auto cit = cx.find(3L);
+ VERIFY( cit != cx.end() && *cit == 3 );
+ cit = cx.find(2L);
+ VERIFY( cit == cx.end() );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+
+ static_assert(std::is_same<decltype(it), test_type::iterator>::value,
+ "find returns iterator");
+ static_assert(std::is_same<decltype(cit), test_type::const_iterator>::value,
+ "const find returns const_iterator");
+}
+
+void
+test02()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ auto n = x.count(1L);
+ VERIFY( n == 1 );
+ n = x.count(2L);
+ VERIFY( n == 0 );
+
+ auto cn = cx.count(3L);
+ VERIFY( cn == 1 );
+ cn = cx.count(2L);
+ VERIFY( cn == 0 );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+}
+
+void
+test03()
+{
+ Hash::count = 0;
+ Equal::count = 0;
+
+ auto it = x.equal_range(1L);
+ VERIFY( it.first != it.second && *it.first == 1 );
+ it = x.equal_range(2L);
+ VERIFY( it.first == it.second && it.first == x.end() );
+
+ auto cit = cx.equal_range(1L);
+ VERIFY( cit.first != cit.second && *cit.first == 1 );
+ cit = cx.equal_range(2L);
+ VERIFY( cit.first == cit.second && cit.first == cx.end() );
+
+ VERIFY( Hash::count == 0 );
+ VERIFY( Equal::count == 0 );
+
+ using pair = std::pair<test_type::iterator, test_type::iterator>;
+ static_assert(std::is_same<decltype(it), pair>::value,
+ "equal_range returns pair<iterator, iterator>");
+ using cpair = std::pair<test_type::const_iterator, test_type::const_iterator>;
+ static_assert(std::is_same<decltype(cit), cpair>::value,
+ "const equal_range returns pair<const_iterator, const_iterator>");
+}
+
+void
+test04()
+{
+ // https://gcc.gnu.org/ml/libstdc++/2015-01/msg00176.html
+ // Verify the new function template overloads do not cause problems
+ // when the comparison function is not transparent.
+ struct I
+ {
+ int i;
+ operator int() const { return i; }
+ };
+
+ std::unordered_set<int> s;
+ I i = { };
+ s.find(i);
+}
+
+void
+test05()
+{
+ struct E
+ {
+ bool operator()(int l, int r) const { return l == r; }
+
+ struct Partition { };
+
+ bool operator()(int l, Partition) const { return l < 6; }
+ bool operator()(Partition, int r) const { return r > 3; }
+
+ using is_transparent = void;
+ };
+
+ struct H
+ {
+ size_t
+ operator()(int x) const
+ { return (size_t)(x / 10); }
+
+ size_t
+ operator()(E::Partition) const
+ { return 0; }
+
+ using is_transparent = void;
+ };
+
+ std::unordered_set<int, H, E> s{ 1, 2, 3, 4, 5 };
+
+ auto n = s.count(E::Partition{});
+ VERIFY( n == 2 );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+}