summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Morph2021-10-31 21:20:51 -0400
committerGravatar Morph2021-11-02 15:20:35 -0400
commita41e9e93dd0786dc0fbdbe0fe61b7294490129ef (patch)
tree86cfb6b0832c619cc1617e2bd50b2b62844b6331 /src
parentMerge pull request #7227 from vonchenplus/fix_memory_leak_v2 (diff)
downloadyuzu-a41e9e93dd0786dc0fbdbe0fe61b7294490129ef.tar.gz
yuzu-a41e9e93dd0786dc0fbdbe0fe61b7294490129ef.tar.xz
yuzu-a41e9e93dd0786dc0fbdbe0fe61b7294490129ef.zip
common: Implement a subset of P0323 (std::expected)
This implementation is based on and is a subset of the proposed implementation of std::expected https://github.com/TartanLlama/expected/blob/master/include/tl/expected.hpp
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/expected.h987
2 files changed, 988 insertions, 0 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index cb5c0f326..23d43a394 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -55,6 +55,7 @@ add_library(common STATIC
55 dynamic_library.h 55 dynamic_library.h
56 error.cpp 56 error.cpp
57 error.h 57 error.h
58 expected.h
58 fiber.cpp 59 fiber.cpp
59 fiber.h 60 fiber.h
60 fs/file.cpp 61 fs/file.cpp
diff --git a/src/common/expected.h b/src/common/expected.h
new file mode 100644
index 000000000..c8d8579c1
--- /dev/null
+++ b/src/common/expected.h
@@ -0,0 +1,987 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This is based on the proposed implementation of std::expected (P0323)
6// https://github.com/TartanLlama/expected/blob/master/include/tl/expected.hpp
7
8#pragma once
9
10#include <type_traits>
11#include <utility>
12
13namespace Common {
14
15template <typename T, typename E>
16class Expected;
17
18template <typename E>
19class Unexpected {
20public:
21 Unexpected() = delete;
22
23 constexpr explicit Unexpected(const E& e) : m_val{e} {}
24
25 constexpr explicit Unexpected(E&& e) : m_val{std::move(e)} {}
26
27 constexpr E& value() & {
28 return m_val;
29 }
30
31 constexpr const E& value() const& {
32 return m_val;
33 }
34
35 constexpr E&& value() && {
36 return std::move(m_val);
37 }
38
39 constexpr const E&& value() const&& {
40 return std::move(m_val);
41 }
42
43private:
44 E m_val;
45};
46
47template <typename E>
48constexpr auto operator<=>(const Unexpected<E>& lhs, const Unexpected<E>& rhs) {
49 return lhs.value() <=> rhs.value();
50}
51
52struct unexpect_t {
53 constexpr explicit unexpect_t() = default;
54};
55
56namespace detail {
57
58struct no_init_t {
59 constexpr explicit no_init_t() = default;
60};
61
62/**
63 * This specialization is for when T is not trivially destructible,
64 * so the destructor must be called on destruction of `expected'
65 * Additionally, this requires E to be trivially destructible
66 */
67template <typename T, typename E, bool = std::is_trivially_destructible_v<T>>
68requires std::is_trivially_destructible_v<E>
69struct expected_storage_base {
70 constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
71
72 constexpr expected_storage_base(no_init_t) : m_has_val{false} {}
73
74 template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
75 constexpr expected_storage_base(std::in_place_t, Args&&... args)
76 : m_val{std::forward<Args>(args)...}, m_has_val{true} {}
77
78 template <typename U, typename... Args,
79 std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
80 nullptr>
81 constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il, Args&&... args)
82 : m_val{il, std::forward<Args>(args)...}, m_has_val{true} {}
83
84 template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
85 constexpr explicit expected_storage_base(unexpect_t, Args&&... args)
86 : m_unexpect{std::forward<Args>(args)...}, m_has_val{false} {}
87
88 template <typename U, typename... Args,
89 std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
90 nullptr>
91 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il,
92 Args&&... args)
93 : m_unexpect{il, std::forward<Args>(args)...}, m_has_val{false} {}
94
95 ~expected_storage_base() {
96 if (m_has_val) {
97 m_val.~T();
98 }
99 }
100
101 union {
102 T m_val;
103 Unexpected<E> m_unexpect;
104 };
105
106 bool m_has_val;
107};
108
109/**
110 * This specialization is for when T is trivially destructible,
111 * so the destructor of `expected` can be trivial
112 * Additionally, this requires E to be trivially destructible
113 */
114template <typename T, typename E>
115requires std::is_trivially_destructible_v<E>
116struct expected_storage_base<T, E, true> {
117 constexpr expected_storage_base() : m_val{T{}}, m_has_val{true} {}
118
119 constexpr expected_storage_base(no_init_t) : m_has_val{false} {}
120
121 template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
122 constexpr expected_storage_base(std::in_place_t, Args&&... args)
123 : m_val{std::forward<Args>(args)...}, m_has_val{true} {}
124
125 template <typename U, typename... Args,
126 std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
127 nullptr>
128 constexpr expected_storage_base(std::in_place_t, std::initializer_list<U> il, Args&&... args)
129 : m_val{il, std::forward<Args>(args)...}, m_has_val{true} {}
130
131 template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
132 constexpr explicit expected_storage_base(unexpect_t, Args&&... args)
133 : m_unexpect{std::forward<Args>(args)...}, m_has_val{false} {}
134
135 template <typename U, typename... Args,
136 std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
137 nullptr>
138 constexpr explicit expected_storage_base(unexpect_t, std::initializer_list<U> il,
139 Args&&... args)
140 : m_unexpect{il, std::forward<Args>(args)...}, m_has_val{false} {}
141
142 ~expected_storage_base() = default;
143
144 union {
145 T m_val;
146 Unexpected<E> m_unexpect;
147 };
148
149 bool m_has_val;
150};
151
152template <typename T, typename E>
153struct expected_operations_base : expected_storage_base<T, E> {
154 using expected_storage_base<T, E>::expected_storage_base;
155
156 template <typename... Args>
157 void construct(Args&&... args) noexcept {
158 new (std::addressof(this->m_val)) T{std::forward<Args>(args)...};
159 this->m_has_val = true;
160 }
161
162 template <typename Rhs>
163 void construct_with(Rhs&& rhs) noexcept {
164 new (std::addressof(this->m_val)) T{std::forward<Rhs>(rhs).get()};
165 this->m_has_val = true;
166 }
167
168 template <typename... Args>
169 void construct_error(Args&&... args) noexcept {
170 new (std::addressof(this->m_unexpect)) Unexpected<E>{std::forward<Args>(args)...};
171 this->m_has_val = false;
172 }
173
174 void assign(const expected_operations_base& rhs) noexcept {
175 if (!this->m_has_val && rhs.m_has_val) {
176 geterr().~Unexpected<E>();
177 construct(rhs.get());
178 } else {
179 assign_common(rhs);
180 }
181 }
182
183 void assign(expected_operations_base&& rhs) noexcept {
184 if (!this->m_has_val && rhs.m_has_val) {
185 geterr().~Unexpected<E>();
186 construct(std::move(rhs).get());
187 } else {
188 assign_common(rhs);
189 }
190 }
191
192 template <typename Rhs>
193 void assign_common(Rhs&& rhs) {
194 if (this->m_has_val) {
195 if (rhs.m_has_val) {
196 get() = std::forward<Rhs>(rhs).get();
197 } else {
198 destroy_val();
199 construct_error(std::forward<Rhs>(rhs).geterr());
200 }
201 } else {
202 if (!rhs.m_has_val) {
203 geterr() = std::forward<Rhs>(rhs).geterr();
204 }
205 }
206 }
207
208 bool has_value() const {
209 return this->m_has_val;
210 }
211
212 constexpr T& get() & {
213 return this->m_val;
214 }
215
216 constexpr const T& get() const& {
217 return this->m_val;
218 }
219
220 constexpr T&& get() && {
221 return std::move(this->m_val);
222 }
223
224 constexpr const T&& get() const&& {
225 return std::move(this->m_val);
226 }
227
228 constexpr Unexpected<E>& geterr() & {
229 return this->m_unexpect;
230 }
231
232 constexpr const Unexpected<E>& geterr() const& {
233 return this->m_unexpect;
234 }
235
236 constexpr Unexpected<E>&& geterr() && {
237 return std::move(this->m_unexpect);
238 }
239
240 constexpr const Unexpected<E>&& geterr() const&& {
241 return std::move(this->m_unexpect);
242 }
243
244 constexpr void destroy_val() {
245 get().~T();
246 }
247};
248
249/**
250 * This manages conditionally having a trivial copy constructor
251 * This specialization is for when T is trivially copy constructible
252 * Additionally, this requires E to be trivially copy constructible
253 */
254template <typename T, typename E, bool = std::is_trivially_copy_constructible_v<T>>
255requires std::is_trivially_copy_constructible_v<E>
256struct expected_copy_base : expected_operations_base<T, E> {
257 using expected_operations_base<T, E>::expected_operations_base;
258};
259
260/**
261 * This specialization is for when T is not trivially copy constructible
262 * Additionally, this requires E to be trivially copy constructible
263 */
264template <typename T, typename E>
265requires std::is_trivially_copy_constructible_v<E>
266struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
267 using expected_operations_base<T, E>::expected_operations_base;
268
269 expected_copy_base() = default;
270
271 expected_copy_base(const expected_copy_base& rhs)
272 : expected_operations_base<T, E>{no_init_t{}} {
273 if (rhs.has_value()) {
274 this->construct_with(rhs);
275 } else {
276 this->construct_error(rhs.geterr());
277 }
278 }
279
280 expected_copy_base(expected_copy_base&&) = default;
281
282 expected_copy_base& operator=(const expected_copy_base&) = default;
283
284 expected_copy_base& operator=(expected_copy_base&&) = default;
285};
286
287/**
288 * This manages conditionally having a trivial move constructor
289 * This specialization is for when T is trivially move constructible
290 * Additionally, this requires E to be trivially move constructible
291 */
292template <typename T, typename E, bool = std::is_trivially_move_constructible_v<T>>
293requires std::is_trivially_move_constructible_v<E>
294struct expected_move_base : expected_copy_base<T, E> {
295 using expected_copy_base<T, E>::expected_copy_base;
296};
297
298/**
299 * This specialization is for when T is not trivially move constructible
300 * Additionally, this requires E to be trivially move constructible
301 */
302template <typename T, typename E>
303requires std::is_trivially_move_constructible_v<E>
304struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
305 using expected_copy_base<T, E>::expected_copy_base;
306
307 expected_move_base() = default;
308
309 expected_move_base(const expected_move_base&) = default;
310
311 expected_move_base(expected_move_base&& rhs) noexcept(std::is_nothrow_move_constructible_v<T>)
312 : expected_copy_base<T, E>{no_init_t{}} {
313 if (rhs.has_value()) {
314 this->construct_with(std::move(rhs));
315 } else {
316 this->construct_error(std::move(rhs.geterr()));
317 }
318 }
319
320 expected_move_base& operator=(const expected_move_base&) = default;
321
322 expected_move_base& operator=(expected_move_base&&) = default;
323};
324
325/**
326 * This manages conditionally having a trivial copy assignment operator
327 * This specialization is for when T is trivially copy assignable
328 * Additionally, this requires E to be trivially copy assignable
329 */
330template <typename T, typename E,
331 bool = std::conjunction_v<std::is_trivially_copy_assignable<T>,
332 std::is_trivially_copy_constructible<T>,
333 std::is_trivially_destructible<T>>>
334requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
335 std::is_trivially_copy_constructible<E>,
336 std::is_trivially_destructible<E>>
337struct expected_copy_assign_base : expected_move_base<T, E> {
338 using expected_move_base<T, E>::expected_move_base;
339};
340
341/**
342 * This specialization is for when T is not trivially copy assignable
343 * Additionally, this requires E to be trivially copy assignable
344 */
345template <typename T, typename E>
346requires std::conjunction_v<std::is_trivially_copy_assignable<E>,
347 std::is_trivially_copy_constructible<E>,
348 std::is_trivially_destructible<E>>
349struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
350 using expected_move_base<T, E>::expected_move_base;
351
352 expected_copy_assign_base() = default;
353
354 expected_copy_assign_base(const expected_copy_assign_base&) = default;
355
356 expected_copy_assign_base(expected_copy_assign_base&&) = default;
357
358 expected_copy_assign_base& operator=(const expected_copy_assign_base& rhs) {
359 this->assign(rhs);
360 return *this;
361 }
362
363 expected_copy_assign_base& operator=(expected_copy_assign_base&&) = default;
364};
365
366/**
367 * This manages conditionally having a trivial move assignment operator
368 * This specialization is for when T is trivially move assignable
369 * Additionally, this requires E to be trivially move assignable
370 */
371template <typename T, typename E,
372 bool = std::conjunction_v<std::is_trivially_move_assignable<T>,
373 std::is_trivially_move_constructible<T>,
374 std::is_trivially_destructible<T>>>
375requires std::conjunction_v<std::is_trivially_move_assignable<E>,
376 std::is_trivially_move_constructible<E>,
377 std::is_trivially_destructible<E>>
378struct expected_move_assign_base : expected_copy_assign_base<T, E> {
379 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
380};
381
382/**
383 * This specialization is for when T is not trivially move assignable
384 * Additionally, this requires E to be trivially move assignable
385 */
386template <typename T, typename E>
387requires std::conjunction_v<std::is_trivially_move_assignable<E>,
388 std::is_trivially_move_constructible<E>,
389 std::is_trivially_destructible<E>>
390struct expected_move_assign_base<T, E, false> : expected_copy_assign_base<T, E> {
391 using expected_copy_assign_base<T, E>::expected_copy_assign_base;
392
393 expected_move_assign_base() = default;
394
395 expected_move_assign_base(const expected_move_assign_base&) = default;
396
397 expected_move_assign_base(expected_move_assign_base&&) = default;
398
399 expected_move_assign_base& operator=(const expected_move_assign_base&) = default;
400
401 expected_move_assign_base& operator=(expected_move_assign_base&& rhs) noexcept(
402 std::conjunction_v<std::is_nothrow_move_constructible<T>,
403 std::is_nothrow_move_assignable<T>>) {
404 this->assign(std::move(rhs));
405 return *this;
406 }
407};
408
409/**
410 * expected_delete_ctor_base will conditionally delete copy and move constructors
411 * depending on whether T is copy/move constructible
412 * Additionally, this requires E to be copy/move constructible
413 */
414template <typename T, typename E, bool EnableCopy = std::is_copy_constructible_v<T>,
415 bool EnableMove = std::is_move_constructible_v<T>>
416requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
417struct expected_delete_ctor_base {
418 expected_delete_ctor_base() = default;
419 expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
420 expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default;
421 expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
422 expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
423};
424
425template <typename T, typename E>
426requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
427struct expected_delete_ctor_base<T, E, true, false> {
428 expected_delete_ctor_base() = default;
429 expected_delete_ctor_base(const expected_delete_ctor_base&) = default;
430 expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete;
431 expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
432 expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
433};
434
435template <typename T, typename E>
436requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
437struct expected_delete_ctor_base<T, E, false, true> {
438 expected_delete_ctor_base() = default;
439 expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
440 expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = default;
441 expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
442 expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
443};
444
445template <typename T, typename E>
446requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>>
447struct expected_delete_ctor_base<T, E, false, false> {
448 expected_delete_ctor_base() = default;
449 expected_delete_ctor_base(const expected_delete_ctor_base&) = delete;
450 expected_delete_ctor_base(expected_delete_ctor_base&&) noexcept = delete;
451 expected_delete_ctor_base& operator=(const expected_delete_ctor_base&) = default;
452 expected_delete_ctor_base& operator=(expected_delete_ctor_base&&) noexcept = default;
453};
454
455/**
456 * expected_delete_assign_base will conditionally delete copy and move assignment operators
457 * depending on whether T is copy/move constructible + assignable
458 * Additionally, this requires E to be copy/move constructible + assignable
459 */
460template <
461 typename T, typename E,
462 bool EnableCopy = std::conjunction_v<std::is_copy_constructible<T>, std::is_copy_assignable<T>>,
463 bool EnableMove = std::conjunction_v<std::is_move_constructible<T>, std::is_move_assignable<T>>>
464requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
465 std::is_copy_assignable<E>, std::is_move_assignable<E>>
466struct expected_delete_assign_base {
467 expected_delete_assign_base() = default;
468 expected_delete_assign_base(const expected_delete_assign_base&) = default;
469 expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
470 expected_delete_assign_base& operator=(const expected_delete_assign_base&) = default;
471 expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = default;
472};
473
474template <typename T, typename E>
475requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
476 std::is_copy_assignable<E>, std::is_move_assignable<E>>
477struct expected_delete_assign_base<T, E, true, false> {
478 expected_delete_assign_base() = default;
479 expected_delete_assign_base(const expected_delete_assign_base&) = default;
480 expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
481 expected_delete_assign_base& operator=(const expected_delete_assign_base&) = default;
482 expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = delete;
483};
484
485template <typename T, typename E>
486requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
487 std::is_copy_assignable<E>, std::is_move_assignable<E>>
488struct expected_delete_assign_base<T, E, false, true> {
489 expected_delete_assign_base() = default;
490 expected_delete_assign_base(const expected_delete_assign_base&) = default;
491 expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
492 expected_delete_assign_base& operator=(const expected_delete_assign_base&) = delete;
493 expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = default;
494};
495
496template <typename T, typename E>
497requires std::conjunction_v<std::is_copy_constructible<E>, std::is_move_constructible<E>,
498 std::is_copy_assignable<E>, std::is_move_assignable<E>>
499struct expected_delete_assign_base<T, E, false, false> {
500 expected_delete_assign_base() = default;
501 expected_delete_assign_base(const expected_delete_assign_base&) = default;
502 expected_delete_assign_base(expected_delete_assign_base&&) noexcept = default;
503 expected_delete_assign_base& operator=(const expected_delete_assign_base&) = delete;
504 expected_delete_assign_base& operator=(expected_delete_assign_base&&) noexcept = delete;
505};
506
507/**
508 * This is needed to be able to construct the expected_default_ctor_base which follows,
509 * while still conditionally deleting the default constructor.
510 */
511struct default_constructor_tag {
512 constexpr explicit default_constructor_tag() = default;
513};
514
515/**
516 * expected_default_ctor_base will ensure that expected
517 * has a deleted default constructor if T is not default constructible
518 * This specialization is for when T is default constructible
519 */
520template <typename T, typename E, bool Enable = std::is_default_constructible_v<T>>
521struct expected_default_ctor_base {
522 constexpr expected_default_ctor_base() noexcept = default;
523 constexpr expected_default_ctor_base(expected_default_ctor_base const&) noexcept = default;
524 constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = default;
525 expected_default_ctor_base& operator=(expected_default_ctor_base const&) noexcept = default;
526 expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = default;
527
528 constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
529};
530
531template <typename T, typename E>
532struct expected_default_ctor_base<T, E, false> {
533 constexpr expected_default_ctor_base() noexcept = delete;
534 constexpr expected_default_ctor_base(expected_default_ctor_base const&) noexcept = default;
535 constexpr expected_default_ctor_base(expected_default_ctor_base&&) noexcept = default;
536 expected_default_ctor_base& operator=(expected_default_ctor_base const&) noexcept = default;
537 expected_default_ctor_base& operator=(expected_default_ctor_base&&) noexcept = default;
538
539 constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
540};
541
542template <typename T, typename E, typename U>
543using expected_enable_forward_value =
544 std::enable_if_t<std::is_constructible_v<T, U&&> &&
545 !std::is_same_v<std::remove_cvref_t<U>, std::in_place_t> &&
546 !std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
547 !std::is_same_v<Unexpected<E>, std::remove_cvref_t<U>>>;
548
549template <typename T, typename E, typename U, typename G, typename UR, typename GR>
550using expected_enable_from_other = std::enable_if_t<
551 std::is_constructible_v<T, UR> && std::is_constructible_v<E, GR> &&
552 !std::is_constructible_v<T, Expected<U, G>&> && !std::is_constructible_v<T, Expected<U, G>&&> &&
553 !std::is_constructible_v<T, const Expected<U, G>&> &&
554 !std::is_constructible_v<T, const Expected<U, G>&&> &&
555 !std::is_convertible_v<Expected<U, G>&, T> && !std::is_convertible_v<Expected<U, G>&&, T> &&
556 !std::is_convertible_v<const Expected<U, G>&, T> &&
557 !std::is_convertible_v<const Expected<U, G>&&, T>>;
558
559} // namespace detail
560
561template <typename T, typename E>
562class Expected : private detail::expected_move_assign_base<T, E>,
563 private detail::expected_delete_ctor_base<T, E>,
564 private detail::expected_delete_assign_base<T, E>,
565 private detail::expected_default_ctor_base<T, E> {
566public:
567 using value_type = T;
568 using error_type = E;
569 using unexpected_type = Unexpected<E>;
570
571 constexpr Expected() = default;
572 constexpr Expected(const Expected&) = default;
573 constexpr Expected(Expected&&) = default;
574 Expected& operator=(const Expected&) = default;
575 Expected& operator=(Expected&&) = default;
576
577 template <typename... Args, std::enable_if_t<std::is_constructible_v<T, Args&&...>>* = nullptr>
578 constexpr Expected(std::in_place_t, Args&&... args)
579 : impl_base{std::in_place, std::forward<Args>(args)...},
580 ctor_base{detail::default_constructor_tag{}} {}
581
582 template <typename U, typename... Args,
583 std::enable_if_t<std::is_constructible_v<T, std::initializer_list<U>&, Args&&...>>* =
584 nullptr>
585 constexpr Expected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
586 : impl_base{std::in_place, il, std::forward<Args>(args)...},
587 ctor_base{detail::default_constructor_tag{}} {}
588
589 template <typename G = E, std::enable_if_t<std::is_constructible_v<E, const G&>>* = nullptr,
590 std::enable_if_t<!std::is_convertible_v<const G&, E>>* = nullptr>
591 constexpr explicit Expected(const Unexpected<G>& e)
592 : impl_base{unexpect_t{}, e.value()}, ctor_base{detail::default_constructor_tag{}} {}
593
594 template <typename G = E, std::enable_if_t<std::is_constructible_v<E, const G&>>* = nullptr,
595 std::enable_if_t<std::is_convertible_v<const G&, E>>* = nullptr>
596 constexpr Expected(Unexpected<G> const& e)
597 : impl_base{unexpect_t{}, e.value()}, ctor_base{detail::default_constructor_tag{}} {}
598
599 template <typename G = E, std::enable_if_t<std::is_constructible_v<E, G&&>>* = nullptr,
600 std::enable_if_t<!std::is_convertible_v<G&&, E>>* = nullptr>
601 constexpr explicit Expected(Unexpected<G>&& e) noexcept(std::is_nothrow_constructible_v<E, G&&>)
602 : impl_base{unexpect_t{}, std::move(e.value())}, ctor_base{
603 detail::default_constructor_tag{}} {}
604
605 template <typename G = E, std::enable_if_t<std::is_constructible_v<E, G&&>>* = nullptr,
606 std::enable_if_t<std::is_convertible_v<G&&, E>>* = nullptr>
607 constexpr Expected(Unexpected<G>&& e) noexcept(std::is_nothrow_constructible_v<E, G&&>)
608 : impl_base{unexpect_t{}, std::move(e.value())}, ctor_base{
609 detail::default_constructor_tag{}} {}
610
611 template <typename... Args, std::enable_if_t<std::is_constructible_v<E, Args&&...>>* = nullptr>
612 constexpr explicit Expected(unexpect_t, Args&&... args)
613 : impl_base{unexpect_t{}, std::forward<Args>(args)...},
614 ctor_base{detail::default_constructor_tag{}} {}
615
616 template <typename U, typename... Args,
617 std::enable_if_t<std::is_constructible_v<E, std::initializer_list<U>&, Args&&...>>* =
618 nullptr>
619 constexpr explicit Expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
620 : impl_base{unexpect_t{}, il, std::forward<Args>(args)...},
621 ctor_base{detail::default_constructor_tag{}} {}
622
623 template <typename U, typename G,
624 std::enable_if_t<!(std::is_convertible_v<U const&, T> &&
625 std::is_convertible_v<G const&, E>)>* = nullptr,
626 detail::expected_enable_from_other<T, E, U, G, const U&, const G&>* = nullptr>
627 constexpr explicit Expected(const Expected<U, G>& rhs)
628 : ctor_base{detail::default_constructor_tag{}} {
629 if (rhs.has_value()) {
630 this->construct(*rhs);
631 } else {
632 this->construct_error(rhs.error());
633 }
634 }
635
636 template <typename U, typename G,
637 std::enable_if_t<(std::is_convertible_v<U const&, T> &&
638 std::is_convertible_v<G const&, E>)>* = nullptr,
639 detail::expected_enable_from_other<T, E, U, G, const U&, const G&>* = nullptr>
640 constexpr Expected(const Expected<U, G>& rhs) : ctor_base{detail::default_constructor_tag{}} {
641 if (rhs.has_value()) {
642 this->construct(*rhs);
643 } else {
644 this->construct_error(rhs.error());
645 }
646 }
647
648 template <typename U, typename G,
649 std::enable_if_t<!(std::is_convertible_v<U&&, T> && std::is_convertible_v<G&&, E>)>* =
650 nullptr,
651 detail::expected_enable_from_other<T, E, U, G, U&&, G&&>* = nullptr>
652 constexpr explicit Expected(Expected<U, G>&& rhs)
653 : ctor_base{detail::default_constructor_tag{}} {
654 if (rhs.has_value()) {
655 this->construct(std::move(*rhs));
656 } else {
657 this->construct_error(std::move(rhs.error()));
658 }
659 }
660
661 template <typename U, typename G,
662 std::enable_if_t<(std::is_convertible_v<U&&, T> && std::is_convertible_v<G&&, E>)>* =
663 nullptr,
664 detail::expected_enable_from_other<T, E, U, G, U&&, G&&>* = nullptr>
665 constexpr Expected(Expected<U, G>&& rhs) : ctor_base{detail::default_constructor_tag{}} {
666 if (rhs.has_value()) {
667 this->construct(std::move(*rhs));
668 } else {
669 this->construct_error(std::move(rhs.error()));
670 }
671 }
672
673 template <typename U = T, std::enable_if_t<!std::is_convertible_v<U&&, T>>* = nullptr,
674 detail::expected_enable_forward_value<T, E, U>* = nullptr>
675 constexpr explicit Expected(U&& v) : Expected{std::in_place, std::forward<U>(v)} {}
676
677 template <typename U = T, std::enable_if_t<std::is_convertible_v<U&&, T>>* = nullptr,
678 detail::expected_enable_forward_value<T, E, U>* = nullptr>
679 constexpr Expected(U&& v) : Expected{std::in_place, std::forward<U>(v)} {}
680
681 template <typename U = T, typename G = T,
682 std::enable_if_t<std::is_nothrow_constructible_v<T, U&&>>* = nullptr,
683 std::enable_if_t<(
684 !std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
685 !std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::remove_cvref_t<U>>> &&
686 std::is_constructible_v<T, U> && std::is_assignable_v<G&, U> &&
687 std::is_nothrow_move_constructible_v<E>)>* = nullptr>
688 Expected& operator=(U&& v) {
689 if (has_value()) {
690 val() = std::forward<U>(v);
691 } else {
692 err().~Unexpected<E>();
693 new (valptr()) T{std::forward<U>(v)};
694 this->m_has_val = true;
695 }
696
697 return *this;
698 }
699
700 template <typename U = T, typename G = T,
701 std::enable_if_t<!std::is_nothrow_constructible_v<T, U&&>>* = nullptr,
702 std::enable_if_t<(
703 !std::is_same_v<Expected<T, E>, std::remove_cvref_t<U>> &&
704 !std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::remove_cvref_t<U>>> &&
705 std::is_constructible_v<T, U> && std::is_assignable_v<G&, U> &&
706 std::is_nothrow_move_constructible_v<E>)>* = nullptr>
707 Expected& operator=(U&& v) {
708 if (has_value()) {
709 val() = std::forward<U>(v);
710 } else {
711 auto tmp = std::move(err());
712 err().~Unexpected<E>();
713 new (valptr()) T{std::forward<U>(v)};
714 this->m_has_val = true;
715 }
716
717 return *this;
718 }
719
720 template <typename G = E, std::enable_if_t<std::is_nothrow_copy_constructible_v<G> &&
721 std::is_assignable_v<G&, G>>* = nullptr>
722 Expected& operator=(const Unexpected<G>& rhs) {
723 if (!has_value()) {
724 err() = rhs;
725 } else {
726 this->destroy_val();
727 new (errptr()) Unexpected<E>{rhs};
728 this->m_has_val = false;
729 }
730
731 return *this;
732 }
733
734 template <typename G = E, std::enable_if_t<std::is_nothrow_move_constructible_v<G> &&
735 std::is_move_assignable_v<G>>* = nullptr>
736 Expected& operator=(Unexpected<G>&& rhs) noexcept {
737 if (!has_value()) {
738 err() = std::move(rhs);
739 } else {
740 this->destroy_val();
741 new (errptr()) Unexpected<E>{std::move(rhs)};
742 this->m_has_val = false;
743 }
744
745 return *this;
746 }
747
748 template <typename... Args,
749 std::enable_if_t<std::is_nothrow_constructible_v<T, Args&&...>>* = nullptr>
750 void emplace(Args&&... args) {
751 if (has_value()) {
752 val() = T{std::forward<Args>(args)...};
753 } else {
754 err().~Unexpected<E>();
755 new (valptr()) T{std::forward<Args>(args)...};
756 this->m_has_val = true;
757 }
758 }
759
760 template <typename... Args,
761 std::enable_if_t<!std::is_nothrow_constructible_v<T, Args&&...>>* = nullptr>
762 void emplace(Args&&... args) {
763 if (has_value()) {
764 val() = T{std::forward<Args>(args)...};
765 } else {
766 auto tmp = std::move(err());
767 err().~Unexpected<E>();
768 new (valptr()) T{std::forward<Args>(args)...};
769 this->m_has_val = true;
770 }
771 }
772
773 template <typename U, typename... Args,
774 std::enable_if_t<std::is_nothrow_constructible_v<T, std::initializer_list<U>&,
775 Args&&...>>* = nullptr>
776 void emplace(std::initializer_list<U> il, Args&&... args) {
777 if (has_value()) {
778 T t{il, std::forward<Args>(args)...};
779 val() = std::move(t);
780 } else {
781 err().~Unexpected<E>();
782 new (valptr()) T{il, std::forward<Args>(args)...};
783 this->m_has_val = true;
784 }
785 }
786
787 template <typename U, typename... Args,
788 std::enable_if_t<!std::is_nothrow_constructible_v<T, std::initializer_list<U>&,
789 Args&&...>>* = nullptr>
790 void emplace(std::initializer_list<U> il, Args&&... args) {
791 if (has_value()) {
792 T t{il, std::forward<Args>(args)...};
793 val() = std::move(t);
794 } else {
795 auto tmp = std::move(err());
796 err().~Unexpected<E>();
797 new (valptr()) T{il, std::forward<Args>(args)...};
798 this->m_has_val = true;
799 }
800 }
801
802 constexpr T* operator->() {
803 return valptr();
804 }
805
806 constexpr const T* operator->() const {
807 return valptr();
808 }
809
810 template <typename U = T>
811 constexpr U& operator*() & {
812 return val();
813 }
814
815 template <typename U = T>
816 constexpr const U& operator*() const& {
817 return val();
818 }
819
820 template <typename U = T>
821 constexpr U&& operator*() && {
822 return std::move(val());
823 }
824
825 template <typename U = T>
826 constexpr const U&& operator*() const&& {
827 return std::move(val());
828 }
829
830 constexpr bool has_value() const noexcept {
831 return this->m_has_val;
832 }
833
834 constexpr explicit operator bool() const noexcept {
835 return this->m_has_val;
836 }
837
838 template <typename U = T>
839 constexpr U& value() & {
840 return val();
841 }
842
843 template <typename U = T>
844 constexpr const U& value() const& {
845 return val();
846 }
847
848 template <typename U = T>
849 constexpr U&& value() && {
850 return std::move(val());
851 }
852
853 template <typename U = T>
854 constexpr const U&& value() const&& {
855 return std::move(val());
856 }
857
858 constexpr E& error() & {
859 return err().value();
860 }
861
862 constexpr const E& error() const& {
863 return err().value();
864 }
865
866 constexpr E&& error() && {
867 return std::move(err().value());
868 }
869
870 constexpr const E&& error() const&& {
871 return std::move(err().value());
872 }
873
874 template <typename U>
875 constexpr T value_or(U&& v) const& {
876 static_assert(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>,
877 "T must be copy-constructible and convertible from U&&");
878 return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
879 }
880
881 template <typename U>
882 constexpr T value_or(U&& v) && {
883 static_assert(std::is_move_constructible_v<T> && std::is_convertible_v<U&&, T>,
884 "T must be move-constructible and convertible from U&&");
885 return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
886 }
887
888private:
889 static_assert(!std::is_reference_v<T>, "T must not be a reference");
890 static_assert(!std::is_same_v<T, std::remove_cv_t<std::in_place_t>>,
891 "T must not be std::in_place_t");
892 static_assert(!std::is_same_v<T, std::remove_cv_t<unexpect_t>>, "T must not be unexpect_t");
893 static_assert(!std::is_same_v<T, std::remove_cv_t<Unexpected<E>>>,
894 "T must not be Unexpected<E>");
895 static_assert(!std::is_reference_v<E>, "E must not be a reference");
896
897 T* valptr() {
898 return std::addressof(this->m_val);
899 }
900
901 const T* valptr() const {
902 return std::addressof(this->m_val);
903 }
904
905 Unexpected<E>* errptr() {
906 return std::addressof(this->m_unexpect);
907 }
908
909 const Unexpected<E>* errptr() const {
910 return std::addressof(this->m_unexpect);
911 }
912
913 template <typename U = T>
914 constexpr U& val() {
915 return this->m_val;
916 }
917
918 template <typename U = T>
919 constexpr const U& val() const {
920 return this->m_val;
921 }
922
923 constexpr Unexpected<E>& err() {
924 return this->m_unexpect;
925 }
926
927 constexpr const Unexpected<E>& err() const {
928 return this->m_unexpect;
929 }
930
931 using impl_base = detail::expected_move_assign_base<T, E>;
932 using ctor_base = detail::expected_default_ctor_base<T, E>;
933};
934
935template <typename T, typename E, typename U, typename F>
936constexpr bool operator==(const Expected<T, E>& lhs, const Expected<U, F>& rhs) {
937 return (lhs.has_value() != rhs.has_value())
938 ? false
939 : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
940}
941
942template <typename T, typename E, typename U, typename F>
943constexpr bool operator!=(const Expected<T, E>& lhs, const Expected<U, F>& rhs) {
944 return !operator==(lhs, rhs);
945}
946
947template <typename T, typename E, typename U>
948constexpr bool operator==(const Expected<T, E>& x, const U& v) {
949 return x.has_value() ? *x == v : false;
950}
951
952template <typename T, typename E, typename U>
953constexpr bool operator==(const U& v, const Expected<T, E>& x) {
954 return x.has_value() ? *x == v : false;
955}
956
957template <typename T, typename E, typename U>
958constexpr bool operator!=(const Expected<T, E>& x, const U& v) {
959 return !operator==(x, v);
960}
961
962template <typename T, typename E, typename U>
963constexpr bool operator!=(const U& v, const Expected<T, E>& x) {
964 return !operator==(v, x);
965}
966
967template <typename T, typename E>
968constexpr bool operator==(const Expected<T, E>& x, const Unexpected<E>& e) {
969 return x.has_value() ? false : x.error() == e.value();
970}
971
972template <typename T, typename E>
973constexpr bool operator==(const Unexpected<E>& e, const Expected<T, E>& x) {
974 return x.has_value() ? false : x.error() == e.value();
975}
976
977template <typename T, typename E>
978constexpr bool operator!=(const Expected<T, E>& x, const Unexpected<E>& e) {
979 return !operator==(x, e);
980}
981
982template <typename T, typename E>
983constexpr bool operator!=(const Unexpected<E>& e, const Expected<T, E>& x) {
984 return !operator==(e, x);
985}
986
987} // namespace Common