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___OPTIONAL_OPTIONAL_REF_H
10#define _LIBCPP___OPTIONAL_OPTIONAL_REF_H
11
12#include <__assert>
13#include <__concepts/invocable.h>
14#include <__config>
15#include <__functional/invoke.h>
16#include <__fwd/optional.h>
17#include <__iterator/bounded_iter.h>
18#include <__iterator/capacity_aware_iterator.h>
19#include <__memory/addressof.h>
20#include <__optional/common.h>
21#include <__optional/comparison.h>
22#include <__optional/hash.h>
23#include <__optional/nullopt_t.h>
24#include <__optional/swap.h>
25#include <__type_traits/add_pointer.h>
26#include <__type_traits/decay.h>
27#include <__type_traits/invoke.h>
28#include <__type_traits/is_array.h>
29#include <__type_traits/is_constructible.h>
30#include <__type_traits/is_convertible.h>
31#include <__type_traits/is_nothrow_constructible.h>
32#include <__type_traits/is_object.h>
33#include <__type_traits/is_reference.h>
34#include <__type_traits/is_same.h>
35#include <__type_traits/reference_constructs_from_temporary.h>
36#include <__type_traits/remove_cv.h>
37#include <__type_traits/remove_cvref.h>
38#include <__type_traits/remove_reference.h>
39#include <__utility/forward.h>
40#include <__utility/in_place.h>
41#include <__utility/move.h>
42#include <__utility/swap.h>
43
44#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
45# pragma GCC system_header
46#endif
47
48_LIBCPP_PUSH_MACROS
49#include <__undef_macros>
50
51#if _LIBCPP_STD_VER >= 26
52
53_LIBCPP_BEGIN_NAMESPACE_STD
54
55template <class _Tp>
56struct __optional_ref_iterator_base {};
57
58# if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
59
60template <class _Tp>
61 requires(is_object_v<_Tp> && !__is_unbounded_array_v<_Tp>)
62struct __optional_ref_iterator_base<_Tp&> {
63# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
64 using iterator = __bounded_iter<_Tp*>;
65# else
66 using iterator = __capacity_aware_iterator<_Tp*, optional<_Tp&>, 1>;
67# endif
68};
69
70# endif
71
72template <class _Tp>
73class optional<_Tp&> : public __optional_ref_iterator_base<_Tp&> {
74public:
75 using value_type = _Tp;
76 static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>, "instantiation of optional with in_place_t is ill-formed");
77 static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed");
78
79private:
80 _Tp* __value_ = nullptr;
81
82 template <class _Up>
83 _LIBCPP_HIDE_FROM_ABI constexpr void __convert_init_ref_val(_Up&& __val) {
84 _Tp& __r(std::forward<_Up>(__val));
85 __value_ = std::addressof(__r);
86 }
87
88 template <class _Up, class _QualUp>
89 static constexpr bool __check_optionalU_ctor =
90 !is_same_v<remove_cv_t<_Tp>, optional<_Up>> && !is_same_v<_Tp&, _Up> && is_constructible_v<_Tp&, _QualUp>;
91
92 template <class _Fp, class... _Args>
93 constexpr optional(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) {
94 __convert_init_ref_val(std::forward<invoke_result_t<_Fp, _Args...>>(
95 std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)));
96 }
97
98 template <class _UArg>
99 _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_UArg&& __val) {
100 static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>,
101 "Attempted to construct a reference element in tuple from a "
102 "possible temporary");
103 __convert_init_ref_val(std::forward<_UArg>(__val));
104 }
105
106 template <class _That>
107 _LIBCPP_HIDE_FROM_ABI constexpr void __construct_from(_That&& __opt) {
108 if (__opt.has_value())
109 __construct(std::forward<_That>(__opt).__get());
110 }
111
112 static constexpr bool __has_iterator_ = requires { typename __optional_ref_iterator_base<_Tp&>::iterator; };
113
114public:
115 constexpr optional() noexcept = default;
116 constexpr optional(nullopt_t) noexcept {}
117 constexpr optional(const optional&) noexcept = default;
118
119 template <class _Arg>
120 requires(is_constructible_v<_Tp&, _Arg> && !reference_constructs_from_temporary_v<_Tp&, _Arg>)
121 constexpr explicit optional(in_place_t, _Arg&& __arg) {
122 static_assert(!__reference_constructs_from_temporary_v<_Tp, _Arg>,
123 "Attempted to construct a reference element in optional from a "
124 "possible temporary");
125 __convert_init_ref_val(std::forward<_Arg>(__arg));
126 }
127
128 template <class _Up>
129 requires(!is_same_v<remove_cvref_t<_Up>, optional> && !is_same_v<remove_cvref_t<_Up>, in_place_t> &&
130 is_constructible_v<_Tp&, _Up> && !reference_constructs_from_temporary_v<_Tp&, _Up>)
131 constexpr explicit(!is_convertible_v<_Up, _Tp&>) optional(_Up&& __v) noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
132 : optional(in_place, std::forward<_Up>(__v)) {}
133
134 template <class _Up>
135 requires(__check_optionalU_ctor<_Up, _Up&> && !reference_constructs_from_temporary_v<_Tp&, _Up&>)
136 constexpr explicit(!is_convertible_v<_Up&, _Tp&>)
137 optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) {
138 this->__construct_from(__rhs);
139 }
140
141 template <class _Up>
142 requires(__check_optionalU_ctor<_Up, const _Up&> && !reference_constructs_from_temporary_v<_Tp&, const _Up&>)
143 constexpr explicit(!is_convertible_v<const _Up&, _Tp&>)
144 optional(const optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up&>) {
145 this->__construct_from(__rhs);
146 }
147
148 template <class _Up>
149 requires(__check_optionalU_ctor<_Up, _Up> && !reference_constructs_from_temporary_v<_Tp&, _Up>)
150 constexpr explicit(!is_convertible_v<_Up, _Tp&>)
151 optional(optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) {
152 this->__construct_from(std::move(__rhs));
153 }
154
155 template <class _Up>
156 requires(__check_optionalU_ctor<_Up, const _Up> && !reference_constructs_from_temporary_v<_Tp&, const _Up>)
157 constexpr explicit(!is_convertible_v<const _Up, _Tp&>)
158 optional(const optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) {
159 this->__construct_from(std::move(__rhs));
160 }
161
162 // deleted overloads
163
164 template <class _Up>
165 requires(!is_same_v<remove_cvref_t<_Up>, optional> && !is_same_v<remove_cvref_t<_Up>, in_place_t> &&
166 is_constructible_v<_Tp&, _Up> && reference_constructs_from_temporary_v<_Tp&, _Up>)
167 constexpr explicit(!is_convertible_v<_Up, _Tp&>)
168 optional(_Up&& __v) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) = delete;
169
170 template <class _Up>
171 requires(__check_optionalU_ctor<_Up, _Up&> && reference_constructs_from_temporary_v<_Tp&, _Up&>)
172 constexpr explicit(!is_convertible_v<_Up&, _Tp&>)
173 optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) = delete;
174
175 template <class _Up>
176 requires(__check_optionalU_ctor<_Up, const _Up&> && reference_constructs_from_temporary_v<_Tp&, const _Up&>)
177 constexpr explicit(!is_convertible_v<const _Up&, _Tp&>)
178 optional(const optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up&>) = delete;
179
180 template <class _Up>
181 requires(__check_optionalU_ctor<_Up, _Up> && reference_constructs_from_temporary_v<_Tp&, _Up>)
182 constexpr explicit(!is_convertible_v<_Up, _Tp&>)
183 optional(optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) = delete;
184
185 template <class _Up>
186 requires(__check_optionalU_ctor<_Up, const _Up> && reference_constructs_from_temporary_v<_Tp&, const _Up>)
187 constexpr explicit(!is_convertible_v<const _Up, _Tp&>)
188 optional(const optional<_Up>&& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) = delete;
189
190 constexpr ~optional() = default;
191
192 _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const noexcept { return *__value_; }
193
194 _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(nullopt_t) noexcept {
195 reset();
196 return *this;
197 }
198
199 constexpr optional& operator=(const optional&) noexcept = default;
200
201 template <class _Up>
202 requires(is_constructible_v<_Tp&, _Up> && !reference_constructs_from_temporary_v<_Tp&, _Up>)
203 constexpr _Tp& emplace(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp&, _Up>) {
204 this->__construct(std::forward<_Up>(__u));
205
206 return this->__get();
207 }
208
209 constexpr void swap(optional& __rhs) noexcept { std::swap(this->__value_, __rhs.__value_); }
210
211 // [optional.ref.observe]
212 _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept {
213 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
214 return __value_;
215 }
216
217 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() const noexcept {
218 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
219 return this->__get();
220 }
221
222 constexpr explicit operator bool() const noexcept { return has_value(); }
223
224 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; }
225
226 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() const {
227 if (!this->has_value())
228 std::__throw_bad_optional_access();
229 return this->__get();
230 }
231
232 template <class _Up = remove_cv_t<_Tp>>
233 requires(!is_array_v<_Tp> && is_object_v<_Tp>)
234 [[nodiscard]] constexpr decay_t<_Tp> value_or(_Up&& __v) const {
235 using _XTp = remove_cv_t<_Tp>;
236 static_assert(is_constructible_v<_XTp, _Tp&>, "optional<T&>::value_or: remove_cv_t<T> must be constructible");
237 static_assert(is_convertible_v<_Up, _XTp>, "optional<T&>::value_or: U must be convertible to remove_cv_t<T>");
238 return this->has_value() ? this->__get() : static_cast<_XTp>(std::forward<_Up>(__v));
239 }
240
241 template <class _Func>
242 [[nodiscard]] constexpr auto and_then(_Func&& __f) const {
243 using _Up = invoke_result_t<_Func, _Tp&>;
244 static_assert(
245 __is_std_optional_v<remove_cvref_t<_Up>>, "Result of f(value()) must be a specialization of std::optional");
246 if (*this)
247 return std::invoke(std::forward<_Func>(__f), value());
248 return remove_cvref_t<_Up>();
249 }
250
251 template <class _Func>
252 [[nodiscard]] constexpr optional<remove_cv_t<invoke_result_t<_Func, _Tp&>>> transform(_Func&& __f) const {
253 using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&>>;
254 static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
255 static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t");
256 static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t");
257 static_assert(
258 __is_valid_optional_contained_type<_Up>, "Result of f(value()) should be a valid contained type for optional");
259
260 if (*this)
261 return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value());
262 return optional<_Up>();
263 }
264
265 template <invocable _Func>
266 [[nodiscard]] constexpr optional or_else(_Func&& __f) const {
267 static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
268 "Result of f() should be the same type as this optional");
269 if (*this)
270 return *this;
271 return std::forward<_Func>(__f)();
272 }
273
274 _LIBCPP_HIDE_FROM_ABI constexpr void reset() noexcept { __value_ = nullptr; }
275
276 // [optional.ref.iterators], iterator support
277# if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
278
279 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const noexcept
280 requires __has_iterator_
281 {
282# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
283 return std::__make_bounded_iter(__value_, __value_, __value_ + (this->has_value() ? 1 : 0));
284# else
285 return std::__make_capacity_aware_iterator<_Tp*, optional<_Tp&>, 1>(__value_);
286# endif
287 }
288
289 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const noexcept
290 requires __has_iterator_
291 {
292 return begin() + (this->has_value() ? 1 : 0);
293 }
294# endif
295};
296
297_LIBCPP_END_NAMESPACE_STD
298
299#endif // _LIBCPP_STD_VER >= 26
300
301_LIBCPP_POP_MACROS
302
303#endif // _LIBCPP___OPTIONAL_OPTIONAL_REF_H
304