blob: 3b9d45f18a1f48047888a47a69f6223d4bda9ede [file] [log] [blame]
Martin Stjernholm4fb51112021-04-30 11:53:52 +01001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <algorithm>
20#include <initializer_list>
21#include <type_traits>
22#include <utility>
23#include <variant>
24
25// android::base::expected is an Android implementation of the std::expected
26// proposal.
27// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0323r7.html
28//
29// Usage:
30// using android::base::expected;
31// using android::base::unexpected;
32//
33// expected<double,std::string> safe_divide(double i, double j) {
34// if (j == 0) return unexpected("divide by zero");
35// else return i / j;
36// }
37//
38// void test() {
39// auto q = safe_divide(10, 0);
Martin Stjernholm413b2b52021-11-15 13:56:19 +000040// if (q.ok()) { printf("%f\n", q.value()); }
Martin Stjernholm4fb51112021-04-30 11:53:52 +010041// else { printf("%s\n", q.error().c_str()); }
42// }
43//
44// When the proposal becomes part of the standard and is implemented by
45// libcxx, this will be removed and android::base::expected will be
46// type alias to std::expected.
47//
48
49namespace android {
50namespace base {
51
52// Synopsis
53template<class T, class E>
54 class expected;
55
56template<class E>
57 class unexpected;
58template<class E>
59 unexpected(E) -> unexpected<E>;
60
61template<class E>
62 class bad_expected_access;
63
64template<>
65 class bad_expected_access<void>;
66
67struct unexpect_t {
68 explicit unexpect_t() = default;
69};
70inline constexpr unexpect_t unexpect{};
71
72// macros for SFINAE
73#define _ENABLE_IF(...) \
74 , std::enable_if_t<(__VA_ARGS__)>* = nullptr
75
76// Define NODISCARD_EXPECTED to prevent expected<T,E> from being
77// ignored when used as a return value. This is off by default.
78#ifdef NODISCARD_EXPECTED
79#define _NODISCARD_ [[nodiscard]]
80#else
81#define _NODISCARD_
82#endif
83
84// Class expected
85template<class T, class E>
86class _NODISCARD_ expected {
87 public:
88 using value_type = T;
89 using error_type = E;
90 using unexpected_type = unexpected<E>;
91
92 template<class U>
93 using rebind = expected<U, error_type>;
94
95 // constructors
96 constexpr expected() = default;
97 constexpr expected(const expected& rhs) = default;
98 constexpr expected(expected&& rhs) noexcept = default;
99
100 template<class U, class G _ENABLE_IF(
101 std::is_constructible_v<T, const U&> &&
102 std::is_constructible_v<E, const G&> &&
103 !std::is_constructible_v<T, expected<U, G>&> &&
104 !std::is_constructible_v<T, expected<U, G>&&> &&
105 !std::is_constructible_v<T, const expected<U, G>&> &&
106 !std::is_constructible_v<T, const expected<U, G>&&> &&
107 !std::is_convertible_v<expected<U, G>&, T> &&
108 !std::is_convertible_v<expected<U, G>&&, T> &&
109 !std::is_convertible_v<const expected<U, G>&, T> &&
110 !std::is_convertible_v<const expected<U, G>&&, T> &&
111 !(!std::is_convertible_v<const U&, T> ||
112 !std::is_convertible_v<const G&, E>) /* non-explicit */
113 )>
114 // NOLINTNEXTLINE(google-explicit-constructor)
115 constexpr expected(const expected<U, G>& rhs) {
116 if (rhs.has_value()) var_ = rhs.value();
117 else var_ = unexpected(rhs.error());
118 }
119
120 template<class U, class G _ENABLE_IF(
121 std::is_constructible_v<T, const U&> &&
122 std::is_constructible_v<E, const G&> &&
123 !std::is_constructible_v<T, expected<U, G>&> &&
124 !std::is_constructible_v<T, expected<U, G>&&> &&
125 !std::is_constructible_v<T, const expected<U, G>&> &&
126 !std::is_constructible_v<T, const expected<U, G>&&> &&
127 !std::is_convertible_v<expected<U, G>&, T> &&
128 !std::is_convertible_v<expected<U, G>&&, T> &&
129 !std::is_convertible_v<const expected<U, G>&, T> &&
130 !std::is_convertible_v<const expected<U, G>&&, T> &&
131 (!std::is_convertible_v<const U&, T> ||
132 !std::is_convertible_v<const G&, E>) /* explicit */
133 )>
134 constexpr explicit expected(const expected<U, G>& rhs) {
135 if (rhs.has_value()) var_ = rhs.value();
136 else var_ = unexpected(rhs.error());
137 }
138
139 template<class U, class G _ENABLE_IF(
140 std::is_constructible_v<T, const U&> &&
141 std::is_constructible_v<E, const G&> &&
142 !std::is_constructible_v<T, expected<U, G>&> &&
143 !std::is_constructible_v<T, expected<U, G>&&> &&
144 !std::is_constructible_v<T, const expected<U, G>&> &&
145 !std::is_constructible_v<T, const expected<U, G>&&> &&
146 !std::is_convertible_v<expected<U, G>&, T> &&
147 !std::is_convertible_v<expected<U, G>&&, T> &&
148 !std::is_convertible_v<const expected<U, G>&, T> &&
149 !std::is_convertible_v<const expected<U, G>&&, T> &&
150 !(!std::is_convertible_v<const U&, T> ||
151 !std::is_convertible_v<const G&, E>) /* non-explicit */
152 )>
153 // NOLINTNEXTLINE(google-explicit-constructor)
154 constexpr expected(expected<U, G>&& rhs) {
155 if (rhs.has_value()) var_ = std::move(rhs.value());
156 else var_ = unexpected(std::move(rhs.error()));
157 }
158
159 template<class U, class G _ENABLE_IF(
160 std::is_constructible_v<T, const U&> &&
161 std::is_constructible_v<E, const G&> &&
162 !std::is_constructible_v<T, expected<U, G>&> &&
163 !std::is_constructible_v<T, expected<U, G>&&> &&
164 !std::is_constructible_v<T, const expected<U, G>&> &&
165 !std::is_constructible_v<T, const expected<U, G>&&> &&
166 !std::is_convertible_v<expected<U, G>&, T> &&
167 !std::is_convertible_v<expected<U, G>&&, T> &&
168 !std::is_convertible_v<const expected<U, G>&, T> &&
169 !std::is_convertible_v<const expected<U, G>&&, T> &&
170 (!std::is_convertible_v<const U&, T> ||
171 !std::is_convertible_v<const G&, E>) /* explicit */
172 )>
173 constexpr explicit expected(expected<U, G>&& rhs) {
174 if (rhs.has_value()) var_ = std::move(rhs.value());
175 else var_ = unexpected(std::move(rhs.error()));
176 }
177
178 template <class U = T _ENABLE_IF(
179 std::is_constructible_v<T, U&&> &&
180 !std::is_same_v<std::remove_cv_t<std::remove_reference_t<U>>, std::in_place_t> &&
181 !std::is_same_v<expected<T, E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
182 !std::is_same_v<unexpected<E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
183 std::is_convertible_v<U&&, T> /* non-explicit */
184 )>
185 // NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload)
186 constexpr expected(U&& v) : var_(std::in_place_index<0>, std::forward<U>(v)) {}
187
188 template <class U = T _ENABLE_IF(
189 std::is_constructible_v<T, U&&> &&
190 !std::is_same_v<std::remove_cv_t<std::remove_reference_t<U>>, std::in_place_t> &&
191 !std::is_same_v<expected<T, E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
192 !std::is_same_v<unexpected<E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
193 !std::is_convertible_v<U&&, T> /* explicit */
194 )>
195 // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
196 constexpr explicit expected(U&& v) : var_(std::in_place_index<0>, T(std::forward<U>(v))) {}
197
198 template<class G = E _ENABLE_IF(
199 std::is_constructible_v<E, const G&> &&
200 std::is_convertible_v<const G&, E> /* non-explicit */
201 )>
202 // NOLINTNEXTLINE(google-explicit-constructor)
203 constexpr expected(const unexpected<G>& e)
204 : var_(std::in_place_index<1>, e.value()) {}
205
206 template<class G = E _ENABLE_IF(
207 std::is_constructible_v<E, const G&> &&
208 !std::is_convertible_v<const G&, E> /* explicit */
209 )>
210 constexpr explicit expected(const unexpected<G>& e)
211 : var_(std::in_place_index<1>, E(e.value())) {}
212
213 template<class G = E _ENABLE_IF(
214 std::is_constructible_v<E, G&&> &&
215 std::is_convertible_v<G&&, E> /* non-explicit */
216 )>
217 // NOLINTNEXTLINE(google-explicit-constructor)
218 constexpr expected(unexpected<G>&& e)
219 : var_(std::in_place_index<1>, std::move(e.value())) {}
220
221 template<class G = E _ENABLE_IF(
222 std::is_constructible_v<E, G&&> &&
223 !std::is_convertible_v<G&&, E> /* explicit */
224 )>
225 constexpr explicit expected(unexpected<G>&& e)
226 : var_(std::in_place_index<1>, E(std::move(e.value()))) {}
227
228 template<class... Args _ENABLE_IF(
229 std::is_constructible_v<T, Args&&...>
230 )>
231 constexpr explicit expected(std::in_place_t, Args&&... args)
232 : var_(std::in_place_index<0>, std::forward<Args>(args)...) {}
233
234 template<class U, class... Args _ENABLE_IF(
235 std::is_constructible_v<T, std::initializer_list<U>&, Args...>
236 )>
237 constexpr explicit expected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
238 : var_(std::in_place_index<0>, il, std::forward<Args>(args)...) {}
239
240 template<class... Args _ENABLE_IF(
241 std::is_constructible_v<E, Args...>
242 )>
243 constexpr explicit expected(unexpect_t, Args&&... args)
244 : var_(unexpected_type(std::forward<Args>(args)...)) {}
245
246 template<class U, class... Args _ENABLE_IF(
247 std::is_constructible_v<E, std::initializer_list<U>&, Args...>
248 )>
249 constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
250 : var_(unexpected_type(il, std::forward<Args>(args)...)) {}
251
252 // destructor
253 ~expected() = default;
254
255 // assignment
256 // Note: SFNAIE doesn't work here because assignment operator should be
257 // non-template. We could workaround this by defining a templated parent class
258 // having the assignment operator. This incomplete implementation however
259 // doesn't allow us to copy assign expected<T,E> even when T is non-copy
260 // assignable. The copy assignment will fail by the underlying std::variant
261 // anyway though the error message won't be clear.
262 expected& operator=(const expected& rhs) = default;
263
264 // Note for SFNAIE above applies to here as well
265 expected& operator=(expected&& rhs) noexcept(
266 std::is_nothrow_move_assignable_v<T>&& std::is_nothrow_move_assignable_v<E>) = default;
267
268 template <class U = T _ENABLE_IF(
269 !std::is_void_v<T> &&
270 !std::is_same_v<expected<T, E>, std::remove_cv_t<std::remove_reference_t<U>>> &&
271 !std::conjunction_v<std::is_scalar<T>, std::is_same<T, std::decay_t<U>>> &&
272 std::is_constructible_v<T, U> && std::is_assignable_v<T&, U> &&
273 std::is_nothrow_move_constructible_v<E>)>
274 expected& operator=(U&& rhs) {
275 var_ = T(std::forward<U>(rhs));
276 return *this;
277 }
278
279 template<class G = E>
280 expected& operator=(const unexpected<G>& rhs) {
281 var_ = rhs;
282 return *this;
283 }
284
285 template<class G = E _ENABLE_IF(
286 std::is_nothrow_move_constructible_v<G> &&
287 std::is_move_assignable_v<G>
288 )>
289 expected& operator=(unexpected<G>&& rhs) {
290 var_ = std::move(rhs);
291 return *this;
292 }
293
294 // modifiers
295 template<class... Args _ENABLE_IF(
296 std::is_nothrow_constructible_v<T, Args...>
297 )>
298 T& emplace(Args&&... args) {
299 expected(std::in_place, std::forward<Args>(args)...).swap(*this);
300 return value();
301 }
302
303 template<class U, class... Args _ENABLE_IF(
304 std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>
305 )>
306 T& emplace(std::initializer_list<U> il, Args&&... args) {
307 expected(std::in_place, il, std::forward<Args>(args)...).swap(*this);
308 return value();
309 }
310
311 // swap
312 template<typename U = T, typename = std::enable_if_t<(
313 std::is_swappable_v<U> &&
314 std::is_swappable_v<E> &&
315 (std::is_move_constructible_v<U> ||
316 std::is_move_constructible_v<E>))>>
317 void swap(expected& rhs) noexcept(
318 std::is_nothrow_move_constructible_v<T> &&
319 std::is_nothrow_swappable_v<T> &&
320 std::is_nothrow_move_constructible_v<E> &&
321 std::is_nothrow_swappable_v<E>) {
322 var_.swap(rhs.var_);
323 }
324
325 // observers
326 constexpr const T* operator->() const { return std::addressof(value()); }
327 constexpr T* operator->() { return std::addressof(value()); }
328 constexpr const T& operator*() const& { return value(); }
329 constexpr T& operator*() & { return value(); }
330 constexpr const T&& operator*() const&& { return std::move(std::get<T>(var_)); }
331 constexpr T&& operator*() && { return std::move(std::get<T>(var_)); }
332
333 constexpr bool has_value() const noexcept { return var_.index() == 0; }
334 constexpr bool ok() const noexcept { return has_value(); }
335
336 constexpr const T& value() const& { return std::get<T>(var_); }
337 constexpr T& value() & { return std::get<T>(var_); }
338 constexpr const T&& value() const&& { return std::move(std::get<T>(var_)); }
339 constexpr T&& value() && { return std::move(std::get<T>(var_)); }
340
341 constexpr const E& error() const& { return std::get<unexpected_type>(var_).value(); }
342 constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
343 constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
344 constexpr E&& error() && { return std::move(std::get<unexpected_type>(var_)).value(); }
345
346 template<class U _ENABLE_IF(
347 std::is_copy_constructible_v<T> &&
348 std::is_convertible_v<U, T>
349 )>
350 constexpr T value_or(U&& v) const& {
351 if (has_value()) return value();
352 else return static_cast<T>(std::forward<U>(v));
353 }
354
355 template<class U _ENABLE_IF(
356 std::is_move_constructible_v<T> &&
357 std::is_convertible_v<U, T>
358 )>
359 constexpr T value_or(U&& v) && {
360 if (has_value()) return std::move(value());
361 else return static_cast<T>(std::forward<U>(v));
362 }
363
364 // expected equality operators
365 template<class T1, class E1, class T2, class E2>
366 friend constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y);
367 template<class T1, class E1, class T2, class E2>
368 friend constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y);
369
370 // Comparison with unexpected<E>
371 template<class T1, class E1, class E2>
372 friend constexpr bool operator==(const expected<T1, E1>&, const unexpected<E2>&);
373 template<class T1, class E1, class E2>
374 friend constexpr bool operator==(const unexpected<E2>&, const expected<T1, E1>&);
375 template<class T1, class E1, class E2>
376 friend constexpr bool operator!=(const expected<T1, E1>&, const unexpected<E2>&);
377 template<class T1, class E1, class E2>
378 friend constexpr bool operator!=(const unexpected<E2>&, const expected<T1, E1>&);
379
380 // Specialized algorithms
381 template<class T1, class E1>
382 friend void swap(expected<T1, E1>& x, expected<T1, E1>& y) noexcept(noexcept(x.swap(y)));
383
384 private:
385 std::variant<value_type, unexpected_type> var_;
386};
387
388template<class T1, class E1, class T2, class E2>
389constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y) {
390 if (x.has_value() != y.has_value()) return false;
391 if (!x.has_value()) return x.error() == y.error();
392 return *x == *y;
393}
394
395template<class T1, class E1, class T2, class E2>
396constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y) {
397 return !(x == y);
398}
399
400// Comparison with unexpected<E>
401template<class T1, class E1, class E2>
402constexpr bool operator==(const expected<T1, E1>& x, const unexpected<E2>& y) {
403 return !x.has_value() && (x.error() == y.value());
404}
405template<class T1, class E1, class E2>
406constexpr bool operator==(const unexpected<E2>& x, const expected<T1, E1>& y) {
407 return !y.has_value() && (x.value() == y.error());
408}
409template<class T1, class E1, class E2>
410constexpr bool operator!=(const expected<T1, E1>& x, const unexpected<E2>& y) {
411 return x.has_value() || (x.error() != y.value());
412}
413template<class T1, class E1, class E2>
414constexpr bool operator!=(const unexpected<E2>& x, const expected<T1, E1>& y) {
415 return y.has_value() || (x.value() != y.error());
416}
417
418template<class T1, class E1>
419void swap(expected<T1, E1>& x, expected<T1, E1>& y) noexcept(noexcept(x.swap(y))) {
420 x.swap(y);
421}
422
423template<class E>
424class _NODISCARD_ expected<void, E> {
425 public:
426 using value_type = void;
427 using error_type = E;
428 using unexpected_type = unexpected<E>;
429
430 // constructors
431 constexpr expected() = default;
432 constexpr expected(const expected& rhs) = default;
433 constexpr expected(expected&& rhs) noexcept = default;
434
435 template<class U, class G _ENABLE_IF(
436 std::is_void_v<U> &&
437 std::is_convertible_v<const G&, E> /* non-explicit */
438 )>
439 // NOLINTNEXTLINE(google-explicit-constructor)
440 constexpr expected(const expected<U, G>& rhs) {
441 if (!rhs.has_value()) var_ = unexpected(rhs.error());
442 }
443
444 template<class U, class G _ENABLE_IF(
445 std::is_void_v<U> &&
446 !std::is_convertible_v<const G&, E> /* explicit */
447 )>
448 constexpr explicit expected(const expected<U, G>& rhs) {
449 if (!rhs.has_value()) var_ = unexpected(rhs.error());
450 }
451
452 template<class U, class G _ENABLE_IF(
453 std::is_void_v<U> &&
454 std::is_convertible_v<const G&&, E> /* non-explicit */
455 )>
456 // NOLINTNEXTLINE(google-explicit-constructor)
457 constexpr expected(expected<U, G>&& rhs) {
458 if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error()));
459 }
460
461 template<class U, class G _ENABLE_IF(
462 std::is_void_v<U> &&
463 !std::is_convertible_v<const G&&, E> /* explicit */
464 )>
465 constexpr explicit expected(expected<U, G>&& rhs) {
466 if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error()));
467 }
468
469 template<class G = E _ENABLE_IF(
470 std::is_constructible_v<E, const G&> &&
471 std::is_convertible_v<const G&, E> /* non-explicit */
472 )>
473 // NOLINTNEXTLINE(google-explicit-constructor)
474 constexpr expected(const unexpected<G>& e)
475 : var_(std::in_place_index<1>, e.value()) {}
476
477 template<class G = E _ENABLE_IF(
478 std::is_constructible_v<E, const G&> &&
479 !std::is_convertible_v<const G&, E> /* explicit */
480 )>
481 constexpr explicit expected(const unexpected<G>& e)
482 : var_(std::in_place_index<1>, E(e.value())) {}
483
484 template<class G = E _ENABLE_IF(
485 std::is_constructible_v<E, G&&> &&
486 std::is_convertible_v<G&&, E> /* non-explicit */
487 )>
488 // NOLINTNEXTLINE(google-explicit-constructor)
489 constexpr expected(unexpected<G>&& e)
490 : var_(std::in_place_index<1>, std::move(e.value())) {}
491
492 template<class G = E _ENABLE_IF(
493 std::is_constructible_v<E, G&&> &&
494 !std::is_convertible_v<G&&, E> /* explicit */
495 )>
496 constexpr explicit expected(unexpected<G>&& e)
497 : var_(std::in_place_index<1>, E(std::move(e.value()))) {}
498
499 template<class... Args _ENABLE_IF(
500 sizeof...(Args) == 0
501 )>
502 constexpr explicit expected(std::in_place_t, Args&&...) {}
503
504 template<class... Args _ENABLE_IF(
505 std::is_constructible_v<E, Args...>
506 )>
507 constexpr explicit expected(unexpect_t, Args&&... args)
508 : var_(unexpected_type(std::forward<Args>(args)...)) {}
509
510 template<class U, class... Args _ENABLE_IF(
511 std::is_constructible_v<E, std::initializer_list<U>&, Args...>
512 )>
513 constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
514 : var_(unexpected_type(il, std::forward<Args>(args)...)) {}
515
516 // destructor
517 ~expected() = default;
518
519 // assignment
520 // Note: SFNAIE doesn't work here because assignment operator should be
521 // non-template. We could workaround this by defining a templated parent class
522 // having the assignment operator. This incomplete implementation however
523 // doesn't allow us to copy assign expected<T,E> even when T is non-copy
524 // assignable. The copy assignment will fail by the underlying std::variant
525 // anyway though the error message won't be clear.
526 expected& operator=(const expected& rhs) = default;
527
528 // Note for SFNAIE above applies to here as well
529 expected& operator=(expected&& rhs) noexcept(std::is_nothrow_move_assignable_v<E>) = default;
530
531 template<class G = E>
532 expected& operator=(const unexpected<G>& rhs) {
533 var_ = rhs;
534 return *this;
535 }
536
537 template<class G = E _ENABLE_IF(
538 std::is_nothrow_move_constructible_v<G> &&
539 std::is_move_assignable_v<G>
540 )>
541 expected& operator=(unexpected<G>&& rhs) {
542 var_ = std::move(rhs);
543 return *this;
544 }
545
546 // modifiers
547 void emplace() {
548 var_ = std::monostate();
549 }
550
551 // swap
552 template<typename = std::enable_if_t<
553 std::is_swappable_v<E>>
554 >
555 void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible_v<E>) {
556 var_.swap(rhs.var_);
557 }
558
559 // observers
560 constexpr bool has_value() const noexcept { return var_.index() == 0; }
561 constexpr bool ok() const noexcept { return has_value(); }
562
563 constexpr void value() const& { if (!has_value()) std::get<0>(var_); }
564
565 constexpr const E& error() const& { return std::get<unexpected_type>(var_).value(); }
566 constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
567 constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
568 constexpr E&& error() && { return std::move(std::get<unexpected_type>(var_)).value(); }
569
570 // expected equality operators
571 template<class E1, class E2>
572 friend constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y);
573
574 // Specialized algorithms
575 template<class T1, class E1>
576 friend void swap(expected<T1, E1>& x, expected<T1, E1>& y) noexcept(noexcept(x.swap(y)));
577
578 private:
579 std::variant<std::monostate, unexpected_type> var_;
580};
581
582template<class E1, class E2>
583constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y) {
584 if (x.has_value() != y.has_value()) return false;
585 if (!x.has_value()) return x.error() == y.error();
586 return true;
587}
588
589template<class T1, class E1, class E2>
590constexpr bool operator==(const expected<T1, E1>& x, const expected<void, E2>& y) {
591 if (x.has_value() != y.has_value()) return false;
592 if (!x.has_value()) return x.error() == y.error();
593 return false;
594}
595
596template<class E1, class T2, class E2>
597constexpr bool operator==(const expected<void, E1>& x, const expected<T2, E2>& y) {
598 if (x.has_value() != y.has_value()) return false;
599 if (!x.has_value()) return x.error() == y.error();
600 return false;
601}
602
603template<class E>
604class unexpected {
605 public:
606 // constructors
607 constexpr unexpected(const unexpected&) = default;
608 constexpr unexpected(unexpected&&) noexcept(std::is_nothrow_move_constructible_v<E>) = default;
609
610 template <class Err = E _ENABLE_IF(
611 std::is_constructible_v<E, Err> &&
612 !std::is_same_v<std::remove_cv_t<std::remove_reference_t<E>>, std::in_place_t> &&
613 !std::is_same_v<std::remove_cv_t<std::remove_reference_t<E>>, unexpected>)>
614 // NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload)
615 constexpr unexpected(Err&& e) : val_(std::forward<Err>(e)) {}
616
617 template<class U, class... Args _ENABLE_IF(
618 std::is_constructible_v<E, std::initializer_list<U>&, Args...>
619 )>
620 constexpr explicit unexpected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
621 : val_(il, std::forward<Args>(args)...) {}
622
623 template<class Err _ENABLE_IF(
624 std::is_constructible_v<E, Err> &&
625 !std::is_constructible_v<E, unexpected<Err>&> &&
626 !std::is_constructible_v<E, unexpected<Err>> &&
627 !std::is_constructible_v<E, const unexpected<Err>&> &&
628 !std::is_constructible_v<E, const unexpected<Err>> &&
629 !std::is_convertible_v<unexpected<Err>&, E> &&
630 !std::is_convertible_v<unexpected<Err>, E> &&
631 !std::is_convertible_v<const unexpected<Err>&, E> &&
632 !std::is_convertible_v<const unexpected<Err>, E> &&
633 std::is_convertible_v<Err, E> /* non-explicit */
634 )>
635 // NOLINTNEXTLINE(google-explicit-constructor)
636 constexpr unexpected(const unexpected<Err>& rhs)
637 : val_(rhs.value()) {}
638
639 template<class Err _ENABLE_IF(
640 std::is_constructible_v<E, Err> &&
641 !std::is_constructible_v<E, unexpected<Err>&> &&
642 !std::is_constructible_v<E, unexpected<Err>> &&
643 !std::is_constructible_v<E, const unexpected<Err>&> &&
644 !std::is_constructible_v<E, const unexpected<Err>> &&
645 !std::is_convertible_v<unexpected<Err>&, E> &&
646 !std::is_convertible_v<unexpected<Err>, E> &&
647 !std::is_convertible_v<const unexpected<Err>&, E> &&
648 !std::is_convertible_v<const unexpected<Err>, E> &&
649 !std::is_convertible_v<Err, E> /* explicit */
650 )>
651 constexpr explicit unexpected(const unexpected<Err>& rhs)
652 : val_(E(rhs.value())) {}
653
654 template<class Err _ENABLE_IF(
655 std::is_constructible_v<E, Err> &&
656 !std::is_constructible_v<E, unexpected<Err>&> &&
657 !std::is_constructible_v<E, unexpected<Err>> &&
658 !std::is_constructible_v<E, const unexpected<Err>&> &&
659 !std::is_constructible_v<E, const unexpected<Err>> &&
660 !std::is_convertible_v<unexpected<Err>&, E> &&
661 !std::is_convertible_v<unexpected<Err>, E> &&
662 !std::is_convertible_v<const unexpected<Err>&, E> &&
663 !std::is_convertible_v<const unexpected<Err>, E> &&
664 std::is_convertible_v<Err, E> /* non-explicit */
665 )>
666 // NOLINTNEXTLINE(google-explicit-constructor)
667 constexpr unexpected(unexpected<Err>&& rhs)
668 : val_(std::move(rhs.value())) {}
669
670 template<class Err _ENABLE_IF(
671 std::is_constructible_v<E, Err> &&
672 !std::is_constructible_v<E, unexpected<Err>&> &&
673 !std::is_constructible_v<E, unexpected<Err>> &&
674 !std::is_constructible_v<E, const unexpected<Err>&> &&
675 !std::is_constructible_v<E, const unexpected<Err>> &&
676 !std::is_convertible_v<unexpected<Err>&, E> &&
677 !std::is_convertible_v<unexpected<Err>, E> &&
678 !std::is_convertible_v<const unexpected<Err>&, E> &&
679 !std::is_convertible_v<const unexpected<Err>, E> &&
680 !std::is_convertible_v<Err, E> /* explicit */
681 )>
682 constexpr explicit unexpected(unexpected<Err>&& rhs)
683 : val_(E(std::move(rhs.value()))) {}
684
685 // assignment
686 constexpr unexpected& operator=(const unexpected&) = default;
687 constexpr unexpected& operator=(unexpected&&) noexcept(std::is_nothrow_move_assignable_v<E>) =
688 default;
689 template<class Err = E>
690 constexpr unexpected& operator=(const unexpected<Err>& rhs) {
691 val_ = rhs.value();
692 return *this;
693 }
694 template<class Err = E>
695 constexpr unexpected& operator=(unexpected<Err>&& rhs) {
696 val_ = std::forward<E>(rhs.value());
697 return *this;
698 }
699
700 // observer
701 constexpr const E& value() const& noexcept { return val_; }
702 constexpr E& value() & noexcept { return val_; }
703 constexpr const E&& value() const&& noexcept { return std::move(val_); }
704 constexpr E&& value() && noexcept { return std::move(val_); }
705
706 void swap(unexpected& other) noexcept(std::is_nothrow_swappable_v<E>) {
707 std::swap(val_, other.val_);
708 }
709
710 template<class E1, class E2>
711 friend constexpr bool
712 operator==(const unexpected<E1>& e1, const unexpected<E2>& e2);
713 template<class E1, class E2>
714 friend constexpr bool
715 operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2);
716
717 template<class E1>
718 friend void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y)));
719
720 private:
721 E val_;
722};
723
724template<class E1, class E2>
725constexpr bool
726operator==(const unexpected<E1>& e1, const unexpected<E2>& e2) {
727 return e1.value() == e2.value();
728}
729
730template<class E1, class E2>
731constexpr bool
732operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2) {
733 return e1.value() != e2.value();
734}
735
736template<class E1>
737void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y))) {
738 x.swap(y);
739}
740
741// TODO: bad_expected_access class
742
743#undef _ENABLE_IF
744#undef _NODISCARD_
745
746} // namespace base
747} // namespace android