Skip to content

Commit 868aa5f

Browse files
authored
[libc++] Introduce _LIBCPP_COMPRESSED_ELEMENT (#134253)
We have multiple classes with an empty base optimization that contains just a single type. This patch introduces `_LIBCPP_COMPRESSED_ELEMENT` to refactor these classes to avoid having them essentially twice, reducing the amount of code significantly.
1 parent 69a0742 commit 868aa5f

File tree

5 files changed

+34
-159
lines changed

5 files changed

+34
-159
lines changed

libcxx/docs/ReleaseNotes/22.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@ Improvements and New Features
5858
- The performance of ``insert(iterator, iterator)`` of ``map``, ``set``, ``multimap`` and ``multiset`` has been improved
5959
by up to 2.5x
6060
- The performance of ``map::insert_or_assign`` has been improved by up to 2x
61-
6261
- ``ofstream::write`` has been optimized to pass through large strings to system calls directly instead of copying them
6362
in chunks into a buffer.
63+
- Multiple internal types have been refactored to use ``[[no_unique_address]]``, resulting in faster compile times and
64+
reduced debug information.
6465

6566
Deprecations and Removals
6667
-------------------------
@@ -88,5 +89,10 @@ ABI Affecting Changes
8889
``_LIBCPP_ABI_NO_ITERATOR_BASES``. If you are using this flag and care about ABI stability, you should set
8990
``_LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER`` as well.
9091

92+
- The internal types ``__map_value_compare``, ``__unordered_map_hasher``, ``__unordered_map_equal``,
93+
``__hash_map_hasher`` and ``__hash_map_equal`` have been refactored to use ``_LIBCPP_COMPRESSED_ELEMENT`` instead of
94+
potentially inheriting from the types they wrap. At this point in time we are not aware of any ABI changes caused by
95+
this.
96+
9197
Build System Changes
9298
--------------------

libcxx/include/__memory/compressed_pair.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ class __compressed_pair_padding {
8080
template <class _ToPad>
8181
class __compressed_pair_padding<_ToPad, true> {};
8282

83+
# define _LIBCPP_COMPRESSED_ELEMENT(T1, Initializer1) \
84+
_LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1; \
85+
_LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding_, __LINE__, _)
86+
8387
// TODO: Fix the ABI for GCC as well once https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121637 is fixed
8488
# ifdef _LIBCPP_COMPILER_GCC
8589
# define _LIBCPP_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \
@@ -121,6 +125,8 @@ class __compressed_pair_padding<_ToPad, true> {};
121125
# endif
122126

123127
#else
128+
# define _LIBCPP_COMPRESSED_ELEMENT(T1, Initializer1) _LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1
129+
124130
# define _LIBCPP_COMPRESSED_PAIR(T1, Name1, T2, Name2) \
125131
_LIBCPP_NO_UNIQUE_ADDRESS T1 Name1; \
126132
_LIBCPP_NO_UNIQUE_ADDRESS T2 Name2

libcxx/include/ext/hash_map

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
206206
#else
207207
# include <__config>
208208
# include <__hash_table>
209+
# include <__memory/compressed_pair.h>
209210
# include <algorithm>
210211
# include <ext/__hash>
211212
# include <functional>
@@ -224,21 +225,9 @@ _LIBCPP_WARNING("Use of the header <ext/hash_map> is deprecated. Migrate to <un
224225

225226
namespace __gnu_cxx {
226227

227-
template <class _Tp, class _Hash, bool = std::is_empty<_Hash>::value && !std::__libcpp_is_final<_Hash>::value >
228-
class __hash_map_hasher : private _Hash {
229-
public:
230-
_LIBCPP_HIDE_FROM_ABI __hash_map_hasher() : _Hash() {}
231-
_LIBCPP_HIDE_FROM_ABI __hash_map_hasher(const _Hash& __h) : _Hash(__h) {}
232-
_LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const { return *this; }
233-
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Tp& __x) const { return static_cast<const _Hash&>(*this)(__x.first); }
234-
_LIBCPP_HIDE_FROM_ABI size_t operator()(const typename _Tp::first_type& __x) const {
235-
return static_cast<const _Hash&>(*this)(__x);
236-
}
237-
};
238-
239228
template <class _Tp, class _Hash>
240-
class __hash_map_hasher<_Tp, _Hash, false> {
241-
_Hash __hash_;
229+
class __hash_map_hasher {
230+
_LIBCPP_COMPRESSED_ELEMENT(_Hash, __hash_);
242231

243232
public:
244233
_LIBCPP_HIDE_FROM_ABI __hash_map_hasher() : __hash_() {}
@@ -248,30 +237,9 @@ public:
248237
_LIBCPP_HIDE_FROM_ABI size_t operator()(const typename _Tp::first_type& __x) const { return __hash_(__x); }
249238
};
250239

251-
template <class _Tp, class _Pred, bool = std::is_empty<_Pred>::value && !std::__libcpp_is_final<_Pred>::value >
252-
class __hash_map_equal : private _Pred {
253-
public:
254-
_LIBCPP_HIDE_FROM_ABI __hash_map_equal() : _Pred() {}
255-
_LIBCPP_HIDE_FROM_ABI __hash_map_equal(const _Pred& __p) : _Pred(__p) {}
256-
_LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const { return *this; }
257-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const {
258-
return static_cast<const _Pred&>(*this)(__x.first, __y.first);
259-
}
260-
_LIBCPP_HIDE_FROM_ABI bool operator()(const typename _Tp::first_type& __x, const _Tp& __y) const {
261-
return static_cast<const _Pred&>(*this)(__x, __y.first);
262-
}
263-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const typename _Tp::first_type& __y) const {
264-
return static_cast<const _Pred&>(*this)(__x.first, __y);
265-
}
266-
_LIBCPP_HIDE_FROM_ABI bool
267-
operator()(const typename _Tp::first_type& __x, const typename _Tp::first_type& __y) const {
268-
return static_cast<const _Pred&>(*this)(__x, __y);
269-
}
270-
};
271-
272240
template <class _Tp, class _Pred>
273-
class __hash_map_equal<_Tp, _Pred, false> {
274-
_Pred __pred_;
241+
class __hash_map_equal {
242+
_LIBCPP_COMPRESSED_ELEMENT(_Pred, __pred_);
275243

276244
public:
277245
_LIBCPP_HIDE_FROM_ABI __hash_map_equal() : __pred_() {}

libcxx/include/map

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
589589
# include <__memory/addressof.h>
590590
# include <__memory/allocator.h>
591591
# include <__memory/allocator_traits.h>
592+
# include <__memory/compressed_pair.h>
592593
# include <__memory/pointer_traits.h>
593594
# include <__memory/unique_ptr.h>
594595
# include <__memory_resource/polymorphic_allocator.h>
@@ -633,47 +634,9 @@ _LIBCPP_PUSH_MACROS
633634

634635
_LIBCPP_BEGIN_NAMESPACE_STD
635636

636-
template <class _Key,
637-
class _CP,
638-
class _Compare,
639-
bool = is_empty<_Compare>::value && !__libcpp_is_final<_Compare>::value>
640-
class __map_value_compare : private _Compare {
641-
public:
642-
_LIBCPP_HIDE_FROM_ABI __map_value_compare() _NOEXCEPT_(is_nothrow_default_constructible<_Compare>::value)
643-
: _Compare() {}
644-
_LIBCPP_HIDE_FROM_ABI __map_value_compare(_Compare __c) _NOEXCEPT_(is_nothrow_copy_constructible<_Compare>::value)
645-
: _Compare(__c) {}
646-
_LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return *this; }
647-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const {
648-
return static_cast<const _Compare&>(*this)(__x.first, __y.first);
649-
}
650-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
651-
return static_cast<const _Compare&>(*this)(__x.first, __y);
652-
}
653-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
654-
return static_cast<const _Compare&>(*this)(__x, __y.first);
655-
}
656-
_LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
657-
using std::swap;
658-
swap(static_cast<_Compare&>(*this), static_cast<_Compare&>(__y));
659-
}
660-
661-
# if _LIBCPP_STD_VER >= 14
662-
template <typename _K2>
663-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
664-
return static_cast<const _Compare&>(*this)(__x, __y.first);
665-
}
666-
667-
template <typename _K2>
668-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
669-
return static_cast<const _Compare&>(*this)(__x.first, __y);
670-
}
671-
# endif
672-
};
673-
674637
template <class _Key, class _CP, class _Compare>
675-
class __map_value_compare<_Key, _CP, _Compare, false> {
676-
_Compare __comp_;
638+
class __map_value_compare {
639+
_LIBCPP_COMPRESSED_ELEMENT(_Compare, __comp_);
677640

678641
public:
679642
_LIBCPP_HIDE_FROM_ABI __map_value_compare() _NOEXCEPT_(is_nothrow_default_constructible<_Compare>::value)
@@ -685,7 +648,7 @@ public:
685648
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const { return __comp_(__x.first, __y.first); }
686649
_LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const { return __comp_(__x.first, __y); }
687650
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const { return __comp_(__x, __y.first); }
688-
void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
651+
_LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) {
689652
using std::swap;
690653
swap(__comp_, __y.__comp_);
691654
}
@@ -747,9 +710,9 @@ struct __lazy_synth_three_way_comparator<__map_value_compare<_Key, _MapValueT, _
747710
};
748711
# endif // _LIBCPP_STD_VER >= 14
749712

