1515
1616#include < mrdocs/Platform.hpp>
1717#include < mrdocs/ADT/Nullable.hpp>
18+ #include < compare>
1819#include < optional>
1920#include < type_traits>
2021#include < utility>
@@ -83,6 +84,11 @@ class Optional {
8384 }())
8485 {}
8586
87+ /* * Construct from std::nullopt
88+ */
89+ constexpr Optional (std::nullopt_t ) noexcept (default_ctor_noex_())
90+ : Optional() {}
91+
8692 // / Copy constructor
8793 constexpr Optional (Optional const &) = default;
8894
@@ -102,15 +108,18 @@ class Optional {
102108 @param u The value to store. It must be convertible to T.
103109 **/
104110 template <class U >
105- requires std::is_constructible_v<T, U>
111+ requires (
112+ !std::same_as<std::remove_cvref_t <U>, Optional>
113+ && !std::same_as<std::remove_cvref_t <U>, std::in_place_t >
114+ && !std::same_as<std::remove_cvref_t <U>, std::nullopt_t >
115+ && std::is_constructible_v<T, U>)
106116 constexpr explicit Optional (U&& u) noexcept (
107117 std::is_nothrow_constructible_v<T, U>)
108118 : s_([&] {
109119 if constexpr (uses_nullable_traits)
110120 {
111121 return storage_t (static_cast <T>(std::forward<U>(u)));
112- }
113- else
122+ } else
114123 {
115124 return storage_t (std::forward<U>(u));
116125 }
@@ -122,11 +131,20 @@ class Optional {
122131 @param u The value to store. It must be convertible to T.
123132 **/
124133 template <class U >
125- requires std::is_constructible_v<T, U> && std::is_assignable_v<T&, U>
126- constexpr Optional&
134+ requires (
135+ !std::same_as<std::remove_cvref_t <U>, Optional>
136+ && std::is_constructible_v<T, U> && std::is_assignable_v<T&, U>)
137+ constexpr
138+ Optional&
127139 operator =(U&& u) noexcept (std::is_nothrow_assignable_v<T&, U>)
128140 {
129- s_ = std::forward<U>(u);
141+ if constexpr (uses_nullable_traits)
142+ {
143+ s_ = std::forward<U>(u);
144+ } else
145+ {
146+ s_ = std::forward<U>(u);
147+ }
130148 return *this ;
131149 }
132150
@@ -330,15 +348,311 @@ class Optional {
330348 return *s_;
331349 }
332350 }
351+ };
333352
334- /* * Three-way comparison defaults when supported by the underlying
335- T/std::optional.
336- **/
337- auto
338- operator <=>(Optional const &) const
339- = default ;
353+ namespace detail {
354+ template <typename T>
355+ inline constexpr bool isOptionalV = false ;
356+
357+ template <typename T>
358+ inline constexpr bool isOptionalV<Optional<T>> = true ;
359+
360+ template <typename T>
361+ using OptionalRelopT = std::enable_if_t <std::is_convertible_v<T, bool >, bool >;
362+
363+ template <typename T, typename U>
364+ using OptionalEqT = OptionalRelopT<
365+ decltype (std::declval<T const &>() == std::declval<U const &>())>;
366+
367+ template <typename T, typename U>
368+ using OptionalNeT = OptionalRelopT<
369+ decltype (std::declval<T const &>() != std::declval<U const &>())>;
370+
371+ template <typename T, typename U>
372+ using OptionalLtT = OptionalRelopT<
373+ decltype (std::declval<T const &>() < std::declval<U const &>())>;
374+
375+ template <typename T, typename U>
376+ using OptionalGtT = OptionalRelopT<
377+ decltype (std::declval<T const &>() > std::declval<U const &>())>;
378+
379+ template <typename T, typename U>
380+ using OptionalLeT = OptionalRelopT<
381+ decltype (std::declval<T const &>() <= std::declval<U const &>())>;
382+
383+ template <typename T, typename U>
384+ using OptionalGeT = detail::OptionalRelopT<
385+ decltype (std::declval<T const &>() >= std::declval<U const &>())>;
386+
387+ template <typename T>
388+ concept isDerivedFromOptional = requires (T const & __t ) {
389+ []<typename U>(Optional<U> const &) {
390+ }(__t );
340391};
341392
393+ } // namespace detail
394+
395+ /* * Compares two Optional values for equality.
396+
397+ Returns true if both are engaged and their contained values are equal, or both are disengaged.
398+ */
399+ template <typename T, typename U>
400+ constexpr detail::OptionalEqT<T, U>
401+ operator ==(Optional<T> const & lhs, Optional<U> const & rhs)
402+ {
403+ return static_cast <bool >(lhs) == static_cast <bool >(rhs)
404+ && (!lhs || *lhs == *rhs);
405+ }
406+
407+ /* * Compares two Optional values for inequality.
408+
409+ Returns true if their engagement states differ or their contained values are not equal.
410+ */
411+ template <typename T, typename U>
412+ constexpr detail::OptionalNeT<T, U>
413+ operator !=(Optional<T> const & lhs, Optional<U> const & rhs)
414+ {
415+ return static_cast <bool >(lhs) != static_cast <bool >(rhs)
416+ || (static_cast <bool >(lhs) && *lhs != *rhs);
417+ }
418+
419+ /* * Checks if the left Optional is less than the right Optional.
420+
421+ Returns true if the right is engaged and either the left is disengaged or its value is less.
422+ */
423+ template <typename T, typename U>
424+ constexpr detail::OptionalLtT<T, U>
425+ operator <(Optional<T> const & lhs, Optional<U> const & rhs)
426+ {
427+ return static_cast <bool >(rhs) && (!lhs || *lhs < *rhs);
428+ }
429+
430+ /* * Checks if the left Optional is greater than the right Optional.
431+
432+ Returns true if the left is engaged and either the right is disengaged or its value is greater.
433+ */
434+ template <typename T, typename U>
435+ constexpr detail::OptionalGtT<T, U>
436+ operator >(Optional<T> const & lhs, Optional<U> const & rhs)
437+ {
438+ return static_cast <bool >(lhs) && (!rhs || *lhs > *rhs);
439+ }
440+
441+ /* * Checks if the left Optional is less than or equal to the right Optional.
442+
443+ Returns true if the left is disengaged or the right is engaged and the left's value is less or equal.
444+ */
445+ template <typename T, typename U>
446+ constexpr detail::OptionalLeT<T, U>
447+ operator <=(Optional<T> const & lhs, Optional<U> const & rhs)
448+ {
449+ return !lhs || (static_cast <bool >(rhs) && *lhs <= *rhs);
450+ }
451+
452+ /* * Checks if the left Optional is greater than or equal to the right Optional.
453+
454+ Returns true if the right is disengaged or the left is engaged and its value is greater or equal.
455+ */
456+ template <typename T, typename U>
457+ constexpr detail::OptionalGeT<T, U>
458+ operator >=(Optional<T> const & lhs, Optional<U> const & rhs)
459+ {
460+ return !rhs || (static_cast <bool >(lhs) && *lhs >= *rhs);
461+ }
462+
463+ /* * Performs a three-way comparison between two Optional values.
464+
465+ If both are engaged, compares their contained values; otherwise, compares engagement state.
466+ */
467+ template <typename T, std::three_way_comparable_with<T> U>
468+ [[nodiscard]]
469+ constexpr std::compare_three_way_result_t <T, U>
470+ operator <=>(Optional<T> const & x, Optional<U> const & y)
471+ {
472+ return x && y ? *x <=> *y : bool (x) <=> bool (y);
473+ }
474+
475+ /* * Checks if the Optional is disengaged (equal to std::nullopt).
476+
477+ Returns true if the Optional does not contain a value.
478+ */
479+ template <typename T>
480+ [[nodiscard]]
481+ constexpr bool
482+ operator ==(Optional<T> const & lhs, std::nullopt_t ) noexcept
483+ {
484+ return !lhs;
485+ }
486+
487+ /* * Performs a three-way comparison between an Optional and std::nullopt.
488+
489+ Returns std::strong_ordering::greater if engaged, std::strong_ordering::equal if disengaged.
490+ */
491+ template <typename T>
492+ [[nodiscard]]
493+ constexpr std::strong_ordering
494+ operator <=>(Optional<T> const & x, std::nullopt_t ) noexcept
495+ {
496+ return bool (x) <=> false ;
497+ }
498+
499+ /* * Compares an engaged Optional to a value for equality.
500+
501+ Returns true if the Optional is engaged and its value equals rhs.
502+ */
503+ template <typename T, typename U>
504+ requires (!detail::isOptionalV<U>)
505+ constexpr detail::OptionalEqT<T, U>
506+ operator == [[nodiscard]] (Optional<T> const & lhs, U const & rhs)
507+ {
508+ return lhs && *lhs == rhs;
509+ }
510+
511+ /* * Compares a value to an engaged Optional for equality.
512+
513+ Returns true if the Optional is engaged and its value equals lhs.
514+ */
515+ template <typename T, typename U>
516+ requires (!detail::isOptionalV<T>)
517+ constexpr detail::OptionalEqT<T, U>
518+ operator == [[nodiscard]] (T const & lhs, Optional<U> const & rhs)
519+ {
520+ return rhs && lhs == *rhs;
521+ }
522+
523+ /* * Compares an Optional to a value for inequality.
524+
525+ Returns true if the Optional is disengaged or its value does not equal rhs.
526+ */
527+ template <typename T, typename U>
528+ requires (!detail::isOptionalV<U>)
529+ constexpr detail::OptionalNeT<T, U>
530+ operator != [[nodiscard]] (Optional<T> const & lhs, U const & rhs)
531+ {
532+ return !lhs || *lhs != rhs;
533+ }
534+
535+ /* * Compares a value to an Optional for inequality.
536+
537+ Returns true if the Optional is disengaged or its value does not equal lhs.
538+ */
539+ template <typename T, typename U>
540+ requires (!detail::isOptionalV<T>)
541+ constexpr detail::OptionalNeT<T, U>
542+ operator != [[nodiscard]] (T const & lhs, Optional<U> const & rhs)
543+ {
544+ return !rhs || lhs != *rhs;
545+ }
546+
547+ /* * Checks if the Optional is less than a value.
548+
549+ Returns true if the Optional is disengaged or its value is less than rhs.
550+ */
551+ template <typename T, typename U>
552+ requires (!detail::isOptionalV<U>)
553+ constexpr detail::OptionalLtT<T, U>
554+ operator <[[nodiscard]] (Optional<T> const & lhs, U const & rhs)
555+ {
556+ return !lhs || *lhs < rhs;
557+ }
558+
559+ /* * Checks if a value is less than an engaged Optional.
560+
561+ Returns true if the Optional is engaged and lhs is less than its value.
562+ */
563+ template <typename T, typename U>
564+ requires (!detail::isOptionalV<T>)
565+ constexpr detail::OptionalLtT<T, U>
566+ operator <[[nodiscard]] (T const & lhs, Optional<U> const & rhs)
567+ {
568+ return rhs && lhs < *rhs;
569+ }
570+
571+ /* * Checks if the Optional is greater than a value.
572+
573+ Returns true if the Optional is engaged and its value is greater than rhs.
574+ */
575+ template <typename T, typename U>
576+ requires (!detail::isOptionalV<U>)
577+ constexpr detail::OptionalGtT<T, U>
578+ operator > [[nodiscard]] (Optional<T> const & lhs, U const & rhs)
579+ {
580+ return lhs && *lhs > rhs;
581+ }
582+
583+ /* * Checks if a value is greater than an Optional.
584+
585+ Returns true if the Optional is disengaged or lhs is greater than its value.
586+ */
587+ template <typename T, typename U>
588+ requires (!detail::isOptionalV<T>)
589+ constexpr detail::OptionalGtT<T, U>
590+ operator > [[nodiscard]] (T const & lhs, Optional<U> const & rhs)
591+ {
592+ return !rhs || lhs > *rhs;
593+ }
594+
595+ /* * Checks if the Optional is less than or equal to a value.
596+
597+ Returns true if the Optional is disengaged or its value is less than or equal to rhs.
598+ */
599+ template <typename T, typename U>
600+ requires (!detail::isOptionalV<U>)
601+ constexpr detail::OptionalLeT<T, U>
602+ operator <= [[nodiscard]] (Optional<T> const & lhs, U const & rhs)
603+ {
604+ return !lhs || *lhs <= rhs;
605+ }
606+
607+ /* * Checks if a value is less than or equal to an engaged Optional.
608+
609+ Returns true if the Optional is engaged and lhs is less than or equal to its value.
610+ */
611+ template <typename T, typename U>
612+ requires (!detail::isOptionalV<T>)
613+ constexpr detail::OptionalLeT<T, U>
614+ operator <= [[nodiscard]] (T const & lhs, Optional<U> const & rhs)
615+ {
616+ return rhs && lhs <= *rhs;
617+ }
618+
619+ /* * Checks if the Optional is greater than or equal to a value.
620+
621+ Returns true if the Optional is engaged and its value is greater than or equal to rhs.
622+ */
623+ template <typename T, typename U>
624+ requires (!detail::isOptionalV<U>)
625+ constexpr detail::OptionalGeT<T, U>
626+ operator >= [[nodiscard]] (Optional<T> const & lhs, U const & rhs)
627+ {
628+ return lhs && *lhs >= rhs;
629+ }
630+
631+ /* * Checks if a value is greater than or equal to an Optional.
632+
633+ Returns true if the Optional is disengaged or lhs is greater than or equal to its value.
634+ */
635+ template <typename T, typename U>
636+ requires (!detail::isOptionalV<T>)
637+ constexpr detail::OptionalGeT<T, U>
638+ operator >= [[nodiscard]] (T const & lhs, Optional<U> const & rhs)
639+ {
640+ return !rhs || lhs >= *rhs;
641+ }
642+
643+ /* * Performs a three-way comparison between an Optional and a value.
644+
645+ If the Optional is engaged, compares its value to v; otherwise, returns less.
646+ */
647+ template <typename T, typename U>
648+ requires (!detail::isDerivedFromOptional<U>)
649+ && requires { typename std::compare_three_way_result_t <T, U>; }
650+ && std::three_way_comparable_with<T, U>
651+ constexpr std::compare_three_way_result_t <T, U>
652+ operator <=> [[nodiscard]] (Optional<T> const & x, U const & v)
653+ {
654+ return bool (x) ? *x <=> v : std::strong_ordering::less;
655+ }
342656} // namespace clang::mrdocs
343657
344658#endif
0 commit comments