diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst index e56f0a88db138..7c97d0b517d8a 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -59,9 +59,10 @@ Improvements and New Features by up to 2.5x - The performance of ``erase(iterator, iterator)`` in the unordered containers has been improved by up to 1.9x - The performance of ``map::insert_or_assign`` has been improved by up to 2x - - ``ofstream::write`` has been optimized to pass through large strings to system calls directly instead of copying them in chunks into a buffer. +- Multiple internal types have been refactored to use ``[[no_unique_address]]``, resulting in faster compile times and + reduced debug information. Deprecations and Removals ------------------------- @@ -89,5 +90,10 @@ ABI Affecting Changes ``_LIBCPP_ABI_NO_ITERATOR_BASES``. If you are using this flag and care about ABI stability, you should set ``_LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER`` as well. +- The internal types ``__map_value_compare``, ``__unordered_map_hasher``, ``__unordered_map_equal``, + ``__hash_map_hasher`` and ``__hash_map_equal`` have been refactored to use ``_LIBCPP_COMPRESSED_ELEMENT`` instead of + potentially inheriting from the types they wrap. At this point in time we are not aware of any ABI changes caused by + this. + Build System Changes -------------------- diff --git a/libcxx/include/__memory/compressed_pair.h b/libcxx/include/__memory/compressed_pair.h index 12163f4af61cf..d9d2720f9c9e4 100644 --- a/libcxx/include/__memory/compressed_pair.h +++ b/libcxx/include/__memory/compressed_pair.h @@ -80,6 +80,10 @@ class __compressed_pair_padding { template class __compressed_pair_padding<_ToPad, true> {}; +# define _LIBCPP_COMPRESSED_ELEMENT(T1, Initializer1) \ + _LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1; \ + _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding _LIBCPP_CONCAT3(__padding_, __LINE__, _) + // TODO: Fix the ABI for GCC as well once https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121637 is fixed # ifdef _LIBCPP_COMPILER_GCC # define _LIBCPP_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \ @@ -121,6 +125,8 @@ class __compressed_pair_padding<_ToPad, true> {}; # endif #else +# define _LIBCPP_COMPRESSED_ELEMENT(T1, Initializer1) _LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1 + # define _LIBCPP_COMPRESSED_PAIR(T1, Name1, T2, Name2) \ _LIBCPP_NO_UNIQUE_ADDRESS T1 Name1; \ _LIBCPP_NO_UNIQUE_ADDRESS T2 Name2 diff --git a/libcxx/include/ext/hash_map b/libcxx/include/ext/hash_map index ae4fb7ec01c9e..70c2fbeec2959 100644 --- a/libcxx/include/ext/hash_map +++ b/libcxx/include/ext/hash_map @@ -206,6 +206,7 @@ template #else # include <__config> # include <__hash_table> +# include <__memory/compressed_pair.h> # include # include # include @@ -224,21 +225,9 @@ _LIBCPP_WARNING("Use of the header is deprecated. Migrate to ::value && !std::__libcpp_is_final<_Hash>::value > -class __hash_map_hasher : private _Hash { -public: - _LIBCPP_HIDE_FROM_ABI __hash_map_hasher() : _Hash() {} - _LIBCPP_HIDE_FROM_ABI __hash_map_hasher(const _Hash& __h) : _Hash(__h) {} - _LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const { return *this; } - _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Tp& __x) const { return static_cast(*this)(__x.first); } - _LIBCPP_HIDE_FROM_ABI size_t operator()(const typename _Tp::first_type& __x) const { - return static_cast(*this)(__x); - } -}; - template -class __hash_map_hasher<_Tp, _Hash, false> { - _Hash __hash_; +class __hash_map_hasher { + _LIBCPP_COMPRESSED_ELEMENT(_Hash, __hash_); public: _LIBCPP_HIDE_FROM_ABI __hash_map_hasher() : __hash_() {} @@ -248,30 +237,9 @@ public: _LIBCPP_HIDE_FROM_ABI size_t operator()(const typename _Tp::first_type& __x) const { return __hash_(__x); } }; -template ::value && !std::__libcpp_is_final<_Pred>::value > -class __hash_map_equal : private _Pred { -public: - _LIBCPP_HIDE_FROM_ABI __hash_map_equal() : _Pred() {} - _LIBCPP_HIDE_FROM_ABI __hash_map_equal(const _Pred& __p) : _Pred(__p) {} - _LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const { return *this; } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { - return static_cast(*this)(__x.first, __y.first); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const typename _Tp::first_type& __x, const _Tp& __y) const { - return static_cast(*this)(__x, __y.first); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const typename _Tp::first_type& __y) const { - return static_cast(*this)(__x.first, __y); - } - _LIBCPP_HIDE_FROM_ABI bool - operator()(const typename _Tp::first_type& __x, const typename _Tp::first_type& __y) const { - return static_cast(*this)(__x, __y); - } -}; - template -class __hash_map_equal<_Tp, _Pred, false> { - _Pred __pred_; +class __hash_map_equal { + _LIBCPP_COMPRESSED_ELEMENT(_Pred, __pred_); public: _LIBCPP_HIDE_FROM_ABI __hash_map_equal() : __pred_() {} diff --git a/libcxx/include/map b/libcxx/include/map index f428c781e5036..e5085076faf02 100644 --- a/libcxx/include/map +++ b/libcxx/include/map @@ -589,6 +589,7 @@ erase_if(multimap& c, Predicate pred); // C++20 # include <__memory/addressof.h> # include <__memory/allocator.h> # include <__memory/allocator_traits.h> +# include <__memory/compressed_pair.h> # include <__memory/pointer_traits.h> # include <__memory/unique_ptr.h> # include <__memory_resource/polymorphic_allocator.h> @@ -633,47 +634,9 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -template ::value && !__libcpp_is_final<_Compare>::value> -class __map_value_compare : private _Compare { -public: - _LIBCPP_HIDE_FROM_ABI __map_value_compare() _NOEXCEPT_(is_nothrow_default_constructible<_Compare>::value) - : _Compare() {} - _LIBCPP_HIDE_FROM_ABI __map_value_compare(_Compare __c) _NOEXCEPT_(is_nothrow_copy_constructible<_Compare>::value) - : _Compare(__c) {} - _LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return *this; } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const { - return static_cast(*this)(__x.first, __y.first); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const { - return static_cast(*this)(__x.first, __y); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const { - return static_cast(*this)(__x, __y.first); - } - _LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) { - using std::swap; - swap(static_cast<_Compare&>(*this), static_cast<_Compare&>(__y)); - } - -# if _LIBCPP_STD_VER >= 14 - template - _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const { - return static_cast(*this)(__x, __y.first); - } - - template - _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const { - return static_cast(*this)(__x.first, __y); - } -# endif -}; - template -class __map_value_compare<_Key, _CP, _Compare, false> { - _Compare __comp_; +class __map_value_compare { + _LIBCPP_COMPRESSED_ELEMENT(_Compare, __comp_); public: _LIBCPP_HIDE_FROM_ABI __map_value_compare() _NOEXCEPT_(is_nothrow_default_constructible<_Compare>::value) @@ -685,7 +648,7 @@ public: _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const { return __comp_(__x.first, __y.first); } _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const { return __comp_(__x.first, __y); } _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const { return __comp_(__x, __y.first); } - void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) { + _LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) { using std::swap; swap(__comp_, __y.__comp_); } @@ -747,9 +710,9 @@ struct __lazy_synth_three_way_comparator<__map_value_compare<_Key, _MapValueT, _ }; # endif // _LIBCPP_STD_VER >= 14 -template +template inline _LIBCPP_HIDE_FROM_ABI void -swap(__map_value_compare<_Key, _CP, _Compare, __b>& __x, __map_value_compare<_Key, _CP, _Compare, __b>& __y) +swap(__map_value_compare<_Key, _CP, _Compare>& __x, __map_value_compare<_Key, _CP, _Compare>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { __x.swap(__y); } diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map index a38e5e0f1b94f..3c19d6f2a7f0d 100644 --- a/libcxx/include/unordered_map +++ b/libcxx/include/unordered_map @@ -600,6 +600,7 @@ template # include <__memory/addressof.h> # include <__memory/allocator.h> # include <__memory/allocator_traits.h> +# include <__memory/compressed_pair.h> # include <__memory/pointer_traits.h> # include <__memory/unique_ptr.h> # include <__memory_resource/polymorphic_allocator.h> @@ -643,34 +644,9 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -template ::value && !__libcpp_is_final<_Hash>::value> -class __unordered_map_hasher : private _Hash { -public: - _LIBCPP_HIDE_FROM_ABI __unordered_map_hasher() _NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value) : _Hash() {} - _LIBCPP_HIDE_FROM_ABI __unordered_map_hasher(const _Hash& __h) _NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value) - : _Hash(__h) {} - _LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const _NOEXCEPT { return *this; } - _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const { return static_cast(*this)(__x.first); } - _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Key& __x) const { return static_cast(*this)(__x); } -# if _LIBCPP_STD_VER >= 20 - template - _LIBCPP_HIDE_FROM_ABI size_t operator()(const _K2& __x) const { - return static_cast(*this)(__x); - } -# endif - _LIBCPP_HIDE_FROM_ABI void swap(__unordered_map_hasher& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Hash>) { - using std::swap; - swap(static_cast<_Hash&>(*this), static_cast<_Hash&>(__y)); - } -}; - template -class __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, false> { - _Hash __hash_; +class __unordered_map_hasher { + _LIBCPP_COMPRESSED_ELEMENT(_Hash, __hash_); public: _LIBCPP_HIDE_FROM_ABI __unordered_map_hasher() _NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value) @@ -692,60 +668,16 @@ public: } }; -template +template inline _LIBCPP_HIDE_FROM_ABI void -swap(__unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __x, - __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { +swap(__unordered_map_hasher<_Key, _Cp, _Hash, _Pred>& __x, __unordered_map_hasher<_Key, _Cp, _Hash, _Pred>& __y) + _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { __x.swap(__y); } -template ::value && !__libcpp_is_final<_Pred>::value> -class __unordered_map_equal : private _Pred { -public: - _LIBCPP_HIDE_FROM_ABI __unordered_map_equal() _NOEXCEPT_(is_nothrow_default_constructible<_Pred>::value) : _Pred() {} - _LIBCPP_HIDE_FROM_ABI __unordered_map_equal(const _Pred& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_Pred>::value) - : _Pred(__p) {} - _LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const _NOEXCEPT { return *this; } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Cp& __y) const { - return static_cast(*this)(__x.first, __y.first); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const { - return static_cast(*this)(__x.first, __y); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const { - return static_cast(*this)(__x, __y.__get_value().first); - } -# if _LIBCPP_STD_VER >= 20 - template - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _K2& __y) const { - return static_cast(*this)(__x.first, __y); - } - template - _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Cp& __y) const { - return static_cast(*this)(__x, __y.__get_value().first); - } - template - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _K2& __y) const { - return static_cast(*this)(__x, __y); - } - template - _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Key& __y) const { - return static_cast(*this)(__x, __y); - } -# endif - _LIBCPP_HIDE_FROM_ABI void swap(__unordered_map_equal& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Pred>) { - using std::swap; - swap(static_cast<_Pred&>(*this), static_cast<_Pred&>(__y)); - } -}; - template -class __unordered_map_equal<_Key, _Cp, _Pred, _Hash, false> { - _Pred __pred_; +class __unordered_map_equal { + _LIBCPP_COMPRESSED_ELEMENT(_Pred, __pred_); public: _LIBCPP_HIDE_FROM_ABI __unordered_map_equal() _NOEXCEPT_(is_nothrow_default_constructible<_Pred>::value) @@ -780,9 +712,9 @@ public: } }; -template +template inline _LIBCPP_HIDE_FROM_ABI void -swap(__unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __x, __unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __y) +swap(__unordered_map_equal<_Key, _Cp, _Pred, _Hash>& __x, __unordered_map_equal<_Key, _Cp, _Pred, _Hash>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { __x.swap(__y); }