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 |