| 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 | |
| 55 | template <class _Tp> |
| 56 | struct __optional_ref_iterator_base {}; |
| 57 | |
| 58 | # if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR |
| 59 | |
| 60 | template <class _Tp> |
| 61 | requires(is_object_v<_Tp> && !__is_unbounded_array_v<_Tp>) |
| 62 | struct __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 | |
| 72 | template <class _Tp> |
| 73 | class optional<_Tp&> : public __optional_ref_iterator_base<_Tp&> { |
| 74 | public: |
| 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 | |
| 79 | private: |
| 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 | |
| 114 | public: |
| 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 | |