Skip to content

Commit 8d3053c

Browse files
committed
[libc++] Replace __compressed_pair with [[no_unique_address]]
1 parent c92d3ce commit 8d3053c

File tree

21 files changed

+822
-568
lines changed

21 files changed

+822
-568
lines changed

libcxx/include/__config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@
168168
// pointer from 16 to 8. This changes the output of std::string::max_size,
169169
// which makes it ABI breaking
170170
# define _LIBCPP_ABI_STRING_8_BYTE_ALIGNMENT
171+
// Don't add padding from __compressed_pair
172+
# define _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
171173
# elif _LIBCPP_ABI_VERSION == 1
172174
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
173175
// Enable compiling copies of now inline methods into the dylib to support

libcxx/include/__functional/function.h

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -138,45 +138,46 @@ class __default_alloc_func;
138138

139139
template <class _Fp, class _Ap, class _Rp, class... _ArgTypes>
140140
class __alloc_func<_Fp, _Ap, _Rp(_ArgTypes...)> {
141-
__compressed_pair<_Fp, _Ap> __f_;
141+
_LIBCPP_COMPRESSED_PAIR(_Fp, __func_, _Ap, __alloc_);
142142

143143
public:
144144
typedef _LIBCPP_NODEBUG _Fp _Target;
145145
typedef _LIBCPP_NODEBUG _Ap _Alloc;
146146

147-
_LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __f_.first(); }
147+
_LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __func_; }
148148

149149
// WIN32 APIs may define __allocator, so use __get_allocator instead.
150-
_LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __f_.second(); }
150+
_LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __alloc_; }
151151

152-
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f)
153-
: __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple()) {}
152+
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f) : __func_(std::move(__f)), __alloc_() {}
154153

155-
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a)
156-
: __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(__a)) {}
154+
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a) : __func_(__f), __alloc_(__a) {}
157155

158156
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, _Alloc&& __a)
159-
: __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(std::move(__a))) {}
157+
: __func_(__f), __alloc_(std::move(__a)) {}
160158

161159
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f, _Alloc&& __a)
162-
: __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple(std::move(__a))) {}
160+
: __func_(std::move(__f)), __alloc_(std::move(__a)) {}
163161

164162
_LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) {
165163
typedef __invoke_void_return_wrapper<_Rp> _Invoker;
166-
return _Invoker::__call(__f_.first(), std::forward<_ArgTypes>(__arg)...);
164+
return _Invoker::__call(__func_, std::forward<_ArgTypes>(__arg)...);
167165
}
168166

169167
_LIBCPP_HIDE_FROM_ABI __alloc_func* __clone() const {
170168
typedef allocator_traits<_Alloc> __alloc_traits;
171169
typedef __rebind_alloc<__alloc_traits, __alloc_func> _AA;
172-
_AA __a(__f_.second());
170+
_AA __a(__alloc_);
173171
typedef __allocator_destructor<_AA> _Dp;
174172
unique_ptr<__alloc_func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
175-
::new ((void*)__hold.get()) __alloc_func(__f_.first(), _Alloc(__a));
173+
::new ((void*)__hold.get()) __alloc_func(__func_, _Alloc(__a));
176174
return __hold.release();
177175
}
178176

179-
_LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~__compressed_pair<_Target, _Alloc>(); }
177+
_LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT {
178+
__func_.~_Fp();
179+
__alloc_.~_Alloc();
180+
}
180181

