tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
optional.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2020 Tobias Hienzsch
3
4#ifndef TETL_OPTIONAL_OPTIONAL_HPP
5#define TETL_OPTIONAL_OPTIONAL_HPP
6
7#include <etl/_config/all.hpp>
8
9#include <etl/_concepts/copy_constructible.hpp>
10#include <etl/_concepts/move_constructible.hpp>
11#include <etl/_concepts/same_as.hpp>
12#include <etl/_contracts/check.hpp>
13#include <etl/_functional/hash.hpp>
14#include <etl/_functional/invoke.hpp>
15#include <etl/_iterator/next.hpp>
16#include <etl/_memory/addressof.hpp>
17#include <etl/_optional/nullopt.hpp>
18#include <etl/_type_traits/add_lvalue_reference.hpp>
19#include <etl/_type_traits/conjunction.hpp>
20#include <etl/_type_traits/decay.hpp>
21#include <etl/_type_traits/invoke_result.hpp>
22#include <etl/_type_traits/is_assignable.hpp>
23#include <etl/_type_traits/is_constructible.hpp>
24#include <etl/_type_traits/is_convertible.hpp>
25#include <etl/_type_traits/is_lvalue_reference.hpp>
26#include <etl/_type_traits/is_nothrow_move_constructible.hpp>
27#include <etl/_type_traits/is_nothrow_swappable.hpp>
28#include <etl/_type_traits/is_same.hpp>
29#include <etl/_type_traits/is_scalar.hpp>
30#include <etl/_type_traits/is_specialized.hpp>
31#include <etl/_type_traits/remove_const.hpp>
32#include <etl/_type_traits/remove_cv.hpp>
33#include <etl/_type_traits/remove_cvref.hpp>
34#include <etl/_utility/forward.hpp>
35#include <etl/_utility/in_place.hpp>
36#include <etl/_utility/in_place_index.hpp>
37#include <etl/_utility/move.hpp>
38#include <etl/_utility/swap.hpp>
39#include <etl/_variant/monostate.hpp>
40#include <etl/_variant/variant.hpp>
41
42namespace etl {
43
44/// \brief The class template optional manages an optional contained value,
45/// i.e. a value that may or may not be present.
46///
47/// \details A common use case for optional is the return value of a function
48/// that may fail. As opposed to other approaches, such as etl::pair<T,bool>,
49/// optional handles expensive-to-construct objects well and is more readable,
50/// as the intent is expressed explicitly.
51///
52/// Any instance of optional at any given point in time either contains a
53/// value or does not contain a value.
54///
55/// If an optional contains a value, the value is guaranteed to be
56/// allocated as part of the optional object footprint, i.e. no dynamic memory
57/// allocation ever takes place. Thus, an optional object models an object, not
58/// a pointer, even though operator*() and operator->() are defined.
59///
60/// When an object of type optional is contextually converted to bool, the
61/// conversion returns true if the object contains a value and false if it does
62/// not contain a value.
63///
64/// The optional object contains a value in the following conditions:
65/// - The object is initialized with/assigned from a value of type T or
66/// another optional that contains a value.
67///
68/// The object does not contain a value in the following conditions:
69/// - The object is default-initialized.
70/// - The object is initialized with/assigned from a value of type
71/// etl::nullopt_t or an optional object that does not contain a value.
72/// - The member function reset() is called.
73///
74/// There are no optional references; a program is ill-formed if it instantiates
75/// an optional with a reference type. Alternatively, an optional of a
76/// etl::reference_wrapper of type T may be used to hold a reference. In
77/// addition, a program is ill-formed if it instantiates an optional with the
78/// (possibly cv-qualified) tag types etl::nullopt_t or etl::in_place_t.
79///
80/// https://en.cppreference.com/w/cpp/utility/optional
81///
82/// \tparam T The type of the value to manage initialization state for. The type
83/// must meet the requirements of Destructible (in particular, array types are
84/// not allowed).
85///
86/// \headerfile etl/optional.hpp
87/// \ingroup optional
88///
89/// \include optional.cpp
90template <typename T>
91struct optional {
92 using value_type = T;
93 using iterator = T*;
94 using const_iterator = T const*;
95
96 static_assert(!is_array_v<T>, "instantiation of optional with an array type is ill-formed");
97 static_assert(!is_same_v<remove_cvref_t<T>, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed");
98 static_assert(!is_same_v<remove_cvref_t<T>, in_place_t>, "instantiation of optional with in_place_t is ill-formed");
99
100 /// Constructs an object that does not contain a value.
101 constexpr optional() noexcept = default;
102
103 /// Constructs an object that does not contain a value.
104 constexpr optional(nullopt_t /*null*/) noexcept { }
105
106 /// Copy constructor.
107 constexpr optional(optional const&) = default;
108
109 /// Move constructor.
111
112 /// Converting copy constructor
113 ///
114 /// If other doesn't contain a value, constructs an optional object
115 /// that does not contain a value. Otherwise, constructs an optional
116 /// object that contains a value, initialized as if direct-initializing
117 /// (but not direct-list-initializing) an object of type T with the
118 /// expression *other.
119 ///
120 /// https://en.cppreference.com/w/cpp/utility/optional/optional
121 template <typename U>
122 requires(
123 is_constructible_v<T, U const&>
124 and not is_same_v<remove_cv_t<U>, bool>
125 and not is_constructible_v<T, optional<U>&>
126 and not is_constructible_v<T, optional<U> const&>
127 and not is_constructible_v<T, optional<U> &&>
128 and not is_constructible_v<T, optional<U> const &&>
129 and not is_convertible_v<optional<U>&, T>
130 and not is_convertible_v<optional<U> const&, T>
131 and not is_convertible_v<optional<U> &&, T>
132 and not is_convertible_v<optional<U> const &&, T>
133
134 )
135 explicit(not is_convertible_v<U const&, T>) constexpr optional(optional<U> const& other)
136 {
137 if (other.has_value()) {
138 emplace(*other);
139 }
140 }
141
142 /// Converting move constructor
143 ///
144 /// If other doesn't contain a value, constructs an optional object that does
145 /// not contain a value. Otherwise, constructs an optional object that contains a value,
146 /// initialized as if direct-initializing (but not direct-list-initializing)
147 /// an object of type T with the expression etl::move(*other).
148 ///
149 /// https://en.cppreference.com/w/cpp/utility/optional/optional
150 template <typename U>
151 requires(
152 is_constructible_v<T, U &&>
153 and not is_same_v<remove_cv_t<U>, bool>
154 and not is_constructible_v<T, optional<U>&>
155 and not is_constructible_v<T, optional<U> const&>
156 and not is_constructible_v<T, optional<U> &&>
157 and not is_constructible_v<T, optional<U> const &&>
158 and not is_convertible_v<optional<U>&, T>
159 and not is_convertible_v<optional<U> const&, T>
160 and not is_convertible_v<optional<U> &&, T>
161 and not is_convertible_v<optional<U> const &&, T>
162 )
163 explicit(not is_convertible_v<U&&, T>) constexpr optional(optional<U>&& other)
164 {
165 if (other.has_value()) {
166 emplace(*etl::move(other));
167 }
168 }
169
170 /// Constructs an optional object that contains a value,
171 /// initialized as if direct-initializing.
172 ///
173 /// https://en.cppreference.com/w/cpp/utility/optional/optional
174 template <typename... Args>
175 requires is_constructible_v<T, Args...>
176 constexpr explicit optional(in_place_t /*tag*/, Args&&... args)
177 : _var(in_place_index<1>, etl::forward<Args>(args)...)
178 {
179 }
180
181 /// Constructs an optional object that contains a value,
182 /// initialized as if direct-initializing.
183 ///
184 /// https://en.cppreference.com/w/cpp/utility/optional/optional
185 template <typename U = T>
186 requires(
187 is_constructible_v<T, U &&>
188 and not is_same_v<remove_cvref_t<U>, in_place_t>
189 and not is_same_v<remove_cvref_t<U>, optional>
190 )
191 explicit(not is_convertible_v<U&&, T>) constexpr optional(U&& value)
192 : _var(in_place_index<1>, etl::forward<U>(value))
193 {
194 }
195
196 /// If *this contains a value before the call, the contained value is
197 /// destroyed by calling its destructor as if by value().T::~T(). *this does
198 /// not contain a value after this call.
199 constexpr auto operator=(etl::nullopt_t /*unused*/) noexcept -> optional&
200 {
201 reset();
202 return *this;
203 }
204
205 /// Assigns the state of other.
206 constexpr auto operator=(optional const& other) -> optional& = default;
207
208 /// Assigns the state of other.
209 constexpr auto operator=(optional&& other) noexcept -> optional& = default;
210
211 /// Perfect-forwarded assignment.
212 ///
213 /// Depending on whether *this contains a value before the call,
214 /// the contained value is either direct-initialized from
215 /// etl::forward<U>(value) or assigned from etl::forward<U>(value).
216 ///
217 /// https://en.cppreference.com/w/cpp/utility/optional/operator%3D
218 template <typename U = T>
219 requires(
220 is_assignable_v<T&, U>
221 and is_constructible_v<T, U>
222 and not is_same_v<optional, decay_t<U>>
223 and not is_scalar_v<T>
224 and not is_same_v<T, decay_t<U>>
225 )
226 constexpr auto operator=(U&& value) -> optional&
227 {
228 emplace(etl::forward<U>(value));
229 return *this;
230 }
231
232 /// Assigns the state of other.
233 template <typename U = T>
234 requires(
235 is_constructible_v<T, U const&>
236 and is_assignable_v<T&, U const&>
237 and not is_constructible_v<T, optional<U>&>
238 and not is_constructible_v<T, optional<U> const&>
239 and not is_constructible_v<T, optional<U> &&>
240 and not is_constructible_v<T, optional<U> const &&>
241 and not is_convertible_v<optional<U>&, T>
242 and not is_convertible_v<optional<U> const&, T>
243 and not is_convertible_v<optional<U> &&, T>
244 and not is_convertible_v<optional<U> const &&, T>
245 and not is_assignable_v<T&, optional<U>&>
246 and not is_assignable_v<T&, optional<U> const&>
247 and not is_assignable_v<T&, optional<U> &&>
248 and not is_assignable_v<T&, optional<U> const &&>
249 )
250 constexpr auto operator=(optional<U> const& other) -> optional&
251 {
252 if (other.has_value()) {
253 emplace(*other);
254 } else {
255 reset();
256 }
257
258 return *this;
259 }
260
261 /// Assigns the state of other.
262 template <typename U = T>
263 requires(
264 is_constructible_v<T, U>
265 and is_assignable_v<T&, U>
266 and not is_constructible_v<T, optional<U>&>
267 and not is_constructible_v<T, optional<U> const&>
268 and not is_constructible_v<T, optional<U> &&>
269 and not is_constructible_v<T, optional<U> const &&>
270 and not is_convertible_v<optional<U>&, T>
271 and not is_convertible_v<optional<U> const&, T>
272 and not is_convertible_v<optional<U> &&, T>
273 and not is_convertible_v<optional<U> const &&, T>
274 and not is_assignable_v<T&, optional<U>&>
275 and not is_assignable_v<T&, optional<U> const&>
276 and not is_assignable_v<T&, optional<U> &&>
277 and not is_assignable_v<T&, optional<U> const &&>
278 )
279 constexpr auto operator=(optional<U>&& other) -> optional&
280 {
281 if (other.has_value()) {
282 emplace(*etl::move(other));
283 } else {
284 reset();
285 }
286
287 return *this;
288 }
289
290 /// Checks whether *this contains a value.
291 [[nodiscard]] constexpr auto has_value() const noexcept -> bool
292 {
293 return _var.index() == 1;
294 }
295
296 /// Checks whether *this contains a value.
297 [[nodiscard]] constexpr explicit operator bool() const noexcept
298 {
299 return has_value();
300 }
301
302 /// If *this contains a value, destroy that value as if by
303 /// value().~value_type(). Otherwise, there are no effects. *this does not
304 /// contain a value after this call.
305 constexpr auto reset() noexcept -> void
306 {
307 _var.template emplace<0>(nullopt);
308 }
309
310 /// Returns the contained value if *this has a value, otherwise
311 /// returns default_value.
312 template <typename U>
313 [[nodiscard]] constexpr auto value_or(U&& defaultValue) const& -> value_type
314 {
315 return has_value() ? (**this) : static_cast<value_type>(etl::forward<U>(defaultValue));
316 }
317
318 /// Returns the contained value if *this has a value, otherwise
319 /// returns default_value.
320 template <typename U>
321 [[nodiscard]] constexpr auto value_or(U&& defaultValue) && -> value_type
322 {
323 return has_value() ? etl::move(**this) : static_cast<value_type>(etl::forward<U>(defaultValue));
324 }
325
326 /// Returns a pointer to the contained value. The pointer is null if
327 /// the optional is empty.
328 [[nodiscard]] constexpr auto operator->() const -> value_type const*
329 {
330 return etl::get_if<1>(&_var);
331 }
332
333 /// Returns a pointer to the contained value. The pointer is null if
334 /// the optional is empty.
335 [[nodiscard]] constexpr auto operator->() -> value_type*
336 {
337 return etl::get_if<1>(&_var);
338 }
339
340 /// Returns a reference to the contained value.
341 ///
342 /// \details This operator only checks whether the optional contains a
343 /// value in debug builds! You can do so manually by using has_value() or
344 /// simply operator bool(). Alternatively, if checked access is needed,
345 /// value() or value_or() may be used.
346 ///
347 /// https://en.cppreference.com/w/cpp/utility/optional/operator*
348 [[nodiscard]] constexpr auto operator*() const& -> T const&
349 {
350 TETL_PRECONDITION(has_value());
351 return etl::unchecked_get<1>(_var);
352 }
353
354 /// Returns a reference to the contained value.
355 ///
356 /// \details This operator only checks whether the optional contains a
357 /// value in debug builds! You can do so manually by using has_value() or
358 /// simply operator bool(). Alternatively, if checked access is needed,
359 /// value() or value_or() may be used.
360 ///
361 /// https://en.cppreference.com/w/cpp/utility/optional/operator*
362 [[nodiscard]] constexpr auto operator*() & -> T&
363 {
364 TETL_PRECONDITION(has_value());
365 return etl::unchecked_get<1>(_var);
366 }
367
368 /// Returns a reference to the contained value.
369 ///
370 /// \details This operator only checks whether the optional contains a
371 /// value in debug builds! You can do so manually by using has_value() or
372 /// simply operator bool(). Alternatively, if checked access is needed,
373 /// value() or value_or() may be used.
374 ///
375 /// https://en.cppreference.com/w/cpp/utility/optional/operator*
376 [[nodiscard]] constexpr auto operator*() const&& -> T const&&
377 {
378 TETL_PRECONDITION(has_value());
379 return etl::move(etl::unchecked_get<1>(_var));
380 }
381
382 /// Returns a reference to the contained value.
383 ///
384 /// \details This operator only checks whether the optional contains a
385 /// value in debug builds! You can do so manually by using has_value() or
386 /// simply operator bool(). Alternatively, if checked access is needed,
387 /// value() or value_or() may be used.
388 ///
389 /// https://en.cppreference.com/w/cpp/utility/optional/operator*
390 [[nodiscard]] constexpr auto operator*() && -> T&&
391 {
392 TETL_PRECONDITION(has_value());
393 return etl::move(etl::unchecked_get<1>(_var));
394 }
395
396 [[nodiscard]] constexpr auto begin() noexcept -> iterator
397 {
398 return has_value() ? etl::addressof(etl::unchecked_get<1>(_var)) : nullptr;
399 }
400
401 [[nodiscard]] constexpr auto begin() const noexcept -> const_iterator
402 {
403 return has_value() ? etl::addressof(etl::unchecked_get<1>(_var)) : nullptr;
404 }
405
406 [[nodiscard]] constexpr auto end() noexcept -> iterator
407 {
408 return etl::next(begin(), static_cast<etl::ptrdiff_t>(has_value()));
409 }
410
411 [[nodiscard]] constexpr auto end() const noexcept -> const_iterator
412 {
413 return etl::next(begin(), static_cast<etl::ptrdiff_t>(has_value()));
414 }
415
416 /// Swaps the contents with those of other.
417 constexpr auto
419 -> void
420 {
421 etl::swap(*this, other);
422 }
423
424 /// Constructs the contained value in-place. If *this already
425 /// contains a value before the call, the contained value is destroyed by
426 /// calling its destructor.
427 template <typename... Args>
428 constexpr auto emplace(Args&&... args) -> value_type&
429 {
430 return _var.template emplace<1>(etl::forward<Args>(args)...);
431 }
432
433 template <typename F>
434 constexpr auto and_then(F&& f) &
435 {
436 if (*this) {
437 return etl::invoke(etl::forward<F>(f), **this);
438 }
439 return remove_cvref_t<invoke_result_t<F, T&>>{};
440 }
441
442 template <typename F>
443 constexpr auto and_then(F&& f) const&
444 {
445 if (*this) {
446 return etl::invoke(etl::forward<F>(f), **this);
447 }
448 return remove_cvref_t<invoke_result_t<F, T const&>>{};
449 }
450
451 template <typename F>
452 constexpr auto and_then(F&& f) &&
453 {
454 if (*this) {
455 return etl::invoke(etl::forward<F>(f), etl::move(**this));
456 }
457 return remove_cvref_t<invoke_result_t<F, T>>{};
458 }
459
460 template <typename F>
461 constexpr auto and_then(F&& f) const&&
462 {
463 if (*this) {
464 return etl::invoke(etl::forward<F>(f), etl::move(**this));
465 }
466 return remove_cvref_t<invoke_result_t<F, T const>>{};
467 }
468
469 template <typename F>
470 requires(copy_constructible<T> and same_as<remove_cvref_t<invoke_result_t<F>>, optional>)
471 constexpr auto or_else(F&& f) const& -> optional
472 {
473 return *this ? *this : etl::forward<F>(f)();
474 }
475
476 template <typename F>
477 requires(move_constructible<T> and same_as<remove_cvref_t<invoke_result_t<F>>, optional>)
478 constexpr auto or_else(F&& f) && -> optional
479 {
480 return *this ? etl::move(*this) : etl::forward<F>(f)();
481 }
482
483private:
484 variant<nullopt_t, T> _var{nullopt};
485};
486
487// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2988r3.pdf
488template <typename T>
489struct optional<T&> {
490 using value_type = T&;
491
492 constexpr optional() noexcept = default;
493
494 constexpr optional(nullopt_t /*tag*/) noexcept
495 : _ptr{nullptr}
496 {
497 }
498
499 template <typename U = T>
500 requires(not is_same_v<remove_cvref_t<U>, optional>)
501 constexpr explicit(not is_convertible_v<U, T>) optional(U&& v)
502 : _ptr(etl::addressof(v))
503 {
504 static_assert(is_constructible_v<add_lvalue_reference_t<T>, U>, "Must be able to bind U to T&");
505 static_assert(is_lvalue_reference_v<U>, "U must be an lvalue");
506 }
507
508 template <typename U>
509 requires(not is_same_v<remove_cvref_t<U>, optional>)
510 constexpr explicit(not is_convertible_v<U, T>) optional(optional<U> const& rhs)
511 : _ptr(etl::addressof(*rhs))
512 {
513 }
514
515 constexpr optional(optional const& other) = default;
516 constexpr optional(optional&& other) noexcept = default;
517 constexpr ~optional() = default;
518
519 constexpr auto operator=(optional const&) noexcept -> optional& = default;
520 constexpr auto operator=(optional&&) noexcept -> optional& = default;
521
522 constexpr auto operator=(nullopt_t /*tag*/) noexcept -> optional&
523 {
524 _ptr = nullptr;
525 return *this;
526 }
527
528 template <typename U = T>
529 requires(not is_same_v<remove_cvref_t<U>, optional> and not conjunction_v<is_scalar<T>, is_same<T, decay_t<U>>>)
530 constexpr auto operator=(U&& v) -> optional&
531 {
532 static_assert(is_constructible_v<add_lvalue_reference_t<T>, U>, "Must be able to bind U to T&");
533 static_assert(is_lvalue_reference_v<U>, "U must be an lvalue");
534 _ptr = etl::addressof(v);
535 return *this;
536 }
537
538 template <typename U>
539 constexpr auto operator=(optional<U> const& rhs) -> optional&
540 {
541 static_assert(is_constructible_v<add_lvalue_reference_t<T>, U>, "Must be able to bind U to T&");
542 _ptr = rhs._ptr;
543 return *this;
544 }
545
546 template <typename U = T>
547 requires(not is_same_v<remove_cvref_t<U>, optional>)
548 constexpr auto emplace(U&& u) noexcept -> optional&
549 {
550 *this = etl::forward<U>(u);
551 return *this;
552 }
553
554 [[nodiscard]] constexpr auto operator->() const noexcept -> T*
555 {
556 return _ptr;
557 }
558
559 [[nodiscard]] constexpr auto operator*() const noexcept -> T&
560 {
561 TETL_PRECONDITION(has_value());
562 return *_ptr;
563 }
564
565 [[nodiscard]] constexpr explicit operator bool() const noexcept
566 {
567 return has_value();
568 }
569
570 [[nodiscard]] constexpr auto has_value() const noexcept -> bool
571 {
572 return _ptr != nullptr;
573 }
574
575 constexpr void reset() noexcept
576 {
577 _ptr = nullptr;
578 }
579
580 constexpr void swap(optional& rhs) noexcept
581 {
582 etl::swap(_ptr, rhs._ptr);
583 }
584
585private:
586 T* _ptr{nullptr};
587};
588
589/// \brief Creates an optional object from value.
590/// \relates optional
591/// \ingroup optional
592template <typename T>
593constexpr auto make_optional(T&& value) -> etl::optional<etl::decay_t<T>>
594{
595 return etl::optional<etl::decay_t<T>>(etl::forward<T>(value));
596}
597
598/// \brief Creates an optional object constructed in-place from args...
599/// \relates optional
600/// \ingroup optional
601template <typename T, typename... Args>
602constexpr auto make_optional(Args&&... args) -> etl::optional<T>
603{
604 return etl::optional<T>(etl::in_place, etl::forward<Args>(args)...);
605}
606
607// One deduction guide is provided for etl::optional to account for the
608// edge cases missed by the implicit deduction guides, in particular,
609// non-copyable arguments and array to pointer conversion.
610/// \relates optional
611/// \ingroup optional
612template <typename T>
614
615/// \brief Compares two optional objects, lhs and rhs.
616/// \relates optional
617/// \ingroup optional
618template <typename T, typename U>
619[[nodiscard]] constexpr auto operator==(optional<T> const& lhs, optional<U> const& rhs) -> bool
620{
621 if (static_cast<bool>(lhs) != static_cast<bool>(rhs)) {
622 return false;
623 }
624 if (not static_cast<bool>(lhs) and not static_cast<bool>(rhs)) {
625 return true;
626 }
627 return (*lhs) == (*rhs);
628}
629
630/// \brief Compares two optional objects, lhs and rhs.
631/// \relates optional
632/// \ingroup optional
633template <typename T, typename U>
634[[nodiscard]] constexpr auto operator<(optional<T> const& lhs, optional<U> const& rhs) -> bool
635{
636 if (not static_cast<bool>(rhs)) {
637 return false;
638 }
639 if (not static_cast<bool>(lhs)) {
640 return true;
641 }
642 return (*lhs) < (*rhs);
643}
644
645/// \brief Compares two optional objects, lhs and rhs.
646/// \relates optional
647/// \ingroup optional
648template <typename T, typename U>
649[[nodiscard]] constexpr auto operator>(optional<T> const& lhs, optional<U> const& rhs) -> bool
650{
651 if (not static_cast<bool>(lhs)) {
652 return false;
653 }
654 if (not static_cast<bool>(rhs)) {
655 return true;
656 }
657 return (*lhs) > (*rhs);
658}
659
660/// \brief Compares two optional objects, lhs and rhs.
661/// \relates optional
662/// \ingroup optional
663template <typename T, typename U>
664[[nodiscard]] constexpr auto operator<=(optional<T> const& lhs, optional<U> const& rhs) -> bool
665{
666 if (not static_cast<bool>(lhs)) {
667 return true;
668 }
669 if (not static_cast<bool>(rhs)) {
670 return false;
671 }
672 return (*lhs) <= (*rhs);
673}
674
675/// \brief Compares two optional objects, lhs and rhs.
676/// \relates optional
677/// \ingroup optional
678template <typename T, typename U>
679[[nodiscard]] constexpr auto operator>=(optional<T> const& lhs, optional<U> const& rhs) -> bool
680{
681 if (not static_cast<bool>(rhs)) {
682 return true;
683 }
684 if (not static_cast<bool>(lhs)) {
685 return false;
686 }
687 return (*lhs) >= (*rhs);
688}
689
690/// Compares opt with a nullopt.
691///
692/// Equivalent to when comparing to an optional that does not contain a value.
693///
694/// \relates optional
695/// \ingroup optional
696template <typename T>
697[[nodiscard]] constexpr auto operator==(optional<T> const& opt, etl::nullopt_t /*unused*/) noexcept -> bool
698{
699 return not opt;
700}
701
702/// Compares opt with a nullopt.
703///
704/// Equivalent to when comparing to an optional that does not contain a value.
705///
706/// \relates optional
707/// \ingroup optional
708template <typename T>
709[[nodiscard]] constexpr auto operator==(etl::nullopt_t /*unused*/, optional<T> const& opt) noexcept -> bool
710{
711 return not opt;
712}
713
714/// Compares opt with a nullopt.
715///
716/// Equivalent to when comparing to an optional that does not contain a value.
717///
718/// \relates optional
719/// \ingroup optional
720template <typename T>
721[[nodiscard]] constexpr auto operator<(optional<T> const& /*opt*/, etl::nullopt_t /*unused*/) noexcept -> bool
722{
723 return false;
724}
725
726/// Compares opt with a nullopt.
727///
728/// Equivalent to when comparing to an optional that does not contain a value.
729///
730/// \relates optional
731/// \ingroup optional
732template <typename T>
733[[nodiscard]] constexpr auto operator<(etl::nullopt_t /*unused*/, optional<T> const& opt) noexcept -> bool
734{
735 return static_cast<bool>(opt);
736}
737
738/// \brief Compares opt with a value. The values are compared (using the
739/// corresponding operator of T) only if opt contains a value. Otherwise, opt is
740/// considered less than value. If the corresponding two-way comparison
741/// expression between *opt and value is not well-formed, or if its result is
742/// not convertible to bool, the program is ill-formed.
743///
744/// https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
745///
746/// \relates optional
747/// \ingroup optional
748template <typename T, typename U>
749[[nodiscard]] constexpr auto operator==(optional<T> const& opt, U const& value) -> bool
750{
751 return static_cast<bool>(opt) ? *opt == value : false;
752}
753
754/// \brief Compares opt with a value. The values are compared (using the
755/// corresponding operator of T) only if opt contains a value. Otherwise, opt is
756/// considered less than value. If the corresponding two-way comparison
757/// expression between *opt and value is not well-formed, or if its result is
758/// not convertible to bool, the program is ill-formed.
759///
760/// https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
761///
762/// \relates optional
763/// \ingroup optional
764template <typename T, typename U>
765[[nodiscard]] constexpr auto operator<(optional<T> const& opt, U const& value) -> bool
766{
767 return static_cast<bool>(opt) ? *opt < value : true;
768}
769
770/// \brief Compares opt with a value. The values are compared (using the
771/// corresponding operator of T) only if opt contains a value. Otherwise, opt is
772/// considered less than value. If the corresponding two-way comparison
773/// expression between *opt and value is not well-formed, or if its result is
774/// not convertible to bool, the program is ill-formed.
775///
776/// https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
777///
778/// \relates optional
779/// \ingroup optional
780template <typename T, typename U>
781[[nodiscard]] constexpr auto operator<(T const& value, optional<U> const& opt) -> bool
782{
783 return static_cast<bool>(opt) ? value < *opt : false;
784}
785
786/// \brief Compares opt with a value. The values are compared (using the
787/// corresponding operator of T) only if opt contains a value. Otherwise, opt is
788/// considered less than value. If the corresponding two-way comparison
789/// expression between *opt and value is not well-formed, or if its result is
790/// not convertible to bool, the program is ill-formed.
791///
792/// https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
793///
794/// \relates optional
795/// \ingroup optional
796template <typename T, typename U>
797[[nodiscard]] constexpr auto operator>(optional<T> const& opt, U const& value) -> bool
798{
799 return static_cast<bool>(opt) ? *opt > value : false;
800}
801
802/// \brief Compares opt with a value. The values are compared (using the
803/// corresponding operator of T) only if opt contains a value. Otherwise, opt is
804/// considered less than value. If the corresponding two-way comparison
805/// expression between *opt and value is not well-formed, or if its result is
806/// not convertible to bool, the program is ill-formed.
807///
808/// https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
809///
810/// \relates optional
811/// \ingroup optional
812template <typename T, typename U>
813[[nodiscard]] constexpr auto operator>(T const& value, optional<U> const& opt) -> bool
814{
815 return static_cast<bool>(opt) ? value > *opt : true;
816}
817
818/// \brief Compares opt with a value. The values are compared (using the
819/// corresponding operator of T) only if opt contains a value. Otherwise, opt is
820/// considered less than value. If the corresponding two-way comparison
821/// expression between *opt and value is not well-formed, or if its result is
822/// not convertible to bool, the program is ill-formed.
823///
824/// https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
825///
826/// \relates optional
827/// \ingroup optional
828template <typename T, typename U>
829[[nodiscard]] constexpr auto operator<=(optional<T> const& opt, U const& value) -> bool
830{
831 return static_cast<bool>(opt) ? *opt <= value : true;
832}
833
834/// \brief Compares opt with a value. The values are compared (using the
835/// corresponding operator of T) only if opt contains a value. Otherwise, opt is
836/// considered less than value. If the corresponding two-way comparison
837/// expression between *opt and value is not well-formed, or if its result is
838/// not convertible to bool, the program is ill-formed.
839///
840/// https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
841///
842/// \relates optional
843/// \ingroup optional
844template <typename T, typename U>
845[[nodiscard]] constexpr auto operator<=(T const& value, optional<U> const& opt) -> bool
846{
847 return static_cast<bool>(opt) ? value <= *opt : false;
848}
849
850/// \brief Compares opt with a value. The values are compared (using the
851/// corresponding operator of T) only if opt contains a value. Otherwise, opt is
852/// considered less than value. If the corresponding two-way comparison
853/// expression between *opt and value is not well-formed, or if its result is
854/// not convertible to bool, the program is ill-formed.
855///
856/// https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
857///
858/// \relates optional
859/// \ingroup optional
860template <typename T, typename U>
861[[nodiscard]] constexpr auto operator>=(optional<T> const& opt, U const& value) -> bool
862{
863 return static_cast<bool>(opt) ? *opt >= value : false;
864}
865
866/// \brief Compares opt with a value. The values are compared (using the
867/// corresponding operator of T) only if opt contains a value. Otherwise, opt is
868/// considered less than value. If the corresponding two-way comparison
869/// expression between *opt and value is not well-formed, or if its result is
870/// not convertible to bool, the program is ill-formed.
871///
872/// https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
873///
874/// \relates optional
875/// \ingroup optional
876template <typename T, typename U>
877[[nodiscard]] constexpr auto operator>=(T const& value, optional<U> const& opt) -> bool
878{
879 return static_cast<bool>(opt) ? value >= *opt : true;
880}
881
882/// \brief The template specialization of etl::hash for the etl::optional class
883/// allows users to obtain hashes of the values contained in optional objects.
884///
885/// The specialization etl::hash<optional<T>> is enabled (see etl::hash)
886/// if etl::hash<etl::remove_const_t<T>> is enabled, and is disabled otherwise.
887///
888/// When enabled, for an object opt of type etl::optional<T> that contains a
889/// value, etl::hash<etl::optional<T>>()(opt) evaluates to the same value as
890/// etl::hash<etl::remove_const_t<T>>()(*opt). For an optional that does not
891/// contain a value, the hash is unspecified.
892///
893/// The member functions of this specialization are not guaranteed to be
894/// noexcept because the hash of the underlying type might throw.
895///
896/// https://en.cppreference.com/w/cpp/utility/optional/hash
897///
898/// \headerfile etl/optional.hpp
899/// \ingroup optional
900template <typename T>
901struct hash<etl::optional<T>> {
902 [[nodiscard]] constexpr auto operator()(etl::optional<T> const& opt) const -> etl::size_t
903 {
904 using type = etl::remove_const_t<T>;
905 static_assert(etl::is_specialized_v<etl::hash, type>);
906 return static_cast<bool>(opt) ? etl::hash<type>{}(*opt) : 0;
907 }
908};
909} // namespace etl
910
911#endif // TETL_OPTIONAL_OPTIONAL_HPP
constexpr auto operator>=(optional< T > const &opt, U const &value) -> bool
Compares opt with a value. The values are compared (using the corresponding operator of T) only if op...
Definition optional.hpp:861
constexpr auto operator==(optional< T > const &opt, U const &value) -> bool
Compares opt with a value. The values are compared (using the corresponding operator of T) only if op...
Definition optional.hpp:749
constexpr auto operator>(optional< T > const &lhs, optional< U > const &rhs) -> bool
Compares two optional objects, lhs and rhs.
Definition optional.hpp:649
optional(T) -> optional< T >
constexpr auto operator>(optional< T > const &opt, U const &value) -> bool
Compares opt with a value. The values are compared (using the corresponding operator of T) only if op...
Definition optional.hpp:797
constexpr auto operator==(etl::nullopt_t, optional< T > const &opt) noexcept -> bool
Compares opt with a nullopt.
Definition optional.hpp:709
constexpr auto operator<=(T const &value, optional< U > const &opt) -> bool
Compares opt with a value. The values are compared (using the corresponding operator of T) only if op...
Definition optional.hpp:845
constexpr auto make_optional(Args &&... args) -> etl::optional< T >
Creates an optional object constructed in-place from args...
Definition optional.hpp:602
constexpr auto operator<=(optional< T > const &opt, U const &value) -> bool
Compares opt with a value. The values are compared (using the corresponding operator of T) only if op...
Definition optional.hpp:829
constexpr auto operator>=(optional< T > const &lhs, optional< U > const &rhs) -> bool
Compares two optional objects, lhs and rhs.
Definition optional.hpp:679
constexpr auto operator<=(optional< T > const &lhs, optional< U > const &rhs) -> bool
Compares two optional objects, lhs and rhs.
Definition optional.hpp:664
constexpr auto operator>=(T const &value, optional< U > const &opt) -> bool
Compares opt with a value. The values are compared (using the corresponding operator of T) only if op...
Definition optional.hpp:877
constexpr auto operator<(T const &value, optional< U > const &opt) -> bool
Compares opt with a value. The values are compared (using the corresponding operator of T) only if op...
Definition optional.hpp:781
constexpr auto operator<(optional< T > const &, etl::nullopt_t) noexcept -> bool
Compares opt with a nullopt.
Definition optional.hpp:721
constexpr auto operator==(optional< T > const &lhs, optional< U > const &rhs) -> bool
Compares two optional objects, lhs and rhs.
Definition optional.hpp:619
constexpr auto operator<(optional< T > const &opt, U const &value) -> bool
Compares opt with a value. The values are compared (using the corresponding operator of T) only if op...
Definition optional.hpp:765
constexpr auto operator<(optional< T > const &lhs, optional< U > const &rhs) -> bool
Compares two optional objects, lhs and rhs.
Definition optional.hpp:634
constexpr auto make_optional(T &&value) -> etl::optional< etl::decay_t< T > >
Creates an optional object from value.
Definition optional.hpp:593
constexpr auto operator<(etl::nullopt_t, optional< T > const &opt) noexcept -> bool
Compares opt with a nullopt.
Definition optional.hpp:733
constexpr auto nullopt
etl::nullopt is a constant of type etl::nullopt_t that is used to indicate optional type with uniniti...
Definition nullopt.hpp:22
constexpr auto operator==(optional< T > const &opt, etl::nullopt_t) noexcept -> bool
Compares opt with a nullopt.
Definition optional.hpp:697
constexpr auto operator>(T const &value, optional< U > const &opt) -> bool
Compares opt with a value. The values are compared (using the corresponding operator of T) only if op...
Definition optional.hpp:813
Definition adjacent_find.hpp:9
constexpr auto operator()(etl::optional< T > const &opt) const -> etl::size_t
Definition optional.hpp:902
Disambiguation tags that can be passed to the constructors of optional, variant, and any to indicate ...
Definition in_place.hpp:21
constexpr auto in_place
Definition in_place.hpp:26
If T and U name the same type (taking into account const/volatile qualifications),...
Definition is_same.hpp:16
etl::nullopt_t is an empty class type used to indicate optional type with uninitialized state....
Definition nullopt.hpp:14
constexpr auto emplace(U &&u) noexcept -> optional &
Definition optional.hpp:548
constexpr optional(optional &&other) noexcept=default
constexpr void swap(optional &rhs) noexcept
Definition optional.hpp:580
constexpr optional() noexcept=default
constexpr auto operator=(U &&v) -> optional &
Definition optional.hpp:530
constexpr auto operator=(nullopt_t) noexcept -> optional &
Definition optional.hpp:522
constexpr operator bool() const noexcept
Definition optional.hpp:565
constexpr explicit(not is_convertible_v< U, T >) optional(optional< U > const &rhs)
Definition optional.hpp:510
constexpr auto operator=(optional &&) noexcept -> optional &=default
constexpr optional(optional const &other)=default
constexpr explicit(not is_convertible_v< U, T >) optional(U &&v)
Definition optional.hpp:501
constexpr auto operator=(optional const &) noexcept -> optional &=default
constexpr ~optional()=default
constexpr void reset() noexcept
Definition optional.hpp:575
constexpr auto operator=(optional< U > const &rhs) -> optional &
Definition optional.hpp:539
constexpr auto operator->() const noexcept -> T *
Definition optional.hpp:554
constexpr auto has_value() const noexcept -> bool
Definition optional.hpp:570
constexpr auto operator*() const noexcept -> T &
Definition optional.hpp:559
constexpr optional(nullopt_t) noexcept
Definition optional.hpp:494
The class template optional manages an optional contained value, i.e. a value that may or may not be ...
Definition optional.hpp:91
constexpr auto operator=(optional< U > &&other) -> optional &
Assigns the state of other.
Definition optional.hpp:279
constexpr auto value_or(U &&defaultValue) &&-> value_type
Returns the contained value if *this has a value, otherwise returns default_value.
Definition optional.hpp:321
constexpr auto operator=(optional const &other) -> optional &=default
Assigns the state of other.
constexpr auto and_then(F &&f) &&
Definition optional.hpp:452
constexpr auto operator=(optional< U > const &other) -> optional &
Assigns the state of other.
Definition optional.hpp:250
constexpr auto or_else(F &&f) const &-> optional
Definition optional.hpp:471
constexpr auto or_else(F &&f) &&-> optional
Definition optional.hpp:478
constexpr optional(in_place_t, Args &&... args)
Constructs an optional object that contains a value, initialized as if direct-initializing.
Definition optional.hpp:176
constexpr auto reset() noexcept -> void
If *this contains a value, destroy that value as if by value().~value_type(). Otherwise,...
Definition optional.hpp:305
constexpr auto operator=(optional &&other) noexcept -> optional &=default
Assigns the state of other.
constexpr auto operator*() const &-> T const &
Returns a reference to the contained value.
Definition optional.hpp:348
constexpr auto and_then(F &&f) &
Definition optional.hpp:434
constexpr optional() noexcept=default
Constructs an object that does not contain a value.
constexpr auto swap(optional &other) noexcept(is_nothrow_move_constructible_v< value_type > and is_nothrow_swappable_v< value_type >) -> void
Swaps the contents with those of other.
Definition optional.hpp:418
constexpr auto begin() noexcept -> iterator
Definition optional.hpp:396
explicit(not is_convertible_v< U &&, T >) const expr optional(optional< U > &&other)
Converting move constructor.
Definition optional.hpp:163
constexpr operator bool() const noexcept
Checks whether *this contains a value.
Definition optional.hpp:297
constexpr auto end() noexcept -> iterator
Definition optional.hpp:406
constexpr auto begin() const noexcept -> const_iterator
Definition optional.hpp:401
explicit(not is_convertible_v< U const &, T >) const expr optional(optional< U > const &other)
Converting copy constructor.
Definition optional.hpp:135
constexpr auto operator=(etl::nullopt_t) noexcept -> optional &
If *this contains a value before the call, the contained value is destroyed by calling its destructor...
Definition optional.hpp:199
constexpr optional(optional &&) noexcept(is_nothrow_move_constructible_v< value_type >)=default
Move constructor.
constexpr auto end() const noexcept -> const_iterator
Definition optional.hpp:411
constexpr auto value_or(U &&defaultValue) const &-> value_type
Returns the contained value if *this has a value, otherwise returns default_value.
Definition optional.hpp:313
constexpr optional(optional const &)=default
Copy constructor.
constexpr auto operator*() &-> T &
Returns a reference to the contained value.
Definition optional.hpp:362
constexpr auto operator->() -> value_type *
Returns a pointer to the contained value. The pointer is null if the optional is empty.
Definition optional.hpp:335
constexpr auto has_value() const noexcept -> bool
Checks whether *this contains a value.
Definition optional.hpp:291
constexpr auto and_then(F &&f) const &&
Definition optional.hpp:461
constexpr auto and_then(F &&f) const &
Definition optional.hpp:443
constexpr auto operator*() const &&-> T const &&
Returns a reference to the contained value.
Definition optional.hpp:376
constexpr auto operator->() const -> value_type const *
Returns a pointer to the contained value. The pointer is null if the optional is empty.
Definition optional.hpp:328
constexpr auto operator*() &&-> T &&
Returns a reference to the contained value.
Definition optional.hpp:390
explicit(not is_convertible_v< U &&, T >) const expr optional(U &&value)
Constructs an optional object that contains a value, initialized as if direct-initializing.
Definition optional.hpp:191
constexpr auto emplace(Args &&... args) -> value_type &
Constructs the contained value in-place. If *this already contains a value before the call,...
Definition optional.hpp:428
constexpr optional(nullopt_t) noexcept
Constructs an object that does not contain a value.
Definition optional.hpp:104
constexpr auto operator=(U &&value) -> optional &
Perfect-forwarded assignment.
Definition optional.hpp:226
Definition variant.hpp:99