Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
optional.hpp
Go to the documentation of this file.
1// Copyright 2024, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_OPTIONAL_OPTIONAL_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_OPTIONAL_OPTIONAL_HPP_
7
8// IWYU pragma: private
9// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
10
11// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
12
13// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
14#include "arene/base/compare/compare_three_way.hpp"
15#include "arene/base/compare/operators.hpp"
16#include "arene/base/compare/strong_ordering.hpp"
17#include "arene/base/compiler_support/attributes.hpp"
18#include "arene/base/compiler_support/diagnostics.hpp"
19#include "arene/base/constraints/constraints.hpp"
20#include "arene/base/constraints/substitution_succeeds.hpp"
21#include "arene/base/contracts/contract.hpp"
22#include "arene/base/functional/invoke.hpp"
23#include "arene/base/memory/construct_at.hpp"
24#include "arene/base/optional/detail/optional_base.hpp"
25#include "arene/base/optional/detail/optional_value_interface.hpp" // IWYU pragma: keep
26#include "arene/base/optional/optional.hpp"
27#include "arene/base/scope_guard/scope_guard.hpp" // IWYU pragma: keep
28#include "arene/base/stdlib_choice/declval.hpp"
29#include "arene/base/stdlib_choice/enable_if.hpp"
30#include "arene/base/stdlib_choice/forward.hpp"
31#include "arene/base/stdlib_choice/is_assignable.hpp"
32#include "arene/base/stdlib_choice/is_constructible.hpp"
33#include "arene/base/stdlib_choice/is_convertible.hpp"
34#include "arene/base/stdlib_choice/is_copy_assignable.hpp"
35#include "arene/base/stdlib_choice/is_copy_constructible.hpp"
36#include "arene/base/stdlib_choice/is_move_assignable.hpp"
37#include "arene/base/stdlib_choice/is_move_constructible.hpp"
38#include "arene/base/stdlib_choice/is_same.hpp"
39#include "arene/base/stdlib_choice/move.hpp"
40#include "arene/base/stdlib_choice/remove_cv.hpp"
41#include "arene/base/stdlib_choice/remove_reference.hpp"
42#include "arene/base/type_manipulation/implicit_constructor_base.hpp"
43#include "arene/base/type_traits/comparison_traits.hpp"
44#include "arene/base/type_traits/decays_to.hpp"
45#include "arene/base/type_traits/has_overloaded_address_operator.hpp"
46#include "arene/base/type_traits/is_instantiation_of.hpp"
47#include "arene/base/type_traits/is_invocable.hpp"
48#include "arene/base/type_traits/is_swappable.hpp"
49#include "arene/base/type_traits/remove_cvref.hpp"
50#include "arene/base/utility/forward_like.hpp"
51#include "arene/base/utility/in_place.hpp"
52#include "arene/base/utility/swap.hpp"
53// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
54
55// parasoft-begin-suppress CERT_C-EXP37-a-3 "False positive: The rule does not mention naming all parameters"
56// parasoft-begin-suppress AUTOSAR-M2_10_1-a-2 "Similar names permitted by M2-10-1 Permit #1"
57
58namespace arene {
59namespace base {
60namespace detail {
61/// @brief Tag type used for @c arene::base::nullopt_t constructor
62struct unspecified_t {};
63} // namespace detail
64
65/// @brief Empty class type used to indicate that @c arene::base::optional does not contain a value.
66/// @note @c arene::base::nullopt_t is a non-aggregate type, has no default constructor, and no
67/// initializer-list constructor.
68class nullopt_t {
69 public:
70 /// @brief constructor for @c nullopt_t
71 /// @note This constructor exists to support both <c> op = {}; </c> and <c> op = nullopt; </c> as the syntax for
72 /// indicating that an @c arene::base::optional does not contain a value.
73 /// @note see ISO/IEC JTC1 SC22 WG21 N3672 for more nuanced discussion of the <c> op = {}; </c> syntax.
74 /// @note In arene-base version 3.47.1 and prior, this @c arene::base::nullopt_t was erroneously default
75 /// constructible.
76 /// @note The type of the parameter to this constructor is unspecified. Users should rely on @c arene::base::nullopt
77 /// for an instance of a @c arene::base::nullopt_t rather than constructing an instance of @c arene::base::nullopt_t
78 /// directly.
79 constexpr explicit nullopt_t(detail::unspecified_t) noexcept {}
80};
81
82/// @brief alias to maintain backwards compatibility with older versions of Arene Base.
83/// @see arene::base::nullopt_t
84/// @deprecated
85using null_opt_t = nullopt_t;
86
87/// @brief Tag variable for empty-optional construction
88ARENE_MAYBE_UNUSED constexpr nullopt_t nullopt{{}};
89
90/// @brief alias to maintain backwards compatibility with older versions of Arene Base.
91/// @see arene::base::nullopt
92/// @deprecated
93ARENE_MAYBE_UNUSED constexpr nullopt_t null_opt{nullopt};
94
95/// @brief Implementation of @c std::optional for pre-C++17 compilers, and which replaces defined undefined behavior
96/// with @c ARENE_PRECONDITION guards.
97/// @tparam T The type which should be held in the optional.
98///
99/// An optional is a sum-type which can be in one of two states:
100/// 1. It is _disengaged_, which means it holds no value
101/// 2. It is _engaged_, which means it holds a value of type @c T .
102///
103/// It is generally used as a return type from an API which is _fallible_, but for which failure is an expected
104/// operating condition and for which no additional context other than a simple boolean pass/fail is useful. It can also
105/// be used as a member variable in a class to allow for deferred initialization without needing dynamic allocation, or
106/// as an input parameter to a function where it is important to distinguish between "not provided" and "default value."
107template <typename T>
108// parasoft-begin-suppress AUTOSAR-A10_1_1-a-2 "False positive: Only one non-interface base class"
109// NOLINTNEXTLINE(hicpp-special-member-functions,cppcoreguidelines-special-member-functions)
110class optional
111 : optional_detail::optional_base<T>
112 , implicit_constructor_base<T>
113 , generic_ordering_from_three_way_compare_and_equals<optional<T>>
114 , public optional_detail::optional_value_interface<optional<T>> {
115 // parasoft-end-suppress AUTOSAR-A10_1_1-a-2
116 /// @brief Internal type alias for the base class
117 using base_type = optional_detail::optional_base<T>;
118
119 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'storage_type' does not hide an identifier in
120 // 'optional_base'"
121 /// @brief Internal type alias for the storage type
122 using storage_type = typename base_type::storage_type;
123 // parasoft-end-suppress AUTOSAR-A2_10_1-e
124
125 /// @brief Internal type alias for the base class
126 using compare_base = generic_ordering_from_three_way_compare_and_equals<optional<T>>;
127
128 /// @brief Internal type alias for the base class
129 using constructor_base = implicit_constructor_base<T>;
130
131 /// @brief Internal type alias for the base class
132 using interface_base = optional_detail::optional_value_interface<optional<T>>;
133
134 static_assert(!has_overloaded_address_operator_v<T>, "Stored type must not have an overloaded address operator");
135
136 public:
137 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'value_type' does not hide an identifier in
138 // 'ebo_holder'"
139 /// @brief The type stored in the optional
140 using value_type = T;
141 // parasoft-end-suppress AUTOSAR-A2_10_1-e
142
143 // parasoft-begin-suppress AUTOSAR-A12_7_1-a "Bases must be initialized explicitly to address a compiler bug"
144 /// @brief Default construct to an empty state
145 // Explicitly initializes bases rather than using @c =default to address a gcc 8 compiler bug
146 constexpr optional() noexcept
147 : base_type{},
148 constructor_base{},
149 compare_base{},
150 interface_base{} {}
151 // parasoft-end-suppress AUTOSAR-A12_7_1-a
152
153 /// @brief Default destructor
154 ~optional() = default;
155
156 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "False positive: Constrained via SFINAE"
157 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: Bases initialized via delegation"
158 /// @brief Explicitly construct to an empty state
159 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
160 constexpr optional(nullopt_t) noexcept
161 : optional{} {}
162 // parasoft-end-suppress AUTOSAR-A12_1_1-a
163 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
164
165 // parasoft-begin-suppress AUTOSAR-A12_8_6-a "Not guaranteed to be a base class"
166 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "False positive: Constrained via SFINAE"
167 /// @brief Copy constructor
168 constexpr optional(optional const&) noexcept(std::is_nothrow_copy_constructible<T>::value) = default;
169 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
170 // parasoft-end-suppress AUTOSAR-A12_8_6-a
171
172 /// @brief Move constructor
173 constexpr optional(optional&&) noexcept(
174 // NOLINTNEXTLINE(hicpp-noexcept-move)
175 std::is_nothrow_move_constructible<T>::value
176 ) = default;
177
178 /// @brief Construct from a value
179 /// @tparam U The type of the value to construct from
180 /// @param other The source to move from
181 template <
182 typename U,
183 constraints<
184 std::enable_if_t<!std::is_same<optional, remove_cvref_t<U>>::value>,
185 std::enable_if_t<!std::is_same<nullopt_t, remove_cvref_t<U>>::value>,
186 std::enable_if_t<std::is_constructible<T, U&&>::value>> = nullptr>
187 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions,bugprone-forwarding-reference-overload)
188 constexpr optional(U&& other) noexcept(std::is_nothrow_constructible<T, U&&>::value)
189 : base_type(std::forward<U>(other)),
190 constructor_base{},
191 compare_base{} {}
192
193 /// @brief Construct from another optional
194 /// @tparam U The type of the value to construct from
195 /// @param other The source to move from
196 template <
197 typename U,
198 constraints<
199 std::enable_if_t<std::is_constructible<T, U>::value>,
200 std::enable_if_t<!std::is_constructible<T, optional<U>>::value>,
201 std::enable_if_t<!std::is_constructible<T, optional<U>&>::value>,
202 std::enable_if_t<!std::is_constructible<T, optional<U> const&>::value>> = nullptr>
203 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
204 constexpr optional(optional<U>&& other) noexcept(noexcept(T(std::declval<U&&>())))
205 : base_type(std::move(other)),
206 constructor_base{},
207 compare_base{} {}
208
209 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "False positive: Constrained via SFINAE"
210 /// @brief Construct from another optional
211 /// @tparam U The type of the value to construct from
212 /// @param other The source to copy from
213 template <
214 typename U,
215 constraints<
216 std::enable_if_t<std::is_constructible<T, U>::value>,
217 std::enable_if_t<!std::is_constructible<T, optional<U>>::value>,
218 std::enable_if_t<!std::is_constructible<T, optional<U>&>::value>,
219 std::enable_if_t<!std::is_constructible<T, optional<U> const&>::value>> = nullptr>
220 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
221 constexpr optional(optional<U> const& other) noexcept(noexcept(T(std::declval<U const&>())))
222 : base_type(other),
223 constructor_base{},
224 compare_base{} {}
225 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
226
227 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "False positive: Constrained via SFINAE"
228 /// @brief Construct from a set of arguments
229 /// @tparam Args The types of the arguments to construct the value from
230 /// @param args The arguments to construct the value from
231 template <
232 typename... Args,
233 constraints<std::enable_if_t<sizeof(decltype(T(std::declval<Args>()...))) != 0>> = nullptr>
234 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
235 constexpr optional(in_place_t, Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...)))
236 : base_type(in_place, std::forward<Args>(args)...),
237 constructor_base{},
238 compare_base{} {}
239 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
240
241 // parasoft-begin-suppress AUTOSAR-A12_8_6-a "Not guaranteed to be a base class"
242
243 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "False positive: Constrained via SFINAE"
244 /// @brief Reset via assignment
245 constexpr auto operator=(nullopt_t) noexcept -> optional& {
246 this->reset();
247 return *this;
248 }
249 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
250
251 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "False positive: Constrained via SFINAE"
252 /// @brief Copy assign
253 /// @param other The value to assign from
254 // NOLINTNEXTLINE(bugprone-exception-escape)
255 constexpr auto operator=(optional const& other
256 ) noexcept(std::is_nothrow_copy_constructible<T>::value && std::is_nothrow_copy_assignable<T>::value) -> optional& {
257 if (this != &other) {
258 internal_do_assign(other);
259 }
260 return *this;
261 }
262 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
263
264 // parasoft-begin-suppress AUTOSAR-A15_5_1-b-2 "False positive: Conditionally noxecept"
265 /// @brief Move assign
266 /// @param other The value to assign from
267 constexpr auto operator=(optional&& other)
268 // NOLINTNEXTLINE(bugprone-exception-escape, hicpp-noexcept-move) We want to exactly match T.
269 noexcept(std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value) -> optional& {
270 internal_do_assign(std::move(other));
271 return *this;
272 }
273 // parasoft-end-suppress AUTOSAR-A15_5_1-b-2
274
275 /// @brief Assign from a value
276 /// @param other The value to assign from
277 template <
278 typename U = T,
279 constraints<
280 std::enable_if_t<!std::is_same<remove_cvref_t<U>, optional>::value>,
281 std::enable_if_t<std::is_constructible<T, U>::value>,
282 std::enable_if_t<std::is_assignable<T, U>::value>> = nullptr>
283 auto operator=(U&& other) noexcept(std::is_nothrow_assignable<T, U>::value&& noexcept(
284 std::declval<optional&>().construct_from(std::forward<U>(other))
285 )) -> optional& {
286 if (this->has_value()) {
287 **this = std::forward<U>(other);
288 } else {
289 construct_from(std::forward<U>(other));
290 }
291 return *this;
292 }
293
294 // parasoft-end-suppress AUTOSAR-A12_8_6-a
295
296 // Make has_value public from base class
297 using base_type::has_value;
298
299 /// @brief Query if this object has a value
300 ///
301 /// @return bool Equivalent to @c has_value() .
302 constexpr explicit operator bool() const noexcept { return this->has_value(); }
303
304 // parasoft-begin-suppress AUTOSAR-A9_3_1-a-2 "This is a wrapper, so non-const access to the value is required"
305 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
306 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
307 /// @brief Accesses the value in the optional.
308 ///
309 /// @return A @c T which is cref-qualified the same as @c *this .
310 /// @pre @c has_value() , else @c ARENE_PRECONDITION violation.
311 /// @{
312 constexpr auto operator*() const& noexcept -> T const& {
313 ARENE_PRECONDITION(this->has_value());
314 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
315 return this->storage().value;
316 }
317 constexpr auto operator*() & noexcept -> T& {
318 ARENE_PRECONDITION(this->has_value());
319 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
320 return this->storage().value;
321 }
322 constexpr auto operator*() const&& noexcept -> T const&& {
323 ARENE_PRECONDITION(this->has_value());
324 // parasoft-begin-suppress AUTOSAR-A18_9_3-a-2 "We want to ensure the qualifier is preserved"
325 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
326 return std::move(this->storage().value);
327 // parasoft-end-suppress AUTOSAR-A18_9_3-a-2
328 }
329 constexpr auto operator*() && noexcept -> T&& {
330 ARENE_PRECONDITION(this->has_value());
331 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
332 return std::move(this->storage().value);
333 }
334 /// @}
335 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
336 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
337 // parasoft-end-suppress AUTOSAR-A9_3_1-a-2
338
339 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
340 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
341 /// @brief Access a pointer to the value in the optional
342 ///
343 /// @return A @c T* which is const-qualified the same as @c *this .
344 /// @pre @c has_value() , else @c ARENE_PRECONDITION violation.
345 /// @{
346 constexpr auto operator->() const noexcept -> T const* {
347 ARENE_PRECONDITION(this->has_value());
348 return &**this;
349 }
350 constexpr auto operator->() noexcept -> T* {
351 ARENE_PRECONDITION(this->has_value());
352 return &**this;
353 }
354 /// @}
355 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
356 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
357
358 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
359 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
360 /// @brief Gets the value held in the optional, or else the provided default.
361 /// @tparam U The type of the default value. @c T must be constructible from @c U.
362 /// @param default_value The value to return if the optional is null.
363 /// @return T constructed from the held value if @c has_value() is @c true , else an instance constructed from
364 /// @c default_value .
365 /// @note This must return a new instance rather than a reference, otherwise it risks dangling references if
366 /// @c default_value is a temporary.
367 ///@{
368 template <
369 typename U,
370 typename R = T,
371 constraints<
372 std::enable_if_t<std::is_copy_constructible<R>::value>,
373 std::enable_if_t<std::is_convertible<U, R>::value>> = nullptr>
374 constexpr auto value_or(U&& default_value
375 ) const& noexcept(noexcept(optional::value_or(std::declval<optional const&>(), std::forward<U>(default_value))))
376 -> T {
377 return optional::value_or(*this, std::forward<U>(default_value));
378 }
379 template <
380 typename U,
381 typename R = T,
382 constraints<
383 std::enable_if_t<std::is_move_constructible<R>::value>,
384 std::enable_if_t<std::is_convertible<U, R>::value>> = nullptr>
385 constexpr auto value_or(U&& default_value
386 ) && noexcept(noexcept(optional::value_or(std::declval<optional&&>(), std::forward<U>(default_value)))) -> T {
387 return optional::value_or(std::move(*this), std::forward<U>(default_value));
388 }
389 ///@}
390 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
391 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
392
393 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
394 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
395 /// @brief Gets the value held in the optional, or else invokes the provided callable to generate one.
396 /// @tparam F The type of the callable to invoke. Must satisfy @c is_invocable_v<F> and
397 /// @c std::is_convertible<invoke_result_t<F>,T> .
398 /// @param default_generator The function to invoke to produce a default if @c !has_value() .
399 /// @return T constructed from the held value if @c has_value() is @c true , else an instance constructed from
400 /// invoking @c default_generator .
401 ///@{
402 template <
403 typename F,
404 typename R = T,
405 constraints<
406 std::enable_if_t<std::is_copy_constructible<R>::value>,
407 std::enable_if_t<std::is_convertible<invoke_result_t<F>, R>::value>> = nullptr>
408 constexpr auto value_or_else(F&& default_generator) const& noexcept(
409 noexcept(optional::value_or_else(std::declval<optional const&>(), std::forward<F>(default_generator)))
410 ) -> T {
411 return optional::value_or_else(*this, std::forward<F>(default_generator));
412 }
413 template <
414 typename F,
415 typename R = T,
416 constraints<
417 std::enable_if_t<std::is_move_constructible<R>::value>,
418 std::enable_if_t<std::is_convertible<invoke_result_t<F>, R>::value>> = nullptr>
419 constexpr auto value_or_else(F&& default_generator
420 ) && noexcept(noexcept(optional::value_or_else(std::declval<optional&&>(), std::forward<F>(default_generator))))
421 -> T {
422 return optional::value_or_else(std::move(*this), std::forward<F>(default_generator));
423 }
424 ///@}
425 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
426 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
427
428 /// @brief Destroy the old value if there is one, and construct a new value
429 /// @tparam Args The types of the arguments for constructing the new value
430 /// @param args The arguments for constructing the new value
431 template <typename... Args>
432 constexpr void emplace(Args&&... args
433 ) noexcept(noexcept(std::declval<optional<T>>().construct_from(std::forward<Args>(args)...))) {
434 this->reset();
435 construct_from(std::forward<Args>(args)...);
436 }
437
438 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
439 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
440 /// @brief Monadic API which invokes a functor with the contents of @c value() if @c has_value() is @c true.
441 /// @tparam F Type of the visiting functor. Must be invocable with @c value_type matching the const/ref qualification
442 /// of @c Self, and return any valid <c>optional&lt;U&gt;</c>.
443 /// @param handle_value the functor to invoke if @c self.has_value() is @c true .
444 /// @return U where @c U is the return type of @c F and is an instantiation of @c optional , which will be:
445 /// * The result of invoking @c handle_value with the contents of @c value() if @c has_value() is @c true.
446 /// * A @c U instantiated with @c nullopt otherwise.
447 ///@{
448 template <typename F>
449 constexpr auto and_then(F&& handle_value) & -> invoke_result_t<F, T&> {
450 static_assert(is_invocable_v<F, T&>, "handle_value must be invocable with value_type.");
451 static_assert(
452 is_instantiation_of_v<invoke_result_t<F, T&>, ::arene::base::optional>,
453 "handle_value must return an optional"
454 );
455 return optional::and_then(*this, std::forward<F>(handle_value));
456 }
457 template <typename F>
458 constexpr auto and_then(F&& handle_value) const& -> invoke_result_t<F, T const&> {
459 static_assert(is_invocable_v<F, T const&>, "handle_value must be invocable with value_type.");
460 static_assert(
461 is_instantiation_of_v<invoke_result_t<F, T const&>, ::arene::base::optional>,
462 "handle_value must return an optional"
463 );
464 return optional::and_then(*this, std::forward<F>(handle_value));
465 }
466 template <typename F>
467 constexpr auto and_then(F&& handle_value) && -> invoke_result_t<F, T&&> {
468 static_assert(is_invocable_v<F, T&&>, "handle_value must be invocable with value_type.");
469 static_assert(
470 is_instantiation_of_v<invoke_result_t<F, T&&>, ::arene::base::optional>,
471 "handle_value must return an optional"
472 );
473 return optional::and_then(std::move(*this), std::forward<F>(handle_value));
474 }
475 template <typename F>
476 constexpr auto and_then(F&& handle_value) const&& -> invoke_result_t<F, T const&&> {
477 static_assert(is_invocable_v<F, T const&&>, "handle_value must be invocable with value_type.");
478 static_assert(
479 is_instantiation_of_v<invoke_result_t<F, T const&&>, ::arene::base::optional>,
480 "handle_value must return an optional"
481 );
482 // parasoft-begin-suppress AUTOSAR-A18_9_3-a-2 "We want to ensure the qualifier is preserved"
483 return optional::and_then(std::move(*this), std::forward<F>(handle_value));
484 // parasoft-end-suppress AUTOSAR-A18_9_3-a-2
485 }
486 ///@}
487 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
488 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
489
490 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
491 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
492 /// @brief Monadic API which invokes a functor if @c has_value() is @c false.
493 /// @tparam F Type of the visiting functor. Must be invocable with no arguments and return @c optional<T> .
494 /// @param handle_null the functor to invoke if @c self.has_value() is @c false .
495 /// @return optional<T> which will be:
496 /// * The result of invoking @c handle_value with the contents of @c value() if @c has_value() is @c false.
497 /// * A instance of @c optional<T> constructed from forwarding @c self .
498 ///@{
499 template <
500 typename F,
501 typename R = T,
502 constraints<std::enable_if_t<is_invocable_v<F>>, std::enable_if_t<std::is_copy_constructible<R>::value>> =
503 nullptr>
504 constexpr auto or_else(F&& handle_null) const& -> optional<T> {
505 static_assert(
506 decays_to_v<invoke_result_t<F>, optional<T>>,
507 "handle_null must be void invocable and return an optional with the same type as this."
508 );
509 return optional::or_else(*this, std::forward<F>(handle_null));
510 }
511 template <
512 typename F,
513 typename R = T,
514 constraints<std::enable_if_t<is_invocable_v<F>>, std::enable_if_t<std::is_move_constructible<R>::value>> =
515 nullptr>
516 constexpr auto or_else(F&& handle_null) && -> optional<T> {
517 static_assert(
518 decays_to_v<invoke_result_t<F>, optional<T>>,
519 "handle_null must be void invocable and return an optional with the same type as this."
520 );
521 return optional::or_else(std::move(*this), std::forward<F>(handle_null));
522 }
523 ///@}
524 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
525 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
526
527 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
528 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
529 // parasoft-begin-suppress AUTOSAR-A2_10_1-d "False positive: it is not hiding anything"
530 /// @brief Calls a provided functor with @c value if it is populated, and produces a new @c optional with the return
531 /// from it.
532 /// @tparam F Type of the visiting functor. Must be invocable with @c value_type matching the const/ref qualification
533 /// of @c this. May return any valid @c value_type
534 /// @param value_transformer the functor to invoke if @c self.has_value() is @c true .
535 /// @return <c>optional&lt;U&gt;</c> where @c U is the return type of @c F , which will contain:
536 /// * The result of invoking @c handle_value with the contents of @c value() if @c has_value() is @c true.
537 /// * @c nullopt otherwise.
538 ///@{
539 template <typename F>
540 constexpr auto transform(F&& value_transformer) & -> optional<invoke_result_t<F, T&>> {
541 static_assert(is_invocable_v<F, T&>, "value_transformer must be invocable with value_type.");
542 static_assert(
543 substitution_succeeds<::arene::base::optional, invoke_result_t<F, T&>>,
544 "value_transformer must return a type that can be validly placed in an optional"
545 );
546 return optional::transform(*this, std::forward<F>(value_transformer));
547 }
548 template <typename F>
549 constexpr auto transform(F&& value_transformer) const& -> optional<invoke_result_t<F, T const&>> {
550 static_assert(is_invocable_v<F, T const&>, "value_transformer must be invocable with value_type.");
551 static_assert(
552 substitution_succeeds<::arene::base::optional, invoke_result_t<F, T const&>>,
553 "value_transformer must return a type that can be validly placed in an optional"
554 );
555 return optional::transform(*this, std::forward<F>(value_transformer));
556 }
557 template <typename F>
558 constexpr auto transform(F&& value_transformer) && -> optional<invoke_result_t<F, T&&>> {
559 static_assert(is_invocable_v<F, T&&>, "value_transformer must be invocable with value_type.");
560 static_assert(
561 substitution_succeeds<::arene::base::optional, invoke_result_t<F, T&&>>,
562 "value_transformer must return a type that can be validly placed in an optional"
563 );
564 return optional::transform(std::move(*this), std::forward<F>(value_transformer));
565 }
566 template <typename F>
567 constexpr auto transform(F&& value_transformer) const&& -> optional<invoke_result_t<F, T const&&>> {
568 static_assert(is_invocable_v<F, T const&&>, "value_transformer must be invocable with value_type.");
569 static_assert(
570 substitution_succeeds<::arene::base::optional, invoke_result_t<F, T const&&>>,
571 "value_transformer must return a type that can be validly placed in an optional"
572 );
573 // parasoft-begin-suppress AUTOSAR-A18_9_3-a-2 "We want to ensure the qualifier is preserved"
574 return optional::transform(std::move(*this), std::forward<F>(value_transformer));
575 // parasoft-end-suppress AUTOSAR-A18_9_3-a-2
576 }
577 ///@}
578 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
579 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
580 // parasoft-end-suppress AUTOSAR-A2_10_1-d
581
582 // parasoft-begin-suppress AUTOSAR-A2_10_1-d "False Positive: 'swap' does not hide anything"
583 ///
584 /// @brief Exchanges the state of two optionals.
585 ///
586 /// @tparam U Must satisfy @c is_swappable_v and @c std::is_move_constructable.
587 /// @param other The optional to swap with.
588 /// @post If both optionals are engaged, they will have their values exchanged as if via @c arene::base::swap .
589 /// Otherwise if one of the optionals was @c nullopt , the states are exchanged as if by move-constructing the
590 /// value from the engaged optional into the unengaged optional, and resetting the previously engaged optional.
591 ///
592 template <
593 typename U = T,
594 constraints<std::enable_if_t<is_swappable_v<U>>, std::enable_if_t<std::is_move_constructible<U>::value>> =
595 nullptr>
596 constexpr void swap(optional& other) noexcept( //
597 is_nothrow_swappable_v<U> && std::is_nothrow_move_constructible<U>::value
598 ) {
599 if (this->has_value() && other.has_value()) {
600 ::arene::base::swap(**this, *other);
601 } else if (this->has_value()) {
602 other.construct_from(std::move(**this));
603 this->reset();
604 } else {
605 construct_from(std::move(*other));
606 other.reset();
607 }
608 }
609 // parasoft-end-suppress AUTOSAR-A2_10_1-d
610
611 // parasoft-begin-suppress AUTOSAR-A2_7_2-a "False positive: no commented-out code"
612 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
613 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
614 /// @brief swaps the elements between two optionals.
615 ///
616 /// @tparam U the type of the element in the optional. Must satisfy @c is_swappable_v .
617 /// @param lhs the left hand optional to swap.
618 /// @param rhs the right hand optional to swap.
619 /// @post Equivalent to having called @c lhs.swap(rhs);
620 /// @see optional::swap.
621 ///
622 template <
623 typename U = T,
624 constraints<std::enable_if_t<is_swappable_v<U>>, std::enable_if_t<std::is_move_constructible<U>::value>> =
625 nullptr>
626 friend constexpr void swap(optional& lhs, optional& rhs) noexcept(noexcept(lhs.swap(rhs))) {
627 lhs.swap(rhs);
628 }
629 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
630 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
631 // parasoft-end-suppress AUTOSAR-A2_7_2-a
632
633 /// @brief Make @c reset public from base class
634 using base_type::reset;
635
636 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'three_way_compare' does not hide an identifier in
637 // 'optional'"
638 /// @brief Three-way comparison between an @c optional and @c nullopt_t
639 /// @param lhs The first object to compare
640 /// @return strong_ordering @c strong_ordering::equal if the @c lhs is empty, otherwise @c strong_ordering::greater
641 static constexpr auto three_way_compare(optional const& lhs, nullopt_t) noexcept -> strong_ordering {
642 return lhs ? strong_ordering::greater : strong_ordering::equal;
643 }
644 // parasoft-end-suppress AUTOSAR-A2_10_1-e
645
646 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'fast_inequality_check' does not hide an identifier in
647 // 'optional'"
648 /// @brief Fast inequality check between two @c optional instances, where there is not a fast inequality check between
649 /// the two stored types.
650 /// @tparam U The value type of the second @c optional
651 /// @param lhs The first object to compare
652 /// @param rhs The first object to compare
653 /// @return inequality_heuristic @c inequality_heuristic::definitely_not_equal if @c lhs has a value and @c rhs does
654 /// not, or vice versa, @c inequality_heuristic::may_or_may_not_be_equal otherwise
655 template <typename U, constraints<std::enable_if_t<!has_fast_inequality_check_v<T, U>>> = nullptr>
656 static constexpr auto fast_inequality_check(optional const& lhs, optional<U> const& rhs) noexcept
657 -> inequality_heuristic {
658 return (lhs.has_value() != rhs.has_value()) ? inequality_heuristic::definitely_not_equal
659 : inequality_heuristic::may_be_equal_or_not_equal;
660 }
661 // parasoft-end-suppress AUTOSAR-A2_10_1-e
662
663 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'fast_inequality_check' does not hide an identifier in
664 // 'optional'"
665 /// @brief Fast inequality check between two @c optional instances, where there is not a fast inequality check between
666 /// the two stored types.
667 /// @tparam U The value type of the second @c optional
668 /// @param lhs The first object to compare
669 /// @param rhs The first object to compare
670 /// @return inequality_heuristic @c inequality_heuristic::definitely_not_equal if @c lhs has a value and @c rhs does
671 /// not, or vice versa, @c inequality_heuristic::may_or_may_not_be_equal if neither has a value, and delegeates to @c
672 /// fast_inequality_check on the stored values otherwise
673 template <typename U, constraints<std::enable_if_t<has_fast_inequality_check_v<T, U>>> = nullptr>
674 static constexpr auto fast_inequality_check(optional const& lhs, optional<U> const& rhs) noexcept
675 -> inequality_heuristic {
676 if (lhs.has_value() != rhs.has_value()) {
677 return inequality_heuristic::definitely_not_equal;
678 }
679 if (!lhs) {
680 return inequality_heuristic::may_be_equal_or_not_equal;
681 }
682 return T::fast_inequality_check(*lhs, *rhs);
683 }
684 // parasoft-end-suppress AUTOSAR-A2_10_1-e
685
686 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'three_way_compare' does not hide an identifier in
687 // 'optional'"
688 /// @brief Three-way comparison between two @c optional instances
689 /// @tparam Self The type of the optional
690 /// @tparam U The value type of the second @c optional
691 /// @param lhs The first object to compare
692 /// @param rhs The first object to compare
693 /// @return strong_ordering @c strong_ordering::less if @c lhs is empty and @c rhs has a value, @c
694 /// strong_ordering::equal if both @c lhs and @c rhs are empty, @c strong_ordering::greater if @c lhs has a value and
695 /// @c rhs is empty, and the result of three-way comparison between the stored values if both @c lhs and @c rhs have
696 /// values
697 /// @pre @c T and @c U must be three-way-comparable
698 template <
699 typename Self,
700 typename U,
701 constraints<
702 std::enable_if_t<std::is_same<Self, optional>::value>,
703 std::enable_if_t<compare_three_way_supported_v<T, U>>> = nullptr>
704 static constexpr auto three_way_compare(Self const& lhs, optional<U> const& rhs) noexcept -> strong_ordering {
705 if (lhs) {
706 if (rhs) {
707 return compare_three_way{}(*lhs, *rhs);
708 }
709 return strong_ordering::greater;
710 }
711 if (rhs) {
712 return strong_ordering::less;
713 }
714 return strong_ordering::equal;
715 }
716 // parasoft-end-suppress AUTOSAR-A2_10_1-e
717
718 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'fast_inequality_check' does not hide an identifier in
719 // 'optional'"
720 /// @brief Fast inequality check between an @c optional instance and a value, where there is not a fast inequality
721 /// check between the two stored types.
722 /// @tparam U The value type of the second @c optional
723 /// @param lhs The first object to compare
724 /// @return inequality_heuristic @c inequality_heuristic::definitely_not_equal if @c lhs is empty, @c
725 /// inequality_heuristic::may_or_may_not_be_equal otherwise
726 template <
727 typename U,
728 constraints<
729 std::enable_if_t<!has_fast_inequality_check_v<T, U>>,
730 std::enable_if_t<!std::is_same<U, nullopt_t>::value>> = nullptr>
731 static constexpr auto fast_inequality_check(optional const& lhs, U const&) noexcept -> inequality_heuristic {
732 return !lhs ? inequality_heuristic::definitely_not_equal : inequality_heuristic::may_be_equal_or_not_equal;
733 }
734 // parasoft-end-suppress AUTOSAR-A2_10_1-e
735
736 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'fast_inequality_check' does not hide an identifier in
737 // 'optional'"
738 /// @brief Fast inequality check between an @c optional instance and a value, where there is a fast inequality
739 /// check between the stored type and the other value.
740 /// @tparam U The value type of the second @c optional
741 /// @param lhs The first object to compare
742 /// @param rhs The first object to compare
743 /// @return inequality_heuristic @c inequality_heuristic::definitely_not_equal if @c lhs is empty, delegeates to @c
744 /// fast_inequality_check on the stored values otherwise
745 template <
746 typename U,
747 constraints<
748 std::enable_if_t<has_fast_inequality_check_v<T, U>>,
749 std::enable_if_t<!std::is_same<U, nullopt_t>::value>> = nullptr>
750 static constexpr auto fast_inequality_check(optional const& lhs, U const& rhs) noexcept -> inequality_heuristic {
751 if (!lhs) {
752 return inequality_heuristic::definitely_not_equal;
753 }
754 return T::fast_inequality_check(*lhs, rhs);
755 }
756 // parasoft-end-suppress AUTOSAR-A2_10_1-e
757
758 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: 'three_way_compare' does not hide an identifier in
759 // 'optional'"
760 /// @brief Three-way comparison between an @c optional instance and a value
761 /// @tparam Self The type of the optional
762 /// @tparam U the type of the value to compare against
763 /// @param lhs The first object to compare
764 /// @param rhs The first object to compare
765 /// @return strong_ordering @c strong_ordering::less if @c lhs is empty, and the result of three-way comparison
766 /// between the stored value of @c lhs and @c rhs otherwise
767 /// @pre @c T and @c U must be three-way-comparable
768 template <
769 typename Self,
770 typename U,
771 constraints<
772 std::enable_if_t<std::is_same<Self, optional>::value>,
773 std::enable_if_t<!optional_detail::is_optional<U>::value>,
774 std::enable_if_t<compare_three_way_supported_v<T, U>>> = nullptr>
775 static constexpr auto three_way_compare(Self const& lhs, U const& rhs) noexcept -> strong_ordering {
776 if (lhs) {
777 return compare_three_way{}(*lhs, rhs);
778 }
779 return strong_ordering::less;
780 }
781 // parasoft-end-suppress AUTOSAR-A2_10_1-e
782
783 ARENE_IGNORE_START();
784 ARENE_IGNORE_ALL("-Wfloat-equal", "Can only suppress this here, not in user code; std::vector does the same thing");
785 ARENE_IGNORE_ALL("-Wsign-compare", "Can only suppress this here, not in user code; std::vector does the same thing");
786
787 // parasoft-begin-suppress AUTOSAR-A13_5_5-b-2 "Mixed comparisons permitted by A13-5-5 Permit #1"
788 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "False positive: comparison operators are permitted"
789 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
790 /// @brief equality comparison between an @c optional instance and a value
791 /// @tparam Self The type of the optional
792 /// @tparam U the type of the value to compare against the optional
793 /// @param lhs The first object to compare
794 /// @param rhs The first object to compare
795 /// @return bool @c false if @c lhs is empty, and the result of an equality comparison
796 /// between the stored value of @c lhs and @c rhs otherwise
797 /// @pre @c T and @c U must be equality-comparable
798 template <
799 typename Self,
800 typename U,
801 constraints<
802 std::enable_if_t<std::is_same<Self, optional>::value>,
803 std::enable_if_t<!optional_detail::is_optional<U>::value>,
804 std::enable_if_t<is_equality_comparable_v<T, U>>> = nullptr>
805 friend constexpr auto operator==(Self const& lhs, U const& rhs) noexcept -> bool {
806 if (lhs) {
807 return *lhs == rhs;
808 }
809 return false;
810 }
811 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
812 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
813 // parasoft-end-suppress AUTOSAR-A13_5_5-b-2
814
815 ARENE_IGNORE_END();
816
817 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "False positive: comparison operators are permitted"
818 // parasoft-begin-suppress AUTOSAR-A13_5_5-b-2 "Mixed comparisons permitted by A13-5-5 Permit #1"
819 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
820 /// @brief equality comparison between two @c optional instances
821 /// @tparam Self The type of the optional
822 /// @tparam U the type stored in the other optional
823 /// @param lhs The first object to compare
824 /// @param rhs The first object to compare
825 /// @return bool @c true if both @c lhs and @c rhs are empty, @c false if only one of @c lhs and @c rhs is empty, and
826 /// the result of an equality comparison between the stored value of @c lhs and the stored value of @c rhs otherwise
827 /// @pre @c T and @c U must be equality-comparable
828 template <
829 typename Self,
830 typename U,
831 constraints<
832 std::enable_if_t<std::is_same<Self, optional>::value>,
833 std::enable_if_t<!optional_detail::is_optional<U>::value>,
834 std::enable_if_t<is_equality_comparable_v<T, U>>> = nullptr>
835 friend constexpr auto operator==(Self const& lhs, optional<U> const& rhs) noexcept -> bool {
836 if (lhs) {
837 if (rhs) {
838 return *lhs == *rhs;
839 }
840 return false;
841 }
842 if (rhs) {
843 return false;
844 }
845 return true;
846 }
847 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
848
849 // parasoft-begin-suppress AUTOSAR-A0_1_3-a "False positive: these are public functions with external linkage"
850 /// @brief equality comparison between an @c optional instance and an explicit @c nullopt
851 /// @param lhs The @c optional instance to compare
852 /// @return bool @c true if @c lhs is null (that is, !has_value()), @c false if it has a value
853 friend constexpr auto operator==(optional const& lhs, nullopt_t) noexcept -> bool { return !lhs.has_value(); }
854
855 /// @brief inequality comparison between an @c optional instance and an explicit @c nullopt
856 /// @param lhs The @c optional instance to compare
857 /// @return bool @c true if @c lhs has a value (that is, has_value()), @c false if it does not
858 friend constexpr auto operator!=(optional const& lhs, nullopt_t) noexcept -> bool { return lhs.has_value(); }
859
860 /// @brief inequality comparison between an explicit @c nullopt and an @c optional instance
861 /// @param rhs The @c optional instance to compare
862 /// @return bool @c true if @c rhs has a value (that is, has_value()), @c false if it does not
863 friend constexpr auto operator!=(nullopt_t, optional const& rhs) noexcept -> bool { return rhs.has_value(); }
864 // parasoft-end-suppress AUTOSAR-A0_1_3-a
865
866 // parasoft-begin-suppress AUTOSAR-M3_3_2-a-2 "False positive: cannot apply static here"
867 /// @brief inequality comparison between two @c optional instances
868 /// @tparam Self The type of the optional
869 /// @tparam U the type stored in the other optional
870 /// @param lhs The first object to compare
871 /// @param rhs The first object to compare
872 /// @return bool @c false if @c lhs is empty, and the result of an inequality comparison
873 /// between the stored value of @c lhs and @c rhs otherwise
874 /// @pre @c T and @c U must be equality-comparable
875 template <
876 typename Self,
877 typename U,
878 constraints<
879 std::enable_if_t<std::is_same<Self, optional>::value>,
880 std::enable_if_t<!optional_detail::is_optional<U>::value>,
881 std::enable_if_t<is_equality_comparable_v<T, U>>> = nullptr>
882 friend constexpr auto operator!=(Self const& lhs, optional<U> const& rhs) noexcept -> bool {
883 return !(lhs == rhs);
884 }
885 // parasoft-end-suppress AUTOSAR-M3_3_2-a-2
886 // parasoft-end-suppress AUTOSAR-A13_5_5-b-2
887 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
888
889 private:
890 /// @brief Internal function to construct a new @c T in the storage.
891 /// This overload handles the case where everything is @c noexcept
892 /// @tparam Args The types of the arguments to construct from
893 /// @param args The arguments to construct from
894 /// Assumes @c has_value() is @c false
895 template <
896 typename... Args,
897 constraints<std::enable_if_t<noexcept(storage_type(in_place, std::declval<Args>()...))>> = nullptr>
898 void construct_from(Args&&... args) noexcept {
899 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
900 this->storage().~storage_type();
901 construct_at(&this->storage(), in_place, std::forward<Args>(args)...);
902 this->set_has_value();
903 }
904
905 /// @brief Internal function to construct a new @c T in the storage.
906 /// This overload handles the case where the constructor might throw
907 /// @tparam Args The types of the arguments to construct from
908 /// @param args The arguments to construct from
909 /// Assumes @c has_value() is @c false
910 template <
911 typename... Args,
912 constraints<std::enable_if_t<!noexcept(storage_type(in_place, std::declval<Args>()...))>> = nullptr>
913 void construct_from(Args&&... args) {
914 // parasoft-begin-suppress AUTOSAR-A7_1_7-a "False positive: no expression statement and identifier declaration on
915 // same line"
916
917 // If the constructor throws, we want to leave the optional in a valid state while letting the exception bubble
918 // without using try/catch/throw in order to compile cleanly with -fno-exceptions. Therefore, we use a scope_guard
919 // which resets the storage, and cancel it if construction is successful.
920 auto make_empty_on_throw = on_scope_exit([this]() noexcept { construct_at(&this->storage()); });
921
922 // parasoft-end-suppress AUTOSAR-A7_1_7-a
923
924 construct_at(&this->storage(), in_place, std::forward<Args>(args)...);
925 this->set_has_value();
926 make_empty_on_throw.cancel();
927 }
928
929 /// @brief Internal function to implement assignment.
930 /// @tparam OtherOptional The type of the optional being assigned from, including the value category
931 /// @param other The optional being assigned from
932 template <typename OtherOptional>
933 constexpr void internal_do_assign(OtherOptional&& other) noexcept(
934 std::is_nothrow_constructible<T, decltype(*std::forward<OtherOptional>(other))>::value &&
935 std::is_nothrow_assignable<T&, decltype(*std::forward<OtherOptional>(other))>::value
936 ) {
937 if (this->has_value() && other.has_value()) {
938 **this = *std::forward<OtherOptional>(other);
939 } else if (this->has_value()) {
940 this->reset();
941 } else if (other.has_value()) {
942 construct_from(*std::forward<OtherOptional>(other));
943 } else {
944 // do nothing
945 }
946 }
947
948 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Preserve type safety by allowing different instantiations of optional
949 // to access private members without making them public"
950 template <typename U>
951 friend class optional;
952 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
953
954 /// @brief deduced-this helper for @c optional::value_or<F>(F&&) .
955 /// @tparam Self The qualified result type to invoke with. Must satisfy @c decays_to<Self,optional>
956 /// @tparam U The type of the default value. @c T must be constructible from @c U.
957 /// @param self The @c optional to operate on
958 /// @param default_value The value to return if the optional is null.
959 /// @return T constructed from the held value if @c has_value() is @c true , else an instance constructed from
960 /// @c default_value .
961 /// @note This must return a new instance rather than a reference, otherwise it risks dangling references if
962 /// @c default_value is a temporary.
963 template <typename Self, typename U, constraints<std::enable_if_t<decays_to_v<Self, optional>>> = nullptr>
964 static constexpr auto value_or(Self&& self, U&& default_value) noexcept(noexcept(T{default_value}
965 ) && noexcept(T{*std::forward<Self>(self)})) -> T {
966 return self.has_value() ? static_cast<T>(forward_like<Self>(std::forward<Self>(self).storage().value))
967 : static_cast<T>(std::forward<U>(default_value));
968 }
969
970 /// @brief deduced-this helper for @c optional::value_or_else<F>(F&&) .
971 /// @tparam Self The qualified result type to invoke with. Must satisfy @c decays_to<Self,optional>
972 /// @tparam F The type of the callable to invoke. Must have signature @c U(void) , where @c U is a type from which
973 /// @c T is constructible.
974 /// @param self the instance of the result to use.
975 /// @param default_generator The function to invoke to produce a default if optional is null.
976 /// @return T constructed from the held value if @c has_value() is @c true , else an instance constructed from
977 /// invoking @c default_generator .
978 template <typename Self, typename F, constraints<std::enable_if_t<decays_to_v<Self, optional>>> = nullptr>
979 static constexpr auto value_or_else(Self&& self, F&& default_generator) noexcept(noexcept(T{
980 ::arene::base::invoke(std::forward<F>(default_generator))
981 }) && noexcept(T{*std::forward<Self>(self)})) -> T {
982 return self.has_value() ? static_cast<T>(forward_like<Self>(std::forward<Self>(self).storage().value))
983 : static_cast<T>(::arene::base::invoke(std::forward<F>(default_generator)));
984 }
985
986 ///
987 /// @brief deduced-this helper for @c optional::and_then<F>(F&&) .
988 /// @tparam Self The qualified result type to invoke with. Must satisfy @c decays_to<Self,optional>
989 /// @tparam F Type of the visiting functor. Must be invocable with @c value_type matching the const/ref qualification
990 /// of @c Self, and return any valid <c>optional&lt;U&gt;</c>.
991 /// @param self the instance of the result to use.
992 /// @param handle_value the functor to invoke if @c self.has_value() is @c true .
993 /// @return U, where @c U is the return type of @c F and is an instantiation of @c optional , which will be:
994 /// * The result of invoking @c handle_value with the contents of @c value() if @c has_value() is @c true.
995 /// * A @c U instantiated with @c nullopt otherwise.
996 template <typename Self, typename F, constraints<std::enable_if_t<decays_to_v<Self, optional>>> = nullptr>
997 static constexpr auto and_then(Self&& self, F&& handle_value)
998 -> invoke_result_t<F, decltype(forward_like<Self>(std::declval<Self&&>().storage().value))> {
999 using f_optional_t = invoke_result_t<F, decltype(forward_like<Self>(std::forward<Self>(self).storage().value))>;
1000 if (self.has_value()) {
1001 return ::arene::base::invoke(
1002 std::forward<F>(handle_value),
1003 forward_like<Self>(std::forward<Self>(self).storage().value)
1004 );
1005 }
1006 return f_optional_t{};
1007 }
1008
1009 ///
1010 /// @brief deduced-this helper for @c optional::or_else<F>(F&&) .
1011 /// @tparam Self The qualified result type to invoke with. Must satisfy @c decays_to<Self,optional>
1012 /// @tparam F Type of the visiting functor. Must be invocable with no arguments and return @c optional<T> .
1013 /// @param self the instance of the result to use.
1014 /// @param handle_null the functor to invoke if @c self.has_value() is @c false .
1015 /// @return optional<T> which will be:
1016 /// * The result of invoking @c handle_value with the contents of @c value() if @c has_value() is @c false.
1017 /// * A instance of @c optional<T> constructed from forwarding @c self .
1018 template <typename Self, typename F, constraints<std::enable_if_t<decays_to_v<Self, optional>>> = nullptr>
1019 static constexpr auto or_else(Self&& self, F&& handle_null) -> optional<T> {
1020 if (self.has_value()) {
1021 return {std::forward<Self>(self)};
1022 }
1023 return ::arene::base::invoke(std::forward<F>(handle_null));
1024 }
1025
1026 // parasoft-begin-suppress AUTOSAR-A2_10_1-d "False positive: it is not hiding anything"
1027 ///
1028 /// @brief deduced-this helper for @c optional::transform<F>(F&&) .
1029 /// @tparam Self The qualified result type to invoke with. Must satisfy @c decays_to<Self,optional>
1030 /// @tparam F Type of the visiting functor. Must be invocable with @c value_type matching the const/ref qualification
1031 /// of @c Self. May return any valid @c value_type
1032 /// @param self the instance of the result to use.
1033 /// @param value_transformer the functor to invoke if @c self.has_value() is @c true .
1034 /// @return optional<U>, where @c U is the return type of @c F , which will contain:
1035 /// * The result of invoking @c handle_value with the contents of @c value() if @c has_value() is @c true.
1036 /// * @c nullopt otherwise.
1037 template <typename Self, typename F, constraints<std::enable_if_t<decays_to_v<Self, optional>>> = nullptr>
1038 static constexpr auto transform(Self&& self, F&& value_transformer)
1039 -> optional<invoke_result_t<F, decltype(forward_like<Self>(std::declval<Self&&>().storage().value))>> {
1040 using f_return_t = invoke_result_t<F, decltype(forward_like<Self>(std::forward<Self>(self).storage().value))>;
1041 using optional_t = optional<f_return_t>;
1042 if (self.has_value()) {
1043 return optional_t{::arene::base::invoke(
1044 std::forward<F>(value_transformer),
1045 forward_like<Self>(std::forward<Self>(self).storage().value)
1046 )};
1047 }
1048 return optional_t{};
1049 }
1050};
1051// parasoft-end-suppress AUTOSAR-A2_10_1-d "False positive: it is not hiding anything"
1052
1053} // namespace base
1054} // namespace arene
1055
1056// parasoft-end-suppress AUTOSAR-M2_10_1-a-2
1057// parasoft-end-suppress AUTOSAR-A7_1_5-a-2
1058
1059#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_OPTIONAL_OPTIONAL_HPP_
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10