181182
_LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__alloc_func* __f) {
182183
typedef allocator_traits<_Alloc> __alloc_traits;

libcxx/include/__hash_table

Lines changed: 87 additions & 68 deletions
Large diffs are not rendered by default.

libcxx/include/__memory/compressed_pair.h

Lines changed: 20 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -11,161 +11,39 @@
1111
#define _LIBCPP___MEMORY_COMPRESSED_PAIR_H
1212

1313
#include <__config>
14-
#include <__fwd/get.h>
15-
#include <__fwd/tuple.h>
16-
#include <__tuple/tuple_indices.h>
17-
#include <__type_traits/decay.h>
18-
#include <__type_traits/dependent_type.h>
19-
#include <__type_traits/enable_if.h>
20-
#include <__type_traits/is_default_constructible.h>
14+
#include <__type_traits/datasizeof.h>
2115
#include <__type_traits/is_empty.h>
2216
#include <__type_traits/is_final.h>
23-
#include <__type_traits/is_same.h>
24-
#include <__type_traits/is_swappable.h>
25-
#include <__utility/forward.h>
26-
#include <__utility/move.h>
27-
#include <__utility/piecewise_construct.h>
28-
#include <cstddef>
17+
#include <__type_traits/is_object.h>
2918

3019
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
3120
# pragma GCC system_header
3221
#endif
3322

34-
_LIBCPP_PUSH_MACROS
35-
#include <__undef_macros>
36-
3723
_LIBCPP_BEGIN_NAMESPACE_STD
3824

39-
// Tag used to default initialize one or both of the pair's elements.
40-
struct __default_init_tag {};
41-
struct __value_init_tag {};
42-
43-
template <class _Tp, int _Idx, bool _CanBeEmptyBase = is_empty<_Tp>::value && !__libcpp_is_final<_Tp>::value>
44-
struct __compressed_pair_elem {
45-
using _ParamT = _Tp;
46-
using reference = _Tp&;
47-
using const_reference = const _Tp&;
48-
49-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__default_init_tag) {}
50-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__value_init_tag) : __value_() {}
51-
52-
template <class _Up, class = __enable_if_t<!is_same<__compressed_pair_elem, __decay_t<_Up> >::value> >
53-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(_Up&& __u)
54-
: __value_(std::forward<_Up>(__u)) {}
55-
56-
#ifndef _LIBCPP_CXX03_LANG
57-
template <class... _Args, size_t... _Indices>
58-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit __compressed_pair_elem(
59-
piecewise_construct_t, tuple<_Args...> __args, __tuple_indices<_Indices...>)
60-
: __value_(std::forward<_Args>(std::get<_Indices>(__args))...) {}
61-
#endif
62-
63-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference __get() _NOEXCEPT { return __value_; }
64-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference __get() const _NOEXCEPT { return __value_; }
65-
66-
private:
67-
_Tp __value_;
68-
};
69-
70-
template <class _Tp, int _Idx>
71-
struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp {
72-
using _ParamT = _Tp;
73-
using reference = _Tp&;
74-
using const_reference = const _Tp&;
75-
using __value_type = _Tp;
76-
77-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem() = default;
78-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__default_init_tag) {}
79-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__value_init_tag) : __value_type() {}
80-
81-
template <class _Up, class = __enable_if_t<!is_same<__compressed_pair_elem, __decay_t<_Up> >::value> >
82-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(_Up&& __u)
83-
: __value_type(std::forward<_Up>(__u)) {}
84-
85-
#ifndef _LIBCPP_CXX03_LANG
86-
template <class... _Args, size_t... _Indices>
87-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17
88-
__compressed_pair_elem(piecewise_construct_t, tuple<_Args...> __args, __tuple_indices<_Indices...>)
89-
: __value_type(std::forward<_Args>(std::get<_Indices>(__args))...) {}
90-
#endif
91-
92-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference __get() _NOEXCEPT { return *this; }
93-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference __get() const _NOEXCEPT { return *this; }
94-
};
95-
96-
template <class _T1, class _T2>
97-
class __compressed_pair : private __compressed_pair_elem<_T1, 0>, private __compressed_pair_elem<_T2, 1> {
98-
public:
99-
// NOTE: This static assert should never fire because __compressed_pair
100-
// is *almost never* used in a scenario where it's possible for T1 == T2.
101-
// (The exception is std::function where it is possible that the function
102-
// object and the allocator have the same type).
103-
static_assert(
104-
(!is_same<_T1, _T2>::value),
105-
"__compressed_pair cannot be instantiated when T1 and T2 are the same type; "
106-
"The current implementation is NOT ABI-compatible with the previous implementation for this configuration");
107-
108-
using _Base1 _LIBCPP_NODEBUG = __compressed_pair_elem<_T1, 0>;
109-
using _Base2 _LIBCPP_NODEBUG = __compressed_pair_elem<_T2, 1>;
110-
111-
template <bool _Dummy = true,
112-
class = __enable_if_t< __dependent_type<is_default_constructible<_T1>, _Dummy>::value &&
113-
__dependent_type<is_default_constructible<_T2>, _Dummy>::value > >
114-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair()
115-
: _Base1(__value_init_tag()), _Base2(__value_init_tag()) {}
116-
117-
template <class _U1, class _U2>
118-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair(_U1&& __t1, _U2&& __t2)
119-
: _Base1(std::forward<_U1>(__t1)), _Base2(std::forward<_U2>(__t2)) {}
120-
121-
#ifndef _LIBCPP_CXX03_LANG
122-
template <class... _Args1, class... _Args2>
123-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit __compressed_pair(
124-
piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args)
125-
: _Base1(__pc, std::move(__first_args), typename __make_tuple_indices<sizeof...(_Args1)>::type()),
126-
_Base2(__pc, std::move(__second_args), typename __make_tuple_indices<sizeof...(_Args2)>::type()) {}
127-
#endif
128-
129-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename _Base1::reference first() _NOEXCEPT {
130-
return static_cast<_Base1&>(*this).__get();
131-
}
132-
133-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename _Base1::const_reference first() const _NOEXCEPT {
134-
return static_cast<_Base1 const&>(*this).__get();
135-
}
136-
137-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename _Base2::reference second() _NOEXCEPT {
138-
return static_cast<_Base2&>(*this).__get();
139-
}
25+
#ifndef _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
14026

141-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename _Base2::const_reference second() const _NOEXCEPT {
142-
return static_cast<_Base2 const&>(*this).__get();
143-
}
144-
145-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static _Base1* __get_first_base(__compressed_pair* __pair) _NOEXCEPT {
146-
return static_cast<_Base1*>(__pair);
147-
}
148-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static _Base2* __get_second_base(__compressed_pair* __pair) _NOEXCEPT {
149-
return static_cast<_Base2*>(__pair);
150-
}
151-
152-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void swap(__compressed_pair& __x)
153-
_NOEXCEPT_(__is_nothrow_swappable<_T1>::value&& __is_nothrow_swappable<_T2>::value) {
154-
using std::swap;
155-
swap(first(), __x.first());
156-
swap(second(), __x.second());
157-
}
27+
template <class _ToPad>
28+
class __compressed_pair_padding {
29+
char __padding_[(!is_object<_ToPad>::value || (is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value))
30+
? 0
31+
: sizeof(_ToPad) - __libcpp_datasizeof<_ToPad>::value];
15832
};
15933

160-
template <class _T1, class _T2>
161-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
162-
swap(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y)
163-
_NOEXCEPT_(__is_nothrow_swappable<_T1>::value&& __is_nothrow_swappable<_T2>::value) {
164-
__x.swap(__y);
165-
}
34+
# define _LIBCPP_COMPRESSED_PAIR_PADDING(T, Name) _LIBCPP_NO_UNIQUE_ADDRESS __compressed_pair_padding<T> Name
35+
# define _LIBCPP_COMPRESSED_PAIR(T1, Name1, T2, Name2) \
36+
[[__gnu__::__aligned__(_LIBCPP_ALIGNOF(T2))]] _LIBCPP_NO_UNIQUE_ADDRESS T1 Name1; \
37+
_LIBCPP_COMPRESSED_PAIR_PADDING(T1, Name1##_padding_); \
38+
_LIBCPP_NO_UNIQUE_ADDRESS T2 Name2; \
39+
_LIBCPP_COMPRESSED_PAIR_PADDING(T2, Name2##_padding_)
40+
#else
41+
# define _LIBCPP_COMPRESSED_PAIR_PADDING(T, Name)
42+
# define _LIBCPP_COMPRESSED_PAIR(T1, Name1, T2, Name2) \
43+
_LIBCPP_NO_UNIQUE_ADDRESS T1 Name1; \
44+
_LIBCPP_NO_UNIQUE_ADDRESS T2 Name2;
45+
#endif // _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
16646

16747
_LIBCPP_END_NAMESPACE_STD
16848

169-
_LIBCPP_POP_MACROS
170-
17149
#endif // _LIBCPP___MEMORY_COMPRESSED_PAIR_H

libcxx/include/__memory/shared_ptr.h

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,17 @@ class _LIBCPP_EXPORTED_FROM_ABI __shared_weak_count : private __shared_count {
196196

197197
template <class _Tp, class _Dp, class _Alloc>
198198
class __shared_ptr_pointer : public __shared_weak_count {
199-
__compressed_pair<__compressed_pair<_Tp, _Dp>, _Alloc> __data_;
199+
[[using __gnu__: __aligned__(_LIBCPP_ALIGNOF(_Dp)),
200+
__aligned__(_LIBCPP_ALIGNOF(_Alloc))]] _LIBCPP_NO_UNIQUE_ADDRESS _Tp __ptr_;
201+
_LIBCPP_COMPRESSED_PAIR_PADDING(_Tp, __ptr_padding_);
202+
_LIBCPP_NO_UNIQUE_ADDRESS _Dp __deleter_;
203+
_LIBCPP_COMPRESSED_PAIR_PADDING(_Dp, __deleter_padding_);
204+
_LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
205+
_LIBCPP_COMPRESSED_PAIR_PADDING(_Alloc, __alloc_padding_);
200206

201207
public:
202208
_LIBCPP_HIDE_FROM_ABI __shared_ptr_pointer(_Tp __p, _Dp __d, _Alloc __a)
203-
: __data_(__compressed_pair<_Tp, _Dp>(__p, std::move(__d)), std::move(__a)) {}
209+
: __ptr_(__p), __deleter_(std::move(__d)), __alloc_(std::move(__a)) {}
204210

205211
#ifndef _LIBCPP_HAS_NO_RTTI
206212
_LIBCPP_HIDE_FROM_ABI_VIRTUAL const void* __get_deleter(const type_info&) const _NOEXCEPT override;
@@ -215,15 +221,15 @@ class __shared_ptr_pointer : public __shared_weak_count {
215221

216222
template <class _Tp, class _Dp, class _Alloc>
217223
const void* __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__get_deleter(const type_info& __t) const _NOEXCEPT {
218-
return __t == typeid(_Dp) ? std::addressof(__data_.first().second()) : nullptr;
224+
return __t == typeid(_Dp) ? std::addressof(__deleter_) : nullptr;
219225
}
220226

221227
#endif // _LIBCPP_HAS_NO_RTTI
222228

223229
template <class _Tp, class _Dp, class _Alloc>
224230
void __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared() _NOEXCEPT {
225-
__data_.first().second()(__data_.first().first());
226-
__data_.first().second().~_Dp();
231+
__deleter_(__ptr_);
232+
__deleter_.~_Dp();
227233
}
228234

229235
template <class _Tp, class _Dp, class _Alloc>
@@ -232,8 +238,8 @@ void __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT {
232238
typedef allocator_traits<_Al> _ATraits;
233239
typedef pointer_traits<typename _ATraits::pointer> _PTraits;
234240

235-
_Al __a(__data_.second());
236-
__data_.second().~_Alloc();
241+
_Al __a(__alloc_);
242+
__alloc_.~_Alloc();
237243
__a.deallocate(_PTraits::pointer_to(*this), 1);
238244
}
239245

@@ -299,28 +305,19 @@ struct __shared_ptr_emplace : __shared_weak_count {
299305
// with Allocator construction for _Tp. To allow implementing P0674 in C++20,
300306
// we now use a properly aligned char buffer while making sure that we maintain
301307
// the same layout that we had when we used a compressed pair.
302-
using _CompressedPair = __compressed_pair<_Alloc, _Tp>;
303-
struct _ALIGNAS_TYPE(_CompressedPair) _Storage {
304-
char __blob_[sizeof(_CompressedPair)];
308+
struct [[using __gnu__: __aligned__(_LIBCPP_ALIGNOF(_Alloc)), __aligned__(_LIBCPP_ALIGNOF(_Tp))]] _Storage {
309+
union {
310+
struct {
311+
_LIBCPP_COMPRESSED_PAIR(_Alloc, __alloc_, _Tp, __elem_);
312+
};
313+
};
305314

306315
_LIBCPP_HIDE_FROM_ABI explicit _Storage(_Alloc&& __a) { ::new ((void*)__get_alloc()) _Alloc(std::move(__a)); }
307316
_LIBCPP_HIDE_FROM_ABI ~_Storage() { __get_alloc()->~_Alloc(); }
308-
_LIBCPP_HIDE_FROM_ABI _Alloc* __get_alloc() _NOEXCEPT {
309-
_CompressedPair* __as_pair = reinterpret_cast<_CompressedPair*>(__blob_);
310-
typename _CompressedPair::_Base1* __first = _CompressedPair::__get_first_base(__as_pair);
311-
_Alloc* __alloc = reinterpret_cast<_Alloc*>(__first);
312-
return __alloc;
313-
}
314-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI _Tp* __get_elem() _NOEXCEPT {
315-
_CompressedPair* __as_pair = reinterpret_cast<_CompressedPair*>(__blob_);
316-
typename _CompressedPair::_Base2* __second = _CompressedPair::__get_second_base(__as_pair);
317-
_Tp* __elem = reinterpret_cast<_Tp*>(__second);
318-
return __elem;
319-
}
317+
_LIBCPP_HIDE_FROM_ABI _Alloc* __get_alloc() _NOEXCEPT { return std::addressof(__alloc_); }
318+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI _Tp* __get_elem() _NOEXCEPT { return std::addressof(__elem_); }
320319
};
321320

322-
static_assert(_LIBCPP_ALIGNOF(_Storage) == _LIBCPP_ALIGNOF(_CompressedPair), "");
323-
static_assert(sizeof(_Storage) == sizeof(_CompressedPair), "");
324321
_Storage __storage_;
325322
};
326323

0 commit comments

Comments
 (0)