750-
template <class _Key, class _CP, class _Compare, bool __b>
713+
template <class _Key, class _CP, class _Compare>
751714
inline _LIBCPP_HIDE_FROM_ABI void
752-
swap(__map_value_compare<_Key, _CP, _Compare, __b>& __x, __map_value_compare<_Key, _CP, _Compare, __b>& __y)
715+
swap(__map_value_compare<_Key, _CP, _Compare>& __x, __map_value_compare<_Key, _CP, _Compare>& __y)
753716
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) {
754717
__x.swap(__y);
755718
}

libcxx/include/unordered_map

Lines changed: 10 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
600600
# include <__memory/addressof.h>
601601
# include <__memory/allocator.h>
602602
# include <__memory/allocator_traits.h>
603+
# include <__memory/compressed_pair.h>
603604
# include <__memory/pointer_traits.h>
604605
# include <__memory/unique_ptr.h>
605606
# include <__memory_resource/polymorphic_allocator.h>
@@ -643,34 +644,9 @@ _LIBCPP_PUSH_MACROS
643644

644645
_LIBCPP_BEGIN_NAMESPACE_STD
645646

646-
template <class _Key,
647-
class _Cp,
648-
class _Hash,
649-
class _Pred,
650-
bool = is_empty<_Hash>::value && !__libcpp_is_final<_Hash>::value>
651-
class __unordered_map_hasher : private _Hash {
652-
public:
653-
_LIBCPP_HIDE_FROM_ABI __unordered_map_hasher() _NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value) : _Hash() {}
654-
_LIBCPP_HIDE_FROM_ABI __unordered_map_hasher(const _Hash& __h) _NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value)
655-
: _Hash(__h) {}
656-
_LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const _NOEXCEPT { return *this; }
657-
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const { return static_cast<const _Hash&>(*this)(__x.first); }
658-
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _Key& __x) const { return static_cast<const _Hash&>(*this)(__x); }
659-
# if _LIBCPP_STD_VER >= 20
660-
template <typename _K2>
661-
_LIBCPP_HIDE_FROM_ABI size_t operator()(const _K2& __x) const {
662-
return static_cast<const _Hash&>(*this)(__x);
663-
}
664-
# endif
665-
_LIBCPP_HIDE_FROM_ABI void swap(__unordered_map_hasher& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Hash>) {
666-
using std::swap;
667-
swap(static_cast<_Hash&>(*this), static_cast<_Hash&>(__y));
668-
}
669-
};
670-
671647
template <class _Key, class _Cp, class _Hash, class _Pred>
672-
class __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, false> {
673-
_Hash __hash_;
648+
class __unordered_map_hasher {
649+
_LIBCPP_COMPRESSED_ELEMENT(_Hash, __hash_);
674650

675651
public:
676652
_LIBCPP_HIDE_FROM_ABI __unordered_map_hasher() _NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value)
@@ -692,60 +668,16 @@ public:
692668
}
693669
};
694670

