Skip to content

Commit

Permalink
[libc++] Replace __compressed_pair with [[no_unique_address]]
Browse files Browse the repository at this point in the history
  • Loading branch information
philnik777 committed Jan 31, 2024
1 parent 583129d commit 2f30123
Show file tree
Hide file tree
Showing 19 changed files with 580 additions and 606 deletions.
8 changes: 6 additions & 2 deletions libcxx/docs/ReleaseNotes/19.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ What's New in Libc++ 19.0.0?

Implemented Papers
------------------

- P2637R3 - Member ``visit``


Improvements and New Features
-----------------------------
TODO

- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``, resulting in reduced
compile times and smaller debug information as well as better code gen if optimizations are disabled.

Deprecations and Removals
-------------------------
Expand Down Expand Up @@ -91,8 +93,10 @@ TODO

ABI Affecting Changes
---------------------
TODO

- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``. This change results in
empty final types being placed at the beginning of the object instead of where the beginning of the
``__compressed_pair`` subobject was. This is only observable by checking the address of the subobject.

Build System Changes
--------------------
Expand Down
8 changes: 8 additions & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@

# define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y
# define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y)
# define _LIBCPP_CONCAT3(X, Y, Z) _LIBCPP_CONCAT(X, _LIBCPP_CONCAT(Y, Z))

# if __STDC_HOSTED__ == 0
# define _LIBCPP_FREESTANDING
Expand Down Expand Up @@ -174,6 +175,13 @@
// The implementation moved to the header, but we still export the symbols from
// the dylib for backwards compatibility.
# define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
// Historically, libc++ used a type called `__compressed_pair` to reduce storage need in cases of empty types (e.g. an
// empty allocator in std::vector). We switched to using `[[no_unique_address]]`. However, for ABI compatibility reasons
// we had to add artificial padding in a few places.
//
// This setting disables the addition of such artificial padding, leading to a more optimal
// representation for several types.
# define _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
# elif _LIBCPP_ABI_VERSION == 1
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
// Enable compiling copies of now inline methods into the dylib to support
Expand Down
27 changes: 14 additions & 13 deletions libcxx/include/__functional/function.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,45 +141,46 @@ class __default_alloc_func;

template <class _Fp, class _Ap, class _Rp, class... _ArgTypes>
class __alloc_func<_Fp, _Ap, _Rp(_ArgTypes...)> {
__compressed_pair<_Fp, _Ap> __f_;
_LIBCPP_COMPRESSED_PAIR(_Fp, __func_, _Ap, __alloc_);

public:
typedef _LIBCPP_NODEBUG _Fp _Target;
typedef _LIBCPP_NODEBUG _Ap _Alloc;

_LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __f_.first(); }
_LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __func_; }

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

_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f)
: __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple()) {}
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f) : __func_(std::move(__f)), __alloc_() {}

_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a)
: __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(__a)) {}
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a) : __func_(__f), __alloc_(__a) {}

_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, _Alloc&& __a)
: __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(std::move(__a))) {}
: __func_(__f), __alloc_(std::move(__a)) {}

_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f, _Alloc&& __a)
: __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple(std::move(__a))) {}
: __func_(std::move(__f)), __alloc_(std::move(__a)) {}

_LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) {
typedef __invoke_void_return_wrapper<_Rp> _Invoker;
return _Invoker::__call(__f_.first(), std::forward<_ArgTypes>(__arg)...);
return _Invoker::__call(__func_, std::forward<_ArgTypes>(__arg)...);
}

_LIBCPP_HIDE_FROM_ABI __alloc_func* __clone() const {
typedef allocator_traits<_Alloc> __alloc_traits;
typedef __rebind_alloc<__alloc_traits, __alloc_func> _AA;
_AA __a(__f_.second());
_AA __a(__alloc_);
typedef __allocator_destructor<_AA> _Dp;
unique_ptr<__alloc_func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
::new ((void*)__hold.get()) __alloc_func(__f_.first(), _Alloc(__a));
::new ((void*)__hold.get()) __alloc_func(__func_, _Alloc(__a));
return __hold.release();
}

_LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~__compressed_pair<_Target, _Alloc>(); }
_LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT {
__func_.~_Fp();
__alloc_.~_Alloc();
}

_LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__alloc_func* __f) {
typedef allocator_traits<_Alloc> __alloc_traits;
Expand Down
Loading

0 comments on commit 2f30123

Please sign in to comment.