Skip to content

Conversation

philnik777
Copy link
Contributor

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.

@philnik777 philnik777 requested a review from a team as a code owner April 3, 2025 14:23
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Apr 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 3, 2025

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/134253.diff

5 Files Affected:

  • (modified) libcxx/include/__memory/compressed_pair.h (+6)
  • (modified) libcxx/include/ext/hash_map (+4-37)
  • (modified) libcxx/include/map (+4-42)
  • (modified) libcxx/include/tuple (+9-65)
  • (modified) libcxx/include/unordered_map (+9-80)
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);
 }

@philnik777 philnik777 force-pushed the compressed_element branch 3 times, most recently from fde7de2 to 935e035 Compare April 12, 2025 08:55
Copy link
Member

@ldionne ldionne left a 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 {
Copy link
Member

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.

Copy link
Member

@ldionne ldionne left a 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.

philnik777 added a commit that referenced this pull request Sep 4, 2025
…56416)

#134253 refactors a few classes to use `[[no_unique_address]]` instead
of the EBO. This adds tests to ensure there are no ABI breaks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants