Skip to content

Commit 82b98cc

Browse files
committed
[libc++] Simplify the implementation of __tuple_leaf
1 parent 4c4db3c commit 82b98cc

File tree

5 files changed

+134
-146
lines changed

5 files changed

+134
-146
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,7 @@ set(files
861861
__utility/as_lvalue.h
862862
__utility/auto_cast.h
863863
__utility/cmp.h
864+
__utility/conditional_no_unique_address.h
864865
__utility/convert_to_integral.h
865866
__utility/declval.h
866867
__utility/empty.h

libcxx/include/__expected/expected.h

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <__type_traits/remove_cv.h>
4141
#include <__type_traits/remove_cvref.h>
4242
#include <__utility/as_const.h>
43+
#include <__utility/conditional_no_unique_address.h>
4344
#include <__utility/exception_guard.h>
4445
#include <__utility/forward.h>
4546
#include <__utility/in_place.h>
@@ -81,55 +82,6 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
8182
# endif
8283
}
8384

84-
// If parameter type `_Tp` of `__conditional_no_unique_address` is neither
85-
// copyable nor movable, a constructor with this tag is provided. For that
86-
// constructor, the user has to provide a function and arguments. The function
87-
// must return an object of type `_Tp`. When the function is invoked by the
88-
// constructor, guaranteed copy elision kicks in and the `_Tp` is constructed
89-
// in place.
90-
struct __conditional_no_unique_address_invoke_tag {};
91-
92-
// This class implements an object with `[[no_unique_address]]` conditionally applied to it,
93-
// based on the value of `_NoUnique`.
94-
//
95-
// A member of this class must always have `[[no_unique_address]]` applied to
96-
// it. Otherwise, the `[[no_unique_address]]` in the "`_NoUnique == true`" case
97-
// would not have any effect. In the `false` case, the `__v` is not
98-
// `[[no_unique_address]]`, so nullifies the effects of the "outer"
99-
// `[[no_unique_address]]` regarding data layout.
100-
//
101-
// If we had a language feature, this class would basically be replaced by `[[no_unique_address(condition)]]`.
102-
template <bool _NoUnique, class _Tp>
103-
struct __conditional_no_unique_address;
104-
105-
template <class _Tp>
106-
struct __conditional_no_unique_address<true, _Tp> {
107-
template <class... _Args>
108-
_LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
109-
: __v(std::forward<_Args>(__args)...) {}
110-
111-
template <class _Func, class... _Args>
112-
_LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(
113-
__conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
114-
: __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
115-
116-
_LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
117-
};
118-
119-
template <class _Tp>
120-
struct __conditional_no_unique_address<false, _Tp> {
121-
template <class... _Args>
122-
_LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
123-
: __v(std::forward<_Args>(__args)...) {}
124-
125-
template <class _Func, class... _Args>
126-
_LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(
127-
__conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
128-
: __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
129-
130-
_Tp __v;
131-
};
132-
13385
// This function returns whether the type `_Second` can be stuffed into the tail padding
13486
// of the `_First` type if both of them are given `[[no_unique_address]]`.
13587
template <class _First, class _Second>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___UTILITY_CONDITIONAL_NO_UNIQUE_ADDRESS_H
10+
#define _LIBCPP___UTILITY_CONDITIONAL_NO_UNIQUE_ADDRESS_H
11+
12+
#include <__config>
13+
#include <__type_traits/invoke.h>
14+
#include <__type_traits/is_swappable.h>
15+
#include <__utility/forward.h>
16+
#include <__utility/in_place.h>
17+
18+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
19+
# pragma GCC system_header
20+
#endif
21+
22+
_LIBCPP_PUSH_MACROS
23+
#include <__undef_macros>
24+
25+
_LIBCPP_BEGIN_NAMESPACE_STD
26+
27+
// If parameter type `_Tp` of `__conditional_no_unique_address` is neither
28+
// copyable nor movable, a constructor with this tag is provided. For that
29+
// constructor, the user has to provide a function and arguments. The function
30+
// must return an object of type `_Tp`. When the function is invoked by the
31+
// constructor, guaranteed copy elision kicks in and the `_Tp` is constructed
32+
// in place.
33+
struct __conditional_no_unique_address_invoke_tag {};
34+
35+
// This class implements an object with `[[no_unique_address]]` conditionally applied to it,
36+
// based on the value of `_NoUnique`.
37+
//
38+
// A member of this class must always have `[[no_unique_address]]` applied to
39+
// it. Otherwise, the `[[no_unique_address]]` in the "`_NoUnique == true`" case
40+
// would not have any effect. In the `false` case, the `__v` is not
41+
// `[[no_unique_address]]`, so nullifies the effects of the "outer"
42+
// `[[no_unique_address]]` regarding data layout.
43+
//
44+
// If we had a language feature, this class would basically be replaced by `[[no_unique_address(condition)]]`.
45+
template <bool _NoUnique, class _Tp>
46+
struct __conditional_no_unique_address;
47+
48+
template <class _Tp>
49+
struct __conditional_no_unique_address<true, _Tp> {
50+
template <class... _Args>
51+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
52+
: __v(std::forward<_Args>(__args)...) {}
53+
54+
template <class _Func, class... _Args>
55+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __conditional_no_unique_address(
56+
__conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
57+
: __v(std::__invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
58+
59+
_LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
60+
};
61+
62+
template <class _Tp>
63+
struct __conditional_no_unique_address<false, _Tp> {
64+
template <class... _Args>
65+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
66+
: __v(std::forward<_Args>(__args)...) {}
67+
68+
template <class _Func, class... _Args>
69+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __conditional_no_unique_address(
70+
__conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
71+
: __v(std::__invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
72+
73+
_Tp __v;
74+
};
75+
76+
template <bool _NoUnique, class _Tp>
77+
void swap(__conditional_no_unique_address<_NoUnique, _Tp>& __lhs,
78+
__conditional_no_unique_address<_NoUnique, _Tp>& __rhs) _NOEXCEPT_(__is_swappable_v<_Tp>) {
79+
using std::swap;
80+
swap(__lhs.__v, __rhs.__v);
81+
}
82+
83+
_LIBCPP_END_NAMESPACE_STD
84+
85+
_LIBCPP_POP_MACROS
86+
87+
#endif // _LIBCPP___UTILITY_CONDITIONAL_NO_UNIQUE_ADDRESS_H

libcxx/include/module.modulemap

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,35 +1978,36 @@ module std [system] {
19781978
}
19791979

19801980
module utility {
1981-
module as_const { header "__utility/as_const.h" }
1982-
module as_lvalue { header "__utility/as_lvalue.h" }
1983-
module auto_cast {
1981+
module as_const { header "__utility/as_const.h" }
1982+
module as_lvalue { header "__utility/as_lvalue.h" }
1983+
module auto_cast {
19841984
header "__utility/auto_cast.h"
19851985
export std_core.type_traits.decay // the macro expansion uses that trait
19861986
}
1987-
module cmp { header "__utility/cmp.h" }
1988-
module convert_to_integral { header "__utility/convert_to_integral.h" }
1989-
module exception_guard { header "__utility/exception_guard.h" }
1990-
module exchange { header "__utility/exchange.h" }
1991-
module forward_like { header "__utility/forward_like.h" }
1987+
module cmp { header "__utility/cmp.h" }
1988+
module conditional_no_unique_address { header "__utility/conditional_no_unique_address.h" }
1989+
module convert_to_integral { header "__utility/convert_to_integral.h" }
1990+
module exception_guard { header "__utility/exception_guard.h" }
1991+
module exchange { header "__utility/exchange.h" }
1992+
module forward_like { header "__utility/forward_like.h" }
19921993
module in_place {
19931994
header "__utility/in_place.h"
19941995
export std_core.type_traits.integral_constant
19951996
}
1996-
module integer_sequence { header "__utility/integer_sequence.h" }
1997-
module is_pointer_in_range { header "__utility/is_pointer_in_range.h" }
1998-
module is_valid_range { header "__utility/is_valid_range.h" }
1999-
module move { header "__utility/move.h" }
2000-
module no_destroy { header "__utility/no_destroy.h" }
2001-
module pair { header "__utility/pair.h" }
2002-
module piecewise_construct { header "__utility/piecewise_construct.h" }
2003-
module priority_tag { header "__utility/priority_tag.h" }
2004-
module private_constructor_tag { header "__utility/private_constructor_tag.h" }
2005-
module rel_ops { header "__utility/rel_ops.h" }
2006-
module small_buffer { header "__utility/small_buffer.h" }
2007-
module swap { header "__utility/swap.h" }
2008-
module to_underlying { header "__utility/to_underlying.h" }
2009-
module unreachable { header "__utility/unreachable.h" }
1997+
module integer_sequence { header "__utility/integer_sequence.h" }
1998+
module is_pointer_in_range { header "__utility/is_pointer_in_range.h" }
1999+
module is_valid_range { header "__utility/is_valid_range.h" }
2000+
module move { header "__utility/move.h" }
2001+
module no_destroy { header "__utility/no_destroy.h" }
2002+
module pair { header "__utility/pair.h" }
2003+
module piecewise_construct { header "__utility/piecewise_construct.h" }
2004+
module priority_tag { header "__utility/priority_tag.h" }
2005+
module private_constructor_tag { header "__utility/private_constructor_tag.h" }
2006+
module rel_ops { header "__utility/rel_ops.h" }
2007+
module small_buffer { header "__utility/small_buffer.h" }
2008+
module swap { header "__utility/swap.h" }
2009+
module to_underlying { header "__utility/to_underlying.h" }
2010+
module unreachable { header "__utility/unreachable.h" }
20102011

20112012
header "utility"
20122013
export *

libcxx/include/tuple

Lines changed: 22 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,10 @@ template <class... Types>
257257
#include <__type_traits/remove_cvref.h>
258258
#include <__type_traits/remove_reference.h>
259259
#include <__type_traits/unwrap_ref.h>
260+
#include <__utility/conditional_no_unique_address.h>
260261
#include <__utility/declval.h>
261262
#include <__utility/forward.h>
263+
#include <__utility/in_place.h>
262264
#include <__utility/integer_sequence.h>
263265
#include <__utility/move.h>
264266
#include <__utility/piecewise_construct.h>
@@ -283,25 +285,26 @@ _LIBCPP_BEGIN_NAMESPACE_STD
283285

284286
// __tuple_leaf
285287

286-
template <size_t _Ip, class _Hp, bool = is_empty<_Hp>::value && !__libcpp_is_final<_Hp>::value >
288+
template <size_t _Ip, class _Hp>
287289
class __tuple_leaf;
288290

289-
template <size_t _Ip, class _Hp, bool _Ep>
291+
template <size_t _Ip, class _Hp>
290292
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
291-
swap(__tuple_leaf<_Ip, _Hp, _Ep>& __x, __tuple_leaf<_Ip, _Hp, _Ep>& __y) noexcept(__is_nothrow_swappable_v<_Hp>) {
293+
swap(__tuple_leaf<_Ip, _Hp>& __x, __tuple_leaf<_Ip, _Hp>& __y) noexcept(__is_nothrow_swappable_v<_Hp>) {
292294
swap(__x.get(), __y.get());
293295
}
294296

295-
template <size_t _Ip, class _Hp, bool _Ep>
297+
template <size_t _Ip, class _Hp>
296298
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
297-
swap(const __tuple_leaf<_Ip, _Hp, _Ep>& __x,
298-
const __tuple_leaf<_Ip, _Hp, _Ep>& __y) noexcept(__is_nothrow_swappable_v<const _Hp>) {
299+
swap(const __tuple_leaf<_Ip, _Hp>& __x,
300+
const __tuple_leaf<_Ip, _Hp>& __y) noexcept(__is_nothrow_swappable_v<const _Hp>) {
299301
swap(__x.get(), __y.get());
300302
}
301303

302-
template <size_t _Ip, class _Hp, bool>
304+
template <size_t _Ip, class _Hp>
303305
class __tuple_leaf {
304-
_Hp __value_;
306+
_LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<is_empty<_Hp>::value && !__libcpp_is_final<_Hp>::value, _Hp>
307+
__value_;
305308

306309
template <class _Tp>
307310
static _LIBCPP_HIDE_FROM_ABI constexpr bool __can_bind_reference() {
@@ -315,23 +318,24 @@ class __tuple_leaf {
315318
public:
316319
_LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_leaf& operator=(const __tuple_leaf&) = delete;
317320

318-
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value) : __value_() {
321+
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value)
322+
: __value_(in_place) {
319323
static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple");
320324
}
321325

322326
template <class _Alloc>
323-
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 0>, const _Alloc&) : __value_() {
327+
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 0>, const _Alloc&) : __value_(in_place) {
324328
static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple");
325329
}
326330

327331
template <class _Alloc>
328332
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a)
329-
: __value_(allocator_arg_t(), __a) {
333+
: __value_(in_place, allocator_arg_t(), __a) {
330334
static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple");
331335
}
332336

333337
template <class _Alloc>
334-
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a) : __value_(__a) {
338+
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a) : __value_(in_place, __a) {
335339
static_assert(!is_reference<_Hp>::value, "Attempted to default construct a reference element in a tuple");
336340
}
337341

@@ -340,30 +344,30 @@ public:
340344
__enable_if_t<_And<_IsNotSame<__remove_cvref_t<_Tp>, __tuple_leaf>, is_constructible<_Hp, _Tp> >::value, int> = 0>
341345
_LIBCPP_HIDE_FROM_ABI
342346
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(_Tp&& __t) noexcept(is_nothrow_constructible<_Hp, _Tp>::value)
343-
: __value_(std::forward<_Tp>(__t)) {
347+
: __value_(in_place, std::forward<_Tp>(__t)) {
344348
static_assert(__can_bind_reference<_Tp&&>(),
345349
"Attempted construction of reference element binds to a temporary whose lifetime has ended");
346350
}
347351

348352
template <class _Tp, class _Alloc>
349353
_LIBCPP_HIDE_FROM_ABI
350354
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(integral_constant<int, 0>, const _Alloc&, _Tp&& __t)
351-
: __value_(std::forward<_Tp>(__t)) {
355+
: __value_(in_place, std::forward<_Tp>(__t)) {
352356
static_assert(__can_bind_reference<_Tp&&>(),
353357
"Attempted construction of reference element binds to a temporary whose lifetime has ended");
354358
}
355359

356360
template <class _Tp, class _Alloc>
357361
_LIBCPP_HIDE_FROM_ABI
358362
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a, _Tp&& __t)
359-
: __value_(allocator_arg_t(), __a, std::forward<_Tp>(__t)) {
363+
: __value_(in_place, allocator_arg_t(), __a, std::forward<_Tp>(__t)) {
360364
static_assert(!is_reference<_Hp>::value, "Attempted to uses-allocator construct a reference element in a tuple");
361365
}
362366

363367
template <class _Tp, class _Alloc>
364368
_LIBCPP_HIDE_FROM_ABI
365369
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t)
366-
: __value_(std::forward<_Tp>(__t), __a) {
370+
: __value_(in_place, std::forward<_Tp>(__t), __a) {
367371
static_assert(!is_reference<_Hp>::value, "Attempted to uses-allocator construct a reference element in a tuple");
368372
}
369373

@@ -382,65 +386,8 @@ public:
382386
return 0;
383387
}
384388

385-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Hp& get() _NOEXCEPT { return __value_; }
386-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT { return __value_; }
387-
};
388-
389-
template <size_t _Ip, class _Hp>
390-
class __tuple_leaf<_Ip, _Hp, true> : private _Hp {
391-
public:
392-
_LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_leaf& operator=(const __tuple_leaf&) = delete;
393-
394-
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf() noexcept(is_nothrow_default_constructible<_Hp>::value) {}
395-
396-
template <class _Alloc>
397-
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 0>, const _Alloc&) {}
398-
399-
template <class _Alloc>
400-
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a)
401-
: _Hp(allocator_arg_t(), __a) {}
402-
403-
template <class _Alloc>
404-
_LIBCPP_HIDE_FROM_ABI constexpr __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a) : _Hp(__a) {}
405-
406-
template <class _Tp,
407-
__enable_if_t< _And< _IsNotSame<__remove_cvref_t<_Tp>, __tuple_leaf>, is_constructible<_Hp, _Tp> >::value,
408-
int> = 0>
409-
_LIBCPP_HIDE_FROM_ABI
410-
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_leaf(_Tp&& __t) noexcept(is_nothrow_constructible<_Hp, _Tp>::value)
411-
: _Hp(std::forward<_Tp>(__t)) {}
412-
413-
template <class _Tp, class _Alloc>
414-
_LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant<int, 0>, const _Alloc&, _Tp&& __t)
415-
: _Hp(std::forward<_Tp>(__t)) {}
416-
417-
template <class _Tp, class _Alloc>
418-
_LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a, _Tp&& __t)
419-
: _Hp(allocator_arg_t(), __a, std::forward<_Tp>(__t)) {}
420-
421-
template <class _Tp, class _Alloc>
422-
_LIBCPP_HIDE_FROM_ABI constexpr explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t)
423-
: _Hp(std::forward<_Tp>(__t), __a) {}
424-
425-
__tuple_leaf(__tuple_leaf const&) = default;
426-
__tuple_leaf(__tuple_leaf&&) = default;
427-
428-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int
429-
swap(__tuple_leaf& __t) noexcept(__is_nothrow_swappable_v<__tuple_leaf>) {
430-
std::swap(*this, __t);
431-
return 0;
432-
}
433-
434-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int swap(const __tuple_leaf& __rhs) const
435-
noexcept(__is_nothrow_swappable_v<const __tuple_leaf>) {
436-
std::swap(*this, __rhs);
437-
return 0;
438-
}
439-
440-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Hp& get() _NOEXCEPT { return static_cast<_Hp&>(*this); }
441-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT {
442-
return static_cast<const _Hp&>(*this);
443-
}
389+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Hp& get() _NOEXCEPT { return __value_.__v; }
390+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Hp& get() const _NOEXCEPT { return __value_.__v; }
444391
};
445392

446393
template <class... _Tp>

0 commit comments

Comments
 (0)