GCC Code Coverage Report


Directory: include/sumty/
File: include/sumty/option.hpp
Date: 2024-04-28 13:27:51
Warnings: 1 unchecked decisions!
Exec Total Coverage
Lines: 193 194 99.5%
Functions: 137 137 100.0%
Branches: 66 72 91.7%
Decisions: 34 38 89.5%

Line Branch Decision Exec Source
1 /* Copyright 2023 Jack A Bernard Jr.
2 *
3 * Licensed under the Apache License, Version 2.0 (the License);
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an AS IS BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef SUMTY_OPTION_HPP
17 #define SUMTY_OPTION_HPP
18
19 #include "sumty/detail/fwd.hpp" // IWYU pragma: export
20 #include "sumty/detail/traits.hpp" // IWYU pragma: export
21 #include "sumty/detail/utils.hpp"
22 #include "sumty/exceptions.hpp"
23 #include "sumty/result.hpp" // IWYU pragma: keep
24 #include "sumty/utils.hpp" // IWYU pragma: export
25 #include "sumty/variant.hpp"
26
27 #include <compare>
28 #include <cstddef>
29 #include <functional>
30 #include <initializer_list>
31 #include <optional>
32 #include <type_traits>
33 #include <utility>
34
35 namespace sumty {
36
37 /// @class option option.hpp <sumty/option.hpp>
38 /// @brief Type that either contains some value or none
39 ///
40 /// @details
41 /// @ref option is a reimplementation of `std::optional` with several
42 /// improvements. The key difference is that @ref option can contain `void`
43 /// and references (lvalue and rvalue). `option<void>` turns out to
44 /// essentially be a `bool` with the @ref option interface, and `option<T&>`
45 /// behaves like non-owning, nullable smart pointer to `T`.
46 ///
47 /// Internally, `option<T>` is represented as a @ref variant<void, T>. Thus,
48 /// @ref option benefits from the size optimizations implemented by @ref
49 /// variant (see @ref variant documentation for details). In particular, an
50 /// @ref option of `void` or an empty type has the size of a `bool`, and an
51 /// @ref option of an lvalue reference has the size of a raw pointer.
52 ///
53 /// ```cpp
54 /// struct empty_t {};
55 ///
56 /// assert(sizeof(option<void>) == sizeof(bool));
57 ///
58 /// assert(sizeof(option<empty_t>) == sizeof(bool));
59 ///
60 /// assert(sizeof(option<int&>) == sizeof(int*));
61 ///
62 /// assert(sizeof(option<const int&>) == sizeof(const int*));
63 /// ```
64 ///
65 /// In practice, the benefit of @ref option over `std::optional` is that @ref
66 /// option can be used in more places, espeicially with generic code. A generic
67 /// function (function template) that wants to be able to return a value of any
68 /// type, but also allow that return value to be "null" or "none" can simply
69 /// return a `option<T>`, where `T` is now allowed to be a reference or even
70 /// `void`.
71 ///
72 /// ```cpp
73 /// // Returns the result of invoking func, even if that result is void or a
74 /// // reference, if the condition is true. Otherwise returns none.
75 /// template <typename F>
76 /// option<std::invoke_result_t<F>> call_if(bool condition, F&& func) {
77 /// if (condition) {
78 /// // sumty::invoke needed to handle `void` return type
79 /// return invoke(std::forward<F>(func));
80 /// } else {
81 /// return none;
82 /// }
83 /// }
84 /// ```
85 ///
86 /// An @ref option of an lvalue reference can also be used as an alternative
87 /// to raw pointers is many cases. `option<T&>` communicates that the pointer
88 /// is allowed to be null and that the pointer is non-owning. Depending on a
89 /// project's C++ coding practices, `option<T&>` may be preferable to `T*`, for
90 /// single-object pointers.
91 ///
92 /// @tparam T The possibly contained type
93 template <typename T>
94 class option : variant<void, T> {
95 private:
96 154 [[nodiscard]] constexpr variant<void, T>& opt_() & noexcept {
97 154 return *static_cast<variant<void, T>*>(this);
98 }
99
100 584 [[nodiscard]] constexpr const variant<void, T>& opt_() const& noexcept {
101 584 return *static_cast<const variant<void, T>*>(this);
102 }
103
104 1 [[nodiscard]] constexpr variant<void, T>&& opt_() && {
105 1 return std::move(*static_cast<variant<void, T>*>(this));
106 }
107
108 [[nodiscard]] constexpr variant<void, T>&& opt_() const&& {
109 return std::move(*static_cast<const variant<void, T>*>(this));
110 }
111
112 public:
113 #ifndef DOXYGEN
114 using value_type = typename detail::traits<T>::value_type;
115 using reference = typename detail::traits<T>::reference;
116 using const_reference = typename detail::traits<T>::const_reference;
117 using rvalue_reference = typename detail::traits<T>::rvalue_reference;
118 using const_rvalue_reference = typename detail::traits<T>::const_rvalue_reference;
119 using pointer = typename detail::traits<T>::pointer;
120 using const_pointer = typename detail::traits<T>::const_pointer;
121 #else
122 using value_type = ...;
123 using reference = ...;
124 using const_reference = ...;
125 using rvalue_reference = ...;
126 using const_rvalue_reference = ...;
127 using pointer = ...;
128 using const_pointer = ...;
129 #endif
130
131 /// @brief Default constructor
132 ///
133 /// @details
134 /// Initializes the @ref option as none or null.
135 ///
136 /// ## Example
137 /// ```cpp
138 /// option<int> opt;
139 ///
140 /// assert(!opt);
141 ///
142 /// assert(opt.has_value() == false);
143 /// ```
144 80 constexpr option() noexcept
145 #ifndef DOXYGEN
146 = default;
147 #else
148 ;
149 #endif
150
151 /// @brief Copy constructor
152 ///
153 /// @details
154 /// If the source @ref option is not none, the new @ref option is
155 /// initialized with a value copy constructed from the value contained in
156 /// the source @ref option.
157 ///
158 /// ## Example
159 /// ```cpp
160 /// option<int> opt1;
161 /// option<int> opt2 = 42;
162 ///
163 /// option<int> opt1_copy{opt1};
164 /// option<int> opt2_copy{opt2};
165 ///
166 /// assert(!opt1_copy);
167 ///
168 /// assert(opt2_copy);
169 /// assert(*opt2_copy == 42);
170 /// ```
171 10 constexpr option(const option&)
172 #ifndef DOXYGEN
173 noexcept(detail::traits<T>::is_nothrow_copy_constructible) = default;
174 #else
175 CONDITIONALLY_NOEXCEPT;
176 #endif
177
178 /// @brief Move constructor
179 ///
180 /// @details
181 /// If the source @ref option is not none, the new @ref option is
182 /// initialized with a value move constructed from the value contained in
183 /// the source @ref option.
184 ///
185 /// ## Example
186 /// ```
187 /// option<int> opt1;
188 /// option<int> opt2;
189 ///
190 /// option<int> opt1_moved{std::move(opt1)};
191 /// option<int> opt2_moved{std::move(opt2)};
192 ///
193 /// assert(!opt1_moved);
194 ///
195 /// assert(opt2_moved);
196 /// assert(*opt2_moved == 42);
197 /// ```
198 constexpr option(option&&)
199 #ifndef DOXYGEN
200 noexcept(detail::traits<T>::is_nothrow_move_constructible) = default;
201 #else
202 CONDITIONALLY_NOEXCEPT;
203 #endif
204
205 /// @brief None constructor
206 ///
207 /// @details
208 /// Initializes the @ref option to the `none` value. That is, the @ref
209 /// option will contain no value, and `.has_value()` will return `false`.
210 ///
211 /// ## Example
212 /// ```
213 /// option<int> opt{none};
214 ///
215 /// assert(!opt);
216 /// assert(opt.has_value() == false);
217 /// assert(opt == none);
218 /// ```
219 // NOLINTNEXTLINE(hicpp-explicit-conversions)
220 constexpr option([[maybe_unused]] none_t null) noexcept : option() {}
221
222 /// @brief `std::nullopt` constructor
223 ///
224 /// @details
225 /// Initializes the @ref option to the `none` value. That is, the @ref
226 /// option will contain no value, and `.has_value()` will return `false`.
227 ///
228 /// ## Example
229 /// ```
230 /// option<int> opt{std::nullopt};
231 ///
232 /// assert(!opt);
233 /// assert(opt.has_value() == false);
234 /// assert(opt == std::nullopt);
235 /// ```
236 // NOLINTNEXTLINE(hicpp-explicit-conversions)
237 constexpr option([[maybe_unused]] std::nullopt_t null) noexcept : option() {}
238
239 /// @brief `nullptr` constructor
240 ///
241 /// @details
242 /// Initializes the @ref option to the `none` value. That is, the @ref
243 /// option will contain no value, and `.has_value()` will return `false`.
244 ///
245 /// This constructor only participates in overload resolution if the
246 /// contained value type is an lvalue reference, in which case the @ref
247 /// option behaves like a smart pointer.
248 ///
249 /// ## Example
250 /// ```
251 /// option<int&> opt{nullptr};
252 ///
253 /// assert(!opt);
254 /// assert(opt.has_value() == false);
255 /// assert(opt == nullptr);
256 /// ```
257 // NOLINTNEXTLINE(hicpp-explicit-conversions)
258 constexpr option([[maybe_unused]] std::nullptr_t null) noexcept
259 #ifndef DOXYGEN
260 requires(std::is_lvalue_reference_v<T>)
261 #endif
262 : option() {
263 }
264
265 /// @brief Pointer constructor
266 ///
267 /// @details
268 /// Initializes the @ref option to contain a reference to the value that
269 /// the pointer points to. If the pointer is null, the @ref option will
270 /// be `none`. That is, the @ref option will contain no value, and
271 /// `.has_value()` will return `false`.
272 ///
273 /// This constructor only participates in overload resolution if the
274 /// contained value type is an lvalue reference, in which case the @ref
275 /// option behaves like a smart pointer.
276 ///
277 /// This constructor is `explicit` if the pointer is not implicitly
278 /// convertible to `T*`.
279 ///
280 /// ## Example
281 /// ```
282 /// int value = 42;
283 /// int* ptr = &value;
284 /// int* null_ptr = nullptr;
285 ///
286 /// option<int&> opt1{ptr};
287 /// option<int&> opt2{null_ptr};
288 ///
289 /// assert(opt1);
290 /// assert(opt1 == ptr);
291 ///
292 /// assert(!opt2);
293 /// assert(opt2 == null_ptr);
294 /// ```
295 template <typename U>
296 #ifndef DOXYGEN
297 requires(std::is_lvalue_reference_v<T> && std::is_convertible_v<U*, pointer>)
298 explicit(!std::is_convertible_v<U*, pointer>)
299 #else
300 CONDITIONALLY_EXPLICIT
301 #endif
302 // NOLINTNEXTLINE(hicpp-explicit-conversions)
303 2 constexpr option(U* ptr) noexcept {
304
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (ptr != nullptr) { opt_().template emplace<1>(*ptr); }
305 2 }
306
307 /// @brief Converting copy constructor
308 ///
309 /// @details
310 /// Initializes the @ref option to contain the value of the source @ref
311 /// option where the contained value `U` is converted to `T`, as if by
312 /// `T{U_value}`. If the source @ref option is `none`, then the destination
313 /// @ref option will also be `none`.
314 ///
315 /// This constructor only participates in overload resolution if the
316 /// value type `T` of the destination @ref option is constructible from
317 /// the contained value of the source @ref option `U`.
318 ///
319 /// This constructor is `explicit` if `U` is not implicitly convertible to
320 /// `T`.
321 ///
322 /// ## Example
323 /// ```
324 /// option<float> opt1{3.14};
325 ///
326 /// option<int> opt2{opt1};
327 ///
328 /// assert(opt2);
329 ///
330 /// assert(*opt2 == 3);
331 /// ```
332 template <typename U>
333 #ifndef DOXYGEN
334 requires(std::is_constructible_v<variant<void, T>,
335 std::in_place_index_t<1>,
336 typename detail::traits<U>::const_reference>)
337 explicit(!detail::traits<T>::template is_convertible_from<U>)
338 #else
339 CONDITIONALLY_EXPLICIT
340 #endif
341 // NOLINTNEXTLINE(hicpp-explicit-conversions)
342 4 constexpr option(const option<U>& other)
343 4 : option() {
344
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
0/1
? Decision couldn't be analyzed.
4 if (other.has_value()) { opt_().template emplace<1>(*other); }
345 4 }
346
347 /// @brief Converting move constructor
348 ///
349 /// @details
350 /// Initializes the @ref option to contain the value of the source @ref
351 /// option where the contained value `U` is moved and converted to `T`, as
352 /// if by `T{std::move(U_value)}`. If the source @ref option is `none`,
353 /// the the destination @ref option will also be `none`.
354 ///
355 /// This constructor only participates in overload resolution if the
356 /// value type `T` of the destination @ref option is convertible from
357 /// the contained value of the source @ref option `U`.
358 ///
359 /// This constructor is `explicit` if `U` is not implicitly convertible to
360 /// `T`.
361 ///
362 /// ## Example
363 /// ```
364 /// option<float> opt1{3.14};
365 ///
366 /// option<int> opt2{std::move(opt1)};
367 ///
368 /// assert(opt2);
369 ///
370 /// assert(*opt2 == 3);
371 /// ```
372 template <typename U>
373 #ifndef DOXYGEN
374 requires(std::is_constructible_v<variant<void, T>,
375 std::in_place_index_t<1>,
376 typename detail::traits<U>::rvalue_reference>)
377 explicit(!detail::traits<T>::template is_convertible_from<U>)
378 #else
379 CONDITIONALLY_EXPLICIT
380 #endif
381 // NOLINTNEXTLINE(hicpp-explicit-conversions)
382 constexpr option(option<U>&& other)
383 : option() {
384 if (other.has_value()) { opt_().template emplace<1>(*std::move(other)); }
385 }
386
387 /// @brief Emplacement constructor
388 ///
389 /// @details
390 /// The @ref option is initialized such that it contains a value that is
391 /// constructed in place from the forwarded arguments.
392 ///
393 /// This constructor is `explicit` if `inplace` is the only argument.
394 ///
395 /// ## Example
396 /// ```
397 /// option<std::string> opt{std::in_place, 5, 'a'};
398 ///
399 /// assert(opt);
400 ///
401 /// assert(*opt == "aaaaa");
402 /// ```
403 template <typename... Args>
404 #ifndef DOXYGEN
405 explicit(sizeof...(Args) == 0)
406 #else
407 CONDITIONALLY_EXPLICIT
408 #endif
409 // NOLINTNEXTLINE(hicpp-explicit-conversions)
410 14 constexpr option([[maybe_unused]] std::in_place_t inplace, Args&&... args)
411 14 : variant<void, T>(std::in_place_index<1>, std::forward<Args>(args)...) {
412 14 }
413
414 /// @brief Emplacement constructor with initializer list
415 ///
416 /// @details
417 /// The @ref option is initialized such that it contains a value that is
418 /// constructed in place from the forwarded arguments.
419 ///
420 /// ## Example
421 /// ```
422 /// option<std::vector<int>> opt{std::in_place, {1, 2, 3, 4, 5}};
423 ///
424 /// assert(opt);
425 ///
426 /// assert(opt->size() == 5);
427 /// ```
428 template <typename U, typename... Args>
429 constexpr option([[maybe_unused]] std::in_place_t inplace,
430 std::initializer_list<U> init,
431 Args&&... args)
432 : variant<void, T>(std::in_place_index<1>, init, std::forward<Args>(args)...) {}
433
434 /// @brief Forwarding constructor
435 ///
436 /// @details
437 /// The @ref option is initialized such that it contains a value that is
438 /// constructed in place with the passed value forwarded to the value
439 /// type's constructor.
440 ///
441 /// This constructor only participates in overload resolution if the
442 /// contained value type is constructible from the passed value, the passed
443 /// value is not of type `std::in_place_t`, and either the the contained
444 /// value type is not a scalar, or the forwarded value is not an @ref
445 /// option instance.
446 ///
447 /// This constructor is `explicit` if the passed value is not implicitly
448 /// convertible to `T`.
449 ///
450 /// ## Example
451 /// ```
452 /// float value = 3.14;
453 ///
454 /// option<int> opt{value};
455 ///
456 /// assert(opt);
457 ///
458 /// assert(*opt == 3);
459 /// ```
460 template <typename U>
461 #ifndef DOXYGEN
462 requires(detail::traits<T>::template is_constructible<U> &&
463 !std::is_same_v<std::remove_cvref_t<U>, std::in_place_t> &&
464 (!std::is_scalar_v<std::remove_cvref_t<T>> ||
465 !detail::is_option_v<std::remove_cvref_t<U>>))
466 explicit(!detail::traits<T>::template is_convertible_from<U>)
467 #else
468 CONDITIONALLY_EXPLICIT
469 #endif
470 // NOLINTNEXTLINE(hicpp-explicit-conversions)
471 46 constexpr option(U&& value)
472 46 : variant<void, T>(std::in_place_index<1>, std::forward<U>(value)) {
473 46 }
474
475 /// @brief Destructor
476 ///
477 /// @details
478 /// If the @ref option is not `none`, the contained value is destroy in
479 /// place.
480 ///
481 /// The destructor is `noexcept` if the contained value type is nothrow
482 /// destructible.
483 138 constexpr ~option()
484 #ifndef DOXYGEN
485 noexcept(detail::traits<T>::is_nothrow_destructible) = default;
486 #else
487 CONDITIONALLY_NOEXCEPT;
488 #endif
489
490 /// @brief Copy assignment operator
491 ///
492 /// @details
493 /// The destination @ref option is reassigned such that it contains the
494 /// value of the source @ref option, if it has any.
495 ///
496 /// If both the source and desitnation @ref option are not `none`, then the
497 /// value contained in the destination @ref option is copy assigned from
498 /// the value contained in the source @ref option.
499 ///
500 /// If the source @ref option contains a value and the destination is
501 /// `none`, the value contained in the source @ref option is destroyed in
502 /// place, making the destination @ref option `none`.
503 ///
504 /// If the source @ref option is `none` and the destination contains a
505 /// value, a new value is copy constructed in place in the source @ref
506 /// option.
507 ///
508 /// If both the source and destination @ref option are `none`, both remain
509 /// `none`.
510 ///
511 /// This function is `noexcept` if the contained value type is nothrow
512 /// copy assignable, nothrow copy constructible, and nothrow destructible.
513 ///
514 /// ## Example
515 /// ```
516 /// option<int> opt1{42};
517 /// option<int> opt2{};
518 ///
519 /// opt2 = opt1;
520 ///
521 /// assert(opt2);
522 /// assert(*opt2 == 42);
523 ///
524 /// opt1 = none;
525 /// opt2 = opt1;
526 ///
527 /// assert(!opt2);
528 /// ```
529 constexpr option& operator=(const option&)
530 #ifndef DOXYGEN
531 noexcept(detail::traits<T>::is_nothrow_copy_assignable &&
532 detail::traits<T>::is_nothrow_copy_constructible &&
533 detail::traits<T>::is_nothrow_destructible) = default;
534 #else
535 CONDITIONALLY_NOEXCEPT;
536 #endif
537
538 /// @brief Move assignment operator
539 ///
540 /// @details
541 /// The destination @ref option is reassigned such that it contains the
542 /// moved value of the source @ref option, if it has any. In all cases,
543 /// the source @ref option will be `none` after the move.
544 ///
545 /// If both the source and destination @ref option are not `none`, then the
546 /// value contained in the destination @ref option is move assigned from
547 /// the moved value from the source @ref option. The old value in the
548 /// source @ref option is destroyed in place.
549 ///
550 /// If the source @ref option contains a value and the desitnation is
551 /// `none`, the value contained in the source @ref option is destroyed in
552 /// place, making the desitnation @ref option `none`.
553 ///
554 /// If the source @ref option is `none` and the destination contains a
555 /// value, a new value is move constructed in place in the source @ref
556 /// option. The old value in the source @ref option is destroyed in place.
557 ///
558 /// If both the source and destination @ref option are `none`, both remain
559 /// `none`.
560 ///
561 /// This function is `noexcept` if the contained value type is nothrow
562 /// move assignable, nothrow move constructible, and nothrow destructible.
563 ///
564 /// ## Example
565 /// ```
566 /// option<int> opt1{42};
567 /// option<int> opt2{};
568 ///
569 /// opt2 = std::move(opt1);
570 ///
571 /// assert(!opt1);
572 /// assert(opt2);
573 /// assert(*opt2 == 42);
574 ///
575 /// opt1 = std::move(opt2);
576 ///
577 /// assert(!opt2);
578 /// assert(opt1);
579 /// assert(*opt1 == 42);
580 /// ```
581 12 constexpr option& operator=(option&&)
582 #ifndef DOXYGEN
583 noexcept(detail::traits<T>::is_nothrow_move_assignable &&
584 detail::traits<T>::is_nothrow_move_constructible &&
585 detail::traits<T>::is_nothrow_destructible) = default;
586 #else
587 CONDITIONALLY_NOEXCEPT;
588 #endif
589
590 /// @brief `none` assignment operator
591 ///
592 /// @details
593 /// If the @ref option contains a value, the value is destroyed in place.
594 /// If the @ref option is already `none`, this function has no effect.
595 ///
596 /// This function is `noexcept` if the contained value type is nothrow
597 /// destructible.
598 ///
599 /// ## Example
600 /// ```
601 /// option<int> opt{42};
602 ///
603 /// opt = none;
604 ///
605 /// assert(!opt);
606 /// ```
607 1 constexpr option& operator=([[maybe_unused]] none_t null)
608 #ifndef DOXYGEN
609 noexcept(detail::traits<T>::is_nothrow_destructible)
610 #else
611 CONDTIONALLY_NOEXCEPT
612 #endif
613 {
614 1 opt_().template emplace<0>();
615 1 return *this;
616 }
617
618 /// @brief `std::nullopt` assignment operator
619 ///
620 /// @details
621 /// If the @ref option contains a value, the value is destroyed in place.
622 /// If the @ref option is already `none`, this function has no effect.
623 ///
624 /// This function is `noexcept` if the contained value type is nothrow
625 /// destructible.
626 ///
627 /// ## Example
628 /// ```
629 /// option<int> opt{42};
630 ///
631 /// opt = std::nullopt;
632 ///
633 /// assert(!opt);
634 /// ```
635 constexpr option& operator=([[maybe_unused]] std::nullopt_t null)
636 #ifndef DOXYGEN
637 noexcept(detail::traits<T>::is_nothrow_destructible)
638 #else
639 CONDITIONALLY_NOEXCEPT
640 #endif
641 {
642 opt_().template emplace<0>();
643 return *this;
644 }
645
646 /// @brief `nullptr` assignment operator
647 ///
648 /// @details
649 /// Sets an lvalue reference @ref option to `none`.
650 ///
651 /// This function only participates in overload resolution if the contained
652 /// value type is an lvalue reference.
653 ///
654 /// ## Example
655 /// ```
656 /// int value = 42;
657 /// option<int&> opt{value};
658 ///
659 /// opt = nullptr;
660 ///
661 /// assert(!opt);
662 /// ```
663 constexpr option& operator=([[maybe_unused]] std::nullptr_t null) noexcept
664 #ifndef DOXYGEN
665 requires(std::is_lvalue_reference_v<T>)
666 #endif
667 {
668 opt_().template emplace<0>();
669 return *this;
670 }
671
672 /// @brief Value assignment operator
673 ///
674 /// @details
675 /// Sets the @ref option to contain the provided value, converted to `T`.
676 /// If the @ref option holds a value (is not `none`) before the assigment,
677 /// the value is directly assigned the forwarded source value. If the @ref
678 /// option is `none`, a new value is constructed in place from the
679 /// forwarded source value.
680 ///
681 /// This function only participates in overload resolution if:
682 /// * The source value is not an @ref option
683 /// * `T` is constructible from `U`
684 /// * `T` is assignable from `U`
685 /// * `T` is not scalar or `U` is not equivalent to `T`
686 ///
687 /// ## Example
688 /// ```
689 /// option<long long> opt{};
690 ///
691 /// opt = 42;
692 ///
693 /// assert(opt);
694 ///
695 /// assert(*opt == 42);
696 /// ```
697 template <typename U>
698 #ifndef DOXYGEN
699 requires(
700 !detail::is_option_v<std::remove_cvref_t<U>> &&
701 std::is_constructible_v<variant<void, T>, std::in_place_index_t<1>, U &&> &&
702 detail::traits<T>::template is_assignable<U &&> &&
703 (!std::is_scalar_v<value_type> || !std::is_same_v<T, std::decay_t<U>>))
704 #endif
705 1 constexpr option& operator=(U&& value) {
706
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (opt_().index() == 1) {
707 opt_()[index<1>] = std::forward<U>(value);
708 } else {
709 1 opt_().template emplace<1>(std::forward<U>(value));
710 }
711 1 return *this;
712 }
713
714 /// @brief Pointer assignment operator
715 ///
716 /// @details
717 /// The destination @ref option is assigned such that it contains an lvalue
718 /// reference that the source pointer points to. If the pointer is null,
719 /// the destination @ref option will be `none`.
720 ///
721 /// This function only participates in overload resolution if `T` is an
722 /// lvalue reference and the pointer `U*` can be implicitly converted to
723 /// `pointer`.
724 ///
725 /// ## Example
726 /// ```
727 /// int value = 42;
728 /// int* ptr = &value;
729 ///
730 /// option<int&> opt{};
731 ///
732 /// opt = ptr;
733 ///
734 /// assert(opt)
735 ///
736 /// assert(opt == ptr);
737 /// ```
738 template <typename U>
739 #ifndef DOXYGEN
740 requires(std::is_lvalue_reference_v<value_type> &&
741 std::is_convertible_v<U*, pointer>)
742 #endif
743 2 constexpr option& operator=(U* ptr) noexcept {
744
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (ptr == nullptr) {
745 1 opt_().template emplace<0>();
746 } else {
747 1 opt_().template emplace<1>(*ptr);
748 }
749 2 return *this;
750 }
751
752 /// @brief Converting copy assignment operator
753 ///
754 /// @details
755 /// This function performs copy assignment just like the standard copy
756 /// assignment operator, but it also performs conversion from the value
757 /// contained in the source @ref option to the value type of contained
758 /// in the destination @ref option.
759 ///
760 /// This function only participates in overload resolution if `T` is not
761 /// construcitble from, convertible from, or assignable from any cvref
762 /// qualified form of `option<U>`, and `T` is both constructible and
763 /// assignable from `U`.
764 ///
765 /// ## Example
766 /// ```
767 /// option<float> opt1{3.14};
768 /// option<int> opt2{};
769 ///
770 /// opt2 = opt1;
771 ///
772 /// assert(opt2);
773 ///
774 /// assert(*opt2 == 3);
775 /// ```
776 template <typename U>
777 #ifndef DOXYGEN
778 requires(!detail::traits<T>::template is_constructible<option<U>&> &&
779 !detail::traits<T>::template is_constructible<const option<U>&> &&
780 !detail::traits<T>::template is_constructible<option<U> &&> &&
781 !detail::traits<T>::template is_constructible<const option<U> &&> &&
782 !detail::traits<T>::template is_convertible_from<option<U>&> &&
783 !detail::traits<T>::template is_convertible_from<const option<U>&> &&
784 !detail::traits<T>::template is_convertible_from<option<U> &&> &&
785 !detail::traits<T>::template is_convertible_from<const option<U> &&> &&
786 !detail::traits<T>::template is_assignable<option<U>&> &&
787 !detail::traits<T>::template is_assignable<const option<U>&> &&
788 !detail::traits<T>::template is_assignable<option<U> &&> &&
789 !detail::traits<T>::template is_assignable<const option<U> &&> &&
790 (std::is_lvalue_reference_v<T> ||
791 detail::traits<T>::template is_constructible<
792 typename detail::traits<U>::const_reference>) &&
793 detail::traits<T>::template is_assignable<
794 typename detail::traits<U>::const_reference>)
795 #endif
796 constexpr option& operator=(const option<U>& value) {
797 if (value.has_value()) {
798 opt_().template emplace<1>(*value);
799 } else {
800 opt_().template emplace<0>();
801 }
802 return *this;
803 }
804
805 /// @brief Converting move assignment operator
806 ///
807 /// @details
808 /// This function performs move assignment just like the standard move
809 /// assignment operator, but it also performs conversion from the value
810 /// contained in the source @ref option to the value type of contained
811 /// in the destination @ref option.
812 ///
813 /// This function only participates in overload resolution if `T` is not
814 /// construcitble from, convertible from, or assignable from any cvref
815 /// qualified form of `option<U>`, and `T` is both constructible and
816 /// assignable from `U`.
817 ///
818 /// ## Example
819 /// ```
820 /// option<float> opt1{3.14};
821 /// option<int> opt2{};
822 ///
823 /// opt2 = std::move(opt1);
824 ///
825 /// assert(opt2);
826 ///
827 /// assert(*opt2 == 3);
828 /// ```
829 template <typename U>
830 #ifndef DOXYGEN
831 requires(!detail::traits<T>::template is_constructible<option<U>&> &&
832 !detail::traits<T>::template is_constructible<const option<U>&> &&
833 !detail::traits<T>::template is_constructible<option<U> &&> &&
834 !detail::traits<T>::template is_constructible<const option<U> &&> &&
835 !detail::traits<T>::template is_convertible_from<option<U>&> &&
836 !detail::traits<T>::template is_convertible_from<const option<U>&> &&
837 !detail::traits<T>::template is_convertible_from<option<U> &&> &&
838 !detail::traits<T>::template is_convertible_from<const option<U> &&> &&
839 !detail::traits<T>::template is_assignable<option<U>&> &&
840 !detail::traits<T>::template is_assignable<const option<U>&> &&
841 !detail::traits<T>::template is_assignable<option<U> &&> &&
842 !detail::traits<T>::template is_assignable<const option<U> &&> &&
843 (std::is_lvalue_reference_v<T> ||
844 detail::traits<T>::template is_constructible<
845 typename detail::traits<U>::rvalue_reference>) &&
846 detail::traits<T>::template is_assignable<
847 typename detail::traits<U>::rvalue_reference>)
848 #endif
849 constexpr option& operator=(option<U>&& value) {
850 if (value.has_value()) {
851 opt_().template emplace<1>(*std::move(value));
852 } else {
853 opt_().template emplace<0>();
854 }
855 return *this;
856 }
857
858 /// @brief Implicit conversion to `bool`.
859 ///
860 /// @details
861 /// This implicit conversion allows an @ref option to be used directly in
862 /// a condition to check if the @ref option contains a value.
863 ///
864 /// ## Example
865 /// ```
866 /// option<int> opt1{};
867 /// option<int> opt2{42};
868 ///
869 /// if (opt1) {
870 /// assert(false);
871 /// } else {
872 /// assert(true);
873 /// }
874 ///
875 /// if (opt2) {
876 /// assert(true);
877 /// } else {
878 /// assert(false);
879 /// }
880 /// ```
881 // NOLINTNEXTLINE(hicpp-explicit-conversions)
882 2 constexpr operator bool() const noexcept { return opt_().index() != 0; }
883
884 /// @brief Conversion to raw pointer.
885 ///
886 /// @details
887 /// This conversion allows an @ref option of an lvalue to be converted into
888 /// a raw pointer, where the resulting pointer points to the referenced
889 /// value or is null if the @ref option is none.
890 ///
891 /// This conversion only participates in overload resolution if `T` is an
892 /// lvalue reference and `pointer` can be cast to `U*`.
893 ///
894 /// This conversion is explicit if `pointer` is not implicitly convertible
895 /// to `U*`.
896 ///
897 /// ## Example
898 /// ```
899 /// int value = 42;
900 ///
901 /// option<int&> opt{value};
902 ///
903 /// int* ptr = opt;
904 ///
905 /// assert(ptr == &value);
906 /// ```
907 template <typename U>
908 #ifndef DOXYGEN
909 requires(std::is_lvalue_reference_v<T> &&
910 requires(pointer src, U* dst) { dst = static_cast<U*>(src); })
911 explicit(!std::is_convertible_v<pointer, U*>)
912 #else
913 CONDITIONALLY_EXPLICIT
914 #endif
915 constexpr
916 // NOLINTNEXTLINE(hicpp-explicit-conversions)
917 2 operator U*() const noexcept {
918
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (opt_().index() == 0) {
919 1 return nullptr;
920 } else {
921 1 return static_cast<U*>(&opt_()[index<1>]);
922 }
923 }
924
925 /// @brief Returns true if the @ref option contains a value.
926 ///
927 /// @details
928 /// ## Example
929 /// ```
930 /// option<int> opt1{};
931 /// option<int> opt2{42};
932 ///
933 /// assert(opt1.has_value() == false);
934 ///
935 /// assert(opt2.has_value() == true);
936 /// ```
937 422 [[nodiscard]] constexpr bool has_value() const noexcept { return opt_().index() != 0; }
938
939 /// @brief Returns true if the @ref option contains a value.
940 ///
941 /// @details
942 /// ## Example
943 /// ```
944 /// option<int> opt1{};
945 /// option<int> opt2{42};
946 ///
947 /// assert(opt1.is_some() == false);
948 ///
949 /// assert(opt2.is_some() == true);
950 /// ```
951 [[nodiscard]] constexpr bool is_some() const noexcept { return opt_().index() != 0; }
952
953 /// @brief Returns true if the @ref options does not contain a value.
954 ///
955 /// @details
956 /// ## Example
957 /// ```
958 /// option<int> opt1{};
959 /// option<int> opt2{42};
960 ///
961 /// assert(opt1.is_none() == true);
962 ///
963 /// assert(opt2.is_none() == false);
964 /// ```
965 [[nodiscard]] constexpr bool is_none() const noexcept { return opt_().index() == 0; }
966
967 /// @brief Accesses the value contained in the @ref option.
968 ///
969 /// @details
970 /// This operator does not check if the @ref option contains a value. Use
971 /// of this operator when the @ref option is `none` results in undefined
972 /// behavior.
973 ///
974 /// ## Example
975 /// ```
976 /// option<int> opt{42};
977 ///
978 /// assert(*opt == 42);
979 /// ```
980 38 [[nodiscard]] constexpr reference operator*() & noexcept { return opt_()[index<1>]; }
981
982 /// @brief Accesses the value contained in the @ref option.
983 ///
984 /// @details
985 /// This operator does not check if the @ref option contains a value. Use
986 /// of this operator when the @ref option is `none` results in undefined
987 /// behavior.
988 ///
989 /// ## Example
990 /// ```
991 /// const option<int> opt{42};
992 ///
993 /// assert(*opt == 42);
994 /// ```
995 47 [[nodiscard]] constexpr const_reference operator*() const& noexcept {
996 47 return opt_()[index<1>];
997 }
998
999 /// @brief Accesses the value contained in the @ref option.
1000 ///
1001 /// @details
1002 /// This operator does not check if the @ref option contains a value. Use
1003 /// of this operator when the @ref option is `none` results in undefined
1004 /// behavior.
1005 ///
1006 /// ## Example
1007 /// ```
1008 /// option<int> opt{42};
1009 ///
1010 /// assert(*std::move(opt) == 42);
1011 /// ```
1012 1 [[nodiscard]] constexpr rvalue_reference operator*() && {
1013 1 return std::move(*this).opt_()[index<1>];
1014 }
1015
1016 /// @brief Accesses the value contained in the @ref option.
1017 ///
1018 /// @details
1019 /// This operator does not check if the @ref option contains a value. Use
1020 /// of this operator when the @ref option is `none` results in undefined
1021 /// behavior.
1022 ///
1023 /// ## Example
1024 /// ```
1025 /// const option<int> opt{42};
1026 ///
1027 /// assert(*std::move(opt) == 42);
1028 /// ```
1029 [[nodiscard]] constexpr const_rvalue_reference operator*() const&& {
1030 return std::move(*this).opt_()[index<1>];
1031 }
1032
1033 /// @brief Accesses members of the value contained in the @ref option.
1034 ///
1035 /// @details
1036 /// This operator does not check if the @ref option contains a value. Use
1037 /// of this operator when the @ref option is `none` results in undefined
1038 /// behavior.
1039 ///
1040 /// ## Example
1041 /// ```
1042 /// option<std::string> opt{"hello"};
1043 ///
1044 /// assert(opt->size() == 5);
1045 /// ```
1046 [[nodiscard]] constexpr pointer operator->() noexcept {
1047 return opt_().template get_if<1>();
1048 }
1049
1050 /// @brief Accesses members of the value contained in the @ref option.
1051 ///
1052 /// @details
1053 /// This operator does not check if the @ref option contains a value. Use
1054 /// of this operator when the @ref option is `none` results in undefined
1055 /// behavior.
1056 ///
1057 /// ## Example
1058 /// ```
1059 /// const option<std::string> opt{"hello"};
1060 ///
1061 /// assert(opt->size() == 5);
1062 /// ```
1063 [[nodiscard]] constexpr const_pointer operator->() const noexcept {
1064 return opt_().template get_if<1>();
1065 }
1066
1067 /// @brief Accesses the value contained in the @ref option.
1068 ///
1069 /// @details
1070 /// This function first checks if the @ref option contains a value before
1071 /// attempting to access the value. If the @ref option is `none`, then this
1072 /// function throws an exception.
1073 ///
1074 /// ## Example
1075 /// ```
1076 /// option<int> opt{42};
1077 ///
1078 /// assert(opt.value() == 42);
1079 /// ```
1080 ///
1081 /// @throws bad_option_access Thrown if the @ref option is `none`.
1082 2 [[nodiscard]] constexpr reference value() & {
1083
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
2 if (opt_().index() == 0) { throw bad_option_access(); }
1084 2 return opt_()[index<1>];
1085 }
1086
1087 /// @brief Accesses the value contained in the @ref option.
1088 ///
1089 /// @details
1090 /// This function first checks if the @ref option contains a value before
1091 /// attempting to access the value. If the @ref option is `none`, then this
1092 /// function throws an exception.
1093 ///
1094 /// ## Example
1095 /// ```
1096 /// const option<int> opt{42};
1097 ///
1098 /// assert(opt.value() == 42);
1099 /// ```
1100 ///
1101 /// @throws bad_option_access Thrown if the @ref option is `none`.
1102 [[nodiscard]] constexpr const_reference value() const& {
1103 if (opt_().index() == 0) { throw bad_option_access(); }
1104 return opt_()[index<1>];
1105 }
1106
1107 /// @brief Accesses the value contained in the @ref option.
1108 ///
1109 /// @details
1110 /// This function first checks if the @ref option contains a value before
1111 /// attempting to access the value. If the @ref option is `none`, then this
1112 /// function throws an exception.
1113 ///
1114 /// ## Example
1115 /// ```
1116 /// option<int> opt{42};
1117 ///
1118 /// assert(std::move(opt).value() == 42);
1119 /// ```
1120 ///
1121 /// @throws bad_option_access Thrown if the @ref option is `none`.
1122 [[nodiscard]] constexpr rvalue_reference value() && {
1123 if (opt_().index() == 0) { throw bad_option_access(); }
1124 return std::move(*this).opt_()[index<1>];
1125 }
1126
1127 /// @brief Accesses the value contained in the @ref option.
1128 ///
1129 /// @details
1130 /// This function first checks if the @ref option contains a value before
1131 /// attempting to access the value. If the @ref option is `none`, then this
1132 /// function throws an exception.
1133 ///
1134 /// ## Example
1135 /// ```
1136 /// const option<int> opt{42};
1137 ///
1138 /// assert(std::move(opt).value() == 42);
1139 /// ```
1140 ///
1141 /// @throws bad_option_access Thrown if the @ref option is `none`.
1142 [[nodiscard]] constexpr rvalue_reference value() const&& {
1143 if (opt_().index() == 0) { throw bad_option_access(); }
1144 return std::move(*this).opt_()[index<1>];
1145 }
1146
1147 /// @brief Gets the @ref option value with a default used for `none`.
1148 ///
1149 /// @details
1150 /// If the @ref option contains a value, a copy of the value is returned.
1151 /// If the @ref option is `none`, the provided default value is returned
1152 /// as `static_cast<T>(std::forward<U>(default_value))`.
1153 ///
1154 /// ## Example
1155 /// ```
1156 /// option<int> opt1{};
1157 /// option<int> opt2{42};
1158 ///
1159 /// assert(opt1.value_or(0) == 0);
1160 ///
1161 /// assert(opt2.value_or(0) == 42);
1162 /// ```
1163 ///
1164 /// @param default_value The value to use if the @ref option is `none`.
1165 template <typename U>
1166 8 [[nodiscard]] constexpr value_type value_or(U&& default_value) const& {
1167
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
8 if (opt_().index() != 0) {
1168 4 return opt_()[index<1>];
1169 } else {
1170 4 return static_cast<value_type>(std::forward<U>(default_value));
1171 }
1172 }
1173
1174 /// @brief Gets the @ref option value with a default used for `none`.
1175 ///
1176 /// @details
1177 /// If the @ref option contains a value, the moved value is returned. If
1178 /// the @ref option is `none`, the provided default value is returned as
1179 /// `static_cast<T>(std::forward<U>(default_value))`.
1180 ///
1181 /// ## Example
1182 /// ```
1183 /// option<int> opt1{};
1184 /// option<int> opt2{42};
1185 ///
1186 /// assert(std::move(opt1).value_or(0) == 0);
1187 ///
1188 /// assert(std::move(opt2).value_or(0) == 42);
1189 /// ```
1190 ///
1191 /// @param default_value The value to use if the @ref option is `none`.
1192 template <typename U>
1193 [[nodiscard]] constexpr value_type value_or(U&& default_value) && {
1194 if (opt_().index() != 0) {
1195 return std::move(*this).opt_()[index<1>];
1196 } else {
1197 return static_cast<value_type>(std::forward<U>(default_value));
1198 }
1199 }
1200
1201 /// @brief Gets the @ref option value with a default used for `none`.
1202 ///
1203 /// @details
1204 /// If the @ref option contains a value, the copied value is returned. If
1205 /// the @ref option is `none`, the result of invoking `f` is returned. The
1206 /// returned value of `f` is also explicitly cast to `value_type` before
1207 /// return.
1208 ///
1209 /// This function might be preferred over `.value_or(default_value)` when
1210 /// the default value is expensive to create or move. This function allows
1211 /// the default value to never be instantiated if the @ref option is not
1212 /// `none`.
1213 ///
1214 /// ## Example
1215 /// ```
1216 /// option<int> opt1{};
1217 /// option<int> opt2{42};
1218 ///
1219 /// assert(opt1.value_or_else([] { return 0; }) == 0);
1220 ///
1221 /// assert(opt2.value_or_else([] { return 0; }) == 42);
1222 /// ```
1223 ///
1224 /// @param f A callable that creates a default value.
1225 template <typename F>
1226 8 [[nodiscard]] constexpr value_type value_or_else(F&& f) const& {
1227
2/2
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 2 times.
8 if (opt_().index() != 0) {
1228 4 return opt_()[index<1>];
1229 } else {
1230 4 return static_cast<value_type>(invoke(std::forward<F>(f)));
1231 }
1232 }
1233
1234 /// @brief Gets the @ref option value with a default used for `none`.
1235 ///
1236 /// @details
1237 /// If the @ref option contains a value, the moved value is returned. If
1238 /// the @ref option is `none`, the result of invoking `f` is returned. The
1239 /// returned value of `f` is also explicitly cast to `value_type` before
1240 /// return.
1241 ///
1242 /// This function might be preferred over `.value_or(default_value)` when
1243 /// the default value is expensive to create or move. This function allows
1244 /// the default value to never be instantiated if the @ref option is not
1245 /// `none`.
1246 ///
1247 /// ## Example
1248 /// ```
1249 /// option<int> opt1{};
1250 /// option<int> opt2{42};
1251 ///
1252 /// assert(std::move(opt1).value_or_else([] { return 0; }) == 0);
1253 ///
1254 /// assert(std::move(opt2).value_or_else([] { return 0; }) == 42);
1255 /// ```
1256 ///
1257 /// @param f A callable that creates a default value.
1258 template <typename F>
1259 [[nodiscard]] constexpr value_type value_or_else(F&& f) && {
1260 if (opt_().index() != 0) {
1261 return std::move(*this).opt_()[index<1>];
1262 } else {
1263 return static_cast<value_type>(invoke(std::forward<F>(f)));
1264 }
1265 }
1266
1267 /// @brief Accesses the value contained in the @ref option.
1268 ///
1269 /// @details
1270 /// This function first checks if the @ref option contains a value before
1271 /// attempting to access the value. If the @ref option is `none`, then this
1272 /// function throws an exception.
1273 ///
1274 /// ## Example
1275 /// ```
1276 /// option<int> opt{42};
1277 ///
1278 /// assert(opt.some() == 42);
1279 /// ```
1280 ///
1281 /// @throws bad_option_access Thrown if the @ref option is `none`.
1282 [[nodiscard]] constexpr reference some() & { return value(); }
1283
1284 /// @brief Accesses the value contained in the @ref option.
1285 ///
1286 /// @details
1287 /// This function first checks if the @ref option contains a value before
1288 /// attempting to access the value. If the @ref option is `none`, then this
1289 /// function throws an exception.
1290 ///
1291 /// ## Example
1292 /// ```
1293 /// const option<int> opt{42};
1294 ///
1295 /// assert(opt.some() == 42);
1296 /// ```
1297 ///
1298 /// @throws bad_option_access Thrown if the @ref option is `none`.
1299 [[nodiscard]] constexpr const_reference some() const& { return value(); }
1300
1301 /// @brief Accesses the value contained in the @ref option.
1302 ///
1303 /// @details
1304 /// This function first checks if the @ref option contains a value before
1305 /// attempting to access the value. If the @ref option is `none`, then this
1306 /// function throws an exception.
1307 ///
1308 /// ## Example
1309 /// ```
1310 /// option<int> opt{42};
1311 ///
1312 /// assert(std::move(opt).some() == 42);
1313 /// ```
1314 ///
1315 /// @throws bad_option_access Thrown if the @ref option is `none`.
1316 [[nodiscard]] constexpr rvalue_reference some() && { return std::move(*this).value(); }
1317
1318 /// @brief Accesses the value contained in the @ref option.
1319 ///
1320 /// @details
1321 /// This function first checks if the @ref option contains a value before
1322 /// attempting to access the value. If the @ref option is `none`, then this
1323 /// function throws an exception.
1324 ///
1325 /// ## Example
1326 /// ```
1327 /// const option<int> opt{42};
1328 ///
1329 /// assert(std::move(opt).some() == 42);
1330 /// ```
1331 ///
1332 /// @throws bad_option_access Thrown if the @ref option is `none`.
1333 [[nodiscard]] constexpr rvalue_reference some() const&& {
1334 return std::move(*this).value();
1335 }
1336
1337 /// @brief Gets the @ref option value with a default used for `none`.
1338 ///
1339 /// @details
1340 /// If the @ref option contains a value, a copy of the value is returned.
1341 /// If the @ref option is `none`, the provided default value is returned
1342 /// as `static_cast<T>(std::forward<U>(default_value))`.
1343 ///
1344 /// ## Example
1345 /// ```
1346 /// option<int> opt1{};
1347 /// option<int> opt2{42};
1348 ///
1349 /// assert(opt1.some_or(0) == 0);
1350 ///
1351 /// assert(opt2.some_or(0) == 42);
1352 /// ```
1353 ///
1354 /// @param default_value The value to use if the @ref option is `none`.
1355 template <typename U>
1356 [[nodiscard]] constexpr value_type some_or(U&& default_value) const& {
1357 return value_or(std::forward<U>(default_value));
1358 }
1359
1360 /// @brief Gets the @ref option value with a default used for `none`.
1361 ///
1362 /// @details
1363 /// If the @ref option contains a value, the moved value is returned. If
1364 /// the @ref option is `none`, the provided default value is returned as
1365 /// `static_cast<T>(std::forward<U>(default_value))`.
1366 ///
1367 /// ## Example
1368 /// ```
1369 /// option<int> opt1{};
1370 /// option<int> opt2{42};
1371 ///
1372 /// assert(std::move(opt1).some_or(0) == 0);
1373 ///
1374 /// assert(std::move(opt2).some_or(0) == 42);
1375 /// ```
1376 ///
1377 /// @param default_value The value to use if the @ref option is `none`.
1378 template <typename U>
1379 [[nodiscard]] constexpr value_type some_or(U&& default_value) && {
1380 return std::move(*this).value_or(std::forward<U>(default_value));
1381 }
1382
1383 /// @brief Gets the @ref option value with a default used for `none`.
1384 ///
1385 /// @details
1386 /// If the @ref option contains a value, the copied value is returned. If
1387 /// the @ref option is `none`, the result of invoking `f` is returned. The
1388 /// returned value of `f` is also explicitly cast to `value_type` before
1389 /// return.
1390 ///
1391 /// This function might be preferred over `.value_or(default_value)` when
1392 /// the default value is expensive to create or move. This function allows
1393 /// the default value to never be instantiated if the @ref option is not
1394 /// `none`.
1395 ///
1396 /// ## Example
1397 /// ```
1398 /// option<int> opt1{};
1399 /// option<int> opt2{42};
1400 ///
1401 /// assert(opt1.some_or_else([] { return 0; }) == 0);
1402 ///
1403 /// assert(opt2.some_or_else([] { return 0; }) == 42);
1404 /// ```
1405 ///
1406 /// @param f A callable that creates a default value.
1407 template <typename F>
1408 [[nodiscard]] constexpr value_type some_or_else(F&& f) const& {
1409 return value_or_else(std::forward<F>(f));
1410 }
1411
1412 /// @brief Gets the @ref option value with a default used for `none`.
1413 ///
1414 /// @details
1415 /// If the @ref option contains a value, the moved value is returned. If
1416 /// the @ref option is `none`, the result of invoking `f` is returned. The
1417 /// returned value of `f` is also explicitly cast to `value_type` before
1418 /// return.
1419 ///
1420 /// This function might be preferred over `.value_or(default_value)` when
1421 /// the default value is expensive to create or move. This function allows
1422 /// the default value to never be instantiated if the @ref option is not
1423 /// `none`.
1424 ///
1425 /// ## Example
1426 /// ```
1427 /// option<int> opt1{};
1428 /// option<int> opt2{42};
1429 ///
1430 /// assert(std::move(opt1).some_or_else([] { return 0; }) == 0);
1431 ///
1432 /// assert(std::move(opt2).some_or_else([] { return 0; }) == 42);
1433 /// ```
1434 ///
1435 /// @param f A callable that creates a default value.
1436 template <typename F>
1437 [[nodiscard]] constexpr value_type some_or_else(F&& f) && {
1438 return std::move(*this).value_or_else(std::forward<F>(f));
1439 }
1440
1441 /// @brief Converts an @ref option to a @ref result.
1442 ///
1443 /// @details
1444 /// This function constructs and returns a @ref result such that the
1445 /// contained value of the @ref option becomes the `ok` value of the
1446 /// @ref result. If the @ref option is `none`, the provided default
1447 /// value is used as the `error` value of the @ref result.
1448 ///
1449 /// The default error value is always converted to a non-reference. If a
1450 /// reference is desired, use the overload of this function that accepts
1451 /// an @ref error_t.
1452 ///
1453 /// This function only participates in overload resolution if `E` is not
1454 /// an @ref error_t.
1455 ///
1456 /// ## Example
1457 /// ```
1458 /// option<int> opt1{};
1459 /// option<int> opt2{42};
1460 ///
1461 /// result<int, int> res1 = opt1.ok_or(-42);
1462 /// result<int, int> res2 = opt2.ok_or(-42);
1463 ///
1464 /// assert(!res1.has_value());
1465 /// assert(res1.error() == -42);
1466 ///
1467 /// assert(res2.has_value());
1468 /// assert(*res2 == 42);
1469 /// ```
1470 ///
1471 /// @param err The default error value used if the @ref option is `none`.
1472 template <typename E>
1473 2 [[nodiscard]] constexpr result<T, std::remove_cvref_t<E>> ok_or(E&& err) const& {
1474
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (opt_().index() != 0) {
1475 if constexpr (std::is_void_v<T>) {
1476 return {};
1477 } else {
1478 1 return opt_()[index<1>];
1479 }
1480 } else {
1481 1 return result<T, std::remove_cvref_t<E>>{in_place_error, std::forward<E>(err)};
1482 }
1483 }
1484
1485 /// @brief Converts an @ref option to a @ref result.
1486 ///
1487 /// @details
1488 /// This function constructs and returns a @ref result such that the
1489 /// contained value of the @ref option becomes the `ok` value of the
1490 /// @ref result. If the @ref option is `none`, the provided default
1491 /// value is used as the `error` value of the @ref result.
1492 ///
1493 /// The default error value is always converted to a non-reference. If a
1494 /// reference is desired, use the overload of this function that accepts
1495 /// an @ref error_t.
1496 ///
1497 /// This function only participates in overload resolution if `E` is not
1498 /// an @ref error_t.
1499 ///
1500 /// ## Example
1501 /// ```
1502 /// option<int> opt1{};
1503 /// option<int> opt2{42};
1504 ///
1505 /// result<int, int> res1 = std::move(opt1).ok_or(-42);
1506 /// result<int, int> res2 = std::move(opt2).ok_or(-42);
1507 ///
1508 /// assert(!res1.has_value());
1509 /// assert(res1.error() == -42);
1510 ///
1511 /// assert(res2.has_value());
1512 /// assert(*res2 == 42);
1513 /// ```
1514 ///
1515 /// @param err The default error value used if the @ref option is `none`.
1516 template <typename E>
1517 [[nodiscard]] constexpr result<T, std::remove_cvref_t<E>> ok_or(E&& err) && {
1518 if (opt_().index() != 0) {
1519 if constexpr (std::is_void_v<T>) {
1520 return {};
1521 } else {
1522 return std::move(*this).opt_()[index<1>];
1523 }
1524 } else {
1525 return result<T, std::remove_cvref_t<E>>{in_place_error, std::forward<E>(err)};
1526 }
1527 }
1528
1529 /// @brief Converts an @ref option to a @ref result.
1530 ///
1531 /// @details
1532 /// This function constructs and returns a @ref result such that the
1533 /// contained value of the @ref option becomes the `ok` value of the
1534 /// @ref result. If the @ref option is `none`, the provided error value
1535 /// is used as the error value of the @ref result.
1536 ///
1537 /// ## Example
1538 /// ```
1539 /// option<int> opt1{};
1540 /// option<int> opt2{42};
1541 ///
1542 /// const auto err = error<int>(-42);
1543 ///
1544 /// result<int, int> res1 = opt1.ok_or(err);
1545 /// result<int, int> res2 = opt2.ok_or(err);
1546 ///
1547 /// assert(!res1.has_value());
1548 /// assert(res1.error() == -42);
1549 ///
1550 /// assert(res2.has_value());
1551 /// assert(*res2 == 42);
1552 /// ```
1553 ///
1554 /// @param err The default error value used if the @ref option is `none`.
1555 template <typename E>
1556 [[nodiscard]] constexpr result<T, E> ok_or(const result<never, E>& err) const& {
1557 if (opt_().index() != 0) {
1558 if constexpr (std::is_void_v<T>) {
1559 return {};
1560 } else {
1561 return opt_()[index<1>];
1562 }
1563 } else {
1564 return err;
1565 }
1566 }
1567
1568 /// @brief Converts an @ref option to a @ref result.
1569 ///
1570 /// @details
1571 /// This function constructs and returns a @ref result such that the
1572 /// contained value of the @ref option becomes the `ok` value of the
1573 /// @ref result. If the @ref option is `none`, the provided error value
1574 /// is used as the error value of the @ref result.
1575 ///
1576 /// ## Example
1577 /// ```
1578 /// option<int> opt1{};
1579 /// option<int> opt2{42};
1580 ///
1581 /// const auto err = error<int>(-42);
1582 ///
1583 /// result<int, int> res1 = std::move(opt1).ok_or(err);
1584 /// result<int, int> res2 = std::move(opt2).ok_or(err);
1585 ///
1586 /// assert(!res1.has_value());
1587 /// assert(res1.error() == -42);
1588 ///
1589 /// assert(res2.has_value());
1590 /// assert(*res2 == 42);
1591 /// ```
1592 ///
1593 /// @param err The default error value used if the @ref option is `none`.
1594 template <typename E>
1595 [[nodiscard]] constexpr result<T, E> ok_or(const result<never, E>& err) && {
1596 if (opt_().index() != 0) {
1597 if constexpr (std::is_void_v<T>) {
1598 return {};
1599 } else {
1600 return std::move(*this).opt_()[index<1>];
1601 }
1602 } else {
1603 return err;
1604 }
1605 }
1606
1607 /// @brief Converts an @ref option to a @ref result.
1608 ///
1609 /// @details
1610 /// This function constructs and returns a @ref result such that the
1611 /// contained value of the @ref option becomes the `ok` value of the
1612 /// @ref result. If the @ref option is `none`, the provided error value
1613 /// is used as the error value of the @ref result.
1614 ///
1615 /// ## Example
1616 /// ```
1617 /// option<int> opt1{};
1618 /// option<int> opt2{42};
1619 ///
1620 /// result<int, int> res1 = opt1.ok_or(error<int>(-42));
1621 /// result<int, int> res2 = opt2.ok_or(error<int>(-42));
1622 ///
1623 /// assert(!res1.has_value());
1624 /// assert(res1.error() == -42);
1625 ///
1626 /// assert(res2.has_value());
1627 /// assert(*res2 == 42);
1628 /// ```
1629 ///
1630 /// @param err The default error value used if the @ref option is `none`.
1631 template <typename E>
1632 [[nodiscard]] constexpr result<T, E> ok_or(result<never, E>&& err) const& {
1633 if (opt_().index() != 0) {
1634 if constexpr (std::is_void_v<T>) {
1635 return {};
1636 } else {
1637 return opt_()[index<1>];
1638 }
1639 } else {
1640 return std::move(err);
1641 }
1642 }
1643
1644 /// @brief Converts an @ref option to a @ref result.
1645 ///
1646 /// @details
1647 /// This function constructs and returns a @ref result such that the
1648 /// contained value of the @ref option becomes the `ok` value of the
1649 /// @ref result. If the @ref option is `none`, the provided error value
1650 /// is used as the error value of the @ref result.
1651 ///
1652 /// ## Example
1653 /// ```
1654 /// option<int> opt1{};
1655 /// option<int> opt2{42};
1656 ///
1657 /// result<int, int> res1 = std::move(opt1).ok_or(error<int>(-42));
1658 /// result<int, int> res2 = std::move(opt2).ok_or(error<int>(-42));
1659 ///
1660 /// assert(!res1.has_value());
1661 /// assert(res1.error() == -42);
1662 ///
1663 /// assert(res2.has_value());
1664 /// assert(*res2 == 42);
1665 /// ```
1666 ///
1667 /// @param err The default error value used if the @ref option is `none`.
1668 template <typename E>
1669 [[nodiscard]] constexpr result<T, E> ok_or(result<never, E>&& err) && {
1670 if (opt_().index() != 0) {
1671 if constexpr (std::is_void_v<T>) {
1672 return {};
1673 } else {
1674 return std::move(*this).opt_()[index<1>];
1675 }
1676 } else {
1677 return std::move(err);
1678 }
1679 }
1680
1681 /// @brief Converts an @ref option to a @ref result.
1682 ///
1683 /// @details
1684 /// This fucntion constructs and returns a @ref result such that the
1685 /// contained value of the @ref option becomes the `ok` value of the
1686 /// @ref result. If the @ref option is `none`, the result of invoking
1687 /// the provided callable is used as the error value of the @ref result.
1688 ///
1689 /// This function might be preferred over `.ok_or(error_value)` when the
1690 /// error type is expense to construct, copy, or move. This function allows
1691 /// the error value to never be instantiated if the @ref option is not
1692 /// `none`.
1693 ///
1694 /// ## Example
1695 /// ```
1696 /// option<int> opt1{};
1697 /// option<int> opt2{42};
1698 ///
1699 /// result<int, int> res1 = opt1.ok_or_else([] { return -42; });
1700 /// result<int, int> res2 = opt2.ok_or_else([] { return -42; });
1701 ///
1702 /// assert(!res1.has_value());
1703 /// assert(res1.error() == -42);
1704 ///
1705 /// assert(res2.has_value());
1706 /// assert(*res2 == 42);
1707 /// ```
1708 ///
1709 /// @param f A callable that creates a default error value.
1710 template <typename F>
1711 4 [[nodiscard]] constexpr result<T, std::invoke_result_t<F>> ok_or_else(F&& f) const& {
1712
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
4 if (opt_().index() != 0) {
1713 if constexpr (std::is_void_v<T>) {
1714 return {};
1715 } else {
1716 2 return opt_()[index<1>];
1717 }
1718 } else {
1719 return result<T, std::invoke_result_t<F>>(in_place_error,
1720
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
4 invoke(std::forward<F>(f)));
1721 }
1722 }
1723
1724 /// @brief Converts an @ref option to a @ref result.
1725 ///
1726 /// @details
1727 /// This fucntion constructs and returns a @ref result such that the
1728 /// contained value of the @ref option becomes the `ok` value of the
1729 /// @ref result. If the @ref option is `none`, the result of invoking
1730 /// the provided callable is used as the error value of the @ref result.
1731 ///
1732 /// This function might be preferred over `.ok_or(error_value)` when the
1733 /// error type is expense to construct, copy, or move. This function allows
1734 /// the error value to never be instantiated if the @ref option is not
1735 /// `none`.
1736 ///
1737 /// ## Example
1738 /// ```
1739 /// option<int> opt1{};
1740 /// option<int> opt2{42};
1741 ///
1742 /// result<int, int> res1 = std::move(opt1).ok_or_else([] { return -42; });
1743 /// result<int, int> res2 = std::move(opt2).ok_or_else([] { return -42; });
1744 ///
1745 /// assert(!res1.has_value());
1746 /// assert(res1.error() == -42);
1747 ///
1748 /// assert(res2.has_value());
1749 /// assert(*res2 == 42);
1750 /// ```
1751 ///
1752 /// @param f A callable that creates a default error value.
1753 template <typename F>
1754 [[nodiscard]] constexpr result<T, std::invoke_result_t<F>> ok_or_else(F&& f) && {
1755 if (opt_().index() != 0) {
1756 if constexpr (std::is_void_v<T>) {
1757 return {};
1758 } else {
1759 return std::move(*this).opt_()[index<1>];
1760 }
1761 } else {
1762 return result<T, std::invoke_result_t<F>>(in_place_error,
1763 invoke(std::forward<F>(f)));
1764 }
1765 }
1766
1767 /// @brief Converts an @ref option to a @ref result.
1768 ///
1769 /// @details
1770 /// This function constructs and returns a @ref result such that the
1771 /// contained value of the @ref option becomes the `error` value of the
1772 /// @ref result. If the @ref option is `none`, the provided default
1773 /// value is used as the `ok` value of the @ref result.
1774 ///
1775 /// The default ok value is always converted to a non-reference. If a
1776 /// reference is desired, use the overload of this function that accepts
1777 /// an @ref ok_t.
1778 ///
1779 /// This function only participates in overload resolution if `U` is not
1780 /// an @ref ok_t.
1781 ///
1782 /// ## Example
1783 /// ```
1784 /// option<int> opt1{};
1785 /// option<int> opt2{42};
1786 ///
1787 /// result<int, int> res1 = opt1.error_or(-42);
1788 /// result<int, int> res2 = opt2.error_or(-42);
1789 ///
1790 /// assert(res1.has_value());
1791 /// assert(*res1 == -42);
1792 ///
1793 /// assert(!res2.has_value());
1794 /// assert(res2.error() == 42);
1795 /// ```
1796 ///
1797 /// @param err The default ok value used if the @ref option is `none`.
1798 template <typename U>
1799 2 [[nodiscard]] constexpr result<std::remove_cvref_t<U>, T> error_or(U&& value) const& {
1800
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (opt_().index() != 0) {
1801 if constexpr (std::is_void_v<T>) {
1802 return result<std::remove_cvref_t<U>, T>{in_place_error};
1803 } else {
1804 1 return result<std::remove_cvref_t<U>, T>{in_place_error, opt_()[index<1>]};
1805 }
1806 } else {
1807 1 return result<std::remove_cvref_t<U>, T>{std::in_place, std::forward<U>(value)};
1808 }
1809 }
1810
1811 /// @brief Converts an @ref option to a @ref result.
1812 ///
1813 /// @details
1814 /// This function constructs and returns a @ref result such that the
1815 /// contained value of the @ref option becomes the `error` value of the
1816 /// @ref result. If the @ref option is `none`, the provided default
1817 /// value is used as the `ok` value of the @ref result.
1818 ///
1819 /// The default ok value is always converted to a non-reference. If a
1820 /// reference is desired, use the overload of this function that accepts
1821 /// an @ref ok_t.
1822 ///
1823 /// This function only participates in overload resolution if `U` is not
1824 /// an @ref ok_t.
1825 ///
1826 /// ## Example
1827 /// ```
1828 /// option<int> opt1{};
1829 /// option<int> opt2{42};
1830 ///
1831 /// result<int, int> res1 = std::move(opt1).error_or(-42);
1832 /// result<int, int> res2 = std::move(opt2).error_or(-42);
1833 ///
1834 /// assert(res1.has_value());
1835 /// assert(*res1 == -42);
1836 ///
1837 /// assert(!res2.has_value());
1838 /// assert(res2.error() == 42);
1839 /// ```
1840 ///
1841 /// @param err The default ok value used if the @ref option is `none`.
1842 template <typename U>
1843 [[nodiscard]] constexpr result<std::remove_cvref_t<U>, T> error_or(U&& value) && {
1844 if (opt_().index() != 0) {
1845 if constexpr (std::is_void_v<T>) {
1846 return result<std::remove_cvref_t<U>, T>{in_place_error};
1847 } else {
1848 return result<std::remove_cvref_t<U>, T>{in_place_error,
1849 std::move(*this).opt_()[index<1>]};
1850 }
1851 } else {
1852 return result<std::remove_cvref_t<U>, T>{std::in_place, std::forward<U>(value)};
1853 }
1854 }
1855
1856 /// @brief Converts an @ref option to a @ref result.
1857 ///
1858 /// @details
1859 /// This function constructs and returns a @ref result such that the
1860 /// contained value of the @ref option becomes the `error` value of the
1861 /// @ref result. If the @ref option is `none`, the provided default
1862 /// value is used as the `ok` value of the @ref result.
1863 ///
1864 /// ## Example
1865 /// ```
1866 /// option<int> opt1{};
1867 /// option<int> opt2{42};
1868 ///
1869 /// const auto value = ok<int>(-42);
1870 ///
1871 /// result<int, int> res1 = opt1.error_or(value);
1872 /// result<int, int> res2 = opt2.error_or(value);
1873 ///
1874 /// assert(res1.has_value());
1875 /// assert(*res1 == -42);
1876 ///
1877 /// assert(!res2.has_value());
1878 /// assert(res2.error() == 42);
1879 /// ```
1880 ///
1881 /// @param err The default ok value used if the @ref option is `none`.
1882 template <typename U>
1883 [[nodiscard]] constexpr result<U, T> error_or(const result<U, never>& value) const& {
1884 if (opt_().index() != 0) {
1885 if constexpr (std::is_void_v<T>) {
1886 return result<U, T>{in_place_error};
1887 } else {
1888 return result<U, T>{in_place_error, opt_()[index<1>]};
1889 }
1890 } else {
1891 return value;
1892 }
1893 }
1894
1895 /// @brief Converts an @ref option to a @ref result.
1896 ///
1897 /// @details
1898 /// This function constructs and returns a @ref result such that the
1899 /// contained value of the @ref option becomes the `error` value of the
1900 /// @ref result. If the @ref option is `none`, the provided default
1901 /// value is used as the `ok` value of the @ref result.
1902 ///
1903 /// ## Example
1904 /// ```
1905 /// option<int> opt1{};
1906 /// option<int> opt2{42};
1907 ///
1908 /// const auto value = ok<int>(-42);
1909 ///
1910 /// result<int, int> res1 = std::move(opt1).error_or(value);
1911 /// result<int, int> res2 = std::move(opt2).error_or(value);
1912 ///
1913 /// assert(res1.has_value());
1914 /// assert(*res1 == -42);
1915 ///
1916 /// assert(!res2.has_value());
1917 /// assert(res2.error() == 42);
1918 /// ```
1919 ///
1920 /// @param err The default ok value used if the @ref option is `none`.
1921 template <typename U>
1922 [[nodiscard]] constexpr result<U, T> error_or(const result<U, never>& value) && {
1923 if (opt_().index() != 0) {
1924 if constexpr (std::is_void_v<T>) {
1925 return result<U, T>{in_place_error};
1926 } else {
1927 return result<U, T>{in_place_error, std::move(*this).opt_()[index<1>]};
1928 }
1929 } else {
1930 return value;
1931 }
1932 }
1933
1934 /// @brief Converts an @ref option to a @ref result.
1935 ///
1936 /// @details
1937 /// This function constructs and returns a @ref result such that the
1938 /// contained value of the @ref option becomes the `error` value of the
1939 /// @ref result. If the @ref option is `none`, the provided default
1940 /// value is used as the `ok` value of the @ref result.
1941 ///
1942 /// ## Example
1943 /// ```
1944 /// option<int> opt1{};
1945 /// option<int> opt2{42};
1946 ///
1947 /// result<int, int> res1 = opt1.error_or(ok<int>(-42));
1948 /// result<int, int> res2 = opt2.error_or(ok<int>(-42));
1949 ///
1950 /// assert(res1.has_value());
1951 /// assert(*res1 == -42);
1952 ///
1953 /// assert(!res2.has_value());
1954 /// assert(res2.error() == 42);
1955 /// ```
1956 ///
1957 /// @param err The default ok value used if the @ref option is `none`.
1958 template <typename U>
1959 [[nodiscard]] constexpr result<U, T> error_or(result<U, never>&& value) const& {
1960 if (opt_().index() != 0) {
1961 if constexpr (std::is_void_v<T>) {
1962 return result<U, T>{in_place_error};
1963 } else {
1964 return result<U, T>{in_place_error, opt_()[index<1>]};
1965 }
1966 } else {
1967 return std::move(value);
1968 }
1969 }
1970
1971 /// @brief Converts an @ref option to a @ref result.
1972 ///
1973 /// @details
1974 /// This function constructs and returns a @ref result such that the
1975 /// contained value of the @ref option becomes the `error` value of the
1976 /// @ref result. If the @ref option is `none`, the provided default
1977 /// value is used as the `ok` value of the @ref result.
1978 ///
1979 /// ## Example
1980 /// ```
1981 /// option<int> opt1{};
1982 /// option<int> opt2{42};
1983 ///
1984 /// result<int, int> res1 = std::move(opt1).error_or(ok<int>(-42));
1985 /// result<int, int> res2 = std::move(opt2).error_or(ok<int>(-42));
1986 ///
1987 /// assert(res1.has_value());
1988 /// assert(*res1 == -42);
1989 ///
1990 /// assert(!res2.has_value());
1991 /// assert(res2.error() == 42);
1992 /// ```
1993 ///
1994 /// @param err The default ok value used if the @ref option is `none`.
1995 template <typename U>
1996 [[nodiscard]] constexpr result<U, T> error_or(result<U, never>&& value) && {
1997 if (opt_().index() != 0) {
1998 if constexpr (std::is_void_v<T>) {
1999 return result<U, T>{in_place_error};
2000 } else {
2001 return result<U, T>{in_place_error, std::move(*this).opt_()[index<1>]};
2002 }
2003 } else {
2004 return std::move(value);
2005 }
2006 }
2007
2008 /// @brief Converts an @ref option to a @ref result.
2009 ///
2010 /// @details
2011 /// This fucntion constructs and returns a @ref result such that the
2012 /// contained value of the @ref option becomes the `error` value of the
2013 /// @ref result. If the @ref option is `none`, the result of invoking
2014 /// the provided callable is used as the `ok` value of the @ref result.
2015 ///
2016 /// This function might be preferred over `.error_or(ok_value)` when the
2017 /// value type is expensive to construct, copy, or move. This function
2018 /// allows the value to never be instantiated if the @ref option is not
2019 /// `none`.
2020 ///
2021 /// ## Example
2022 /// ```
2023 /// option<int> opt1{};
2024 /// option<int> opt2{42};
2025 ///
2026 /// result<int, int> res1 = opt1.error_or_else([] { return -42; });
2027 /// result<int, int> res2 = opt2.error_or_else([] { return -42; });
2028 ///
2029 /// assert(res1.has_value());
2030 /// assert(*res1 == -42);
2031 ///
2032 /// assert(!res2.has_value());
2033 /// assert(res2.error() == 42);
2034 /// ```
2035 ///
2036 /// @param f A callable that creates a default ok value.
2037 template <typename F>
2038 4 [[nodiscard]] constexpr result<std::invoke_result_t<F>, T> error_or_else(F&& f) const& {
2039
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
4 if (opt_().index() != 0) {
2040 if constexpr (std::is_void_v<T>) {
2041 return result<std::invoke_result_t<F>, T>{in_place_error};
2042 } else {
2043 2 return result<std::invoke_result_t<F>, T>{in_place_error, opt_()[index<1>]};
2044 }
2045 } else {
2046 return result<std::invoke_result_t<F>, T>{std::in_place,
2047
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
4 invoke(std::forward<F>(f))};
2048 }
2049 }
2050
2051 /// @brief Converts an @ref option to a @ref result.
2052 ///
2053 /// @details
2054 /// This fucntion constructs and returns a @ref result such that the
2055 /// contained value of the @ref option becomes the `error` value of the
2056 /// @ref result. If the @ref option is `none`, the result of invoking
2057 /// the provided callable is used as the `ok` value of the @ref result.
2058 ///
2059 /// This function might be preferred over `.error_or(ok_value)` when the
2060 /// value type is expensive to construct, copy, or move. This function
2061 /// allows the value to never be instantiated if the @ref option is not
2062 /// `none`.
2063 ///
2064 /// ## Example
2065 /// ```
2066 /// option<int> opt1{};
2067 /// option<int> opt2{42};
2068 ///
2069 /// result<int, int> res1 = std::move(opt1).error_or_else([] {
2070 /// return -42;
2071 /// });
2072 /// result<int, int> res2 = std::move(opt2).error_or_else([] {
2073 /// return -42;
2074 /// });
2075 ///
2076 /// assert(res1.has_value());
2077 /// assert(*res1 == -42);
2078 ///
2079 /// assert(!res2.has_value());
2080 /// assert(res2.error() == 42);
2081 /// ```
2082 ///
2083 /// @param f A callable that creates a default ok value.
2084 template <typename F>
2085 [[nodiscard]] constexpr result<std::invoke_result_t<F>, T> error_or_else(F&& f) && {
2086 if (opt_().index() != 0) {
2087 if constexpr (std::is_void_v<T>) {
2088 return result<std::invoke_result_t<F>, T>{in_place_error};
2089 } else {
2090 return result<std::invoke_result_t<F>, T>{
2091 in_place_error, std::move(*this).opt_()[index<1>]};
2092 }
2093 } else {
2094 return result<std::invoke_result_t<F>, T>{std::in_place,
2095 invoke(std::forward<F>(f))};
2096 }
2097 }
2098
2099 /// @brief Converts an @ref option into an @ref option of a reference.
2100 ///
2101 /// @details
2102 /// This function acts as a monadic operation that gets a reference to the
2103 /// contained value without unwrapping the @ref option. In the case where
2104 /// the contained value is `void`, the returned @ref option is also `void`.
2105 ///
2106 /// ## Example
2107 /// ```
2108 /// option<int> opt1{};
2109 /// option<int> opt2{42};
2110 ///
2111 /// option<int&> opt1_ref = opt1.ref();
2112 /// option<int&> opt2_ref = opt2.ref();
2113 ///
2114 /// assert(opt1_ref == nullptr);
2115 /// assert(opt2_ref == &*opt2);
2116 /// ```
2117 [[nodiscard]] constexpr option<reference> ref() noexcept {
2118 if (opt_().index() != 0) {
2119 return option<reference>{std::in_place, opt_()[index<1>]};
2120 } else {
2121 return option<reference>{};
2122 }
2123 }
2124
2125 /// @brief Converts an @ref option into an @ref option of a reference.
2126 ///
2127 /// @details
2128 /// This function acts as a monadic operation that gets a reference to the
2129 /// contained value without unwrapping the @ref option. In the case where
2130 /// the contained value is `void`, the returned @ref option is also `void`.
2131 ///
2132 /// ## Example
2133 /// ```
2134 /// const option<int> opt1{};
2135 /// const option<int> opt2{42};
2136 ///
2137 /// option<const int&> opt1_ref = opt1.ref();
2138 /// option<const int&> opt2_ref = opt2.ref();
2139 ///
2140 /// assert(opt1_ref == nullptr);
2141 /// assert(opt2_ref == &*opt2);
2142 /// ```
2143 2 [[nodiscard]] constexpr option<const_reference> ref() const noexcept {
2144
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
2 if (opt_().index() != 0) {
2145 1 return option<const_reference>{std::in_place, opt_()[index<1>]};
2146 } else {
2147 1 return option<const_reference>{};
2148 }
2149 }
2150
2151 /// @brief Converts an @ref option into an @ref option of a reference.
2152 ///
2153 /// @details
2154 /// This function acts as a monadic operation that gets a reference to the
2155 /// contained value without unwrapping the @ref option. In the case where
2156 /// the contained value is `void`, the returned @ref option is also `void`.
2157 ///
2158 /// ## Example
2159 /// ```
2160 /// option<int> opt1{};
2161 /// option<int> opt2{42};
2162 ///
2163 /// option<const int&> opt1_ref = opt1.cref();
2164 /// option<const int&> opt2_ref = opt2.cref();
2165 ///
2166 /// assert(opt1_ref == nullptr);
2167 /// assert(opt2_ref == &*opt2);
2168 /// ```
2169 [[nodiscard]] constexpr option<const_reference> cref() const noexcept { return ref(); }
2170
2171 /// @brief Applies a callable to the contents of an @ref option.
2172 ///
2173 /// @details
2174 /// If the @ref option contains a value, the value is passed into the
2175 /// callable, and the invocation result is returned from this function.
2176 /// If the @ref option is `none`, the callable is not invoked and `none`
2177 /// is returned.
2178 ///
2179 /// This function only participates in overload resolution if the
2180 /// invocation result of the callable is an @ref option.
2181 ///
2182 /// ## Example
2183 /// ```
2184 /// option<int> opt1{};
2185 /// option<int> opt2{42};
2186 /// option<int> opt3{-42};
2187 ///
2188 /// auto callable = [](int value) -> option<unsigned int> {
2189 /// if (value < 0) {
2190 /// return none;
2191 /// } else {
2192 /// return static_cast<unsigned int>(value);
2193 /// }
2194 /// };
2195 ///
2196 /// auto opt1_res = opt1.and_then(callable);
2197 /// auto opt2_res = opt2.and_then(callable);
2198 /// auto opt3_res = opt3.and_then(callable);
2199 ///
2200 /// assert(!opt1_res.has_value());
2201 ///
2202 /// assert(opt2_res.has_value());
2203 /// assert(*opt2_res == 42);
2204 ///
2205 /// assert(!opt3_res.has_value());
2206 /// ```
2207 ///
2208 /// @param f Callable applied to the contained option value
2209 template <typename F>
2210 #ifndef DOXYGEN
2211 requires(
2212 detail::is_option_v<std::remove_cvref_t<detail::invoke_result_t<F, reference>>>)
2213 #endif
2214 4 constexpr auto and_then(F&& f) & {
2215 if constexpr (std::is_void_v<reference>) {
2216 if (opt_().index() != 0) {
2217 return std::invoke(std::forward<F>(f), void_v);
2218 } else {
2219 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{};
2220 }
2221 } else {
2222
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
4 if (opt_().index() != 0) {
2223 2 return std::invoke(std::forward<F>(f), opt_()[index<1>]);
2224 } else {
2225 2 return std::remove_cvref_t<std::invoke_result_t<F, reference>>{};
2226 }
2227 }
2228 }
2229
2230 /// @brief Applies a callable to the contents of an @ref option.
2231 ///
2232 /// @details
2233 /// If the @ref option contains a value, the value is passed into the
2234 /// callable, and the invocation result is returned from this function.
2235 /// If the @ref option is `none`, the callable is not invoked and `none`
2236 /// is returned.
2237 ///
2238 /// This function only participates in overload resolution if the
2239 /// invocation result of the callable is an @ref option.
2240 ///
2241 /// ## Example
2242 /// ```
2243 /// const option<int> opt1{};
2244 /// const option<int> opt2{42};
2245 /// const option<int> opt3{-42};
2246 ///
2247 /// auto callable = [](int value) -> option<unsigned int> {
2248 /// if (value < 0) {
2249 /// return none;
2250 /// } else {
2251 /// return static_cast<unsigned int>(value);
2252 /// }
2253 /// };
2254 ///
2255 /// auto opt1_res = opt1.and_then(callable);
2256 /// auto opt2_res = opt2.and_then(callable);
2257 /// auto opt3_res = opt3.and_then(callable);
2258 ///
2259 /// assert(!opt1_res.has_value());
2260 ///
2261 /// assert(opt2_res.has_value());
2262 /// assert(*opt2_res == 42);
2263 ///
2264 /// assert(!opt3_res.has_value());
2265 /// ```
2266 ///
2267 /// @param f Callable applied to the contained option value
2268 template <typename F>
2269 #ifndef DOXYGEN
2270 requires(detail::is_option_v<
2271 std::remove_cvref_t<detail::invoke_result_t<F, const_reference>>>)
2272 #endif
2273 constexpr auto and_then(F&& f) const& {
2274 if constexpr (std::is_void_v<const_reference>) {
2275 if (opt_().index() != 0) {
2276 return std::invoke(std::forward<F>(f), void_v);
2277 } else {
2278 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{};
2279 }
2280 } else {
2281 if (opt_().index() != 0) {
2282 return std::invoke(std::forward<F>(f), opt_()[index<1>]);
2283 } else {
2284 return std::remove_cvref_t<std::invoke_result_t<F, const_reference>>{};
2285 }
2286 }
2287 }
2288
2289 /// @brief Applies a callable to the contents of an @ref option.
2290 ///
2291 /// @details
2292 /// If the @ref option contains a value, the value is passed into the
2293 /// callable, and the invocation result is returned from this function.
2294 /// If the @ref option is `none`, the callable is not invoked and `none`
2295 /// is returned.
2296 ///
2297 /// This function only participates in overload resolution if the
2298 /// invocation result of the callable is an @ref option.
2299 ///
2300 /// ## Example
2301 /// ```
2302 /// option<int> opt1{};
2303 /// option<int> opt2{42};
2304 /// option<int> opt3{-42};
2305 ///
2306 /// auto callable = [](int value) -> option<unsigned int> {
2307 /// if (value < 0) {
2308 /// return none;
2309 /// } else {
2310 /// return static_cast<unsigned int>(value);
2311 /// }
2312 /// };
2313 ///
2314 /// auto opt1_res = std::move(opt1).and_then(callable);
2315 /// auto opt2_res = std::move(opt2).and_then(callable);
2316 /// auto opt3_res = std::move(opt3).and_then(callable);
2317 ///
2318 /// assert(!opt1_res.has_value());
2319 ///
2320 /// assert(opt2_res.has_value());
2321 /// assert(*opt2_res == 42);
2322 ///
2323 /// assert(!opt3_res.has_value());
2324 /// ```
2325 ///
2326 /// @param f Callable applied to the contained option value
2327 template <typename F>
2328 #ifndef DOXYGEN
2329 requires(detail::is_option_v<
2330 std::remove_cvref_t<detail::invoke_result_t<F, rvalue_reference>>>)
2331 #endif
2332 constexpr auto and_then(F&& f) && {
2333 if constexpr (std::is_void_v<rvalue_reference>) {
2334 if (opt_().index() != 0) {
2335 return std::invoke(std::forward<F>(f), void_v);
2336 } else {
2337 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{};
2338 }
2339 } else {
2340 if (opt_().index() != 0) {
2341 return std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>]);
2342 } else {
2343 return std::remove_cvref_t<std::invoke_result_t<F, rvalue_reference>>{};
2344 }
2345 }
2346 }
2347
2348 /// @brief Applies a callable to the contents of an @ref option.
2349 ///
2350 /// @details
2351 /// If the @ref option contains a value, the value is passed into the
2352 /// callable, and the invocation result is returned from this function.
2353 /// If the @ref option is `none`, the callable is not invoked and `none`
2354 /// is returned.
2355 ///
2356 /// This function only participates in overload resolution if the
2357 /// invocation result of the callable is an @ref option.
2358 ///
2359 /// ## Example
2360 /// ```
2361 /// const option<int> opt1{};
2362 /// const option<int> opt2{42};
2363 /// const option<int> opt3{-42};
2364 ///
2365 /// auto callable = [](int value) -> option<unsigned int> {
2366 /// if (value < 0) {
2367 /// return none;
2368 /// } else {
2369 /// return static_cast<unsigned int>(value);
2370 /// }
2371 /// };
2372 ///
2373 /// auto opt1_res = std::move(opt1).and_then(callable);
2374 /// auto opt2_res = std::move(opt2).and_then(callable);
2375 /// auto opt3_res = std::move(opt3).and_then(callable);
2376 ///
2377 /// assert(!opt1_res.has_value());
2378 ///
2379 /// assert(opt2_res.has_value());
2380 /// assert(*opt2_res == 42);
2381 ///
2382 /// assert(!opt3_res.has_value());
2383 /// ```
2384 ///
2385 /// @param f Callable applied to the contained option value
2386 template <typename F>
2387 #ifndef DOXYGEN
2388 requires(detail::is_option_v<
2389 std::remove_cvref_t<detail::invoke_result_t<F, const_rvalue_reference>>>)
2390 #endif
2391 constexpr auto and_then(F&& f) const&& {
2392 if constexpr (std::is_void_v<const_rvalue_reference>) {
2393 if (opt_().index() != 0) {
2394 return std::invoke(std::forward<F>(f), void_v);
2395 } else {
2396 return std::remove_cvref_t<std::invoke_result_t<F, void_t>>{};
2397 }
2398 } else {
2399 if (opt_().index() != 0) {
2400 return std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>]);
2401 } else {
2402 return std::remove_cvref_t<
2403 std::invoke_result_t<F, const_rvalue_reference>>{};
2404 }
2405 }
2406 }
2407
2408 /// @brief Performs a transformation on the content of an @ref option.
2409 ///
2410 /// @details
2411 /// This function is a monadic operation that passes the value contained
2412 /// in the @ref option, if any, to the callable `f`. The value returned by
2413 /// the call to `f` is then returned from this function wrapped in a new
2414 /// @ref option. If the original @ref option is `none`, the returned value
2415 /// is a `none` @ref option of the type that would have been returned by
2416 /// `f`.
2417 ///
2418 /// Note that this function is identical to @ref map, but the name
2419 /// `transform` make @ref option able to be a drop in replacement for
2420 /// `std::optional`. `map` is the more typical name of this monadic
2421 /// operation outside of C++.
2422 ///
2423 /// ## Example
2424 /// ```
2425 /// option<int> opt1{};
2426 /// option<int> opt2{42};
2427 ///
2428 /// auto opt1_mapped = opt1.transform([](auto value) {
2429 /// return std::to_string(value);
2430 /// });
2431 /// auto opt2_mapped = opt2.transform([](auto value) {
2432 /// return std::to_string(value);
2433 /// });
2434 ///
2435 /// assert(!opt1_mapped.has_value());
2436 ///
2437 /// assert(opt2_mapped.has_value());
2438 /// assert(*opt2_mapped = "42");
2439 /// ```
2440 ///
2441 /// @param f A callable that transforms the @ref option value
2442 template <typename F>
2443 4 constexpr auto transform(F&& f) & {
2444 if constexpr (std::is_void_v<reference>) {
2445 using res_t = std::invoke_result_t<F, void_t>;
2446 if (opt_().index() != 0) {
2447 if constexpr (std::is_void_v<res_t>) {
2448 std::invoke(std::forward<F>(f), void_v);
2449 return option<res_t>{std::in_place};
2450 } else {
2451 return option<res_t>{std::in_place,
2452 std::invoke(std::forward<F>(f), void_v)};
2453 }
2454 } else {
2455 return option<res_t>{};
2456 }
2457 } else {
2458 using res_t = std::invoke_result_t<F, reference>;
2459
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
4 if (opt_().index() != 0) {
2460 if constexpr (std::is_void_v<res_t>) {
2461 std::invoke(std::forward<F>(f), opt_()[index<1>]);
2462 return option<res_t>{std::in_place};
2463 } else {
2464 return option<res_t>{std::in_place,
2465
1/2
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
4 std::invoke(std::forward<F>(f), opt_()[index<1>])};
2466 }
2467 } else {
2468 2 return option<res_t>{};
2469 }
2470 }
2471 }
2472
2473 /// @brief Performs a transformation on the content of an @ref option.
2474 ///
2475 /// @details
2476 /// This function is a monadic operation that passes the value contained
2477 /// in the @ref option, if any, to the callable `f`. The value returned by
2478 /// the call to `f` is then returned from this function wrapped in a new
2479 /// @ref option. If the original @ref option is `none`, the returned value
2480 /// is a `none` @ref option of the type that would have been returned by
2481 /// `f`.
2482 ///
2483 /// Note that this function is identical to @ref map, but the name
2484 /// `transform` make @ref option able to be a drop in replacement for
2485 /// `std::optional`. `map` is the more typical name of this monadic
2486 /// operation outside of C++.
2487 ///
2488 /// ## Example
2489 /// ```
2490 /// const option<int> opt1{};
2491 /// const option<int> opt2{42};
2492 ///
2493 /// auto opt1_mapped = opt1.transform([](auto value) {
2494 /// return std::to_string(value);
2495 /// });
2496 /// auto opt2_mapped = opt2.transform([](auto value) {
2497 /// return std::to_string(value);
2498 /// });
2499 ///
2500 /// assert(!opt1_mapped.has_value());
2501 ///
2502 /// assert(opt2_mapped.has_value());
2503 /// assert(*opt2_mapped = "42");
2504 /// ```
2505 ///
2506 /// @param f A callable that transforms the @ref option value
2507 template <typename F>
2508 constexpr auto transform(F&& f) const& {
2509 if constexpr (std::is_void_v<const_reference>) {
2510 using res_t = std::invoke_result_t<F, void_t>;
2511 if (opt_().index() != 0) {
2512 if constexpr (std::is_void_v<res_t>) {
2513 std::invoke(std::forward<F>(f), void_v);
2514 return option<res_t>{std::in_place};
2515 } else {
2516 return option<res_t>{std::in_place,
2517 std::invoke(std::forward<F>(f), void_v)};
2518 }
2519 } else {
2520 return option<res_t>{};
2521 }
2522 } else {
2523 using res_t = std::invoke_result_t<F, const_reference>;
2524 if (opt_().index() != 0) {
2525 if constexpr (std::is_void_v<res_t>) {
2526 std::invoke(std::forward<F>(f), opt_()[index<1>]);
2527 return option<res_t>{std::in_place};
2528 } else {
2529 return option<res_t>{std::in_place,
2530 std::invoke(std::forward<F>(f), opt_()[index<1>])};
2531 }
2532 } else {
2533 return option<res_t>{};
2534 }
2535 }
2536 }
2537
2538 /// @brief Performs a transformation on the content of an @ref option.
2539 ///
2540 /// @details
2541 /// This function is a monadic operation that passes the value contained
2542 /// in the @ref option, if any, to the callable `f`. The value returned by
2543 /// the call to `f` is then returned from this function wrapped in a new
2544 /// @ref option. If the original @ref option is `none`, the returned value
2545 /// is a `none` @ref option of the type that would have been returned by
2546 /// `f`.
2547 ///
2548 /// Note that this function is identical to @ref map, but the name
2549 /// `transform` make @ref option able to be a drop in replacement for
2550 /// `std::optional`. `map` is the more typical name of this monadic
2551 /// operation outside of C++.
2552 ///
2553 /// ## Example
2554 /// ```
2555 /// option<int> opt1{};
2556 /// option<int> opt2{42};
2557 ///
2558 /// auto opt1_mapped = std::move(opt1).transform([](auto value) {
2559 /// return std::to_string(value);
2560 /// });
2561 /// auto opt2_mapped = std::move(opt2).transform([](auto value) {
2562 /// return std::to_string(value);
2563 /// });
2564 ///
2565 /// assert(!opt1_mapped.has_value());
2566 ///
2567 /// assert(opt2_mapped.has_value());
2568 /// assert(*opt2_mapped = "42");
2569 /// ```
2570 ///
2571 /// @param f A callable that transforms the @ref option value
2572 template <typename F>
2573 constexpr auto transform(F&& f) && {
2574 if constexpr (std::is_void_v<rvalue_reference>) {
2575 using res_t = std::invoke_result_t<F, void_t>;
2576 if (opt_().index() != 0) {
2577 if constexpr (std::is_void_v<res_t>) {
2578 std::invoke(std::forward<F>(f), void_v);
2579 return option<res_t>{std::in_place};
2580 } else {
2581 return option<res_t>{std::in_place,
2582 std::invoke(std::forward<F>(f), void_v)};
2583 }
2584 } else {
2585 return option<res_t>{};
2586 }
2587 } else {
2588 using res_t = std::invoke_result_t<F, rvalue_reference>;
2589 if (opt_().index() != 0) {
2590 if constexpr (std::is_void_v<res_t>) {
2591 std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>]);
2592 return option<res_t>{std::in_place};
2593 } else {
2594 return option<res_t>{
2595 std::in_place,
2596 std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>])};
2597 }
2598 } else {
2599 return option<res_t>{};
2600 }
2601 }
2602 }
2603
2604 /// @brief Performs a transformation on the content of an @ref option.
2605 ///
2606 /// @details
2607 /// This function is a monadic operation that passes the value contained
2608 /// in the @ref option, if any, to the callable `f`. The value returned by
2609 /// the call to `f` is then returned from this function wrapped in a new
2610 /// @ref option. If the original @ref option is `none`, the returned value
2611 /// is a `none` @ref option of the type that would have been returned by
2612 /// `f`.
2613 ///
2614 /// Note that this function is identical to @ref map, but the name
2615 /// `transform` make @ref option able to be a drop in replacement for
2616 /// `std::optional`. `map` is the more typical name of this monadic
2617 /// operation outside of C++.
2618 ///
2619 /// ## Example
2620 /// ```
2621 /// const option<int> opt1{};
2622 /// const option<int> opt2{42};
2623 ///
2624 /// auto opt1_mapped = std::move(opt1).transform([](auto value) {
2625 /// return std::to_string(value);
2626 /// });
2627 /// auto opt2_mapped = std::move(opt2).transform([](auto value) {
2628 /// return std::to_string(value);
2629 /// });
2630 ///
2631 /// assert(!opt1_mapped.has_value());
2632 ///
2633 /// assert(opt2_mapped.has_value());
2634 /// assert(*opt2_mapped = "42");
2635 /// ```
2636 ///
2637 /// @param f A callable that transforms the @ref option value
2638 template <typename F>
2639 constexpr auto transform(F&& f) const&& {
2640 if constexpr (std::is_void_v<const_rvalue_reference>) {
2641 using res_t = std::invoke_result_t<F, void_t>;
2642 if (opt_().index() != 0) {
2643 if constexpr (std::is_void_v<res_t>) {
2644 std::invoke(std::forward<F>(f), void_v);
2645 return option<res_t>{std::in_place};
2646 } else {
2647 return option<res_t>{std::in_place,
2648 std::invoke(std::forward<F>(f), void_v)};
2649 }
2650 } else {
2651 return option<res_t>{};
2652 }
2653 } else {
2654 using res_t = std::invoke_result_t<F, const_rvalue_reference>;
2655 if (opt_().index() != 0) {
2656 if constexpr (std::is_void_v<res_t>) {
2657 std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>]);
2658 return option<res_t>{std::in_place};
2659 } else {
2660 return option<res_t>{
2661 std::in_place,
2662 std::invoke(std::forward<F>(f), std::move(*this).opt_()[index<1>])};
2663 }
2664 } else {
2665 return option<res_t>{};
2666 }
2667 }
2668 }
2669
2670 /// @brief Performs a transformation on the content of an @ref option.
2671 ///
2672 /// @details
2673 /// This function is a monadic operation that passes the value contained
2674 /// in the @ref option, if any, to the callable `f`. The value returned by
2675 /// the call to `f` is then returned from this function wrapped in a new
2676 /// @ref option. If the original @ref option is `none`, the returned value
2677 /// is a `none` @ref option of the type that would have been returned by
2678 /// `f`.
2679 ///
2680 /// Note that this function is identical to @ref transform, but the name
2681 /// `map` is the more typical name of this monadic operation outside of
2682 /// C++.
2683 ///
2684 /// ## Example
2685 /// ```
2686 /// option<int> opt1{};
2687 /// option<int> opt2{42};
2688 ///
2689 /// auto opt1_mapped = opt1.map([](auto value) {
2690 /// return std::to_string(value);
2691 /// });
2692 /// auto opt2_mapped = opt2.map([](auto value) {
2693 /// return std::to_string(value);
2694 /// });
2695 ///
2696 /// assert(!opt1_mapped.has_value());
2697 ///
2698 /// assert(opt2_mapped.has_value());
2699 /// assert(*opt2_mapped = "42");
2700 /// ```
2701 ///
2702 /// @param f A callable that maps the @ref option value
2703 template <typename F>
2704 constexpr auto map(F&& f) & {
2705 return transform(std::forward<F>(f));
2706 }
2707
2708 /// @brief Performs a transformation on the content of an @ref option.
2709 ///
2710 /// @details
2711 /// This function is a monadic operation that passes the value contained
2712 /// in the @ref option, if any, to the callable `f`. The value returned by
2713 /// the call to `f` is then returned from this function wrapped in a new
2714 /// @ref option. If the original @ref option is `none`, the returned value
2715 /// is a `none` @ref option of the type that would have been returned by
2716 /// `f`.
2717 ///
2718 /// Note that this function is identical to @ref transform, but the name
2719 /// `map` is the more typical name of this monadic operation outside of
2720 /// C++.
2721 ///
2722 /// ## Example
2723 /// ```
2724 /// const option<int> opt1{};
2725 /// const option<int> opt2{42};
2726 ///
2727 /// auto opt1_mapped = opt1.map([](auto value) {
2728 /// return std::to_string(value);
2729 /// });
2730 /// auto opt2_mapped = opt2.map([](auto value) {
2731 /// return std::to_string(value);
2732 /// });
2733 ///
2734 /// assert(!opt1_mapped.has_value());
2735 ///
2736 /// assert(opt2_mapped.has_value());
2737 /// assert(*opt2_mapped = "42");
2738 /// ```
2739 ///
2740 /// @param f A callable that maps the @ref option value
2741 template <typename F>
2742 constexpr auto map(F&& f) const& {
2743 return transform(std::forward<F>(f));
2744 }
2745
2746 /// @brief Performs a transformation on the content of an @ref option.
2747 ///
2748 /// @details
2749 /// This function is a monadic operation that passes the value contained
2750 /// in the @ref option, if any, to the callable `f`. The value returned by
2751 /// the call to `f` is then returned from this function wrapped in a new
2752 /// @ref option. If the original @ref option is `none`, the returned value
2753 /// is a `none` @ref option of the type that would have been returned by
2754 /// `f`.
2755 ///
2756 /// Note that this function is identical to @ref transform, but the name
2757 /// `map` is the more typical name of this monadic operation outside of
2758 /// C++.
2759 ///
2760 /// ## Example
2761 /// ```
2762 /// option<int> opt1{};
2763 /// option<int> opt2{42};
2764 ///
2765 /// auto opt1_mapped = std::move(opt1).map([](auto value) {
2766 /// return std::to_string(value);
2767 /// });
2768 /// auto opt2_mapped = std::move(opt2).map([](auto value) {
2769 /// return std::to_string(value);
2770 /// });
2771 ///
2772 /// assert(!opt1_mapped.has_value());
2773 ///
2774 /// assert(opt2_mapped.has_value());
2775 /// assert(*opt2_mapped = "42");
2776 /// ```
2777 ///
2778 /// @param f A callable that maps the @ref option value
2779 template <typename F>
2780 constexpr auto map(F&& f) && {
2781 return std::move(*this).transform(std::forward<F>(f));
2782 }
2783
2784 /// @brief Performs a transformation on the content of an @ref option.
2785 ///
2786 /// @details
2787 /// This function is a monadic operation that passes the value contained
2788 /// in the @ref option, if any, to the callable `f`. The value returned by
2789 /// the call to `f` is then returned from this function wrapped in a new
2790 /// @ref option. If the original @ref option is `none`, the returned value
2791 /// is a `none` @ref option of the type that would have been returned by
2792 /// `f`.
2793 ///
2794 /// Note that this function is identical to @ref transform, but the name
2795 /// `map` is the more typical name of this monadic operation outside of
2796 /// C++.
2797 ///
2798 /// ## Example
2799 /// ```
2800 /// const option<int> opt1{};
2801 /// const option<int> opt2{42};
2802 ///
2803 /// auto opt1_mapped = std::move(opt1).map([](auto value) {
2804 /// return std::to_string(value);
2805 /// });
2806 /// auto opt2_mapped = std::move(opt2).map([](auto value) {
2807 /// return std::to_string(value);
2808 /// });
2809 ///
2810 /// assert(!opt1_mapped.has_value());
2811 ///
2812 /// assert(opt2_mapped.has_value());
2813 /// assert(*opt2_mapped = "42");
2814 /// ```
2815 ///
2816 /// @param f A callable that maps the @ref option value
2817 template <typename F>
2818 constexpr auto map(F&& f) const&& {
2819 return std::move(*this).transform(std::forward<F>(f));
2820 }
2821
2822 /// @brief Returns the result of `f` if the @ref option is `none`.
2823 ///
2824 /// @details
2825 /// If the @ref option contains a value, a copy of the @ref option is
2826 /// returned. Otherwise, the result of invoking `f` is returned.
2827 ///
2828 /// ## Example
2829 /// ```
2830 /// option<int> opt1{};
2831 /// option<int> opt2{42};
2832 ///
2833 /// auto opt1_new = opt1.or_else([] { return 0; });
2834 /// auto opt2_new = opt2.or_else([] { return 0; });
2835 ///
2836 /// assert(opt1_new.has_value());
2837 /// assert(*opt1_new == 0);
2838 ///
2839 /// assert(opt2_new.has_value());
2840 /// assert(*opt2_new == 42);
2841 /// ```
2842 ///
2843 /// @param f A callable that returns the "else" @ref option
2844 template <typename F>
2845 4 constexpr option or_else(F&& f) const& {
2846
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
4 if (opt_().index() != 0) {
2847 2 return *this;
2848 } else {
2849 2 return std::invoke(std::forward<F>(f));
2850 }
2851 }
2852
2853 /// @brief Returns the result of `f` if the @ref option is `none`.
2854 ///
2855 /// @details
2856 /// If the @ref option contains a value, a copy of the @ref option is
2857 /// returned. Otherwise, the result of invoking `f` is returned.
2858 ///
2859 /// ## Example
2860 /// ```
2861 /// option<int> opt1{};
2862 /// option<int> opt2{42};
2863 ///
2864 /// auto opt1_new = std::move(opt1).or_else([] { return 0; });
2865 /// auto opt2_new = std::move(opt2).or_else([] { return 0; });
2866 ///
2867 /// assert(opt1_new.has_value());
2868 /// assert(*opt1_new == 0);
2869 ///
2870 /// assert(opt2_new.has_value());
2871 /// assert(*opt2_new == 42);
2872 /// ```
2873 ///
2874 /// @param f A callable that returns the "else" @ref option
2875 template <typename F>
2876 constexpr option or_else(F&& f) && {
2877 if (opt_().index() != 0) {
2878 return std::move(*this);
2879 } else {
2880 return std::invoke(std::forward<F>(f));
2881 }
2882 }
2883
2884 /// @brief Converts `option<option<T>>` to `option<T>`
2885 ///
2886 /// @details
2887 /// If the outer @ref option is `none` or the inner @ref option is `none`,
2888 /// `none` is returned. Otherwise the flattend @ref option with a contained
2889 /// value is returned.
2890 ///
2891 /// Note that only one level of @ref option is removed. An
2892 /// `option<option<option<T>>>` will flatten to an `option<option<T>>`.
2893 ///
2894 /// This function only participates in overload resolution if `T` is an
2895 /// @ref option.
2896 ///
2897 /// ## Example
2898 /// ```
2899 /// option<option<int>> opt1{};
2900 /// option<option<int>> opt2 = some<option<int>>(none);
2901 /// option<option<int>> opt3 = some<option<int>>(42);
2902 ///
2903 /// auto opt1_flat = opt1.flatten();
2904 /// auto opt2_flat = opt2.flatten();
2905 /// auto opt3_flat = opt3.flatten();
2906 ///
2907 /// assert(opt1_flat.is_none());
2908 /// assert(opt2_flat.is_none());
2909 ///
2910 /// assert(opt3_flat.is_some());
2911 /// assert(*opt3_flat = 42);
2912 /// ```
2913 [[nodiscard]] constexpr T flatten() const&
2914 #ifndef DOXYGEN
2915 requires(detail::is_option_v<T>)
2916 #endif
2917 {
2918 return value_or_else([]() -> T { return none; });
2919 }
2920
2921 /// @brief Converts `option<option<T>>` to `option<T>`
2922 ///
2923 /// @details
2924 /// If the outer @ref option is `none` or the inner @ref option is `none`,
2925 /// `none` is returned. Otherwise the flattend @ref option with a contained
2926 /// value is returned.
2927 ///
2928 /// Note that only one level of @ref option is removed. An
2929 /// `option<option<option<T>>>` will flatten to an `option<option<T>>`.
2930 ///
2931 /// This function only participates in overload resolution if `T` is an
2932 /// @ref option.
2933 ///
2934 /// ## Example
2935 /// ```
2936 /// option<option<int>> opt1{};
2937 /// option<option<int>> opt2 = some<option<int>>(none);
2938 /// option<option<int>> opt3 = some<option<int>>(42);
2939 ///
2940 /// auto opt1_flat = std::move(opt1).flatten();
2941 /// auto opt2_flat = std::move(opt2).flatten();
2942 /// auto opt3_flat = std::move(opt3).flatten();
2943 ///
2944 /// assert(opt1_flat.is_none());
2945 /// assert(opt2_flat.is_none());
2946 ///
2947 /// assert(opt3_flat.is_some());
2948 /// assert(*opt3_flat = 42);
2949 /// ```
2950 [[nodiscard]] constexpr T flatten() &&
2951 #ifndef DOXYGEN
2952 requires(detail::is_option_v<T>)
2953 #endif
2954 {
2955 return std::move(*this).value_or_else([]() -> T { return none; });
2956 }
2957
2958 /// @brief Converts nested @ref option types into a single @ref option
2959 ///
2960 /// @details
2961 /// Like @ref flatten, this function removes nested layers of @ref option,
2962 /// such as converting `option<option<T>>` into `option<T>`. However,
2963 /// unlike @ref flatten, this function removes all layers of nesting and
2964 /// works for unnested @ref option types. For example,
2965 /// `option<option<option<T>>>` is converted directly to `option<T>`, and
2966 /// for `option<T>`, where `T` is not an @ref option type, no layers of
2967 /// @ref option are removed.
2968 ///
2969 /// ## Example
2970 /// ```
2971 /// option<option<option<int>>> opt1{in_place, in_place, in_place, 42};
2972 /// option<option<option<int>>> opt2{none};
2973 /// option<option<option<int>>> opt3{in_place, none};
2974 /// option<option<option<int>>> opt4{in_place, in_place, none};
2975 ///
2976 /// option<int> opt1_flat = opt1.flatten_all();
2977 /// option<int> opt2_flat = opt2.flatten_all();
2978 /// option<int> opt3_flat = opt3.flatten_all();
2979 /// option<int> opt4_flat = opt4.flatten_all();
2980 ///
2981 /// assert(opt1_flat.is_some());
2982 /// assert(*opt1_flat == 42);
2983 ///
2984 /// assert(opt2_flat.is_none());
2985 /// assert(opt3_flat.is_none());
2986 /// assert(opt4_flat.is_none());
2987 /// ```
2988 [[nodiscard]] constexpr auto flatten_all() const& {
2989 if constexpr (detail::is_option_v<T>) {
2990 return flatten().flatten_all();
2991 } else {
2992 return *this;
2993 }
2994 }
2995
2996 /// @brief Converts nested @ref option types into a single @ref option
2997 ///
2998 /// @details
2999 /// Like @ref flatten, this function removes nested layers of @ref option,
3000 /// such as converting `option<option<T>>` into `option<T>`. However,
3001 /// unlike @ref flatten, this function removes all layers of nesting and
3002 /// works for unnested @ref option types. For example,
3003 /// `option<option<option<T>>>` is converted directly to `option<T>`, and
3004 /// for `option<T>`, where `T` is not an @ref option type, no layers of
3005 /// @ref option are removed.
3006 ///
3007 /// ## Example
3008 /// ```
3009 /// option<option<option<int>>> opt1{in_place, in_place, in_place, 42};
3010 /// option<option<option<int>>> opt2{none};
3011 /// option<option<option<int>>> opt3{in_place, none};
3012 /// option<option<option<int>>> opt4{in_place, in_place, none};
3013 ///
3014 /// option<int> opt1_flat = std::move(opt1).flatten_all();
3015 /// option<int> opt2_flat = std::move(opt2).flatten_all();
3016 /// option<int> opt3_flat = std::move(opt3).flatten_all();
3017 /// option<int> opt4_flat = std::move(opt4).flatten_all();
3018 ///
3019 /// assert(opt1_flat.is_some());
3020 /// assert(*opt1_flat == 42);
3021 ///
3022 /// assert(opt2_flat.is_none());
3023 /// assert(opt3_flat.is_none());
3024 /// assert(opt4_flat.is_none());
3025 /// ```
3026 [[nodiscard]] constexpr auto flatten_all() && {
3027 if constexpr (detail::is_option_v<T>) {
3028 return std::move(*this).flatten().flatten_all();
3029 } else {
3030 return std::move(*this);
3031 }
3032 }
3033
3034 /// @brief Filters the @ref option based on a predicate
3035 ///
3036 /// @details
3037 /// If the @ref option is already `none`, `none` is returned. If the @ref
3038 /// option contains a value, the returned value depends on the predicate.
3039 /// If the predicate returns `true`, an @ref option with a copy of the
3040 /// original contained value is returned. Otherwise, `none` is returned.
3041 ///
3042 /// The predicate must have a signature compatible with:
3043 /// `bool pred(const T&)`.
3044 ///
3045 /// ## Example
3046 /// ```
3047 /// option<int> opt1{};
3048 /// option<int> opt2{42};
3049 /// option<int> opt3{-42};
3050 ///
3051 /// auto opt1_filt = opt1.filter([](int val) { return val > 0; });
3052 /// auto opt2_filt = opt2.filter([](int val) { return val > 0; });
3053 /// auto opt3_filt = opt3.filter([](int val) { return val > 0; });
3054 ///
3055 /// assert(opt1_filt.is_none());
3056 ///
3057 /// assert(opt2_filt.is_some());
3058 /// assert(*opt2_filt == 42);
3059 ///
3060 /// assert(opt3_filt.is_none());
3061 /// ```
3062 template <typename Pred>
3063 constexpr option filter(Pred&& pred) const& {
3064 if constexpr (std::is_void_v<T>) {
3065 if (is_some() && std::invoke(std::forward<Pred>(pred), void_v)) {
3066 return *this;
3067 } else {
3068 return none;
3069 }
3070 } else {
3071 if (is_some() && std::invoke(std::forward<Pred>(pred), opt_()[index<1>])) {
3072 return *this;
3073 } else {
3074 return none;
3075 }
3076 }
3077 }
3078
3079 /// @brief Filters the @ref option based on a predicate
3080 ///
3081 /// @details
3082 /// If the @ref option is already `none`, `none` is returned. If the @ref
3083 /// option contains a value, the returned value depends on the predicate.
3084 /// If the predicate returns `true`, an @ref option with the moved
3085 /// original contained value is returned. Otherwise, `none` is returned.
3086 ///
3087 /// The predicate must have a signature compatible with:
3088 /// `bool pred(T&)` or `bool pred(const T&)`.
3089 ///
3090 /// ## Example
3091 /// ```
3092 /// option<int> opt1{};
3093 /// option<int> opt2{42};
3094 /// option<int> opt3{-42};
3095 ///
3096 /// auto opt1_filt = std::move(opt1).filter([](int val) {
3097 /// return val > 0;
3098 /// });
3099 /// auto opt2_filt = std::move(opt2).filter([](int val) {
3100 /// return val > 0;
3101 /// });
3102 /// auto opt3_filt = std::move(opt3).filter([](int val) {
3103 /// return val > 0;
3104 /// });
3105 ///
3106 /// assert(opt1_filt.is_none());
3107 ///
3108 /// assert(opt2_filt.is_some());
3109 /// assert(*opt2_filt == 42);
3110 ///
3111 /// assert(opt3_filt.is_none());
3112 /// ```
3113 template <typename Pred>
3114 constexpr option filter(Pred&& pred) && {
3115 if constexpr (std::is_void_v<T>) {
3116 if (is_some() && std::invoke(std::forward<Pred>(pred), void_v)) {
3117 return std::move(*this);
3118 } else {
3119 return none;
3120 }
3121 } else {
3122 if (is_some() && std::invoke(std::forward<Pred>(pred), opt_()[index<1>])) {
3123 return std::move(*this);
3124 } else {
3125 return none;
3126 }
3127 }
3128 }
3129
3130 /// @brief Converts `option<result<T, E>>` into `result<option<T>, E>`
3131 ///
3132 /// @details
3133 /// If the @ref option is `none`, a @ref result containing a `none` @ref
3134 /// option is returned. If the @ref option contains an ok @ref result,
3135 /// a @ref result containing an ok value of an @ref option with a value
3136 /// is returned. If the @ref option contains a @ref result with an error
3137 /// value, a result with an error value is returned.
3138 ///
3139 /// This function only participates in overload resolution if `T` is a
3140 /// @ref result.
3141 ///
3142 /// ## Example
3143 /// ```
3144 /// option<result<int, std::string>> val1{};
3145 /// option<result<int, std::string>> val2{ok<int>(42)};
3146 /// option<result<int, std::string>> val3{error<std::string>("oh no")};
3147 ///
3148 /// auto val1_trans = val1.transpose();
3149 /// auto val2_trans = val2.transpose();
3150 /// auto val3_trans = val3.transpose();
3151 ///
3152 /// assert(val1_trans.is_ok());
3153 /// assert(val1_trans->is_none());
3154 ///
3155 /// assert(val2_trans.is_ok());
3156 /// assert(val2_trans->is_some());
3157 /// assert(**val2_trans == 42);
3158 ///
3159 /// assert(val3_trans.is_error());
3160 /// assert(val3_trans.error() == "oh no");
3161 /// ```
3162 [[nodiscard]] constexpr auto transpose() const&
3163 #ifndef DOXYGEN
3164 requires(detail::is_result_v<T>)
3165 #endif
3166 {
3167 using ret_t = result<option<typename T::value_type>, typename T::error_type>;
3168 if (is_some()) {
3169 if (opt_()[index<1>].is_ok()) {
3170 return ret_t{in_place, *opt_()[index<1>]};
3171 } else {
3172 return ret_t{in_place_error, opt_()[index<1>].error()};
3173 }
3174 } else {
3175 return ret_t{in_place, none};
3176 }
3177 }
3178
3179 /// @brief Converts `option<result<T, E>>` into `result<option<T>, E>`
3180 ///
3181 /// @details
3182 /// If the @ref option is `none`, a @ref result containing a `none` @ref
3183 /// option is returned. If the @ref option contains an ok @ref result,
3184 /// a @ref result containing an ok value of an @ref option with a value
3185 /// is returned. If the @ref option contains a @ref result with an error
3186 /// value, a result with an error value is returned.
3187 ///
3188 /// This function only participates in overload resolution if `T` is a
3189 /// @ref result.
3190 ///
3191 /// ## Example
3192 /// ```
3193 /// option<result<int, std::string>> val1{};
3194 /// option<result<int, std::string>> val2{ok<int>(42)};
3195 /// option<result<int, std::string>> val3{error<std::string>("oh no")};
3196 ///
3197 /// auto val1_trans = std::move(val1).transpose();
3198 /// auto val2_trans = std::move(val2).transpose();
3199 /// auto val3_trans = std::move(val3).transpose();
3200 ///
3201 /// assert(val1_trans.is_ok());
3202 /// assert(val1_trans->is_none());
3203 ///
3204 /// assert(val2_trans.is_ok());
3205 /// assert(val2_trans->is_some());
3206 /// assert(**val2_trans == 42);
3207 ///
3208 /// assert(val3_trans.is_error());
3209 /// assert(val3_trans.error() == "oh no");
3210 /// ```
3211 [[nodiscard]] constexpr auto transpose() &&
3212 #ifndef DOXYGEN
3213 requires(detail::is_result_v<T>)
3214 #endif
3215 {
3216 using ret_t = result<option<typename T::value_type>, typename T::error_type>;
3217 if (is_some()) {
3218 if (opt_()[index<1>].is_ok()) {
3219 return ret_t{in_place, *std::move(*this).opt_()[index<1>]};
3220 } else {
3221 return ret_t{in_place_error, std::move(*this).opt_()[index<1>].error()};
3222 }
3223 } else {
3224 return ret_t{in_place, none};
3225 }
3226 }
3227
3228 /// @brief Calls a visitor callable with the contained value or `void`.
3229 ///
3230 /// @details
3231 /// This function treats an @ref option as if it was a @ref variant of
3232 /// `void` and `T`. If the @ref option contains a value, that value is
3233 /// passed to the visitor. If the @ref option is `none`, the visitor is
3234 /// called with @ref void_t.
3235 ///
3236 /// Note that the @ref overload function can be helpful for defining a
3237 /// visitor inline.
3238 ///
3239 /// ## Example
3240 /// ```cpp
3241 /// option<int> opt1{};
3242 /// option<int> opt2{42};
3243 ///
3244 /// opt1.visit(overload([](int value) {
3245 /// assert(false);
3246 /// }, [](void_t value) {
3247 /// assert(true);
3248 /// });
3249 ///
3250 /// opt2.visit(overload([](int value) {
3251 /// assert(value == 42);
3252 /// }, [](void_t value) {
3253 /// assert(false);
3254 /// });
3255 /// ```
3256 template <typename V>
3257 constexpr
3258 #ifndef DOXYGEN
3259 decltype(auto)
3260 #else
3261 DEDUCED
3262 #endif
3263 24 visit(V&& visitor) & {
3264 24 return opt_().visit(std::forward<V>(visitor));
3265 }
3266
3267 /// @brief Calls a visitor callable with the contained value or `void`.
3268 ///
3269 /// @details
3270 /// This function treats an @ref option as if it was a @ref variant of
3271 /// `void` and `T`. If the @ref option contains a value, that value is
3272 /// passed to the visitor. If the @ref option is `none`, the visitor is
3273 /// called with @ref void_t.
3274 ///
3275 /// Note that the @ref overload function can be helpful for defining a
3276 /// visitor inline.
3277 ///
3278 /// ## Example
3279 /// ```cpp
3280 /// const option<int> opt1{};
3281 /// const option<int> opt2{42};
3282 ///
3283 /// opt1.visit(overload([](int value) {
3284 /// assert(false);
3285 /// }, [](void_t value) {
3286 /// assert(true);
3287 /// });
3288 ///
3289 /// opt2.visit(overload([](int value) {
3290 /// assert(value == 42);
3291 /// }, [](void_t value) {
3292 /// assert(false);
3293 /// });
3294 /// ```
3295 template <typename V>
3296 constexpr
3297 #ifndef DOXYGEN
3298 decltype(auto)
3299 #else
3300 DEDUCED
3301 #endif
3302 visit(V&& visitor) const& {
3303 return opt_().visit(std::forward<V>(visitor));
3304 }
3305
3306 /// @brief Calls a visitor callable with the contained value or `void`.
3307 ///
3308 /// @details
3309 /// This function treats an @ref option as if it was a @ref variant of
3310 /// `void` and `T`. If the @ref option contains a value, that value is
3311 /// passed to the visitor. If the @ref option is `none`, the visitor is
3312 /// called without any arguments.
3313 ///
3314 /// Note that the @ref overload function can be helpful for defining a
3315 /// visitor inline.
3316 ///
3317 /// ## Example
3318 /// ```cpp
3319 /// option<int> opt1{};
3320 /// option<int> opt2{42};
3321 ///
3322 /// std::move(opt1).visit(overload([](int value) {
3323 /// assert(false);
3324 /// }, [](void_t value) {
3325 /// assert(true);
3326 /// });
3327 ///
3328 /// std::move(opt2).visit(overload([](int value) {
3329 /// assert(value == 42);
3330 /// }, [](void_t value) {
3331 /// assert(false);
3332 /// });
3333 /// ```
3334 template <typename V>
3335 constexpr
3336 #ifndef DOXYGEN
3337 decltype(auto)
3338 #else
3339 DEDUCED
3340 #endif
3341 visit(V&& visitor) && {
3342 return std::move(*this).opt_().visit(std::forward<V>(visitor));
3343 }
3344
3345 /// @brief Calls a visitor callable with the contained value or `void`.
3346 ///
3347 /// @details
3348 /// This function treats an @ref option as if it was a @ref variant of
3349 /// `void` and `T`. If the @ref option contains a value, that value is
3350 /// passed to the visitor. If the @ref option is `none`, the visitor is
3351 /// called with @ref void_t.
3352 ///
3353 /// Note that the @ref overload function can be helpful for defining a
3354 /// visitor inline.
3355 ///
3356 /// ## Example
3357 /// ```cpp
3358 /// const option<int> opt1{};
3359 /// const option<int> opt2{42};
3360 ///
3361 /// std::move(opt1).visit(overload([](int value) {
3362 /// assert(false);
3363 /// }, [](void_t value) {
3364 /// assert(true);
3365 /// });
3366 ///
3367 /// std::move(opt2).visit(overload([](int value) {
3368 /// assert(value == 42);
3369 /// }, [](void_t value) {
3370 /// assert(false);
3371 /// });
3372 /// ```
3373 template <typename V>
3374 constexpr
3375 #ifndef DOXYGEN
3376 decltype(auto)
3377 #else
3378 DEDUCED
3379 #endif
3380 visit(V&& visitor) const&& {
3381 return std::move(*this).opt_().visit(std::forward<V>(visitor));
3382 }
3383
3384 /// @brief Calls a visitor callable with the contained value and meta data.
3385 ///
3386 /// @details
3387 /// This function treats an @ref option as if it was a @ref variant of
3388 /// `void` and `T`. If the @ref option contains a value, that value is
3389 /// passed to the visitor. If the @ref option is `none`, the visitor is
3390 /// called with @ref void_t.
3391 ///
3392 /// In either case, an additional (second) parameter is passed to the
3393 /// visitor, which provides `constexpr` information about the specific
3394 /// alternative being visited. This `info` parameter has the API shown
3395 /// below. Note that this type is always an empty type.
3396 ///
3397 /// ```
3398 /// struct alternative_info {
3399 /// // index of the alternative in the source variant
3400 /// static inline constexpr size_t index = ...;
3401 ///
3402 /// // type of the alternative as declared in the source variant
3403 /// using type = ...;
3404 ///
3405 /// // helper function for forwarding non-const alternative values
3406 /// // without needing to provide a template argument.
3407 /// static constexpr decltype(auto) forward(...);
3408 /// };
3409 /// ```
3410 ///
3411 /// Note that the @ref overload function can be helpful for defining a
3412 /// visitor inline.
3413 ///
3414 /// ## Example
3415 /// ```cpp
3416 /// option<int> opt1{};
3417 /// option<int> opt2{42};
3418 ///
3419 /// opt1.visit_informed([](auto value, auto info) {
3420 /// if constexpr (info.index == 0) { // none
3421 /// assert(true);
3422 /// } else if constexpr (info.index == 1) { // some
3423 /// assert(false);
3424 /// }
3425 /// });
3426 ///
3427 /// opt1.visit_informed([](auto value, auto info) {
3428 /// if constexpr (info.index == 0) { // none
3429 /// assert(false);
3430 /// } else if constexpr (info.index == 1) { // some
3431 /// assert(value == 42);
3432 /// }
3433 /// });
3434 /// ```
3435 template <typename V>
3436 constexpr
3437 #ifndef DOXYGEN
3438 decltype(auto)
3439 #else
3440 DEDUCED
3441 #endif
3442 visit_informed(V&& visitor) & {
3443 return opt_().visit(std::forward<V>(visitor));
3444 }
3445
3446 /// @brief Calls a visitor callable with the contained value and meta data.
3447 ///
3448 /// @details
3449 /// This function treats an @ref option as if it was a @ref variant of
3450 /// `void` and `T`. If the @ref option contains a value, that value is
3451 /// passed to the visitor. If the @ref option is `none`, the visitor is
3452 /// called with @ref void_t.
3453 ///
3454 /// In either case, an additional (second) parameter is passed to the
3455 /// visitor, which provides `constexpr` information about the specific
3456 /// alternative being visited. This `info` parameter has the API shown
3457 /// below. Note that this type is always an empty type.
3458 ///
3459 /// ```
3460 /// struct alternative_info {
3461 /// // index of the alternative in the source variant
3462 /// static inline constexpr size_t index = ...;
3463 ///
3464 /// // type of the alternative as declared in the source variant
3465 /// using type = ...;
3466 ///
3467 /// // helper function for forwarding non-const alternative values
3468 /// // without needing to provide a template argument.
3469 /// static constexpr decltype(auto) forward(...);
3470 /// };
3471 /// ```
3472 ///
3473 /// Note that the @ref overload function can be helpful for defining a
3474 /// visitor inline.
3475 ///
3476 /// ## Example
3477 /// ```cpp
3478 /// const option<int> opt1{};
3479 /// const option<int> opt2{42};
3480 ///
3481 /// opt1.visit_informed([](auto value, auto info) {
3482 /// if constexpr (info.index == 0) { // none
3483 /// assert(true);
3484 /// } else if constexpr (info.index == 1) { // some
3485 /// assert(false);
3486 /// }
3487 /// });
3488 ///
3489 /// opt1.visit_informed([](auto value, auto info) {
3490 /// if constexpr (info.index == 0) { // none
3491 /// assert(false);
3492 /// } else if constexpr (info.index == 1) { // some
3493 /// assert(value == 42);
3494 /// }
3495 /// });
3496 /// ```
3497 template <typename V>
3498 constexpr
3499 #ifndef DOXYGEN
3500 decltype(auto)
3501 #else
3502 DEDUCED
3503 #endif
3504 visit_informed(V&& visitor) const& {
3505 return opt_().visit(std::forward<V>(visitor));
3506 }
3507
3508 /// @brief Calls a visitor callable with the contained value and meta data.
3509 ///
3510 /// @details
3511 /// This function treats an @ref option as if it was a @ref variant of
3512 /// `void` and `T`. If the @ref option contains a value, that value is
3513 /// passed to the visitor. If the @ref option is `none`, the visitor is
3514 /// called with @ref void_t.
3515 ///
3516 /// In either case, an additional (second) parameter is passed to the
3517 /// visitor, which provides `constexpr` information about the specific
3518 /// alternative being visited. This `info` parameter has the API shown
3519 /// below. Note that this type is always an empty type.
3520 ///
3521 /// ```
3522 /// struct alternative_info {
3523 /// // index of the alternative in the source variant
3524 /// static inline constexpr size_t index = ...;
3525 ///
3526 /// // type of the alternative as declared in the source variant
3527 /// using type = ...;
3528 ///
3529 /// // helper function for forwarding non-const alternative values
3530 /// // without needing to provide a template argument.
3531 /// static constexpr decltype(auto) forward(...);
3532 /// };
3533 /// ```
3534 ///
3535 /// Note that the @ref overload function can be helpful for defining a
3536 /// visitor inline.
3537 ///
3538 /// ## Example
3539 /// ```cpp
3540 /// option<int> opt1{};
3541 /// option<int> opt2{42};
3542 ///
3543 /// std::move(opt1).visit_informed([](auto value, auto info) {
3544 /// if constexpr (info.index == 0) { // none
3545 /// assert(true);
3546 /// } else if constexpr (info.index == 1) { // some
3547 /// assert(false);
3548 /// }
3549 /// });
3550 ///
3551 /// std::move(opt1).visit_informed([](auto value, auto info) {
3552 /// if constexpr (info.index == 0) { // none
3553 /// assert(false);
3554 /// } else if constexpr (info.index == 1) { // some
3555 /// assert(value == 42);
3556 /// }
3557 /// });
3558 /// ```
3559 template <typename V>
3560 constexpr
3561 #ifndef DOXYGEN
3562 decltype(auto)
3563 #else
3564 DEDUCED
3565 #endif
3566 visit_informed(V&& visitor) && {
3567 return std::move(*this).opt_().visit(std::forward<V>(visitor));
3568 }
3569
3570 /// @brief Calls a visitor callable with the contained value and meta data.
3571 ///
3572 /// @details
3573 /// This function treats an @ref option as if it was a @ref variant of
3574 /// `void` and `T`. If the @ref option contains a value, that value is
3575 /// passed to the visitor. If the @ref option is `none`, the visitor is
3576 /// called with @ref void_t.
3577 ///
3578 /// In either case, an additional (second) parameter is passed to the
3579 /// visitor, which provides `constexpr` information about the specific
3580 /// alternative being visited. This `info` parameter has the API shown
3581 /// below. Note that this type is always an empty type.
3582 ///
3583 /// ```
3584 /// struct alternative_info {
3585 /// // index of the alternative in the source variant
3586 /// static inline constexpr size_t index = ...;
3587 ///
3588 /// // type of the alternative as declared in the source variant
3589 /// using type = ...;
3590 ///
3591 /// // helper function for forwarding non-const alternative values
3592 /// // without needing to provide a template argument.
3593 /// static constexpr decltype(auto) forward(...);
3594 /// };
3595 /// ```
3596 ///
3597 /// Note that the @ref overload function can be helpful for defining a
3598 /// visitor inline.
3599 ///
3600 /// ## Example
3601 /// ```cpp
3602 /// const option<int> opt1{};
3603 /// const option<int> opt2{42};
3604 ///
3605 /// std::move(opt1).visit_informed([](auto value, auto info) {
3606 /// if constexpr (info.index == 0) { // none
3607 /// assert(true);
3608 /// } else if constexpr (info.index == 1) { // some
3609 /// assert(false);
3610 /// }
3611 /// });
3612 ///
3613 /// std::move(opt1).visit_informed([](auto value, auto info) {
3614 /// if constexpr (info.index == 0) { // none
3615 /// assert(false);
3616 /// } else if constexpr (info.index == 1) { // some
3617 /// assert(value == 42);
3618 /// }
3619 /// });
3620 /// ```
3621 template <typename V>
3622 constexpr
3623 #ifndef DOXYGEN
3624 decltype(auto)
3625 #else
3626 DEDUCED
3627 #endif
3628 visit_informed(V&& visitor) const&& {
3629 return std::move(*this).opt_().visit(std::forward<V>(visitor));
3630 }
3631
3632 /// @brief Swaps two @ref option instances
3633 ///
3634 /// @details
3635 /// If both @ref option instances contain a value, the two contained values
3636 /// are swapped directly. Otherwise, if one @ref option contains a value,
3637 /// that value is move constructed into the other @ref option, and the old
3638 /// value is destroyed in place. If both @ref option instances are `none`,
3639 /// nothing is done.
3640 ///
3641 /// This function is `noexcept` if the contained value type is nothrow
3642 /// swappable.
3643 ///
3644 /// ## Example
3645 /// ```
3646 /// option<int> opt1{};
3647 /// option<int> opt2{42};
3648 ///
3649 /// opt1.swap(opt2);
3650 ///
3651 /// assert(opt1.has_value());
3652 /// assert(*opt1 == 42);
3653 ///
3654 /// assert(!opt1.has_value());
3655 /// ```
3656 3 constexpr void swap(option& other)
3657 #ifndef DOXYGEN
3658 noexcept(noexcept(opt_().swap(other.opt_())))
3659 #else
3660 CONDITIONALLY_NOEXCEPT
3661 #endif
3662 {
3663 3 opt_().swap(other.opt_());
3664 3 }
3665
3666 /// @brief Sets the @ref option to `none`.
3667 ///
3668 /// @details
3669 /// If the @ref option contains a value, the value is destroyed in place.
3670 /// Otherwise, nothing is done.
3671 ///
3672 /// ## Example
3673 /// ```
3674 /// option<int> opt1{};
3675 /// option<int> opt2{42};
3676 ///
3677 /// opt1.reset();
3678 /// opt2.reset();
3679 ///
3680 /// assert(!opt1.has_value());
3681 /// assert(!opt2.has_value());
3682 /// ```
3683 8 constexpr void reset() noexcept { opt_().template emplace<0>(); }
3684
3685 /// @brief Constructs a new value in place into the @ref option.
3686 ///
3687 /// @details
3688 /// If the @ref option already contains a value, the old value is first
3689 /// destroyed in place. In any case, a new value is constructed in place
3690 /// in the @ref option.
3691 ///
3692 /// ## Example
3693 /// ```
3694 /// option<std::string> opt1{};
3695 /// option<std::string> opt2{"hello"};
3696 ///
3697 /// opt1.emplace(5, 'a');
3698 /// opt2.emplace(5, 'a');
3699 ///
3700 /// assert(opt1.has_value());
3701 /// assert(*opt1 == "aaaaa");
3702 ///
3703 /// assert(opt2.has_value());
3704 /// assert(*opt2 == "aaaaa");
3705 /// ```
3706 template <typename... Args>
3707 18 constexpr reference emplace(Args&&... args) {
3708 18 opt_().template emplace<1>(std::forward<Args>(args)...);
3709 18 return opt_()[index<1>];
3710 }
3711 };
3712
3713 /// @relates option
3714 /// @brief Gets an @ref option value by index, as if it were a @ref variant.
3715 ///
3716 /// @details
3717 /// This function is provided to make @ref option generically compatible with
3718 /// @ref variant. This function treats `option<T>` as if it were
3719 /// `variant<void, T>`, where index 0 gets `void` (which represents `none`)
3720 /// and index 1 gets `T` (which is the contained value).
3721 ///
3722 /// ## Example
3723 /// ```
3724 /// option<int> opt{42};
3725 ///
3726 /// assert(get<1>(opt) == 42);
3727 /// ```
3728 ///
3729 /// @tparam IDX The "alternative" index
3730 ///
3731 /// @param opt The @ref option to access
3732 ///
3733 /// @return A reference to the accessed "alternative"
3734 ///
3735 /// @throws bad_option_access Thrown if the @ref option state does not match
3736 /// the index `IDX`.
3737 template <size_t IDX, typename T>
3738 constexpr
3739 #ifndef DOXYGEN
3740 typename detail::traits<detail::select_t<IDX, void, T>>::reference
3741 #else
3742 REFERENCE
3743 #endif
3744 get(option<T>& opt) {
3745 if constexpr (IDX == 0) {
3746 if (opt.has_value()) { throw bad_option_access(); }
3747 } else {
3748 static_assert(IDX == 1, "Invalid get index for sumty::option");
3749 return opt.value();
3750 }
3751 }
3752
3753 /// @relates option
3754 /// @brief Gets an @ref option value by index, as if it were a @ref variant.
3755 ///
3756 /// @details
3757 /// This function is provided to make @ref option generically compatible with
3758 /// @ref variant. This function treats `option<T>` as if it were
3759 /// `variant<void, T>`, where index 0 gets `void` (which represents `none`)
3760 /// and index 1 gets `T` (which is the contained value).
3761 ///
3762 /// ## Example
3763 /// ```
3764 /// const option<int> opt{42};
3765 ///
3766 /// assert(get<1>(opt) == 42);
3767 /// ```
3768 ///
3769 /// @tparam IDX The "alternative" index
3770 ///
3771 /// @param opt The @ref option to access
3772 ///
3773 /// @return A const reference to the accessed "alternative"
3774 ///
3775 /// @throws bad_option_access Thrown if the @ref option state does not match
3776 /// the index `IDX`.
3777 template <size_t IDX, typename T>
3778 constexpr
3779 #ifndef DOXYGEN
3780 typename detail::traits<detail::select_t<IDX, void, T>>::const_reference
3781 #else
3782 CONST_REFERENCE
3783 #endif
3784 get(const option<T>& opt) {
3785 if constexpr (IDX == 0) {
3786 if (opt.has_value()) { throw bad_option_access(); }
3787 } else {
3788 static_assert(IDX == 1, "Invalid get index for sumty::option");
3789 return opt.value();
3790 }
3791 }
3792
3793 /// @relates option
3794 /// @brief Gets an @ref option value by index, as if it were a @ref variant.
3795 ///
3796 /// @details
3797 /// This function is provided to make @ref option generically compatible with
3798 /// @ref variant. This function treats `option<T>` as if it were
3799 /// `variant<void, T>`, where index 0 gets `void` (which represents `none`)
3800 /// and index 1 gets `T` (which is the contained value).
3801 ///
3802 /// ## Example
3803 /// ```
3804 /// option<int> opt{42};
3805 ///
3806 /// assert(get<1>(std::move(opt)) == 42);
3807 /// ```
3808 ///
3809 /// @tparam IDX The "alternative" index
3810 ///
3811 /// @param opt The @ref option to access
3812 ///
3813 /// @return An rvalue reference to the accessed "alternative"
3814 ///
3815 /// @throws bad_option_access Thrown if the @ref option state does not match
3816 /// the index `IDX`.
3817 template <size_t IDX, typename T>
3818 constexpr
3819 #ifndef DOXYGEN
3820 typename detail::traits<detail::select_t<IDX, void, T>>::rvalue_reference
3821 #else
3822 RVALUE_REFERENCE
3823 #endif
3824 get(option<T>&& opt) {
3825 if constexpr (IDX == 0) {
3826 if (opt.has_value()) { throw bad_option_access(); }
3827 } else {
3828 static_assert(IDX == 1, "Invalid get index for sumty::option");
3829 return std::move(opt).value();
3830 }
3831 }
3832
3833 /// @relates option
3834 /// @brief Gets an @ref option value by index, as if it were a @ref variant.
3835 ///
3836 /// @details
3837 /// This function is provided to make @ref option generically compatible with
3838 /// @ref variant. This function treats `option<T>` as if it were
3839 /// `variant<void, T>`, where index 0 gets `void` (which represents `none`)
3840 /// and index 1 gets `T` (which is the contained value).
3841 ///
3842 /// ## Example
3843 /// ```
3844 /// const option<int> opt{42};
3845 ///
3846 /// assert(get<1>(std::move(opt)) == 42);
3847 /// ```
3848 ///
3849 /// @tparam IDX The "alternative" index
3850 ///
3851 /// @param opt The @ref option to access
3852 ///
3853 /// @return A const rvalue reference to the accessed "alternative"
3854 ///
3855 /// @throws bad_option_access Thrown if the @ref option state does not match
3856 /// the index `IDX`.
3857 template <size_t IDX, typename T>
3858 constexpr
3859 #ifndef DOXYGEN
3860 typename detail::traits<detail::select_t<IDX, void, T>>::const_rvalue_reference
3861 #else
3862 CONST_RVALUE_REFERENCE
3863 #endif
3864 get(const option<T>&& opt) {
3865 if constexpr (IDX == 0) {
3866 if (opt.has_value()) { throw bad_option_access(); }
3867 } else {
3868 static_assert(IDX == 1, "Invalid get index for sumty::option");
3869 return std::move(opt).value();
3870 }
3871 }
3872
3873 /// @relates option
3874 /// @brief Gets an @ref option value by type, as if it were a @ref variant.
3875 ///
3876 /// @details
3877 /// This function is provided to make @ref option generically compatible with
3878 /// @ref variant. This function treats `option<T>` as if it were
3879 /// `variant<void, T>`, where `void` is the `none` alternative, and `T` is
3880 /// the alternative with a value.
3881 ///
3882 /// This function only participates in overload resolution if the contained
3883 /// value of the @ref option is not `void`.
3884 ///
3885 /// ## Example
3886 /// ```
3887 /// option<int> opt{42};
3888 ///
3889 /// assert(get<int>(opt) == 42);
3890 /// ```
3891 ///
3892 /// @tparam T The type of the alternative to access
3893 ///
3894 /// @param opt The @ref option to access
3895 ///
3896 /// @return A reference to the accessed alternative
3897 ///
3898 /// @throws bad_option_access Thrown if the @ref option does not contain the
3899 /// requested type `T`.
3900 template <typename T, typename U>
3901 #ifndef DOXYGEN
3902 requires(!std::is_void_v<U>)
3903 #endif
3904 constexpr
3905 #ifndef DOXYGEN
3906 typename detail::traits<T>::reference
3907 #else
3908 REFERENCE
3909 #endif
3910 get(option<U>& opt) {
3911 if constexpr (std::is_void_v<T>) {
3912 if (opt.has_value()) { throw bad_option_access(); }
3913 } else {
3914 static_assert(std::is_same_v<T, U>, "Invalid get type for sumty::option");
3915 return opt.value();
3916 }
3917 }
3918
3919 /// @relates option
3920 /// @brief Gets an @ref option value by type, as if it were a @ref variant.
3921 ///
3922 /// @details
3923 /// This function is provided to make @ref option generically compatible with
3924 /// @ref variant. This function treats `option<T>` as if it were
3925 /// `variant<void, T>`, where `void` is the `none` alternative, and `T` is
3926 /// the alternative with a value.
3927 ///
3928 /// This function only participates in overload resolution if the contained
3929 /// value of the @ref option is not `void`.
3930 ///
3931 /// ## Example
3932 /// ```
3933 /// const option<int> opt{42};
3934 ///
3935 /// assert(get<int>(opt) == 42);
3936 /// ```
3937 ///
3938 /// @tparam T The type of the alternative to access
3939 ///
3940 /// @param opt The @ref option to access
3941 ///
3942 /// @return A const reference to the accessed alternative
3943 ///
3944 /// @throws bad_option_access Thrown if the @ref option does not contain the
3945 /// requested type `T`.
3946 template <typename T, typename U>
3947 #ifndef DOXYGEN
3948 requires(!std::is_void_v<U>)
3949 #endif
3950 constexpr
3951 #ifndef DOXYGEN
3952 typename detail::traits<T>::const_reference
3953 #else
3954 CONST_REFERENCE
3955 #endif
3956 get(const option<U>& opt) {
3957 if constexpr (std::is_void_v<T>) {
3958 if (opt.has_value()) { throw bad_option_access(); }
3959 } else {
3960 static_assert(std::is_same_v<T, U>, "Invalid get type for sumty::option");
3961 return opt.value();
3962 }
3963 }
3964
3965 /// @relates option
3966 /// @brief Gets an @ref option value by type, as if it were a @ref variant.
3967 ///
3968 /// @details
3969 /// This function is provided to make @ref option generically compatible with
3970 /// @ref variant. This function treats `option<T>` as if it were
3971 /// `variant<void, T>`, where `void` is the `none` alternative, and `T` is
3972 /// the alternative with a value.
3973 ///
3974 /// This function only participates in overload resolution if the contained
3975 /// value of the @ref option is not `void`.
3976 ///
3977 /// ## Example
3978 /// ```
3979 /// option<int> opt{42};
3980 ///
3981 /// assert(get<int>(std::move(opt)) == 42);
3982 /// ```
3983 ///
3984 /// @tparam T The type of the alternative to access
3985 ///
3986 /// @param opt The @ref option to access
3987 ///
3988 /// @return An rvalue reference to the accessed alternative
3989 ///
3990 /// @throws bad_option_access Thrown if the @ref option does not contain the
3991 /// requested type `T`.
3992 template <typename T, typename U>
3993 #ifndef DOXYGEN
3994 requires(!std::is_void_v<U>)
3995 #endif
3996 constexpr
3997 #ifndef DOXYGEN
3998 typename detail::traits<T>::rvalue_reference
3999 #else
4000 RVALUE_REFERENCE
4001 #endif
4002 get(option<U>&& opt) {
4003 if constexpr (std::is_void_v<T>) {
4004 if (opt.has_value()) { throw bad_option_access(); }
4005 } else {
4006 static_assert(std::is_same_v<T, U>, "Invalid get type for sumty::option");
4007 return std::move(opt).value();
4008 }
4009 }
4010
4011 /// @relates option
4012 /// @brief Gets an @ref option value by type, as if it were a @ref variant.
4013 ///
4014 /// @details
4015 /// This function is provided to make @ref option generically compatible with
4016 /// @ref variant. This function treats `option<T>` as if it were
4017 /// `variant<void, T>`, where `void` is the `none` alternative, and `T` is
4018 /// the alternative with a value.
4019 ///
4020 /// This function only participates in overload resolution if the contained
4021 /// value of the @ref option is not `void`.
4022 ///
4023 /// ## Example
4024 /// ```
4025 /// const option<int> opt{42};
4026 ///
4027 /// assert(get<int>(std::move(opt)) == 42);
4028 /// ```
4029 ///
4030 /// @tparam T The type of the alternative to access
4031 ///
4032 /// @param opt The @ref option to access
4033 ///
4034 /// @return A const rvalue reference to the accessed alternative
4035 ///
4036 /// @throws bad_option_access Thrown if the @ref option does not contain the
4037 /// requested type `T`.
4038 template <typename T, typename U>
4039 #ifndef DOXYGEN
4040 requires(!std::is_void_v<U>)
4041 #endif
4042 constexpr
4043 #ifndef DOXYGEN
4044 typename detail::traits<T>::const_rvalue_reference
4045 #else
4046 CONST_RVALUE_REFERENCE
4047 #endif
4048 get(const option<U>&& opt) {
4049 if constexpr (std::is_void_v<T>) {
4050 if (opt.has_value()) { throw bad_option_access(); }
4051 } else {
4052 static_assert(std::is_same_v<T, U>, "Invalid get type for sumty::option");
4053 return std::move(opt).value();
4054 }
4055 }
4056
4057 /// @relates option
4058 /// @brief Tests two @ref option instances for equality.
4059 ///
4060 /// @details
4061 /// ## Example
4062 /// ```
4063 /// option<int> opt1{};
4064 /// option<int> opt2{42};
4065 /// option<int> opt3{24};
4066 ///
4067 /// assert(opt1 == opt1);
4068 /// assert(opt2 == opt2);
4069 /// assert(!(opt1 == opt2));
4070 /// assert(!(opt2 == opt3));
4071 /// ```
4072 template <typename T, typename U>
4073 6 constexpr bool operator==(const option<T>& lhs, const option<U>& rhs) {
4074
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 2 times.
6 if (lhs.has_value()) {
4075
4/4
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
4 return rhs.has_value() && *lhs == *rhs;
4076 } else {
4077 2 return !rhs.has_value();
4078 }
4079 }
4080
4081 /// @relates option
4082 /// @brief Tests two @ref option instances for inequality.
4083 ///
4084 /// @details
4085 /// ## Example
4086 /// ```
4087 /// option<int> opt1{};
4088 /// option<int> opt2{42};
4089 /// option<int> opt3{24};
4090 ///
4091 /// assert(!(opt1 != opt1));
4092 /// assert(!(opt2 != opt2));
4093 /// assert(opt1 != opt2);
4094 /// assert(opt2 != opt3);
4095 /// ```
4096 template <typename T, typename U>
4097 6 constexpr bool operator!=(const option<T>& lhs, const option<U>& rhs) {
4098
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
2/2
✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 2 times.
6 if (lhs.has_value()) {
4099
4/4
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 1 times.
4 return !rhs.has_value() || *lhs != *rhs;
4100 } else {
4101 2 return rhs.has_value();
4102 }
4103 }
4104
4105 /// @relates option
4106 /// @brief Compares two @ref option instances.
4107 ///
4108 /// @details
4109 /// `none` is always less than any contained value.
4110 ///
4111 /// ## Example
4112 /// ```
4113 /// option<int> opt1{};
4114 /// option<int> opt2{42};
4115 /// option<int> opt3{24};
4116 ///
4117 /// assert(opt1 < opt2);
4118 /// assert(opt1 < opt3);
4119 /// assert(opt3 < opt2);
4120 /// ```
4121 template <typename T, typename U>
4122 constexpr bool operator<(const option<T>& lhs, const option<U>& rhs) {
4123 return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
4124 }
4125
4126 /// @relates option
4127 /// @brief Compares two @ref option instances.
4128 ///
4129 /// @details
4130 /// `none` is always less than any contained value.
4131 ///
4132 /// ## Example
4133 /// ```
4134 /// option<int> opt1{};
4135 /// option<int> opt2{42};
4136 /// option<int> opt3{24};
4137 ///
4138 /// assert(opt2 > opt1);
4139 /// assert(opt3 > opt1);
4140 /// assert(opt2 > opt3);
4141 /// ```
4142 template <typename T, typename U>
4143 constexpr bool operator>(const option<T>& lhs, const option<U>& rhs) {
4144 return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
4145 }
4146
4147 /// @relates option
4148 /// @brief Compares two @ref option instances.
4149 ///
4150 /// @details
4151 /// `none` is always less than any contained value.
4152 ///
4153 /// ## Example
4154 /// ```
4155 /// option<int> opt1{};
4156 /// option<int> opt2{42};
4157 /// option<int> opt3{24};
4158 ///
4159 /// assert(opt1 <= opt2);
4160 /// assert(opt1 <= opt3);
4161 /// assert(opt3 <= opt2);
4162 /// assert(opt2 <= opt2);
4163 /// ```
4164 template <typename T, typename U>
4165 constexpr bool operator<=(const option<T>& lhs, const option<U>& rhs) {
4166 return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
4167 }
4168
4169 /// @relates option
4170 /// @brief Compares two @ref option instances.
4171 ///
4172 /// @details
4173 /// `none` is always less than any contained value.
4174 ///
4175 /// ## Example
4176 /// ```
4177 /// option<int> opt1{};
4178 /// option<int> opt2{42};
4179 /// option<int> opt3{24};
4180 ///
4181 /// assert(opt2 >= opt1);
4182 /// assert(opt3 >= opt1);
4183 /// assert(opt2 >= opt3);
4184 /// assert(opt2 >= opt2);
4185 /// ```
4186 template <typename T, typename U>
4187 constexpr bool operator>=(const option<T>& lhs, const option<U>& rhs) {
4188 return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
4189 }
4190
4191 /// @relates option
4192 /// @brief Compares two @ref option instances.
4193 ///
4194 /// @details
4195 /// `none` is always less than any contained value.
4196 ///
4197 /// ## Example
4198 /// ```
4199 /// option<int> opt1{};
4200 /// option<int> opt2{42};
4201 /// option<int> opt3{24};
4202 ///
4203 /// assert((opt1 <=> opt2) == std::strong_ordering::less);
4204 /// assert((opt1 <=> opt3) == std::strong_ordering::less);
4205 /// assert((opt2 <=> opt3) == std::strong_ordering::greater);
4206 /// assert((opt2 <=> opt2) == std::strong_ordering::equal);
4207 /// ```
4208 template <typename T, typename U>
4209 #ifndef DOXYGEN
4210 requires(std::three_way_comparable_with<std::remove_cvref_t<U>, std::remove_cvref_t<T>>)
4211 #endif
4212 constexpr
4213 #ifndef DOXYGEN
4214 std::compare_three_way_result_t<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
4215 #else
4216 auto
4217 #endif
4218 30 operator<=>(const option<T>& lhs, const option<U>& rhs) {
4219
6/6
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 10 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 15 times.
✓ Branch 7 taken 15 times.
2/2
✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 15 times.
30 if (lhs.has_value() && rhs.has_value()) {
4220
4/4
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 5 times.
15 return *lhs <=> *rhs;
4221 } else {
4222
4/4
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 5 times.
15 return lhs.has_value() <=> rhs.has_value();
4223 }
4224 }
4225
4226 /// @relates option
4227 /// @brief Compares an @ref option with a value.
4228 ///
4229 /// @details
4230 /// `none` is always less than the value. If not `none`, the contained value
4231 /// is compared with the value.
4232 ///
4233 /// ## Example
4234 /// ```
4235 /// option<int> opt1{};
4236 /// option<int> opt2{42};
4237 ///
4238 /// assert(!(opt1 == 42));
4239 /// assert(opt2 == 42);
4240 /// assert(!(opt2 == 24));
4241 /// ```
4242 template <typename T, typename U>
4243 constexpr bool operator==(const option<T>& lhs, const U& rhs) {
4244 return lhs.has_value() && *lhs == rhs;
4245 }
4246
4247 /// @relates option
4248 /// @brief Compares an @ref option with a value.
4249 ///
4250 /// @details
4251 /// `none` is always less than the value. If not `none`, the contained value
4252 /// is compared with the value.
4253 ///
4254 /// ## Example
4255 /// ```
4256 /// option<int> opt1{};
4257 /// option<int> opt2{42};
4258 ///
4259 /// assert(!(42 == opt1));
4260 /// assert(42 == opt2);
4261 /// assert(!(24 == opt2));
4262 /// ```
4263 template <typename T, typename U>
4264 constexpr bool operator==(const U& lhs, const option<T>& rhs) {
4265 return rhs.has_value() && lhs == *rhs;
4266 }
4267
4268 /// @relates option
4269 /// @brief Compares an @ref option with a value.
4270 ///
4271 /// @details
4272 /// `none` is always less than the value. If not `none`, the contained value
4273 /// is compared with the value.
4274 ///
4275 /// ## Example
4276 /// ```
4277 /// option<int> opt1{};
4278 /// option<int> opt2{42};
4279 ///
4280 /// assert(opt1 != 42);
4281 /// assert(!(opt2 != 42));
4282 /// assert(opt2 != 24);
4283 /// ```
4284 template <typename T, typename U>
4285 constexpr bool operator!=(const option<T>& lhs, const U& rhs) {
4286 return !lhs.has_value() || *lhs != rhs;
4287 }
4288
4289 /// @relates option
4290 /// @brief Compares an @ref option with a value.
4291 ///
4292 /// @details
4293 /// `none` is always less than the value. If not `none`, the contained value
4294 /// is compared with the value.
4295 ///
4296 /// ## Example
4297 /// ```
4298 /// option<int> opt1{};
4299 /// option<int> opt2{42};
4300 ///
4301 /// assert(42 != opt1);
4302 /// assert(!(42 != opt2));
4303 /// assert(24 != opt2);
4304 /// ```
4305 template <typename T, typename U>
4306 constexpr bool operator!=(const U& lhs, const option<T>& rhs) {
4307 return !rhs.has_value() || lhs != *rhs;
4308 }
4309
4310 /// @relates option
4311 /// @brief Compares an @ref option with a value.
4312 ///
4313 /// @details
4314 /// `none` is always less than the value. If not `none`, the contained value
4315 /// is compared with the value.
4316 ///
4317 /// ## Example
4318 /// ```
4319 /// option<int> opt1{};
4320 /// option<int> opt2{42};
4321 ///
4322 /// assert(opt1 < 42);
4323 /// assert(!(opt2 < 42));
4324 /// assert(opt2 < 100);
4325 /// ```
4326 template <typename T, typename U>
4327 constexpr bool operator<(const option<T>& lhs, const U& rhs) {
4328 return !lhs.has_value() || *lhs < rhs;
4329 }
4330
4331 /// @relates option
4332 /// @brief Compares an @ref option with a value.
4333 ///
4334 /// @details
4335 /// `none` is always less than the value. If not `none`, the contained value
4336 /// is compared with the value.
4337 ///
4338 /// ## Example
4339 /// ```
4340 /// option<int> opt1{};
4341 /// option<int> opt2{42};
4342 ///
4343 /// assert(!(42 < opt1));
4344 /// assert(!(42 < opt2));
4345 /// assert(40 < opt2);
4346 /// ```
4347 template <typename T, typename U>
4348 constexpr bool operator<(const U& lhs, const option<T>& rhs) {
4349 return rhs.has_value() && lhs < *rhs;
4350 }
4351
4352 /// @relates option
4353 /// @brief Compares an @ref option with a value.
4354 ///
4355 /// @details
4356 /// `none` is always less than the value. If not `none`, the contained value
4357 /// is compared with the value.
4358 ///
4359 /// ## Example
4360 /// ```
4361 /// option<int> opt1{};
4362 /// option<int> opt2{42};
4363 ///
4364 /// assert(!(opt1 > 42));
4365 /// assert(!(opt2 > 42));
4366 /// assert(opt2 > 40);
4367 /// ```
4368 template <typename T, typename U>
4369 constexpr bool operator>(const option<T>& lhs, const U& rhs) {
4370 return !lhs.has_value() && *lhs > rhs;
4371 }
4372
4373 /// @relates option
4374 /// @brief Compares an @ref option with a value.
4375 ///
4376 /// @details
4377 /// `none` is always less than the value. If not `none`, the contained value
4378 /// is compared with the value.
4379 ///
4380 /// ## Example
4381 /// ```
4382 /// option<int> opt1{};
4383 /// option<int> opt2{42};
4384 ///
4385 /// assert(42 > opt);
4386 /// assert(!(42 > opt2));
4387 /// assert(100 > opt2);
4388 /// ```
4389 template <typename T, typename U>
4390 constexpr bool operator>(const U& lhs, const option<T>& rhs) {
4391 return !rhs.has_value() || lhs > *lhs;
4392 }
4393
4394 /// @relates option
4395 /// @brief Compares an @ref option with a value.
4396 ///
4397 /// @details
4398 /// `none` is always less than the value. If not `none`, the contained value
4399 /// is compared with the value.
4400 ///
4401 /// ## Example
4402 /// ```
4403 /// option<int> opt1{};
4404 /// option<int> opt2{42};
4405 ///
4406 /// assert(opt1 <= 42);
4407 /// assert(opt2 <= 42);
4408 /// assert(!(opt2 <= 100));
4409 /// ```
4410 template <typename T, typename U>
4411 constexpr bool operator<=(const option<T>& lhs, const U& rhs) {
4412 return !lhs.has_value() || *lhs <= rhs;
4413 }
4414
4415 /// @relates option
4416 /// @brief Compares an @ref option with a value.
4417 ///
4418 /// @details
4419 /// `none` is always less than the value. If not `none`, the contained value
4420 /// is compared with the value.
4421 ///
4422 /// ## Example
4423 /// ```
4424 /// option<int> opt1{};
4425 /// option<int> opt2{42};
4426 ///
4427 /// assert(!(42 <= opt1));
4428 /// assert(42 <= opt2);
4429 /// assert(!(100 <= opt2));
4430 /// ```
4431 template <typename T, typename U>
4432 constexpr bool operator<=(const U& lhs, const option<T>& rhs) {
4433 return rhs.has_value() && lhs <= *rhs;
4434 }
4435
4436 /// @relates option
4437 /// @brief Compares an @ref option with a value.
4438 ///
4439 /// @details
4440 /// `none` is always less than the value. If not `none`, the contained value
4441 /// is compared with the value.
4442 ///
4443 /// ## Example
4444 /// ```
4445 /// option<int> opt1{};
4446 /// option<int> opt2{42};
4447 ///
4448 /// assert(!(opt1 >= 42));
4449 /// assert(opt2 >= 42);
4450 /// assert(!(opt2 >= 100));
4451 /// ```
4452 template <typename T, typename U>
4453 constexpr bool operator>=(const option<T>& lhs, const U& rhs) {
4454 return lhs.has_value() && *lhs >= rhs;
4455 }
4456
4457 /// @relates option
4458 /// @brief Compares an @ref option with a value.
4459 ///
4460 /// @details
4461 /// `none` is always less than the value. If not `none`, the contained value
4462 /// is compared with the value.
4463 ///
4464 /// ## Example
4465 /// ```
4466 /// option<int> opt1{};
4467 /// option<int> opt2{42};
4468 ///
4469 /// assert(42 >= opt1);
4470 /// assert(42 >= opt2);
4471 /// assert(!(40 >= opt2));
4472 /// ```
4473 template <typename T, typename U>
4474 constexpr bool operator>=(const U& lhs, const option<T>& rhs) {
4475 return !rhs.has_value() || lhs >= *rhs;
4476 }
4477
4478 /// @relates option
4479 /// @brief Compares an @ref option with a value.
4480 ///
4481 /// @details
4482 /// `none` is always less than the value. If not `none`, the contained value
4483 /// is compared with the value.
4484 ///
4485 /// ## Example
4486 /// ```
4487 /// option<int> opt1{};
4488 /// option<int> opt2{42};
4489 ///
4490 /// assert((opt1 <=> 42) == std::strong_ordering::less);
4491 /// assert((42 <=> opt1) == std::strong_ordering::greater);
4492 /// assert((opt2 <=> 42) == std::strong_ordering::equal);
4493 /// assert((40 <=> opt2) == std::strong_ordering::less);
4494 /// ```
4495 template <typename T, typename U>
4496 #ifndef DOXYGEN
4497 requires(!detail::is_option_v<U>)
4498 #endif
4499 constexpr
4500 #ifndef DOXYGEN
4501 std::compare_three_way_result_t<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
4502 #else
4503 auto
4504 #endif
4505 operator<=>(const option<T>& lhs, const U& rhs)
4506 #ifndef DOXYGEN
4507 requires(std::three_way_comparable_with<std::remove_cvref_t<U>, std::remove_cvref_t<T>>)
4508 #endif
4509 {
4510 if (lhs.has_value()) {
4511 return *lhs <=> rhs;
4512 } else {
4513 return std::strong_ordering::less;
4514 }
4515 }
4516
4517 /// @relates option
4518 /// @brief Compares an @ref option with `none`.
4519 ///
4520 /// @details
4521 /// `none` is always less than an @ref option with a contained value.
4522 ///
4523 /// ## Example
4524 /// ```
4525 /// option<int> opt1{};
4526 /// option<int> opt2{42};
4527 ///
4528 /// assert(opt1 == none);
4529 /// assert(!(opt2 == none));
4530 /// ```
4531 template <typename T>
4532 2 constexpr bool operator==(const option<T>& lhs, [[maybe_unused]] none_t rhs) {
4533 2 return !lhs.has_value();
4534 }
4535
4536 /// @relates option
4537 /// @brief Compares an @ref option with `none`.
4538 ///
4539 /// @details
4540 /// `none` is always less than an @ref option with a contained value.
4541 ///
4542 /// ## Example
4543 /// ```
4544 /// option<int> opt1{};
4545 /// option<int> opt2{42};
4546 ///
4547 /// assert(none == opt1);
4548 /// assert(!(none == opt2));
4549 /// ```
4550 template <typename T>
4551 2 constexpr bool operator==([[maybe_unused]] none_t lhs, const option<T>& rhs) {
4552 2 return !rhs.has_value();
4553 }
4554
4555 /// @relates option
4556 /// @brief Compares an @ref option with `none`.
4557 ///
4558 /// @details
4559 /// `none` is always less than an @ref option with a contained value.
4560 ///
4561 /// ## Example
4562 /// ```
4563 /// option<int> opt1{};
4564 /// option<int> opt2{42};
4565 ///
4566 /// assert(!(opt1 != none));
4567 /// assert(opt2 != none);
4568 /// ```
4569 template <typename T>
4570 2 constexpr bool operator!=(const option<T>& lhs, [[maybe_unused]] none_t rhs) {
4571 2 return lhs.has_value();
4572 }
4573
4574 /// @relates option
4575 /// @brief Compares an @ref option with `none`.
4576 ///
4577 /// @details
4578 /// `none` is always less than an @ref option with a contained value.
4579 ///
4580 /// ## Example
4581 /// ```
4582 /// option<int> opt1{};
4583 /// option<int> opt2{42};
4584 ///
4585 /// assert(!(none != opt1));
4586 /// assert(none != opt2);
4587 /// ```
4588 template <typename T>
4589 2 constexpr bool operator!=([[maybe_unused]] none_t lhs, const option<T>& rhs) {
4590 2 return rhs.has_value();
4591 }
4592
4593 /// @relates option
4594 /// @brief Compares an @ref option with `none`.
4595 ///
4596 /// @details
4597 /// `none` is always less than an @ref option with a contained value.
4598 ///
4599 /// ## Example
4600 /// ```
4601 /// option<int> opt1{};
4602 /// option<int> opt2{42};
4603 ///
4604 /// assert(!(opt1 < none));
4605 /// assert(!(opt2 < none));
4606 /// ```
4607 template <typename T>
4608 2 constexpr bool operator<([[maybe_unused]] const option<T>& lhs,
4609 [[maybe_unused]] none_t rhs) {
4610 2 return false;
4611 }
4612
4613 /// @relates option
4614 /// @brief Compares an @ref option with `none`.
4615 ///
4616 /// @details
4617 /// `none` is always less than an @ref option with a contained value.
4618 ///
4619 /// ## Example
4620 /// ```
4621 /// option<int> opt1{};
4622 /// option<int> opt2{42};
4623 ///
4624 /// assert(!(none < opt1));
4625 /// assert(none < opt2);
4626 /// ```
4627 template <typename T>
4628 2 constexpr bool operator<([[maybe_unused]] none_t lhs, const option<T>& rhs) {
4629 2 return rhs.has_value();
4630 }
4631
4632 /// @relates option
4633 /// @brief Compares an @ref option with `none`.
4634 ///
4635 /// @details
4636 /// `none` is always less than an @ref option with a contained value.
4637 ///
4638 /// ## Example
4639 /// ```
4640 /// option<int> opt1{};
4641 /// option<int> opt2{42};
4642 ///
4643 /// assert(!(opt1 > none));
4644 /// assert(opt2 > none);
4645 /// ```
4646 template <typename T>
4647 2 constexpr bool operator>(const option<T>& lhs, [[maybe_unused]] none_t rhs) {
4648 2 return lhs.has_value();
4649 }
4650
4651 /// @relates option
4652 /// @brief Compares an @ref option with `none`.
4653 ///
4654 /// @details
4655 /// `none` is always less than an @ref option with a contained value.
4656 ///
4657 /// ## Example
4658 /// ```
4659 /// option<int> opt1{};
4660 /// option<int> opt2{42};
4661 ///
4662 /// assert(!(none > opt1));
4663 /// assert(!(none > opt2));
4664 /// ```
4665 template <typename T>
4666 2 constexpr bool operator>([[maybe_unused]] none_t lhs,
4667 [[maybe_unused]] const option<T>& rhs) {
4668 2 return false;
4669 }
4670
4671 /// @relates option
4672 /// @brief Compares an @ref option with `none`.
4673 ///
4674 /// @details
4675 /// `none` is always less than an @ref option with a contained value.
4676 ///
4677 /// ## Example
4678 /// ```
4679 /// option<int> opt1{};
4680 /// option<int> opt2{42};
4681 ///
4682 /// assert(opt1 <= none);
4683 /// assert(!(opt2 <= none));
4684 /// ```
4685 template <typename T>
4686 2 constexpr bool operator<=(const option<T>& lhs, [[maybe_unused]] none_t rhs) {
4687 2 return !lhs.has_value();
4688 }
4689
4690 /// @relates option
4691 /// @brief Compares an @ref option with `none`.
4692 ///
4693 /// @details
4694 /// `none` is always less than an @ref option with a contained value.
4695 ///
4696 /// ## Example
4697 /// ```
4698 /// option<int> opt1{};
4699 /// option<int> opt2{42};
4700 ///
4701 /// assert(none <= opt1);
4702 /// assert(none <= opt2);
4703 /// ```
4704 template <typename T>
4705 2 constexpr bool operator<=([[maybe_unused]] none_t lhs,
4706 [[maybe_unused]] const option<T>& rhs) {
4707 2 return true;
4708 }
4709
4710 /// @relates option
4711 /// @brief Compares an @ref option with `none`.
4712 ///
4713 /// @details
4714 /// `none` is always less than an @ref option with a contained value.
4715 ///
4716 /// ## Example
4717 /// ```
4718 /// option<int> opt1{};
4719 /// option<int> opt2{42};
4720 ///
4721 /// assert(opt1 >= none);
4722 /// assert(opt2 >= none);
4723 /// ```
4724 template <typename T>
4725 2 constexpr bool operator>=([[maybe_unused]] const option<T>& lhs,
4726 [[maybe_unused]] none_t rhs) {
4727 2 return true;
4728 }
4729
4730 /// @relates option
4731 /// @brief Compares an @ref option with `none`.
4732 ///
4733 /// @details
4734 /// `none` is always less than an @ref option with a contained value.
4735 ///
4736 /// ## Example
4737 /// ```
4738 /// option<int> opt1{};
4739 /// option<int> opt2{42};
4740 ///
4741 /// assert(none >= opt1);
4742 /// assert(!(none >= opt2));
4743 /// ```
4744 template <typename T>
4745 2 constexpr bool operator>=([[maybe_unused]] none_t lhs, const option<T>& rhs) {
4746 2 return !rhs.has_value();
4747 }
4748
4749 /// @relates option
4750 /// @brief Compares an @ref option with `none`.
4751 ///
4752 /// @details
4753 /// `none` is always less than an @ref option with a contained value.
4754 ///
4755 /// ## Example
4756 /// ```
4757 /// option<int> opt1{};
4758 /// option<int> opt2{42};
4759 ///
4760 /// assert((opt1 <=> none) == std::strong_ordering::equal);
4761 /// assert((none <=> opt1) == std::strong_ordering::equal);
4762 /// assert((opt2 <=> none) == std::strong_ordering::greater);
4763 /// assert((none <=> opt2) == std::strong_ordering::less);
4764 /// ```
4765 template <typename T>
4766 4 constexpr std::strong_ordering operator<=>(const option<T>& lhs,
4767 [[maybe_unused]] none_t rhs) {
4768
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 return lhs.has_value() <=> false;
4769 }
4770
4771 /// @relates option
4772 /// @brief Compares an @ref option with `std::nullopt`.
4773 ///
4774 /// @details
4775 /// `std::nullopt` is always less than an @ref option with a contained value.
4776 ///
4777 /// ## Example
4778 /// ```
4779 /// option<int> opt1{};
4780 /// option<int> opt2{42};
4781 ///
4782 /// assert(opt1 == std::nullopt);
4783 /// assert(!(opt2 == std::nullopt));
4784 /// ```
4785 template <typename T>
4786 2 constexpr bool operator==(const option<T>& lhs, [[maybe_unused]] std::nullopt_t rhs) {
4787 2 return !lhs.has_value();
4788 }
4789
4790 /// @relates option
4791 /// @brief Compares an @ref option with `std::nullopt`.
4792 ///
4793 /// @details
4794 /// `std::nullopt` is always less than an @ref option with a contained value.
4795 ///
4796 /// ## Example
4797 /// ```
4798 /// option<int> opt1{};
4799 /// option<int> opt2{42};
4800 ///
4801 /// assert(std::nullopt == opt1);
4802 /// assert(!(std::nullopt == opt2));
4803 /// ```
4804 template <typename T>
4805 2 constexpr bool operator==([[maybe_unused]] std::nullopt_t lhs, const option<T>& rhs) {
4806 2 return !rhs.has_value();
4807 }
4808
4809 /// @relates option
4810 /// @brief Compares an @ref option with `std::nullopt`.
4811 ///
4812 /// @details
4813 /// `std::nullopt` is always less than an @ref option with a contained value.
4814 ///
4815 /// ## Example
4816 /// ```
4817 /// option<int> opt1{};
4818 /// option<int> opt2{42};
4819 ///
4820 /// assert(!(opt1 != std::nullopt));
4821 /// assert(opt2 != std::nullopt);
4822 /// ```
4823 template <typename T>
4824 2 constexpr bool operator!=(const option<T>& lhs, [[maybe_unused]] std::nullopt_t rhs) {
4825 2 return lhs.has_value();
4826 }
4827
4828 /// @relates option
4829 /// @brief Compares an @ref option with `std::nullopt`.
4830 ///
4831 /// @details
4832 /// `std::nullopt` is always less than an @ref option with a contained value.
4833 ///
4834 /// ## Example
4835 /// ```
4836 /// option<int> opt1{};
4837 /// option<int> opt2{42};
4838 ///
4839 /// assert(!(std::nullopt != opt1));
4840 /// assert(std::nullopt != opt2);
4841 /// ```
4842 template <typename T>
4843 2 constexpr bool operator!=([[maybe_unused]] std::nullopt_t lhs, const option<T>& rhs) {
4844 2 return rhs.has_value();
4845 }
4846
4847 /// @relates option
4848 /// @brief Compares an @ref option with `std::nullopt`.
4849 ///
4850 /// @details
4851 /// `std::nullopt` is always less than an @ref option with a contained value.
4852 ///
4853 /// ## Example
4854 /// ```
4855 /// option<int> opt1{};
4856 /// option<int> opt2{42};
4857 ///
4858 /// assert(!(opt1 < std::nullopt));
4859 /// assert(!(opt2 < std::nullopt));
4860 /// ```
4861 template <typename T>
4862 2 constexpr bool operator<([[maybe_unused]] const option<T>& lhs,
4863 [[maybe_unused]] std::nullopt_t rhs) {
4864 2 return false;
4865 }
4866
4867 /// @relates option
4868 /// @brief Compares an @ref option with `std::nullopt`.
4869 ///
4870 /// @details
4871 /// `std::nullopt` is always less than an @ref option with a contained value.
4872 ///
4873 /// ## Example
4874 /// ```
4875 /// option<int> opt1{};
4876 /// option<int> opt2{42};
4877 ///
4878 /// assert(!(std::nullopt < opt1));
4879 /// assert(std::nullopt < opt2);
4880 /// ```
4881 template <typename T>
4882 2 constexpr bool operator<([[maybe_unused]] std::nullopt_t lhs, const option<T>& rhs) {
4883 2 return rhs.has_value();
4884 }
4885
4886 /// @relates option
4887 /// @brief Compares an @ref option with `std::nullopt`.
4888 ///
4889 /// @details
4890 /// `std::nullopt` is always less than an @ref option with a contained value.
4891 ///
4892 /// ## Example
4893 /// ```
4894 /// option<int> opt1{};
4895 /// option<int> opt2{42};
4896 ///
4897 /// assert(!(opt1 > std::nullopt));
4898 /// assert(opt2 > std::nullopt);
4899 /// ```
4900 template <typename T>
4901 2 constexpr bool operator>(const option<T>& lhs, [[maybe_unused]] std::nullopt_t rhs) {
4902 2 return lhs.has_value();
4903 }
4904
4905 /// @relates option
4906 /// @brief Compares an @ref option with `std::nullopt`.
4907 ///
4908 /// @details
4909 /// `std::nullopt` is always less than an @ref option with a contained value.
4910 ///
4911 /// ## Example
4912 /// ```
4913 /// option<int> opt1{};
4914 /// option<int> opt2{42};
4915 ///
4916 /// assert(!(std::nullopt > opt1));
4917 /// assert(!(std::nullopt > opt2));
4918 /// ```
4919 template <typename T>
4920 2 constexpr bool operator>([[maybe_unused]] std::nullopt_t lhs,
4921 [[maybe_unused]] const option<T>& rhs) {
4922 2 return false;
4923 }
4924
4925 /// @relates option
4926 /// @brief Compares an @ref option with `std::nullopt`.
4927 ///
4928 /// @details
4929 /// `std::nullopt` is always less than an @ref option with a contained value.
4930 ///
4931 /// ## Example
4932 /// ```
4933 /// option<int> opt1{};
4934 /// option<int> opt2{42};
4935 ///
4936 /// assert(opt1 <= std::nullopt);
4937 /// assert(!(opt2 <= std::nullopt));
4938 /// ```
4939 template <typename T>
4940 2 constexpr bool operator<=(const option<T>& lhs, [[maybe_unused]] std::nullopt_t rhs) {
4941 2 return !lhs.has_value();
4942 }
4943
4944 /// @relates option
4945 /// @brief Compares an @ref option with `std::nullopt`.
4946 ///
4947 /// @details
4948 /// `std::nullopt` is always less than an @ref option with a contained value.
4949 ///
4950 /// ## Example
4951 /// ```
4952 /// option<int> opt1{};
4953 /// option<int> opt2{42};
4954 ///
4955 /// assert(std::nullopt <= opt1);
4956 /// assert(std::nullopt <= opt2);
4957 /// ```
4958 template <typename T>
4959 2 constexpr bool operator<=([[maybe_unused]] std::nullopt_t lhs,
4960 [[maybe_unused]] const option<T>& rhs) {
4961 2 return true;
4962 }
4963
4964 /// @relates option
4965 /// @brief Compares an @ref option with `std::nullopt`.
4966 ///
4967 /// @details
4968 /// `std::nullopt` is always less than an @ref option with a contained value.
4969 ///
4970 /// ## Example
4971 /// ```
4972 /// option<int> opt1{};
4973 /// option<int> opt2{42};
4974 ///
4975 /// assert(opt1 >= std::nullopt);
4976 /// assert(opt2 >= std::nullopt);
4977 /// ```
4978 template <typename T>
4979 2 constexpr bool operator>=([[maybe_unused]] const option<T>& lhs,
4980 [[maybe_unused]] std::nullopt_t rhs) {
4981 2 return true;
4982 }
4983
4984 /// @relates option
4985 /// @brief Compares an @ref option with `std::nullopt`.
4986 ///
4987 /// @details
4988 /// `std::nullopt` is always less than an @ref option with a contained value.
4989 ///
4990 /// ## Example
4991 /// ```
4992 /// option<int> opt1{};
4993 /// option<int> opt2{42};
4994 ///
4995 /// assert(std::nullopt >= opt1);
4996 /// assert(!(std::nullopt >= opt2));
4997 /// ```
4998 template <typename T>
4999 2 constexpr bool operator>=([[maybe_unused]] std::nullopt_t lhs, const option<T>& rhs) {
5000 2 return !rhs.has_value();
5001 }
5002
5003 /// @relates option
5004 /// @brief Compares an @ref option with `std::nullopt`.
5005 ///
5006 /// @details
5007 /// `std::nullopt` is always less than an @ref option with a contained value.
5008 ///
5009 /// ## Example
5010 /// ```
5011 /// option<int> opt1{};
5012 /// option<int> opt2{42};
5013 ///
5014 /// assert((opt1 <=> std::nullopt) == std::strong_ordering::equal);
5015 /// assert((std::nullopt <=> opt1) == std::strong_ordering::equal);
5016 /// assert((opt2 <=> std::nullopt) == std::strong_ordering::greater);
5017 /// assert((std::nullopt <=> opt2) == std::strong_ordering::less);
5018 /// ```
5019 template <typename T>
5020 4 constexpr std::strong_ordering operator<=>(const option<T>& lhs,
5021 [[maybe_unused]] std::nullopt_t rhs) {
5022
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 return lhs.has_value() <=> false;
5023 }
5024
5025 /// @relates option
5026 /// @brief Compares an @ref option with `nullptr`.
5027 ///
5028 /// @details
5029 /// `nullptr` is always less than an @ref option with a contained value.
5030 ///
5031 /// This function only participates in overload resolution if the contained
5032 /// type of the @ref option is an lvalue reference.
5033 ///
5034 /// ## Example
5035 /// ```
5036 /// int value = 42;
5037 /// option<int&> opt1{};
5038 /// option<int&> opt2{value};
5039 ///
5040 /// assert(opt1 == nullptr);
5041 /// assert(!(opt2 == nullptr));
5042 /// ```
5043 template <typename T>
5044 #ifndef DOXYGEN
5045 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5046 #endif
5047 6 constexpr bool operator==(const option<T>& lhs, [[maybe_unused]] std::nullptr_t rhs) {
5048 6 return !lhs.has_value();
5049 }
5050
5051 /// @relates option
5052 /// @brief Compares an @ref option with `nullptr`.
5053 ///
5054 /// @details
5055 /// `nullptr` is always less than an @ref option with a contained value.
5056 ///
5057 /// This function only participates in overload resolution if the contained
5058 /// type of the @ref option is an lvalue reference.
5059 ///
5060 /// ## Example
5061 /// ```
5062 /// int value = 42;
5063 /// option<int&> opt1{};
5064 /// option<int&> opt2{value};
5065 ///
5066 /// assert(nullptr == opt1);
5067 /// assert(!(nullptr == opt2));
5068 /// ```
5069 template <typename T>
5070 #ifndef DOXYGEN
5071 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5072 #endif
5073 2 constexpr bool operator==([[maybe_unused]] std::nullptr_t lhs, const option<T>& rhs) {
5074 2 return !rhs.has_value();
5075 }
5076
5077 /// @relates option
5078 /// @brief Compares an @ref option with `nullptr`.
5079 ///
5080 /// @details
5081 /// `nullptr` is always less than an @ref option with a contained value.
5082 ///
5083 /// This function only participates in overload resolution if the contained
5084 /// type of the @ref option is an lvalue reference.
5085 ///
5086 /// ## Example
5087 /// ```
5088 /// int value = 42;
5089 /// option<int&> opt1{};
5090 /// option<int&> opt2{value};
5091 ///
5092 /// assert(!(opt1 != nullptr));
5093 /// assert(opt2 != nullptr);
5094 /// ```
5095 template <typename T>
5096 #ifndef DOXYGEN
5097 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5098 #endif
5099 2 constexpr bool operator!=(const option<T>& lhs, [[maybe_unused]] std::nullptr_t rhs) {
5100 2 return lhs.has_value();
5101 }
5102
5103 /// @relates option
5104 /// @brief Compares an @ref option with `nullptr`.
5105 ///
5106 /// @details
5107 /// `nullptr` is always less than an @ref option with a contained value.
5108 ///
5109 /// This function only participates in overload resolution if the contained
5110 /// type of the @ref option is an lvalue reference.
5111 ///
5112 /// ## Example
5113 /// ```
5114 /// int value = 42;
5115 /// option<int&> opt1{};
5116 /// option<int&> opt2{value};
5117 ///
5118 /// assert(!(nullptr != opt1));
5119 /// assert(nullptr != opt2);
5120 /// ```
5121 template <typename T>
5122 #ifndef DOXYGEN
5123 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5124 #endif
5125 2 constexpr bool operator!=([[maybe_unused]] std::nullptr_t lhs, const option<T>& rhs) {
5126 2 return rhs.has_value();
5127 }
5128
5129 /// @relates option
5130 /// @brief Compares an @ref option with `nullptr`.
5131 ///
5132 /// @details
5133 /// `nullptr` is always less than an @ref option with a contained value.
5134 ///
5135 /// This function only participates in overload resolution if the contained
5136 /// type of the @ref option is an lvalue reference.
5137 ///
5138 /// ## Example
5139 /// ```
5140 /// int value = 42;
5141 /// option<int&> opt1{};
5142 /// option<int&> opt2{value};
5143 ///
5144 /// assert(!(opt1 < nullptr));
5145 /// assert(!(opt2 < nullptr));
5146 /// ```
5147 template <typename T>
5148 #ifndef DOXYGEN
5149 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5150 #endif
5151 2 constexpr bool operator<([[maybe_unused]] const option<T>& lhs,
5152 [[maybe_unused]] std::nullptr_t rhs) {
5153 2 return false;
5154 }
5155
5156 /// @relates option
5157 /// @brief Compares an @ref option with `nullptr`.
5158 ///
5159 /// @details
5160 /// `nullptr` is always less than an @ref option with a contained value.
5161 ///
5162 /// This function only participates in overload resolution if the contained
5163 /// type of the @ref option is an lvalue reference.
5164 ///
5165 /// ## Example
5166 /// ```
5167 /// int value = 42;
5168 /// option<int&> opt1{};
5169 /// option<int&> opt2{value};
5170 ///
5171 /// assert(!(nullptr < opt1));
5172 /// assert(nullptr < opt2);
5173 /// ```
5174 template <typename T>
5175 #ifndef DOXYGEN
5176 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5177 #endif
5178 2 constexpr bool operator<([[maybe_unused]] std::nullptr_t lhs, const option<T>& rhs) {
5179 2 return rhs.has_value();
5180 }
5181
5182 /// @relates option
5183 /// @brief Compares an @ref option with `nullptr`.
5184 ///
5185 /// @details
5186 /// `nullptr` is always less than an @ref option with a contained value.
5187 ///
5188 /// This function only participates in overload resolution if the contained
5189 /// type of the @ref option is an lvalue reference.
5190 ///
5191 /// ## Example
5192 /// ```
5193 /// int value = 42;
5194 /// option<int&> opt1{};
5195 /// option<int&> opt2{value};
5196 ///
5197 /// assert(!(opt1 > nullptr));
5198 /// assert(opt2 > nullptr);
5199 /// ```
5200 template <typename T>
5201 #ifndef DOXYGEN
5202 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5203 #endif
5204 2 constexpr bool operator>(const option<T>& lhs, [[maybe_unused]] std::nullptr_t rhs) {
5205 2 return lhs.has_value();
5206 }
5207
5208 /// @relates option
5209 /// @brief Compares an @ref option with `nullptr`.
5210 ///
5211 /// @details
5212 /// `nullptr` is always less than an @ref option with a contained value.
5213 ///
5214 /// This function only participates in overload resolution if the contained
5215 /// type of the @ref option is an lvalue reference.
5216 ///
5217 /// ## Example
5218 /// ```
5219 /// int value = 42;
5220 /// option<int&> opt1{};
5221 /// option<int&> opt2{value};
5222 ///
5223 /// assert(!(nullptr > opt1));
5224 /// assert(!(nullptr > opt2));
5225 /// ```
5226 template <typename T>
5227 #ifndef DOXYGEN
5228 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5229 #endif
5230 2 constexpr bool operator>([[maybe_unused]] std::nullptr_t lhs,
5231 [[maybe_unused]] const option<T>& rhs) {
5232 2 return false;
5233 }
5234
5235 /// @relates option
5236 /// @brief Compares an @ref option with `nullptr`.
5237 ///
5238 /// @details
5239 /// `nullptr` is always less than an @ref option with a contained value.
5240 ///
5241 /// This function only participates in overload resolution if the contained
5242 /// type of the @ref option is an lvalue reference.
5243 ///
5244 /// ## Example
5245 /// ```
5246 /// int value = 42;
5247 /// option<int&> opt1{};
5248 /// option<int&> opt2{value};
5249 ///
5250 /// assert(opt1 <= nullptr);
5251 /// assert(!(opt2 <= nullptr));
5252 /// ```
5253 template <typename T>
5254 #ifndef DOXYGEN
5255 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5256 #endif
5257 2 constexpr bool operator<=(const option<T>& lhs, [[maybe_unused]] std::nullptr_t rhs) {
5258 2 return !lhs.has_value();
5259 }
5260
5261 /// @relates option
5262 /// @brief Compares an @ref option with `nullptr`.
5263 ///
5264 /// @details
5265 /// `nullptr` is always less than an @ref option with a contained value.
5266 ///
5267 /// This function only participates in overload resolution if the contained
5268 /// type of the @ref option is an lvalue reference.
5269 ///
5270 /// ## Example
5271 /// ```
5272 /// int value = 42;
5273 /// option<int&> opt1{};
5274 /// option<int&> opt2{value};
5275 ///
5276 /// assert(nullptr <= opt1);
5277 /// assert(nullptr <= opt2);
5278 /// ```
5279 template <typename T>
5280 #ifndef DOXYGEN
5281 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5282 #endif
5283 2 constexpr bool operator<=([[maybe_unused]] std::nullptr_t lhs,
5284 [[maybe_unused]] const option<T>& rhs) {
5285 2 return true;
5286 }
5287
5288 /// @relates option
5289 /// @brief Compares an @ref option with `nullptr`.
5290 ///
5291 /// @details
5292 /// `nullptr` is always less than an @ref option with a contained value.
5293 ///
5294 /// This function only participates in overload resolution if the contained
5295 /// type of the @ref option is an lvalue reference.
5296 ///
5297 /// ## Example
5298 /// ```
5299 /// int value = 42;
5300 /// option<int&> opt1{};
5301 /// option<int&> opt2{value};
5302 ///
5303 /// assert(opt1 >= nullptr);
5304 /// assert(opt2 >= nullptr);
5305 /// ```
5306 template <typename T>
5307 #ifndef DOXYGEN
5308 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5309 #endif
5310 2 constexpr bool operator>=([[maybe_unused]] const option<T>& lhs,
5311 [[maybe_unused]] std::nullptr_t rhs) {
5312 2 return true;
5313 }
5314
5315 /// @relates option
5316 /// @brief Compares an @ref option with `nullptr`.
5317 ///
5318 /// @details
5319 /// `nullptr` is always less than an @ref option with a contained value.
5320 ///
5321 /// This function only participates in overload resolution if the contained
5322 /// type of the @ref option is an lvalue reference.
5323 ///
5324 /// ## Example
5325 /// ```
5326 /// int value = 42;
5327 /// option<int&> opt1{};
5328 /// option<int&> opt2{value};
5329 ///
5330 /// assert(nullptr >= opt1);
5331 /// assert(!(nullptr >= opt2));
5332 /// ```
5333 template <typename T>
5334 #ifndef DOXYGEN
5335 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5336 #endif
5337 2 constexpr bool operator>=([[maybe_unused]] std::nullptr_t lhs, const option<T>& rhs) {
5338 2 return !rhs.has_value();
5339 }
5340
5341 /// @relates option
5342 /// @brief Compares an @ref option with `nullptr`.
5343 ///
5344 /// @details
5345 /// `nullptr` is always less than an @ref option with a contained value.
5346 ///
5347 /// This function only participates in overload resolution if the contained
5348 /// type of the @ref option is an lvalue reference.
5349 ///
5350 /// ## Example
5351 /// ```
5352 /// int value = 42;
5353 /// option<int&> opt1{};
5354 /// option<int&> opt2{value};
5355 ///
5356 /// assert((opt1 <=> nullptr) == std::strong_ordering::equal);
5357 /// assert((nullptr <=> opt1) == std::strong_ordering::equal);
5358 /// assert((opt2 <=> nullptr) == std::strong_ordering::greater);
5359 /// assert((nullptr <=> opt2) == std::strong_ordering::less);
5360 /// ```
5361 template <typename T>
5362 #ifndef DOXYGEN
5363 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5364 #endif
5365 4 constexpr std::strong_ordering operator<=>(const option<T>& lhs,
5366 [[maybe_unused]] std::nullptr_t rhs) {
5367
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 return lhs.has_value() <=> false;
5368 }
5369
5370 /// @relates option
5371 /// @brief Compares an @ref option with a pointer.
5372 ///
5373 /// @details
5374 /// An @ref option of an lvalue reference is a smart pointer and is directly
5375 /// comparable with raw pointers, where `none` is null, and a contained
5376 /// value is a non-null address.
5377 ///
5378 /// This function only participates in overload resolution if the contained
5379 /// type of the @ref option is an lvalue reference.
5380 ///
5381 /// ## Example
5382 /// ```
5383 /// int vals[] = {1, 2, 3, 4, 5};
5384 ///
5385 /// option<int&> opt1{};
5386 /// option<int&> opt2{vals[2]};
5387 ///
5388 /// assert(!(opt1 == (vals + 2)));
5389 /// assert(opt2 == (vals + 2));
5390 /// ```
5391 template <typename T, typename U>
5392 #ifndef DOXYGEN
5393 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5394 #endif
5395 constexpr bool operator==(const option<T>& lhs, const U* rhs) {
5396 return &*lhs == rhs;
5397 }
5398
5399 /// @relates option
5400 /// @brief Compares an @ref option with a pointer.
5401 ///
5402 /// @details
5403 /// An @ref option of an lvalue reference is a smart pointer and is directly
5404 /// comparable with raw pointers, where `none` is null, and a contained
5405 /// value is a non-null address.
5406 ///
5407 /// This function only participates in overload resolution if the contained
5408 /// type of the @ref option is an lvalue reference.
5409 ///
5410 /// ## Example
5411 /// ```
5412 /// int vals[] = {1, 2, 3, 4, 5};
5413 ///
5414 /// option<int&> opt1{};
5415 /// option<int&> opt2{vals[2]};
5416 ///
5417 /// assert(opt1 != (vals + 2));
5418 /// assert(!(opt2 != (vals + 2)));
5419 /// ```
5420 template <typename T, typename U>
5421 #ifndef DOXYGEN
5422 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5423 #endif
5424 constexpr bool operator!=(const option<T>& lhs, const U* rhs) {
5425 return &*lhs != rhs;
5426 }
5427
5428 /// @relates option
5429 /// @brief Compares an @ref option with a pointer.
5430 ///
5431 /// @details
5432 /// An @ref option of an lvalue reference is a smart pointer and is directly
5433 /// comparable with raw pointers, where `none` is null, and a contained
5434 /// value is a non-null address.
5435 ///
5436 /// This function only participates in overload resolution if the contained
5437 /// type of the @ref option is an lvalue reference.
5438 ///
5439 /// ## Example
5440 /// ```
5441 /// int vals[] = {1, 2, 3, 4, 5};
5442 ///
5443 /// option<int&> opt1{};
5444 /// option<int&> opt2{vals[2]};
5445 ///
5446 /// assert(opt1 < (vals + 2));
5447 /// assert(!(opt2 < (vals + 2)));
5448 /// assert(opt2 < (vals + 3));
5449 /// ```
5450 template <typename T, typename U>
5451 #ifndef DOXYGEN
5452 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5453 #endif
5454 constexpr bool operator<(const option<T>& lhs, const U* rhs) {
5455 return &*lhs < rhs;
5456 }
5457
5458 /// @relates option
5459 /// @brief Compares an @ref option with a pointer.
5460 ///
5461 /// @details
5462 /// An @ref option of an lvalue reference is a smart pointer and is directly
5463 /// comparable with raw pointers, where `none` is null, and a contained
5464 /// value is a non-null address.
5465 ///
5466 /// This function only participates in overload resolution if the contained
5467 /// type of the @ref option is an lvalue reference.
5468 ///
5469 /// ## Example
5470 /// ```
5471 /// int vals[] = {1, 2, 3, 4, 5};
5472 ///
5473 /// option<int&> opt1{};
5474 /// option<int&> opt2{vals[2]};
5475 ///
5476 /// assert(!(opt1 > (vals + 2)));
5477 /// assert(!(opt2 > (vals + 2)));
5478 /// assert(opt2 > (vals + 1));
5479 /// ```
5480 template <typename T, typename U>
5481 #ifndef DOXYGEN
5482 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5483 #endif
5484 constexpr bool operator>(const option<T>& lhs, const U* rhs) {
5485 return &*lhs > rhs;
5486 }
5487
5488 /// @relates option
5489 /// @brief Compares an @ref option with a pointer.
5490 ///
5491 /// @details
5492 /// An @ref option of an lvalue reference is a smart pointer and is directly
5493 /// comparable with raw pointers, where `none` is null, and a contained
5494 /// value is a non-null address.
5495 ///
5496 /// This function only participates in overload resolution if the contained
5497 /// type of the @ref option is an lvalue reference.
5498 ///
5499 /// ## Example
5500 /// ```
5501 /// int vals[] = {1, 2, 3, 4, 5};
5502 ///
5503 /// option<int&> opt1{};
5504 /// option<int&> opt2{vals[2]};
5505 ///
5506 /// assert(opt1 <= (vals + 2));
5507 /// assert(!(opt2 <= (vals + 1)));
5508 /// assert(opt2 <= (vals + 2));
5509 /// ```
5510 template <typename T, typename U>
5511 #ifndef DOXYGEN
5512 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5513 #endif
5514 constexpr bool operator<=(const option<T>& lhs, const U* rhs) {
5515 return &*lhs <= rhs;
5516 }
5517
5518 /// @relates option
5519 /// @brief Compares an @ref option with a pointer.
5520 ///
5521 /// @details
5522 /// An @ref option of an lvalue reference is a smart pointer and is directly
5523 /// comparable with raw pointers, where `none` is null, and a contained
5524 /// value is a non-null address.
5525 ///
5526 /// This function only participates in overload resolution if the contained
5527 /// type of the @ref option is an lvalue reference.
5528 ///
5529 /// ## Example
5530 /// ```
5531 /// int vals[] = {1, 2, 3, 4, 5};
5532 ///
5533 /// option<int&> opt1{};
5534 /// option<int&> opt2{vals[2]};
5535 ///
5536 /// assert(!(opt1 >= (vals + 2)));
5537 /// assert(opt2 >= (vals + 2));
5538 /// assert(!(opt2 >= (vals + 3)));
5539 /// ```
5540 template <typename T, typename U>
5541 #ifndef DOXYGEN
5542 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5543 #endif
5544 constexpr bool operator>=(const option<T>& lhs, const U* rhs) {
5545 return &*lhs >= rhs;
5546 }
5547
5548 /// @relates option
5549 /// @brief Compares an @ref option with a pointer.
5550 ///
5551 /// @details
5552 /// An @ref option of an lvalue reference is a smart pointer and is directly
5553 /// comparable with raw pointers, where `none` is null, and a contained
5554 /// value is a non-null address.
5555 ///
5556 /// This function only participates in overload resolution if the contained
5557 /// type of the @ref option is an lvalue reference.
5558 ///
5559 /// ## Example
5560 /// ```
5561 /// int vals[] = {1, 2, 3, 4, 5};
5562 ///
5563 /// option<int&> opt1{};
5564 /// option<int&> opt2{vals[2]};
5565 ///
5566 /// assert(!((vals + 2) == opt1));
5567 /// assert((vals + 2) == opt2);
5568 /// ```
5569 template <typename T, typename U>
5570 #ifndef DOXYGEN
5571 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5572 #endif
5573 constexpr bool operator==(const U* lhs, const option<T>& rhs) {
5574 return lhs == &*rhs;
5575 }
5576
5577 /// @relates option
5578 /// @brief Compares an @ref option with a pointer.
5579 ///
5580 /// @details
5581 /// An @ref option of an lvalue reference is a smart pointer and is directly
5582 /// comparable with raw pointers, where `none` is null, and a contained
5583 /// value is a non-null address.
5584 ///
5585 /// This function only participates in overload resolution if the contained
5586 /// type of the @ref option is an lvalue reference.
5587 ///
5588 /// ## Example
5589 /// ```
5590 /// int vals[] = {1, 2, 3, 4, 5};
5591 ///
5592 /// option<int&> opt1{};
5593 /// option<int&> opt2{vals[2]};
5594 ///
5595 /// assert((vals + 2) != opt1);
5596 /// assert(!((vals + 2) != opt2));
5597 /// ```
5598 template <typename T, typename U>
5599 #ifndef DOXYGEN
5600 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5601 #endif
5602 constexpr bool operator!=(const U* lhs, const option<T>& rhs) {
5603 return lhs != &*rhs;
5604 }
5605
5606 /// @relates option
5607 /// @brief Compares an @ref option with a pointer.
5608 ///
5609 /// @details
5610 /// An @ref option of an lvalue reference is a smart pointer and is directly
5611 /// comparable with raw pointers, where `none` is null, and a contained
5612 /// value is a non-null address.
5613 ///
5614 /// This function only participates in overload resolution if the contained
5615 /// type of the @ref option is an lvalue reference.
5616 ///
5617 /// ## Example
5618 /// ```
5619 /// int vals[] = {1, 2, 3, 4, 5};
5620 ///
5621 /// option<int&> opt1{};
5622 /// option<int&> opt2{vals[2]};
5623 ///
5624 /// assert(!((vals + 2) < opt1));
5625 /// assert((vals + 2) < opt2);
5626 /// assert(!((vals + 3) < opt2));
5627 /// ```
5628 template <typename T, typename U>
5629 #ifndef DOXYGEN
5630 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5631 #endif
5632 constexpr bool operator<(const U* lhs, const option<T>& rhs) {
5633 return lhs < &*rhs;
5634 }
5635
5636 /// @relates option
5637 /// @brief Compares an @ref option with a pointer.
5638 ///
5639 /// @details
5640 /// An @ref option of an lvalue reference is a smart pointer and is directly
5641 /// comparable with raw pointers, where `none` is null, and a contained
5642 /// value is a non-null address.
5643 ///
5644 /// This function only participates in overload resolution if the contained
5645 /// type of the @ref option is an lvalue reference.
5646 ///
5647 /// ## Example
5648 /// ```
5649 /// int vals[] = {1, 2, 3, 4, 5};
5650 ///
5651 /// option<int&> opt1{};
5652 /// option<int&> opt2{vals[2]};
5653 ///
5654 /// assert((vals + 2) > opt1);
5655 /// assert((vals + 2) > opt2);
5656 /// assert(!((vals + 1) > opt2));
5657 /// ```
5658 template <typename T, typename U>
5659 #ifndef DOXYGEN
5660 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5661 #endif
5662 constexpr bool operator>(const U* lhs, const option<T>& rhs) {
5663 return lhs > &*rhs;
5664 }
5665
5666 /// @relates option
5667 /// @brief Compares an @ref option with a pointer.
5668 ///
5669 /// @details
5670 /// An @ref option of an lvalue reference is a smart pointer and is directly
5671 /// comparable with raw pointers, where `none` is null, and a contained
5672 /// value is a non-null address.
5673 ///
5674 /// This function only participates in overload resolution if the contained
5675 /// type of the @ref option is an lvalue reference.
5676 ///
5677 /// ## Example
5678 /// ```
5679 /// int vals[] = {1, 2, 3, 4, 5};
5680 ///
5681 /// option<int&> opt1{};
5682 /// option<int&> opt2{vals[2]};
5683 ///
5684 /// assert(!((vals + 2) <= opt1));
5685 /// assert((vals + 2) <= opt2);
5686 /// assert(!((vals + 3) <= opt2));
5687 /// ```
5688 template <typename T, typename U>
5689 #ifndef DOXYGEN
5690 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5691 #endif
5692 constexpr bool operator<=(const U* lhs, const option<T>& rhs) {
5693 return lhs <= &*rhs;
5694 }
5695
5696 /// @relates option
5697 /// @brief Compares an @ref option with a pointer.
5698 ///
5699 /// @details
5700 /// An @ref option of an lvalue reference is a smart pointer and is directly
5701 /// comparable with raw pointers, where `none` is null, and a contained
5702 /// value is a non-null address.
5703 ///
5704 /// This function only participates in overload resolution if the contained
5705 /// type of the @ref option is an lvalue reference.
5706 ///
5707 /// ## Example
5708 /// ```
5709 /// int vals[] = {1, 2, 3, 4, 5};
5710 ///
5711 /// option<int&> opt1{};
5712 /// option<int&> opt2{vals[2]};
5713 ///
5714 /// assert((vals + 2) >= opt1);
5715 /// assert(!((vals + 1) >= opt2));
5716 /// assert((vals + 2) >= opt2);
5717 /// ```
5718 template <typename T, typename U>
5719 #ifndef DOXYGEN
5720 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5721 #endif
5722 constexpr bool operator>=(const U* lhs, const option<T>& rhs) {
5723 return lhs >= &*rhs;
5724 }
5725
5726 /// @relates option
5727 /// @brief Compares an @ref option with a pointer.
5728 ///
5729 /// @details
5730 /// An @ref option of an lvalue reference is a smart pointer and is directly
5731 /// comparable with raw pointers, where `none` is null, and a contained
5732 /// value is a non-null address.
5733 ///
5734 /// This function only participates in overload resolution if the contained
5735 /// type of the @ref option is an lvalue reference.
5736 ///
5737 /// ## Example
5738 /// ```
5739 /// int vals[] = {1, 2, 3, 4, 5};
5740 ///
5741 /// option<int&> opt1{};
5742 /// option<int&> opt2{vals[2]};
5743 ///
5744 /// assert((opt1 <=> (vals + 2)) == std::strong_ordering::less);
5745 /// assert(((vals + 2) <=> opt1) == std::strong_ordering::greater);
5746 /// assert((opt2 <=> (vals + 1)) == std::strong_ordering::greater);
5747 /// assert((opt2 <=> (vals + 2)) == std::strong_ordering::equal);
5748 /// assert((opt2 <=> (vals + 3)) == std::strong_ordering::less);
5749 /// ```
5750 template <typename T, typename U>
5751 #ifndef DOXYGEN
5752 requires(std::is_lvalue_reference_v<typename option<T>::value_type>)
5753 #endif
5754 constexpr auto operator<=>(const option<T>& lhs, const U* rhs) {
5755 return &*lhs <=> rhs;
5756 }
5757
5758 /// @relates option
5759 /// @brief Constructs an @ref option that contains a value.
5760 ///
5761 /// @details
5762 /// This function is the counterpart to @ref none that creates an @ref option
5763 /// that contains a value instead of being `none`. The contained value is
5764 /// constructed in place in the @ref option, which is then RVO returned.
5765 ///
5766 /// A call to this function must explicitly specify the type `T` that the @ref
5767 /// option should contain, and the passed arguments are forwarded to the
5768 /// constructor of that type.
5769 ///
5770 /// ## Example
5771 /// ```
5772 /// int value = 42;
5773 ///
5774 /// auto opt1 = some<void>();
5775 /// auto opt2 = some<int>(value);
5776 /// auto opt3 = some<int&>(value);
5777 ///
5778 /// assert(opt1.has_value());
5779 ///
5780 /// assert(opt2.has_value());
5781 /// assert(*opt2 == 42);
5782 ///
5783 /// assert(opt3.has_value());
5784 /// assert(opt3 == &value);
5785 /// ```
5786 template <typename T, typename... Args>
5787 1 constexpr option<T> some(Args&&... args) {
5788 1 return option<T>{std::in_place, std::forward<Args>(args)...};
5789 }
5790
5791 /// @relates option
5792 /// @brief Constructs an @ref option that contains a value.
5793 ///
5794 /// @details
5795 /// This function is the counterpart to @ref none that creates an @ref option
5796 /// that contains a value instead of being `none`. The contained value is
5797 /// constructed in place in the @ref option, which is then RVO returned.
5798 ///
5799 /// A call to this function must explicitly specify the type `T` that the @ref
5800 /// option should contain, and the passed arguments are forwarded to the
5801 /// constructor of that type.
5802 ///
5803 /// ## Example
5804 /// ```
5805 /// auto opt = some<std::vector<int>>({1, 2, 3, 4, 5});
5806 ///
5807 /// assert(opt.has_value());
5808 /// assert(opt->size() == 5);
5809 /// ```
5810 template <typename T, typename U, typename... Args>
5811 constexpr option<T> some(std::initializer_list<U> ilist, Args&&... args) {
5812 return option<T>{std::in_place, ilist, std::forward<Args>(args)...};
5813 }
5814
5815 /// @relates option
5816 /// @brief Swaps two @ref option instances
5817 ///
5818 /// @details
5819 /// If both @ref option instances contain a value, the two contained values
5820 /// are swapped directly. Otherwise, if one @ref option contains a value,
5821 /// that value is move constructed into the other @ref option, and the old
5822 /// value is destroyed in place. If both @ref option instances are `none`,
5823 /// nothing is done.
5824 ///
5825 /// This function is `noexcept` if the contained value type is nothrow
5826 /// swappable.
5827 ///
5828 /// # Example
5829 /// ```
5830 /// option<int> opt1{};
5831 /// option<int> opt2{42};
5832 ///
5833 /// swap(opt1, opt2);
5834 ///
5835 /// assert(opt1.has_value());
5836 /// assert(*opt1 == 42);
5837 ///
5838 /// assert(!opt1.has_value());
5839 /// ```
5840 template <typename T>
5841 3 constexpr void swap(option<T>& a, option<T>& b)
5842 #ifndef DOXYGEN
5843 noexcept(noexcept(a.swap(b)))
5844 #else
5845 CONDITIONALLY_NOEXCEPT
5846 #endif
5847 {
5848 3 a.swap(b);
5849 3 }
5850
5851 } // namespace sumty
5852
5853 #endif
5854