Iros
 
Loading...
Searching...
No Matches
optional.h
Go to the documentation of this file.
1#pragma once
2
8#include "di/meta/compare.h"
9#include "di/meta/core.h"
10#include "di/meta/language.h"
11#include "di/meta/operations.h"
12#include "di/meta/trivial.h"
13#include "di/meta/util.h"
14#include "di/meta/vocab.h"
15#include "di/types/in_place.h"
16#include "di/util/addressof.h"
17#include "di/util/declval.h"
19#include "di/util/move.h"
20#include "di/util/swap.h"
24
25namespace di::vocab {
26namespace detail {
27 template<typename Opt, typename From, typename To>
30}
31
32template<typename T>
35 : public meta::EnableView<Optional<T>>
36 , public meta::EnableBorrowedContainer<Optional<T>, concepts::LValueReference<T>>
37 , public function::monad::MonadInterface<Optional<T>> {
38private:
39 static_assert(!concepts::RValueReference<T>);
40
41 using Storage = StorageFor<T>;
42 static_assert(OptionalStorage<Storage, T>);
43
44public:
45 using Value = T;
46
47 constexpr Optional() = default;
48 constexpr Optional(NullOpt) {}
49
50 // Conditionally trivial special member functions. These overloads will
51 // be selected when the special member functions defined below are deleted.
52 constexpr Optional(Optional const&) = default;
53 constexpr Optional(Optional&&) = default;
54 constexpr auto operator=(Optional const&) -> Optional& = default;
55 constexpr auto operator=(Optional&&) -> Optional& = default;
56 constexpr ~Optional() = default;
57
58 constexpr Optional(Optional const& other)
60 {
61 if (other.has_value()) {
62 emplace(other.value());
63 }
64 }
65
66 constexpr Optional(Optional&& other)
68 {
69 if (other.has_value()) {
70 emplace(util::move(other).value());
71 }
72 }
73
74 template<typename U>
78 if (other.has_value()) {
79 emplace(other.value());
80 }
81 }
82
83 template<typename U>
87 if (other.has_value()) {
88 emplace(util::move(other).value());
89 }
90 }
91
92 template<typename... Args>
93 requires(concepts::ConstructibleFrom<T, Args...>)
94 constexpr Optional(types::InPlace, Args&&... args) {
95 emplace(util::forward<Args>(args)...);
96 }
97
98 template<typename U, typename... Args>
100 constexpr Optional(types::InPlace, std::initializer_list<U> list, Args&&... args) {
101 emplace(list, util::forward<Args>(args)...);
102 }
103
104 template<typename U = T>
107 emplace(util::forward<U>(value));
108 }
109
110 constexpr ~Optional()
112 {
113 reset();
114 }
115
116 constexpr auto operator=(NullOpt) -> Optional& {
117 reset();
118 return *this;
119 }
120
121 constexpr auto operator=(Optional const& other)
123 if (other.has_value()) {
124 emplace(other.value());
125 }
126 return *this;
127 }
128
130 if (other.has_value()) {
131 emplace(util::move(other).value());
132 }
133 return *this;
134 }
135
136 template<typename U = T>
139 constexpr auto operator=(U&& value) -> Optional& {
140 emplace(util::forward<U>(value));
141 return *this;
142 }
143
144 template<typename U>
146 constexpr auto operator=(Optional<U> const& other) -> Optional& {
147 if (other.has_value()) {
148 emplace(other.value());
149 }
150 return *this;
151 }
152
153 template<typename U>
155 constexpr auto operator=(Optional<U>&& other) -> Optional& {
156 if (other.has_value()) {
157 emplace(util::move(other).value());
158 }
159 return *this;
160 }
161
162 // Accessors
163 constexpr auto has_value() const -> bool { return !is_nullopt(m_storage); }
164 constexpr explicit operator bool() const { return has_value(); }
165
168
169 using Pointer = decltype(util::addressof(util::declval<Reference>()));
170 using ConstPointer = decltype(util::addressof(util::declval<ConstReference>()));
171
172 constexpr auto operator->() -> Pointer { return util::addressof(value()); }
173 constexpr auto operator->() const -> ConstPointer { return util::addressof(value()); }
174
175 constexpr auto operator*() & -> decltype(auto) { return value(); }
176 constexpr auto operator*() const& -> decltype(auto) { return value(); }
177 constexpr auto operator*() && -> decltype(auto) { return util::move(*this).value(); }
178 constexpr auto operator*() const&& -> decltype(auto) { return util::move(*this).value(); }
179
180 constexpr auto value() & -> decltype(auto) {
182 return get_value(m_storage);
183 }
184 constexpr auto value() const& -> decltype(auto) {
186 return get_value(m_storage);
187 }
188 constexpr auto value() && -> decltype(auto) {
190 return get_value(util::move(m_storage));
191 }
192 constexpr auto value() const&& -> decltype(auto) {
194 return get_value(util::move(m_storage));
195 }
196
197 template<concepts::ConvertibleTo<T> U = T>
198 requires(concepts::Copyable<T>)
199 constexpr auto value_or(U&& fallback) const& -> T {
200 return has_value() ? value() : static_cast<T>(util::forward<U>(fallback));
201 }
202
203 template<concepts::ConvertibleTo<T> U = T>
204 constexpr auto value_or(U&& fallback) && -> T {
205 return has_value() ? util::move(*this).value() : static_cast<T>(util::forward<U>(fallback));
206 }
207
208 // Container interface
209 constexpr auto begin() -> Pointer {
210 if (!has_value()) {
211 return nullptr;
212 }
213 return util::addressof(value());
214 }
215
216 constexpr auto begin() const -> ConstPointer {
217 if (!has_value()) {
218 return nullptr;
219 }
220 return util::addressof(value());
221 }
222
223 constexpr auto end() -> Pointer {
224 if (!has_value()) {
225 return nullptr;
226 }
227 return util::addressof(value()) + 1;
228 }
229
230 constexpr auto end() const -> ConstPointer {
231 if (!has_value()) {
232 return nullptr;
233 }
234 return util::addressof(value()) + 1;
235 }
236
237 constexpr auto empty() const -> bool { return !has_value(); }
238 constexpr auto size() const -> types::size_t { return has_value(); }
239
240 constexpr auto data() -> Pointer { return begin(); }
241 constexpr auto data() const -> ConstPointer { return begin(); }
242
243 constexpr auto front() -> Optional<Reference> {
244 if (!has_value()) {
245 return nullopt;
246 }
247 return **this;
248 }
249 constexpr auto front() const -> Optional<ConstReference> {
250 if (!has_value()) {
251 return nullopt;
252 }
253 return **this;
254 }
255
256 constexpr auto back() -> Optional<Reference> { return front(); }
257 constexpr auto back() const -> Optional<ConstReference> { return front(); }
258
259 constexpr auto operator[](types::ssize_t index) -> Reference { return *at(index); }
260 constexpr auto operator[](types::ssize_t index) const -> ConstReference { return *at(index); }
261
262 constexpr auto at(types::ssize_t index) -> Optional<Reference> {
263 if (index != 0) {
264 return nullopt;
265 }
266 return front();
267 }
268
269 constexpr auto at(types::ssize_t index) const -> Optional<ConstReference> {
270 if (index != 0) {
271 return nullopt;
272 }
273 return front();
274 }
275
276 constexpr void reset() { set_nullopt(m_storage); }
277
278 template<typename... Args>
279 constexpr auto emplace(Args&&... args) -> decltype(auto) {
280 reset();
281 set_value(m_storage, util::forward<Args>(args)...);
282 return **this;
283 }
284
285private:
286 constexpr friend void tag_invoke(types::Tag<util::swap>, Optional& a, Optional& b)
287 requires(concepts::Swappable<T>)
288 {
289 if (a.has_value() && b.has_value()) {
290 util::swap(a.m_storage, b.m_storage);
291 } else if (a.has_value()) {
292 b = util::move(a);
293 a = {};
294 } else if (b.has_value()) {
295 a = util::move(b);
296 b = {};
297 }
298 }
299
300 // Monadic interface
301 template<concepts::DecaySameAs<Optional> Self, concepts::Invocable<meta::Like<Self, Value>> F,
302 typename R = meta::InvokeResult<F, meta::Like<Self, Value>>>
303 requires(concepts::Optional<R>)
304 constexpr friend auto tag_invoke(types::Tag<function::monad::bind>, Self&& self, F&& f) -> R {
305 if (self.has_value()) {
306 return function::invoke(util::forward<F>(f), util::forward<Self>(self).value());
307 }
308 return R();
309 }
310
311 template<concepts::DecaySameAs<Optional> Self, concepts::Invocable<meta::Like<Self, Value>> F,
312 typename R = meta::UnwrapRefDecay<meta::InvokeResult<F, meta::Like<Self, Value>>>>
313 constexpr friend auto tag_invoke(types::Tag<function::monad::fmap>, Self&& self, F&& f) -> Optional<R> {
314 if (self.has_value()) {
315 if constexpr (concepts::LanguageVoid<R>) {
316 function::invoke(util::forward<F>(f), util::forward<Self>(self).value());
318 } else {
320 function::invoke(util::forward<F>(f), util::forward<Self>(self).value()));
321 }
322 } else {
323 return nullopt;
324 }
325 }
326
327 template<concepts::DecaySameAs<Optional> Self, concepts::InvocableTo<Optional> F>
329 constexpr friend auto tag_invoke(types::Tag<function::monad::fail>, Self&& self, F&& f) -> Optional {
330 return self.has_value() ? util::forward<Self>(self) : function::invoke(util::forward<F>(f));
331 }
332
333 Storage m_storage { nullopt };
334};
335
336template<typename T, concepts::EqualityComparableWith<T> U>
337constexpr auto operator==(Optional<T> const& a, Optional<U> const& b) -> bool {
338 return (!a && !b) || (a && b && *a == *b);
339}
340
341template<typename T>
342constexpr auto operator==(Optional<T> const& a, NullOpt) -> bool {
343 return !a;
344}
345
346template<typename T, typename U>
348constexpr auto operator==(Optional<T> const& a, U const& b) -> bool {
349 return a.has_value() && *a == b;
350}
351
352template<typename T, concepts::ThreeWayComparableWith<T> U>
354 if (!a && !b) {
355 return types::strong_ordering::equal;
356 }
357 if (auto result = a.has_value() <=> b.has_value(); result != 0) {
358 return result;
359 }
360 return *a <=> *b;
361}
362
363template<typename T>
364constexpr auto operator<=>(Optional<T> const& a, NullOpt) -> types::strong_ordering {
365 return a.has_value() <=> false;
366}
367
368template<typename T, typename U>
370constexpr auto operator<=>(Optional<T> const& a, U const& b) -> meta::CompareThreeWayResult<T, U> {
371 if (!a.has_value()) {
372 return types::strong_ordering::less;
373 }
374 return *a <=> b;
375}
376
377template<class T>
379}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Definition optional_forward_declaration.h:5
constexpr ~Optional()=default
constexpr ~Optional()
Definition optional.h:110
constexpr auto operator*() &&-> decltype(auto)
Definition optional.h:177
constexpr auto operator->() -> Pointer
Definition optional.h:172
constexpr auto value_or(U &&fallback) const &-> T
Definition optional.h:199
constexpr auto operator*() &-> decltype(auto)
Definition optional.h:175
constexpr auto value() &&-> decltype(auto)
Definition optional.h:188
constexpr auto size() const -> types::size_t
Definition optional.h:238
constexpr auto begin() const -> ConstPointer
Definition optional.h:216
constexpr auto data() const -> ConstPointer
Definition optional.h:241
constexpr auto operator*() const &&-> decltype(auto)
Definition optional.h:178
constexpr auto end() -> Pointer
Definition optional.h:223
constexpr auto value() const &&-> decltype(auto)
Definition optional.h:192
constexpr auto front() -> Optional< Reference >
Definition optional.h:243
decltype(get_value(util::declval< Storage & >())) Reference
Definition optional.h:166
constexpr auto operator=(Optional &&) -> Optional &=default
decltype(get_value(util::declval< Storage const & >())) ConstReference
Definition optional.h:167
constexpr friend auto tag_invoke(types::Tag< function::monad::fail >, Self &&self, F &&f) -> Optional
Definition optional.h:329
constexpr friend auto tag_invoke(types::Tag< function::monad::fmap >, Self &&self, F &&f) -> Optional< R >
Definition optional.h:313
constexpr auto begin() -> Pointer
Definition optional.h:209
constexpr auto operator[](types::ssize_t index) -> Reference
Definition optional.h:259
constexpr friend auto tag_invoke(types::Tag< function::monad::bind >, Self &&self, F &&f) -> R
Definition optional.h:304
constexpr Optional(Optional &&other)
Definition optional.h:66
constexpr auto operator*() const &-> decltype(auto)
Definition optional.h:176
constexpr Optional(types::InPlace, std::initializer_list< U > list, Args &&... args)
Definition optional.h:100
constexpr friend void tag_invoke(types::Tag< util::swap >, Optional &a, Optional &b)
Definition optional.h:286
constexpr auto value() const &-> decltype(auto)
Definition optional.h:184
decltype(util::addressof(util::declval< Reference >())) Pointer
Definition optional.h:169
constexpr Optional(Optional const &)=default
constexpr auto data() -> Pointer
Definition optional.h:240
decltype(util::addressof(util::declval< ConstReference >())) ConstPointer
Definition optional.h:170
constexpr auto operator=(Optional const &other) -> Optional &requires(concepts::Copyable< T > &&!concepts::TriviallyCopyAssignable< Storage >)
Definition optional.h:121
constexpr Optional(Optional const &other)
Definition optional.h:58
T Value
Definition optional.h:45
constexpr auto operator->() const -> ConstPointer
Definition optional.h:173
constexpr auto operator=(Optional &&other) -> Optional &requires(!concepts::TriviallyMoveAssignable< Storage >)
Definition optional.h:129
constexpr Optional(NullOpt)
Definition optional.h:48
constexpr auto empty() const -> bool
Definition optional.h:237
constexpr auto operator=(Optional const &) -> Optional &=default
constexpr auto back() const -> Optional< ConstReference >
Definition optional.h:257
constexpr auto at(types::ssize_t index) -> Optional< Reference >
Definition optional.h:262
constexpr auto end() const -> ConstPointer
Definition optional.h:230
constexpr Optional(types::InPlace, Args &&... args)
Definition optional.h:94
constexpr auto operator[](types::ssize_t index) const -> ConstReference
Definition optional.h:260
constexpr auto emplace(Args &&... args) -> decltype(auto)
Definition optional.h:279
constexpr Optional()=default
constexpr auto value_or(U &&fallback) &&-> T
Definition optional.h:204
constexpr void reset()
Definition optional.h:276
constexpr Optional(Optional &&)=default
constexpr auto back() -> Optional< Reference >
Definition optional.h:256
constexpr auto value() &-> decltype(auto)
Definition optional.h:180
constexpr auto front() const -> Optional< ConstReference >
Definition optional.h:249
constexpr auto operator=(NullOpt) -> Optional &
Definition optional.h:116
constexpr auto has_value() const -> bool
Definition optional.h:163
constexpr auto at(types::ssize_t index) const -> Optional< ConstReference >
Definition optional.h:269
Definition operations.h:11
Definition operations.h:99
Definition operations.h:40
Implicit conversion for this test refers to the ability to return a value of function from a type.
Definition operations.h:89
Definition core.h:128
Definition core.h:117
Definition vocab.h:77
Definition language.h:44
Definition core.h:114
Definition language.h:367
Definition swap.h:31
Definition constructible_from_cref_optional.h:8
Definition optional_storage.h:16
Definition any_storable.h:9
Definition as_bool.h:8
constexpr auto invoke
Definition invoke.h:100
Definition merge_interfaces.h:6
meta::Type< detail::CompareThreeWayResultHelper< T, U > > CompareThreeWayResult
Definition compare.h:133
constexpr auto OptionalRank
Definition vocab.h:85
Definition method.h:5
ptrdiff_t ssize_t
Definition ssize_t.h:6
constexpr auto in_place
Definition in_place.h:8
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
auto declval() -> meta::AddRValueReference< T >
Definition declval.h:8
constexpr struct di::util::SwapFunction swap
Definition erasure_cast.h:7
Definition lazy.h:165
constexpr struct di::vocab::SetValueFunction set_value
Optional(T) -> Optional< T >
constexpr auto operator<=>(Optional< T > const &a, Optional< U > const &b) -> meta::CompareThreeWayResult< T, U >
Definition optional.h:353
constexpr auto nullopt
Definition nullopt.h:15
meta::Conditional< OptionalStorage< meta::WrapReference< T >, T >, meta::WrapReference< T >, BasicOptionalStorage< T > > StorageFor
Definition storage_for.h:11
constexpr struct di::vocab::SetNulloptFunction set_nullopt
constexpr auto operator==(StatusCode< T > const &a, StatusCode< U > const &b) -> bool
Definition status_code_equality.h:7
constexpr struct di::vocab::IsNulloptFunction is_nullopt
constexpr auto get_value
Definition get_value.h:15
constexpr auto front
Definition access.h:58
constexpr auto at
Definition access.h:147
constexpr auto begin
Definition begin.h:44
Definition in_place.h:4
Definition nullopt.h:6