99#pragma once
1010
1111#include < AK/Assertions.h>
12+ #include < AK/Concepts.h>
13+ #include < AK/Forward.h>
1214#include < AK/Noncopyable.h>
15+ #include < AK/Platform.h>
16+ #include < AK/StdLibExtraDetails.h>
1317#include < AK/StdLibExtras.h>
1418#include < AK/Traits.h>
1519#include < AK/Try.h>
@@ -33,10 +37,17 @@ struct ConditionallyResultType<false, T> {
3337 using Type = T;
3438};
3539
40+ template <typename Self, typename T>
41+ struct AddConstIfNeeded {
42+ using Type = Conditional<IsConst<RemoveReference<Self>> && !IsConst<T>, AddConst<T>, T>;
43+ };
44+
3645}
3746
3847template <auto condition, typename T>
3948using ConditionallyResultType = typename Detail::ConditionallyResultType<condition, T>::Type;
49+ template <typename Self, typename T>
50+ using AddConstIfNeeded = typename Detail::AddConstIfNeeded<Self, T>::Type;
4051
4152// NOTE: If you're here because of an internal compiler error in GCC 10.3.0+,
4253// it's because of the following bug:
@@ -53,124 +64,100 @@ struct OptionalNone {
5364 explicit constexpr OptionalNone () = default;
5465};
5566
56- template <typename T, typename Self = Optional<T>>
57- requires (!IsLvalueReference<Self>) class [[nodiscard]] OptionalBase {
67+ template <typename T>
68+ requires (!IsLvalueReference<T>)
69+ class [[nodiscard]] OptionalBase {
5870public:
5971 using ValueType = T;
6072
61- template <SameAs<OptionalNone> V>
62- ALWAYS_INLINE constexpr Self& operator =(V)
73+ template <typename Self, SameAs<OptionalNone> V>
74+ ALWAYS_INLINE constexpr Self& operator =(this Self& self, V)
6375 {
64- static_cast <Self&>(* this ) .clear ();
65- return static_cast <Self&>(* this ) ;
76+ self .clear ();
77+ return self ;
6678 }
6779
68- [[nodiscard]] ALWAYS_INLINE constexpr T* ptr () &
80+ template <typename Self>
81+ [[nodiscard]] ALWAYS_INLINE constexpr AddConstIfNeeded<Self, T>* ptr (this Self& self)
6982 {
70- return static_cast <Self&>(* this ) .has_value () ? __builtin_launder ( reinterpret_cast <T*>(& static_cast <Self&>(* this ) .value ()) ) : nullptr ;
83+ return self .has_value () ? &self .value () : nullptr ;
7184 }
7285
73- [[nodiscard]] ALWAYS_INLINE constexpr T const * ptr () const &
86+ template <typename O = T, typename Fallback = O, typename Self>
87+ [[nodiscard]] ALWAYS_INLINE constexpr O value_or (this Self&& self, Fallback&& fallback)
7488 {
75- return static_cast <Self const &>(*this ).has_value () ? __builtin_launder (reinterpret_cast <T const *>(&static_cast <Self const &>(*this ).value ())) : nullptr ;
89+ if (self.has_value ())
90+ return forward<Self>(self).value ();
91+ return forward<Fallback>(fallback);
7692 }
7793
78- template <typename O = T, typename Fallback = O >
79- [[nodiscard]] ALWAYS_INLINE constexpr O value_or (Fallback const & fallback) const &
94+ template <typename Callback, typename O = T, typename Self >
95+ [[nodiscard]] ALWAYS_INLINE constexpr O value_or_lazy_evaluated ( this Self&& self, Callback callback)
8096 {
81- if (static_cast <Self const &>(*this ).has_value ())
82- return static_cast <Self const &>(*this ).value ();
83- return fallback;
84- }
85-
86- template <typename O = T, typename Fallback = O>
87- requires (!IsLvalueReference<O> && !IsRvalueReference<O>)
88- [[nodiscard]] ALWAYS_INLINE constexpr O value_or (Fallback&& fallback) &&
89- {
90- if (static_cast <Self&>(*this ).has_value ())
91- return move (static_cast <Self&>(*this ).value ());
92- return move (fallback);
93- }
94-
95- template <typename Callback, typename O = T>
96- [[nodiscard]] ALWAYS_INLINE constexpr O value_or_lazy_evaluated (Callback callback) const
97- {
98- if (static_cast <Self const &>(*this ).has_value ())
99- return static_cast <Self const &>(*this ).value ();
97+ if (self.has_value ())
98+ return forward<Self>(self).value ();
10099 return callback ();
101100 }
102101
103- template <typename Callback, typename O = T>
104- [[nodiscard]] ALWAYS_INLINE constexpr Optional<O> value_or_lazy_evaluated_optional (Callback callback) const
102+ template <typename Callback, typename O = T, typename Self >
103+ [[nodiscard]] ALWAYS_INLINE constexpr Optional<O> value_or_lazy_evaluated_optional (this Self&& self, Callback callback)
105104 {
106- if (static_cast <Self const &>(* this ) .has_value ())
107- return static_cast <Self const &>(* this ). value ( );
105+ if (self .has_value ())
106+ return forward <Self>(self );
108107 return callback ();
109108 }
110109
111- template <typename Callback, typename O = T>
112- [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<O> try_value_or_lazy_evaluated (Callback callback) const
110+ template <typename Callback, typename O = T, typename Self >
111+ [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<O> try_value_or_lazy_evaluated (this Self&& self, Callback callback)
113112 {
114- if (static_cast <Self const &>(* this ) .has_value ())
115- return static_cast <Self const &>(* this ).value ();
113+ if (self .has_value ())
114+ return forward <Self>(self ).value ();
116115 return TRY (callback ());
117116 }
118117
119- template <typename Callback, typename O = T>
120- [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<Optional<O>> try_value_or_lazy_evaluated_optional (Callback callback) const
118+ template <typename Callback, typename O = T, typename Self >
119+ [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<Optional<O>> try_value_or_lazy_evaluated_optional (this Self&& self, Callback callback)
121120 {
122- if (static_cast <Self const &>(* this ) .has_value ())
123- return static_cast <Self const &>(* this ). value ( );
121+ if (self .has_value ())
122+ return forward <Self>(self );
124123 return TRY (callback ());
125124 }
126125
127- template <typename Callable>
128- [[nodiscard]] ALWAYS_INLINE constexpr T& ensure (Callable callable) &
126+ template <typename Callable, typename Self >
127+ [[nodiscard]] ALWAYS_INLINE constexpr T& ensure (this Self& self, Callable callable)
129128 {
130- if (!static_cast <Self&>(* this ) .has_value ())
131- static_cast <Self&>(* this ) = callable ();
132- return static_cast <Self&>(* this ) .value ();
129+ if (!self .has_value ())
130+ self = callable ();
131+ return self .value ();
133132 }
134133
135- [[nodiscard]] ALWAYS_INLINE constexpr T const & operator *() const { return static_cast <Self const &>(*this ).value (); }
136- [[nodiscard]] ALWAYS_INLINE constexpr T& operator *() { return static_cast <Self&>(*this ).value (); }
137-
138- ALWAYS_INLINE constexpr T const * operator ->() const { return &static_cast <Self const &>(*this ).value (); }
139- ALWAYS_INLINE constexpr T* operator ->() { return &static_cast <Self&>(*this ).value (); }
134+ template <typename Self>
135+ [[nodiscard]] ALWAYS_INLINE constexpr auto operator *(this Self&& self) -> decltype (forward<Self>(self).value ()) { return forward<Self>(self).value (); }
136+ template <typename Self>
137+ [[nodiscard]] ALWAYS_INLINE constexpr AddConstIfNeeded<Self, T>* operator ->(this Self&& self) { return &self.value (); }
140138
141- template <typename F, typename MappedType = decltype (declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
142- ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map (F&& mapper)
143- {
144- if constexpr (IsErrorOr) {
145- if (static_cast <Self&>(*this ).has_value ())
146- return OptionalType { TRY (mapper (static_cast <Self&>(*this ).value ())) };
147- return OptionalType {};
148- } else {
149- if (static_cast <Self&>(*this ).has_value ())
150- return OptionalType { mapper (static_cast <Self&>(*this ).value ()) };
151-
152- return OptionalType {};
153- }
154- }
155-
156- template <typename F, typename MappedType = decltype (declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
157- ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map (F&& mapper) const
139+ template <typename F,
140+ typename MappedType = decltype (declval<F>()(declval<T&>())),
141+ auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>,
142+ typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>,
143+ typename Self>
144+ ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map (this Self&& self, F&& mapper)
158145 {
159146 if constexpr (IsErrorOr) {
160- if (static_cast <Self const &>(* this ) .has_value ())
161- return OptionalType { TRY (mapper (static_cast <Self const &>(* this ).value ())) };
147+ if (self .has_value ())
148+ return OptionalType { TRY (mapper (forward <Self>(self ).value ())) };
162149 return OptionalType {};
163150 } else {
164- if (static_cast <Self const &>(* this ) .has_value ())
165- return OptionalType { mapper (static_cast <Self const &>(* this ).value ()) };
151+ if (self .has_value ())
152+ return OptionalType { mapper (forward <Self>(self ).value ()) };
166153
167154 return OptionalType {};
168155 }
169156 }
170157};
171158
172159template <typename T>
173- requires (!IsLvalueReference<T>) class [[nodiscard]] Optional<T> : public OptionalBase<T, Optional<T> > {
160+ requires (!IsLvalueReference<T>) class [[nodiscard]] Optional<T> : public OptionalBase<T> {
174161 template <typename U>
175162 friend class Optional ;
176163
@@ -509,12 +496,12 @@ requires(IsLvalueReference<T>) class [[nodiscard]] Optional<T> {
509496
510497 [[nodiscard]] ALWAYS_INLINE constexpr bool has_value () const { return m_pointer != nullptr ; }
511498
512- [[nodiscard]] ALWAYS_INLINE RemoveReference<T>* ptr ()
499+ [[nodiscard]] ALWAYS_INLINE constexpr RemoveReference<T>* ptr ()
513500 {
514501 return m_pointer;
515502 }
516503
517- [[nodiscard]] ALWAYS_INLINE RemoveReference<T> const * ptr () const
504+ [[nodiscard]] ALWAYS_INLINE constexpr RemoveReference<T> const * ptr () const
518505 {
519506 return m_pointer;
520507 }
@@ -532,7 +519,7 @@ requires(IsLvalueReference<T>) class [[nodiscard]] Optional<T> {
532519 }
533520
534521 template <typename U>
535- requires (IsBaseOf<RemoveReference <T>, U>) [[nodiscard]] ALWAYS_INLINE constexpr AddConstToReferencedType<T> value_or (U& fallback) const
522+ requires (IsBaseOf<RemoveCVReference <T>, U>) [[nodiscard]] ALWAYS_INLINE constexpr AddConstToReferencedType<T> value_or (U& fallback) const
536523 {
537524 if (m_pointer)
538525 return value ();
@@ -555,8 +542,8 @@ requires(IsLvalueReference<T>) class [[nodiscard]] Optional<T> {
555542 ALWAYS_INLINE constexpr AddConstToReferencedType<T> operator *() const { return value (); }
556543 ALWAYS_INLINE constexpr T operator *() { return value (); }
557544
558- ALWAYS_INLINE RawPtr<AddConst<RemoveReference<T>>> operator ->() const { return &value (); }
559- ALWAYS_INLINE RawPtr<RemoveReference<T>> operator ->() { return &value (); }
545+ ALWAYS_INLINE constexpr RawPtr<AddConst<RemoveReference<T>>> operator ->() const { return &value (); }
546+ ALWAYS_INLINE constexpr RawPtr<RemoveReference<T>> operator ->() { return &value (); }
560547
561548 // Conversion operators from Optional<T&> -> Optional<T>, implicit when T is trivially copyable.
562549 ALWAYS_INLINE constexpr operator Optional<RemoveCVReference<T>>() const
0 commit comments