-
Notifications
You must be signed in to change notification settings - Fork 15k
[libc++] Introduce _LIBCPP_COMPRESSED_ELEMENT #134253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-libcxx Author: Nikolas Klauser (philnik777) ChangesWe have multiple classes with an empty base optimization that contains just a single type. This patch introduces Full diff: https://github.com/llvm/llvm-project/pull/134253.diff 5 Files Affected:
diff --git a/libcxx/include/__memory/compressed_pair.h b/libcxx/include/__memory/compressed_pair.h
index 38798a21fa3c9..5107660ac1d49 100644
--- a/libcxx/include/__memory/compressed_pair.h
+++ b/libcxx/include/__memory/compressed_pair.h
@@ -73,6 +73,10 @@ class __compressed_pair_padding {
template <class _ToPad>
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<T1> _LIBCPP_CONCAT3(__padding_, __LINE__, _)
+
# define _LIBCPP_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \
_LIBCPP_NO_UNIQUE_ADDRESS __attribute__((__aligned__(::std::__compressed_pair_alignment<T2>))) T1 Initializer1; \
_LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding1_, __LINE__, _); \
@@ -90,6 +94,8 @@ class __compressed_pair_padding<_ToPad, true> {};
_LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T3> _LIBCPP_CONCAT3(__padding3_, __LINE__, _)
#else
+# define _LIBCPP_COMPRESSED_ELEMENT(T1, Initializer1) _LIBCPP_NO_UNQIUE_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 c0336620cf88f..28bbc8209206d 100644
--- a/libcxx/include/ext/hash_map
+++ b/libcxx/include/ext/hash_map
@@ -224,21 +224,9 @@ _LIBCPP_WARNING("Use of the header <ext/hash_map> is deprecated. Migrate to <un
namespace __gnu_cxx {
-template <class _Tp, class _Hash, bool = std::is_empty<_Hash>::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<const _Hash&>(*this)(__x.first); }
- _LIBCPP_HIDE_FROM_ABI size_t operator()(const typename _Tp::first_type& __x) const {
- return static_cast<const _Hash&>(*this)(__x);
- }
-};
-
template <class _Tp, class _Hash>
-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 +236,9 @@ public:
_LIBCPP_HIDE_FROM_ABI size_t operator()(const typename _Tp::first_type& __x) const { return __hash_(__x); }
};
-template <class _Tp, class _Pred, bool = std::is_empty<_Pred>::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<const _Pred&>(*this)(__x.first, __y.first);
- }
- _LIBCPP_HIDE_FROM_ABI bool operator()(const typename _Tp::first_type& __x, const _Tp& __y) const {
- return static_cast<const _Pred&>(*this)(__x, __y.first);
- }
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const typename _Tp::first_type& __y) const {
- return static_cast<const _Pred&>(*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<const _Pred&>(*this)(__x, __y);
- }
-};
-
template <class _Tp, class _Pred>
-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 e7e0c14e36999..06ce26272ed8b 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -633,47 +633,9 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Key,
- class _CP,
- class _Compare,
- bool = is_empty<_Compare>::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<const _Compare&>(*this)(__x.__get_value().first, __y.__get_value().first);
- }
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const {
- return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
- }
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const {
- return static_cast<const _Compare&>(*this)(__x, __y.__get_value().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 <typename _K2>
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const {
- return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);
- }
-
- template <typename _K2>
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const {
- return static_cast<const _Compare&>(*this)(__x.__get_value().first, __y);
- }
-# endif
-};
-
template <class _Key, class _CP, class _Compare>
-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)
@@ -709,9 +671,9 @@ public:
# endif
};
-template <class _Key, class _CP, class _Compare, bool __b>
+template <class _Key, class _CP, class _Compare>
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/tuple b/libcxx/include/tuple
index e284f71200492..a4abca5db84d9 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -222,6 +222,7 @@ template <class... Types>
# include <__fwd/pair.h>
# include <__fwd/tuple.h>
# include <__memory/allocator_arg_t.h>
+# include <__memory/compressed_pair.h>
# include <__memory/uses_allocator.h>
# include <__tuple/find_index.h>
# include <__tuple/ignore.h>
@@ -287,25 +288,25 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// __tuple_leaf
-template <size_t _Ip, class _Hp, bool = is_empty<_Hp>::value && !__libcpp_is_final<_Hp>::value >
+template <size_t _Ip, class _Hp>
class __tuple_leaf;
-template <size_t _Ip, class _Hp, bool _Ep>
+template <size_t _Ip, class _Hp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
-swap(__tuple_leaf<_Ip, _Hp, _Ep>& __x, __tuple_leaf<_Ip, _Hp, _Ep>& __y) noexcept(__is_nothrow_swappable_v<_Hp>) {
+swap(__tuple_leaf<_Ip, _Hp>& __x, __tuple_leaf<_Ip, _Hp>& __y) noexcept(__is_nothrow_swappable_v<_Hp>) {
swap(__x.get(), __y.get());
}
-template <size_t _Ip, class _Hp, bool _Ep>
+template <size_t _Ip, class _Hp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
-swap(const __tuple_leaf<_Ip, _Hp, _Ep>& __x,
- const __tuple_leaf<_Ip, _Hp, _Ep>& __y) noexcept(__is_nothrow_swappable_v<const _Hp>) {
+swap(const __tuple_leaf<_Ip, _Hp>& __x,
+ const __tuple_leaf<_Ip, _Hp>& __y) noexcept(__is_nothrow_swappable_v<const _Hp>) {
swap(__x.get(), __y.get());
}
-template <size_t _Ip, class _Hp, bool>
+template <size_t _Ip, class _Hp>
class __tuple_leaf {
- _Hp __value_;
+ _LIBCPP_COMPRESSED_ELEMENT(_Hp, __value_);
template <class _Tp>
static _LIBCPP_HIDE_FROM_ABI constexpr bool __can_bind_reference() {
@@ -390,63 +391,6 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT { return __value_; }
};
-template <size_t _Ip, class _Hp>
-class __tuple_leaf<_Ip, _Hp, true> : private __remove_cv_t<_Hp> {
-public:
- _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_leaf& operator=(const __tuple_leaf&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value) {}
-
- template <class _Alloc>
- _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 0>, const _Alloc&) {}
-
- template <class _Alloc>
- _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a)
- : _Hp(allocator_arg_t(), __a) {}
-
- template <class _Alloc>
- _LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a) : _Hp(__a) {}
-
- template <class _Tp,
- __enable_if_t< _And< _IsNotSame<__remove_cvref_t<_Tp>, __tuple_leaf>, is_constructible<_Hp, _Tp> >::value,
- int> = 0>
- _LIBCPP_HIDE_FROM_ABI
- _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(_Tp&& __t) noexcept(is_nothrow_constructible<_Hp, _Tp>::value)
- : _Hp(std::forward<_Tp>(__t)) {}
-
- template <class _Tp, class _Alloc>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant<int, 0>, const _Alloc&, _Tp&& __t)
- : _Hp(std::forward<_Tp>(__t)) {}
-
- template <class _Tp, class _Alloc>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a, _Tp&& __t)
- : _Hp(allocator_arg_t(), __a, std::forward<_Tp>(__t)) {}
-
- template <class _Tp, class _Alloc>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t)
- : _Hp(std::forward<_Tp>(__t), __a) {}
-
- __tuple_leaf(__tuple_leaf const&) = default;
- __tuple_leaf(__tuple_leaf&&) = default;
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int
- swap(__tuple_leaf& __t) noexcept(__is_nothrow_swappable_v<__tuple_leaf>) {
- std::swap(*this, __t);
- return 0;
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int swap(const __tuple_leaf& __rhs) const
- noexcept(__is_nothrow_swappable_v<const __tuple_leaf>) {
- std::swap(*this, __rhs);
- return 0;
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Hp& get() _NOEXCEPT { return static_cast<_Hp&>(*this); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT {
- return static_cast<const _Hp&>(*this);
- }
-};
-
template <class... _Tp>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __swallow(_Tp&&...) _NOEXCEPT {}
diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index be36b65cb85b4..9a12b20daab82 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -643,36 +643,9 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Key,
- class _Cp,
- class _Hash,
- class _Pred,
- bool = is_empty<_Hash>::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<const _Hash&>(*this)(__x.__get_value().first);
- }
- _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Key& __x) const { return static_cast<const _Hash&>(*this)(__x); }
-# if _LIBCPP_STD_VER >= 20
- template <typename _K2>
- _LIBCPP_HIDE_FROM_ABI size_t operator()(const _K2& __x) const {
- return static_cast<const _Hash&>(*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 _Key, class _Cp, class _Hash, class _Pred>
-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)
@@ -694,60 +667,16 @@ public:
}
};
-template <class _Key, class _Cp, class _Hash, class _Pred, bool __b>
+template <class _Key, class _Cp, class _Hash, class _Pred>
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 <class _Key,
- class _Cp,
- class _Pred,
- class _Hash,
- bool = is_empty<_Pred>::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<const _Pred&>(*this)(__x.__get_value().first, __y.__get_value().first);
- }
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const {
- return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y);
- }
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const {
- return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);
- }
-# if _LIBCPP_STD_VER >= 20
- template <typename _K2>
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _K2& __y) const {
- return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y);
- }
- template <typename _K2>
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Cp& __y) const {
- return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);
- }
- template <typename _K2>
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _K2& __y) const {
- return static_cast<const _Pred&>(*this)(__x, __y);
- }
- template <typename _K2>
- _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Key& __y) const {
- return static_cast<const _Pred&>(*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 _Key, class _Cp, class _Pred, class _Hash>
-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)
@@ -788,9 +717,9 @@ public:
}
};
-template <class _Key, class _Cp, class _Pred, class _Hash, bool __b>
+template <class _Key, class _Cp, class _Pred, class _Hash>
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);
}
|
fde7de2
to
935e035
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we introduced _LIBCPP_COMPRESSED_PAIR
and started using it, the ABI for a few weird types changed. We investigated it, decided it was fine, and documented that as a release note when we made the change. I think we need to do the same here. Otherwise, I don't see a problem with this patch.
template <class _Key, class _CP, class _Compare> | ||
class __map_value_compare<_Key, _CP, _Compare, false> { | ||
_Compare __comp_; | ||
class __map_value_compare { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're missing includes for compressed_pair.h
. Please check throughout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm fine with the patch. This is simpler than the compressed pair and compressed triple since we don't have to deal with the possibility of having the same type twice (hence no interaction w/ other elements), and the set of types that uses _LIBCPP_COMPRESSED_ELEMENT
is a lot more restricted than for compressed pair.
I'd like to see this rebased onto main
after landing the tests first, though.
935e035
to
c05462b
Compare
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.