https://gcc.gnu.org/g:247e82c72f14dfaa4c496b80ad641a15658a5e4f
commit r15-5219-g247e82c72f14dfaa4c496b80ad641a15658a5e4f Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue Nov 5 22:39:43 2024 +0000 libstdc++: Remove _Equality base class from _Hashtable libstdc++-v3/ChangeLog: * include/bits/hashtable.h (_Hashtable): Remove _Equality base class. (_Hashtable::_M_equal): Define equality comparison here instead of in _Equality::_M_equal. * include/bits/hashtable_policy.h (_Equality): Remove. Diff: --- libstdc++-v3/include/bits/hashtable.h | 111 ++++++++++++++++---- libstdc++-v3/include/bits/hashtable_policy.h | 147 --------------------------- 2 files changed, 94 insertions(+), 164 deletions(-) diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h index 9db568a1f633..7b0a684a2d29 100644 --- a/libstdc++-v3/include/bits/hashtable.h +++ b/libstdc++-v3/include/bits/hashtable.h @@ -168,8 +168,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * not throw and this is enforced by a static assertion. * * Functionality is implemented by decomposition into base classes, - * where the derived _Hashtable class is used in _Map_base, - * _Rehash_base, and _Equality base classes to access the + * where the derived _Hashtable class is used in _Map_base and + * _Rehash_base base classes to access the * "this" pointer. _Hashtable_base is used in the base classes as a * non-recursive, fully-completed-type so that detailed nested type * information, such as iterator type and node type, can be @@ -181,7 +181,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * - __detail::_Hashtable_base * - __detail::_Map_base * - __detail::_Rehash_base - * - __detail::_Equality */ template<typename _Key, typename _Value, typename _Alloc, typename _ExtractKey, typename _Equal, @@ -196,9 +195,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>, - public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, - _Hash, _RangeHash, _Unused, - _RehashPolicy, _Traits>, private __detail::_Hashtable_alloc< __alloc_rebind<_Alloc, __detail::_Hash_node<_Value, @@ -293,10 +289,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>; - using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, - _Equal, _Hash, _RangeHash, _Unused, - _RehashPolicy, _Traits>; - using __node_builder_t = __detail::_NodeBuilder<_ExtractKey>; // Simple RAII type for managing a node containing an element @@ -353,13 +345,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool _Unique_keysa> friend struct __detail::_Map_base; - template<typename _Keya, typename _Valuea, typename _Alloca, - typename _ExtractKeya, typename _Equala, - typename _Hasha, typename _RangeHasha, typename _Unuseda, - typename _RehashPolicya, typename _Traitsa, - bool _Unique_keysa> - friend struct __detail::_Equality; - public: using size_type = typename __hashtable_base::size_type; using difference_type = typename __hashtable_base::difference_type; @@ -1300,6 +1285,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++17 __glibcxx_node_extract + bool + _M_equal(const _Hashtable& __other) const; + private: // Helper rehash method used when keys are unique. void _M_rehash(size_type __bkt_count, true_type __uks); @@ -2798,6 +2786,95 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_buckets = __new_buckets; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr + + // This is for implementing equality comparison for unordered containers, + // per N3068, by John Lakos and Pablo Halpern. + // Algorithmically, we follow closely the reference implementations therein. + template<typename _Key, typename _Value, typename _Alloc, + typename _ExtractKey, typename _Equal, + typename _Hash, typename _RangeHash, typename _Unused, + typename _RehashPolicy, typename _Traits> + bool + _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, + _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>:: + _M_equal(const _Hashtable& __other) const + { + if (size() != __other.size()) + return false; + + if constexpr (__unique_keys::value) + for (auto __x_n = _M_begin(); __x_n; __x_n = __x_n->_M_next()) + { + std::size_t __ybkt = __other._M_bucket_index(*__x_n); + auto __prev_n = __other._M_buckets[__ybkt]; + if (!__prev_n) + return false; + + for (__node_ptr __n = static_cast<__node_ptr>(__prev_n->_M_nxt);; + __n = __n->_M_next()) + { + if (__n->_M_v() == __x_n->_M_v()) + break; + + if (!__n->_M_nxt + || __other._M_bucket_index(*__n->_M_next()) != __ybkt) + return false; + } + } + else // non-unique keys + for (auto __x_n = _M_begin(); __x_n;) + { + std::size_t __x_count = 1; + auto __x_n_end = __x_n->_M_next(); + for (; __x_n_end + && key_eq()(_ExtractKey{}(__x_n->_M_v()), + _ExtractKey{}(__x_n_end->_M_v())); + __x_n_end = __x_n_end->_M_next()) + ++__x_count; + + std::size_t __ybkt = __other._M_bucket_index(*__x_n); + auto __y_prev_n = __other._M_buckets[__ybkt]; + if (!__y_prev_n) + return false; + + __node_ptr __y_n = static_cast<__node_ptr>(__y_prev_n->_M_nxt); + for (;;) + { + if (key_eq()(_ExtractKey{}(__y_n->_M_v()), + _ExtractKey{}(__x_n->_M_v()))) + break; + + auto __y_ref_n = __y_n; + for (__y_n = __y_n->_M_next(); __y_n; __y_n = __y_n->_M_next()) + if (!__other._M_node_equals(*__y_ref_n, *__y_n)) + break; + + if (!__y_n || __other._M_bucket_index(*__y_n) != __ybkt) + return false; + } + + auto __y_n_end = __y_n; + for (; __y_n_end; __y_n_end = __y_n_end->_M_next()) + if (--__x_count == 0) + break; + + if (__x_count != 0) + return false; + + const_iterator __itx(__x_n), __itx_end(__x_n_end); + const_iterator __ity(__y_n); + if (!std::is_permutation(__itx, __itx_end, __ity)) + return false; + + __x_n = __x_n_end; + } + + return true; + } +#pragma GCC diagnostic pop + #if __cplusplus > 201402L template<typename, typename, typename> class _Hash_merge_helper { }; #endif // C++17 diff --git a/libstdc++-v3/include/bits/hashtable_policy.h b/libstdc++-v3/include/bits/hashtable_policy.h index 3fd85bff01d5..c3d89a1101c6 100644 --- a/libstdc++-v3/include/bits/hashtable_policy.h +++ b/libstdc++-v3/include/bits/hashtable_policy.h @@ -1568,153 +1568,6 @@ namespace __detail _M_eq() const { return _EqualEBO::_M_cget(); } }; - /** - * Primary class template _Equality. - * - * This is for implementing equality comparison for unordered - * containers, per N3068, by John Lakos and Pablo Halpern. - * Algorithmically, we follow closely the reference implementations - * therein. - */ - template<typename _Key, typename _Value, typename _Alloc, - typename _ExtractKey, typename _Equal, - typename _Hash, typename _RangeHash, typename _Unused, - typename _RehashPolicy, typename _Traits, - bool _Unique_keys = _Traits::__unique_keys::value> - struct _Equality; - - /// unordered_map and unordered_set specializations. - template<typename _Key, typename _Value, typename _Alloc, - typename _ExtractKey, typename _Equal, - typename _Hash, typename _RangeHash, typename _Unused, - typename _RehashPolicy, typename _Traits> - struct _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, - _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, true> - { - using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, - _Hash, _RangeHash, _Unused, - _RehashPolicy, _Traits>; - - bool - _M_equal(const __hashtable&) const; - }; - - template<typename _Key, typename _Value, typename _Alloc, - typename _ExtractKey, typename _Equal, - typename _Hash, typename _RangeHash, typename _Unused, - typename _RehashPolicy, typename _Traits> - bool - _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, - _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, true>:: - _M_equal(const __hashtable& __other) const - { - using __node_ptr = typename __hashtable::__node_ptr; - const __hashtable* __this = static_cast<const __hashtable*>(this); - if (__this->size() != __other.size()) - return false; - - for (auto __x_n = __this->_M_begin(); __x_n; __x_n = __x_n->_M_next()) - { - std::size_t __ybkt = __other._M_bucket_index(*__x_n); - auto __prev_n = __other._M_buckets[__ybkt]; - if (!__prev_n) - return false; - - for (__node_ptr __n = static_cast<__node_ptr>(__prev_n->_M_nxt);; - __n = __n->_M_next()) - { - if (__n->_M_v() == __x_n->_M_v()) - break; - - if (!__n->_M_nxt - || __other._M_bucket_index(*__n->_M_next()) != __ybkt) - return false; - } - } - - return true; - } - - /// unordered_multiset and unordered_multimap specializations. - template<typename _Key, typename _Value, typename _Alloc, - typename _ExtractKey, typename _Equal, - typename _Hash, typename _RangeHash, typename _Unused, - typename _RehashPolicy, typename _Traits> - struct _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, - _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, false> - { - using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, - _Hash, _RangeHash, _Unused, - _RehashPolicy, _Traits>; - - bool - _M_equal(const __hashtable&) const; - }; - - template<typename _Key, typename _Value, typename _Alloc, - typename _ExtractKey, typename _Equal, - typename _Hash, typename _RangeHash, typename _Unused, - typename _RehashPolicy, typename _Traits> - bool - _Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, - _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, false>:: - _M_equal(const __hashtable& __other) const - { - using __node_ptr = typename __hashtable::__node_ptr; - using const_iterator = typename __hashtable::const_iterator; - const __hashtable* __this = static_cast<const __hashtable*>(this); - if (__this->size() != __other.size()) - return false; - - for (auto __x_n = __this->_M_begin(); __x_n;) - { - std::size_t __x_count = 1; - auto __x_n_end = __x_n->_M_next(); - for (; __x_n_end - && __this->key_eq()(_ExtractKey{}(__x_n->_M_v()), - _ExtractKey{}(__x_n_end->_M_v())); - __x_n_end = __x_n_end->_M_next()) - ++__x_count; - - std::size_t __ybkt = __other._M_bucket_index(*__x_n); - auto __y_prev_n = __other._M_buckets[__ybkt]; - if (!__y_prev_n) - return false; - - __node_ptr __y_n = static_cast<__node_ptr>(__y_prev_n->_M_nxt); - for (;;) - { - if (__this->key_eq()(_ExtractKey{}(__y_n->_M_v()), - _ExtractKey{}(__x_n->_M_v()))) - break; - - auto __y_ref_n = __y_n; - for (__y_n = __y_n->_M_next(); __y_n; __y_n = __y_n->_M_next()) - if (!__other._M_node_equals(*__y_ref_n, *__y_n)) - break; - - if (!__y_n || __other._M_bucket_index(*__y_n) != __ybkt) - return false; - } - - auto __y_n_end = __y_n; - for (; __y_n_end; __y_n_end = __y_n_end->_M_next()) - if (--__x_count == 0) - break; - - if (__x_count != 0) - return false; - - const_iterator __itx(__x_n), __itx_end(__x_n_end); - const_iterator __ity(__y_n); - if (!std::is_permutation(__itx, __itx_end, __ity)) - return false; - - __x_n = __x_n_end; - } - return true; - } - /** * This type deals with all allocation and keeps an allocator instance * through inheritance to benefit from EBO when possible.