Skip to content

Commit 1af6f69

Browse files
committed
[libc++] Add tombstone traits to use in optional, variant
1 parent 74b933c commit 1af6f69

File tree

17 files changed

+388
-4
lines changed

17 files changed

+388
-4
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ set(files
541541
__memory/swap_allocator.h
542542
__memory/temp_value.h
543543
__memory/temporary_buffer.h
544+
__memory/tombstone_traits.h
544545
__memory/uninitialized_algorithms.h
545546
__memory/unique_ptr.h
546547
__memory/uses_allocator.h

libcxx/include/__expected/expected.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <__functional/invoke.h>
1818
#include <__memory/addressof.h>
1919
#include <__memory/construct_at.h>
20+
#include <__memory/tombstone_traits.h>
2021
#include <__type_traits/conjunction.h>
2122
#include <__type_traits/disjunction.h>
2223
#include <__type_traits/integral_constant.h>

libcxx/include/__functional/reference_wrapper.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@
1010
#ifndef _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
1111
#define _LIBCPP___FUNCTIONAL_REFERENCE_WRAPPER_H
1212

13+
#include <__bit/bit_cast.h>
1314
#include <__compare/synth_three_way.h>
1415
#include <__concepts/boolean_testable.h>
1516
#include <__config>
1617
#include <__functional/invoke.h>
1718
#include <__functional/weak_result_type.h>
1819
#include <__memory/addressof.h>
20+
#include <__memory/tombstone_traits.h>
21+
#include <__type_traits/datasizeof.h>
1922
#include <__type_traits/enable_if.h>
2023
#include <__type_traits/is_const.h>
2124
#include <__type_traits/remove_cvref.h>
@@ -122,6 +125,12 @@ template <class _Tp>
122125
reference_wrapper(_Tp&) -> reference_wrapper<_Tp>;
123126
#endif
124127

128+
template <class _Tp>
129+
struct __tombstone_memory_layout<reference_wrapper<_Tp>> {
130+
static constexpr uintptr_t __disengaged_value_ = 0;
131+
static constexpr size_t __is_disengaged_offset_ = 0;
132+
};
133+
125134
template <class _Tp>
126135
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<_Tp> ref(_Tp& __t) _NOEXCEPT {
127136
return reference_wrapper<_Tp>(__t);

libcxx/include/__locale

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <__config>
1414
#include <__locale_dir/locale_base_api.h>
1515
#include <__memory/shared_ptr.h> // __shared_count
16+
#include <__memory/tombstone_traits.h>
1617
#include <__mutex/once_flag.h>
1718
#include <__type_traits/make_unsigned.h>
1819
#include <__utility/no_destroy.h>
@@ -114,6 +115,9 @@ private:
114115
friend const _Facet& use_facet(const locale&);
115116
};
116117

118+
template <>
119+
struct __tombstone_memory_layout<locale> : __tombstone_pointer_layout {};
120+
117121
class _LIBCPP_EXPORTED_FROM_ABI locale::facet : public __shared_count {
118122
protected:
119123
_LIBCPP_HIDE_FROM_ABI explicit facet(size_t __refs = 0) : __shared_count(static_cast<long>(__refs) - 1) {}

libcxx/include/__memory/shared_ptr.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,12 @@ template <class _Tp, class _Dp>
832832
shared_ptr(unique_ptr<_Tp, _Dp>) -> shared_ptr<_Tp>;
833833
#endif
834834

835+
template <class _Tp>
836+
struct __tombstone_memory_layout<shared_ptr<_Tp>> {
837+
static constexpr auto __disengaged_value_ = __tombstone_pointer_layout::__disengaged_value_;
838+
static constexpr size_t __is_disengaged_offset_ = sizeof(void*) + __tombstone_pointer_layout::__is_disengaged_offset_;
839+
};
840+
835841
//
836842
// std::allocate_shared and std::make_shared
837843
//
@@ -1382,6 +1388,12 @@ template <class _Tp>
13821388
weak_ptr(shared_ptr<_Tp>) -> weak_ptr<_Tp>;
13831389
#endif
13841390

1391+
template <class _Tp>
1392+
struct __tombstone_memory_layout<weak_ptr<_Tp>> {
1393+
static constexpr auto __disengaged_value_ = __tombstone_pointer_layout::__disengaged_value_;
1394+
static constexpr size_t __is_disengaged_offset_ = sizeof(void*) + __tombstone_pointer_layout::__is_disengaged_offset_;
1395+
};
1396+
13851397
template <class _Tp>
13861398
inline _LIBCPP_CONSTEXPR weak_ptr<_Tp>::weak_ptr() _NOEXCEPT : __ptr_(nullptr), __cntrl_(nullptr) {}
13871399

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
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___TYPE_TRAITS_DISENGAGED_TRAITS_H
10+
#define _LIBCPP___TYPE_TRAITS_DISENGAGED_TRAITS_H
11+
12+
#include <__config>
13+
#include <__memory/construct_at.h>
14+
#include <__type_traits/datasizeof.h>
15+
#include <__type_traits/enable_if.h>
16+
#include <__type_traits/is_constant_evaluated.h>
17+
#include <__type_traits/is_fundamental.h>
18+
#include <__type_traits/is_trivially_destructible.h>
19+
#include <__type_traits/void_t.h>
20+
#include <__utility/forward_like.h>
21+
#include <__utility/in_place.h>
22+
#include <__utility/piecewise_construct.h>
23+
#include <__utility/pointer_int_pair.h>
24+
25+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26+
# pragma GCC system_header
27+
#endif
28+
29+
_LIBCPP_BEGIN_NAMESPACE_STD
30+
31+
template <class>
32+
struct __tombstone_memory_layout;
33+
34+
// bools have always exactly one bit set. If there is more than one set it's disengaged.
35+
template <>
36+
struct __tombstone_memory_layout<bool> {
37+
static constexpr uint8_t __disengaged_value_ = 3;
38+
static constexpr size_t __is_disengaged_offset_ = 0;
39+
};
40+
41+
struct __tombstone_pointer_layout {
42+
static constexpr uint8_t __disengaged_value_ = 1;
43+
#ifdef _LIBCPP_LITTLE_ENDIAN
44+
static constexpr size_t __is_disengaged_offset_ = 0;
45+
#else
46+
static constexpr size_t __is_disengaged_offset_ = sizeof(void*) - 1;
47+
#endif
48+
};
49+
50+
// TODO: Look into
51+
// - filesystem::directory_iterator
52+
// - vector<T> with alignof(T) == 1
53+
54+
template <class _Tp>
55+
struct __tombstone_memory_layout<__enable_specialization_if<is_fundamental_v<_Tp> && alignof(_Tp) >= 2, _Tp*>>
56+
: __tombstone_pointer_layout {};
57+
58+
template <class _Tp>
59+
struct __tombstone_memory_layout<_Tp**> : __tombstone_pointer_layout {};
60+
61+
inline constexpr struct __init_engaged_t {
62+
} __init_engaged;
63+
inline constexpr struct __init_disengaged_t {
64+
} __init_disengaged;
65+
66+
template <class _Tp, class _Payload>
67+
struct __tombstone_data {
68+
using _TombstoneLayout = __tombstone_memory_layout<_Tp>;
69+
using _IsDisengagedT = remove_cv_t<decltype(_TombstoneLayout::__disengaged_value_)>;
70+
71+
_LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_;
72+
char __padding_[_TombstoneLayout::__is_disengaged_offset_ - __datasizeof_v<_Payload>];
73+
_IsDisengagedT __is_disengaged_;
74+
75+
template <class... _Args>
76+
_LIBCPP_HIDE_FROM_ABI constexpr __tombstone_data(_Args&&... __args)
77+
: __payload_(std::forward<_Args>(__args)...), __is_disengaged_(_TombstoneLayout::__disengaged_value_) {}
78+
};
79+
80+
template <class _Tp, class _Payload>
81+
requires(__tombstone_memory_layout<_Tp>::__is_disengaged_offset_ == 0)
82+
struct __tombstone_data<_Tp, _Payload> {
83+
using _TombstoneLayout = __tombstone_memory_layout<_Tp>;
84+
using _IsDisengagedT = remove_cv_t<decltype(_TombstoneLayout::__disengaged_value_)>;
85+
86+
_IsDisengagedT __is_disengaged_;
87+
_LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_;
88+
89+
template <class... _Args>
90+
_LIBCPP_HIDE_FROM_ABI constexpr __tombstone_data(_Args&&... __args)
91+
: __is_disengaged_(_TombstoneLayout::__disengaged_value_), __payload_(std::forward<_Args>(__args)...) {}
92+
};
93+
94+
template <class _Tp, class _Payload>
95+
struct __tombstone_traits {
96+
using _TombstoneLayout = __tombstone_memory_layout<_Tp>;
97+
using _TombstoneData = __tombstone_data<_Tp, _Payload>;
98+
99+
union {
100+
_Tp __value_;
101+
_TombstoneData __tombstone_;
102+
};
103+
104+
static_assert(sizeof(__tombstone_data<_Tp, _Payload>) <= sizeof(_Tp));
105+
static_assert(is_integral_v<decltype(_TombstoneLayout::__disengaged_value_)>);
106+
static_assert(offsetof(_TombstoneData, __is_disengaged_) == _TombstoneLayout::__is_disengaged_offset_);
107+
108+
template <class... _Args>
109+
_LIBCPP_HIDE_FROM_ABI constexpr __tombstone_traits(__init_disengaged_t, _Args&&... __args)
110+
: __tombstone_(std::forward<_Args>(__args)...) {}
111+
112+
template <class... _Args>
113+
_LIBCPP_HIDE_FROM_ABI constexpr __tombstone_traits(__init_engaged_t, _Args&&... __args)
114+
: __value_(std::forward<_Args>(__args)...) {}
115+
116+
template <class _Class>
117+
_LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value(this _Class&& __self) noexcept {
118+
return std::forward<_Class>(__self).__value_;
119+
}
120+
121+
template <class _Class>
122+
_LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload(this _Class&& __self) noexcept {
123+
return std::forward<_Class>(__self).__tombstone_.__payload_;
124+
}
125+
126+
_LIBCPP_HIDE_FROM_ABI constexpr bool __is_engaged() const noexcept {
127+
if (__libcpp_is_constant_evaluated())
128+
return !__builtin_constant_p(__tombstone_.__is_disengaged_ == _TombstoneLayout::__disengaged_value_);
129+
return __tombstone_.__is_disengaged_ != _TombstoneLayout::__disengaged_value_;
130+
}
131+
132+
template <class _Class, class... _Args>
133+
_LIBCPP_HIDE_FROM_ABI constexpr void __engage(this _Class& __self, piecewise_construct_t, _Args&&... __args) {
134+
std::destroy_at(&__self.__tombstone_);
135+
std::construct_at(&__self.__value_, std::forward<_Args>(__args)...);
136+
}
137+
138+
template <class _Class, class... _Args>
139+
_LIBCPP_HIDE_FROM_ABI constexpr void __disengage(this _Class& __self, piecewise_construct_t, _Args&&... __args) {
140+
std::destroy_at(&__self.__data_.__value_);
141+
std::construct_at(&__self.__data_.__payload_, std::forward<_Args>(__args)...);
142+
__self.__data_.__is_disengaged_ = _TombstoneLayout::__disengaged_value_;
143+
}
144+
145+
__tombstone_traits(const __tombstone_traits&) = default;
146+
__tombstone_traits(__tombstone_traits&&) = default;
147+
__tombstone_traits& operator=(const __tombstone_traits&) = default;
148+
__tombstone_traits& operator=(__tombstone_traits&&) = default;
149+
150+
_LIBCPP_HIDE_FROM_ABI constexpr ~__tombstone_traits() {
151+
if (__is_engaged()) {
152+
std::destroy_at(&__value_);
153+
} else {
154+
std::destroy_at(&__tombstone_);
155+
}
156+
}
157+
158+
~__tombstone_traits()
159+
requires is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Payload>
160+
= default;
161+
};
162+
163+
template <class _Tp, class = void>
164+
inline constexpr bool __has_tombstone_v = false;
165+
166+
template <class _Tp>
167+
inline constexpr bool __has_tombstone_v<_Tp, void_t<decltype(sizeof(__tombstone_memory_layout<_Tp>))>> = true;
168+
169+
_LIBCPP_END_NAMESPACE_STD
170+
171+
#endif // _LIBCPP___TYPE_TRAITS_DISENGAGED_TRAITS_H

libcxx/include/__memory/unique_ptr.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <__memory/allocator_traits.h> // __pointer
2020
#include <__memory/auto_ptr.h>
2121
#include <__memory/compressed_pair.h>
22+
#include <__memory/tombstone_traits.h>
2223
#include <__type_traits/add_lvalue_reference.h>
2324
#include <__type_traits/common_type.h>
2425
#include <__type_traits/conditional.h>
@@ -281,6 +282,14 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
281282
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT { __ptr_.swap(__u.__ptr_); }
282283
};
283284

285+
template <class _Tp>
286+
struct __tombstone_memory_layout<__enable_specialization_if<__has_tombstone_v<_Tp*>, unique_ptr<_Tp>>>
287+
: __tombstone_memory_layout<_Tp*> {};
288+
289+
template <class _Tp>
290+
struct __tombstone_memory_layout<__enable_specialization_if<__has_tombstone_v<_Tp*>, unique_ptr<_Tp[]>>>
291+
: __tombstone_memory_layout<_Tp*> {};
292+
284293
template <class _Tp, class _Dp>
285294
class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> {
286295
public:

libcxx/include/__type_traits/datasizeof.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
_LIBCPP_BEGIN_NAMESPACE_STD
2828

29-
#if __has_keyword(__datasizeof) || __has_extension(datasizeof)
29+
#if __has_extension(datasizeof) && 0
3030
template <class _Tp>
3131
inline const size_t __datasizeof_v = __datasizeof(_Tp);
3232
#else

libcxx/include/__type_traits/enable_if.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ template <bool _Bp, class _Tp = void>
3232
using enable_if_t = typename enable_if<_Bp, _Tp>::type;
3333
#endif
3434

35+
template <bool _Bp, class _Tp, class = enable_if_t<_Bp>>
36+
using __enable_specialization_if = _Tp;
37+
3538
_LIBCPP_END_NAMESPACE_STD
3639

3740
#endif // _LIBCPP___TYPE_TRAITS_ENABLE_IF_H

libcxx/include/__utility/pair.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <__fwd/array.h>
1717
#include <__fwd/pair.h>
1818
#include <__fwd/tuple.h>
19+
#include <__memory/tombstone_traits.h>
1920
#include <__tuple/sfinae_helpers.h>
2021
#include <__tuple/tuple_element.h>
2122
#include <__tuple/tuple_indices.h>
@@ -448,6 +449,18 @@ template <class _T1, class _T2>
448449
pair(_T1, _T2) -> pair<_T1, _T2>;
449450
#endif
450451

452+
template <class _Tp, class _Up>
453+
requires __has_tombstone_v<_Up>
454+
struct __tombstone_memory_layout<pair<_Tp, _Up>> {
455+
static constexpr auto __disengaged_value_ = __tombstone_memory_layout<_Up>::__disengaged_value_;
456+
static constexpr size_t __is_disengaged_offset_ =
457+
sizeof(_Tp) + __tombstone_memory_layout<_Up>::__is_disengaged_offset_;
458+
};
459+
460+
template <class _Tp, class _Up>
461+
requires(!__has_tombstone_v<_Up> && __has_tombstone_v<_Tp>)
462+
struct __tombstone_memory_layout<pair<_Tp, _Up>> : __tombstone_memory_layout<_Tp> {};
463+
451464
// [pairs.spec], specialized algorithms
452465

453466
template <class _T1, class _T2, class _U1, class _U2>

0 commit comments

Comments
 (0)