695-
template <class _Key, class _Cp, class _Hash, class _Pred, bool __b>
671+
template <class _Key, class _Cp, class _Hash, class _Pred>
696672
inline _LIBCPP_HIDE_FROM_ABI void
697-
swap(__unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __x,
698-
__unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) {
673+
swap(__unordered_map_hasher<_Key, _Cp, _Hash, _Pred>& __x, __unordered_map_hasher<_Key, _Cp, _Hash, _Pred>& __y)
674+
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) {
699675
__x.swap(__y);
700676
}
701677

702-
template <class _Key,
703-
class _Cp,
704-
class _Pred,
705-
class _Hash,
706-
bool = is_empty<_Pred>::value && !__libcpp_is_final<_Pred>::value>
707-
class __unordered_map_equal : private _Pred {
708-
public:
709-
_LIBCPP_HIDE_FROM_ABI __unordered_map_equal() _NOEXCEPT_(is_nothrow_default_constructible<_Pred>::value) : _Pred() {}
710-
_LIBCPP_HIDE_FROM_ABI __unordered_map_equal(const _Pred& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_Pred>::value)
711-
: _Pred(__p) {}
712-
_LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const _NOEXCEPT { return *this; }
713-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Cp& __y) const {
714-
return static_cast<const _Pred&>(*this)(__x.first, __y.first);
715-
}
716-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const {
717-
return static_cast<const _Pred&>(*this)(__x.first, __y);
718-
}
719-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const {
720-
return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);
721-
}
722-
# if _LIBCPP_STD_VER >= 20
723-
template <typename _K2>
724-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _K2& __y) const {
725-
return static_cast<const _Pred&>(*this)(__x.first, __y);
726-
}
727-
template <typename _K2>
728-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Cp& __y) const {
729-
return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);
730-
}
731-
template <typename _K2>
732-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _K2& __y) const {
733-
return static_cast<const _Pred&>(*this)(__x, __y);
734-
}
735-
template <typename _K2>
736-
_LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Key& __y) const {
737-
return static_cast<const _Pred&>(*this)(__x, __y);
738-
}
739-
# endif
740-
_LIBCPP_HIDE_FROM_ABI void swap(__unordered_map_equal& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Pred>) {
741-
using std::swap;
742-
swap(static_cast<_Pred&>(*this), static_cast<_Pred&>(__y));
743-
}
744-
};
745-
746678
template <class _Key, class _Cp, class _Pred, class _Hash>
747-
class __unordered_map_equal<_Key, _Cp, _Pred, _Hash, false> {
748-
_Pred __pred_;
679+
class __unordered_map_equal {
680+
_LIBCPP_COMPRESSED_ELEMENT(_Pred, __pred_);
749681

750682
public:
751683
_LIBCPP_HIDE_FROM_ABI __unordered_map_equal() _NOEXCEPT_(is_nothrow_default_constructible<_Pred>::value)
@@ -780,9 +712,9 @@ public:
780712
}
781713
};
782714

783-
template <class _Key, class _Cp, class _Pred, class _Hash, bool __b>
715+
template <class _Key, class _Cp, class _Pred, class _Hash>
784716
inline _LIBCPP_HIDE_FROM_ABI void
785-
swap(__unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __x, __unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __y)
717+
swap(__unordered_map_equal<_Key, _Cp, _Pred, _Hash>& __x, __unordered_map_equal<_Key, _Cp, _Pred, _Hash>& __y)
786718
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) {
787719
__x.swap(__y);
788720
}

0 commit comments

Comments
 (0)