1 /*
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);
40 // if (q) { printf("%f\n", q.value()); }
41 // 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
49 namespace android {
50 namespace base {
51
52 // Synopsis
53 template<class T, class E>
54 class expected;
55
56 template<class E>
57 class unexpected;
58 template<class E>
59 unexpected(E) -> unexpected<E>;
60
61 template<class E>
62 class bad_expected_access;
63
64 template<>
65 class bad_expected_access<void>;
66
67 struct unexpect_t {
68 explicit unexpect_t() = default;
69 };
70 inline 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
85 template<class T, class E>
86 class _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)
expected(const expected<U,G> & rhs)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 )>
expected(const expected<U,G> & rhs)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)
expected(expected<U,G> && rhs)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 )>
expected(expected<U,G> && rhs)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)
expected(U && v)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)
expected(U && v)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)
expected(const unexpected<G> & e)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 )>
expected(const unexpected<G> & e)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)
expected(unexpected<G> && e)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 )>
expected(unexpected<G> && e)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 )>
expected(std::in_place_t,Args &&...args)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 )>
expected(std::in_place_t,std::initializer_list<U> il,Args &&...args)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 )>
expected(unexpect_t,Args &&...args)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 )>
expected(unexpect_t,std::initializer_list<U> il,Args &&...args)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 )>
emplace(Args &&...args)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 )>
emplace(std::initializer_list<U> il,Args &&...args)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>))>>
swap(expected & rhs)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
has_value()333 constexpr bool has_value() const noexcept { return var_.index() == 0; }
ok()334 constexpr bool ok() const noexcept { return has_value(); }
335
value()336 constexpr const T& value() const& { return std::get<T>(var_); }
value()337 constexpr T& value() & { return std::get<T>(var_); }
value()338 constexpr const T&& value() const&& { return std::move(std::get<T>(var_)); }
value()339 constexpr T&& value() && { return std::move(std::get<T>(var_)); }
340
error()341 constexpr const E& error() const& { return std::get<unexpected_type>(var_).value(); }
error()342 constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
error()343 constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
error()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 )>
value_or(U && v)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 )>
value_or(U && v)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
388 template<class T1, class E1, class T2, class E2>
389 constexpr 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
395 template<class T1, class E1, class T2, class E2>
396 constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y) {
397 return !(x == y);
398 }
399
400 // Comparison with unexpected<E>
401 template<class T1, class E1, class E2>
402 constexpr bool operator==(const expected<T1, E1>& x, const unexpected<E2>& y) {
403 return !x.has_value() && (x.error() == y.value());
404 }
405 template<class T1, class E1, class E2>
406 constexpr bool operator==(const unexpected<E2>& x, const expected<T1, E1>& y) {
407 return !y.has_value() && (x.value() == y.error());
408 }
409 template<class T1, class E1, class E2>
410 constexpr bool operator!=(const expected<T1, E1>& x, const unexpected<E2>& y) {
411 return x.has_value() || (x.error() != y.value());
412 }
413 template<class T1, class E1, class E2>
414 constexpr bool operator!=(const unexpected<E2>& x, const expected<T1, E1>& y) {
415 return y.has_value() || (x.value() != y.error());
416 }
417
418 template<class T1, class E1>
swap(expected<T1,E1> & x,expected<T1,E1> & y)419 void swap(expected<T1, E1>& x, expected<T1, E1>& y) noexcept(noexcept(x.swap(y))) {
420 x.swap(y);
421 }
422
423 template<class E>
424 class _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)
expected(const expected<U,G> & rhs)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 )>
expected(const expected<U,G> & rhs)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)
expected(expected<U,G> && rhs)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 )>
expected(expected<U,G> && rhs)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)
expected(const unexpected<G> & e)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 )>
expected(const unexpected<G> & e)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)
expected(unexpected<G> && e)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 )>
expected(unexpected<G> && e)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 )>
expected(std::in_place_t,Args &&...)502 constexpr explicit expected(std::in_place_t, Args&&...) {}
503
504 template<class... Args _ENABLE_IF(
505 std::is_constructible_v<E, Args...>
506 )>
expected(unexpect_t,Args &&...args)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 )>
expected(unexpect_t,std::initializer_list<U> il,Args &&...args)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
emplace()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 >
swap(expected & rhs)555 void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible_v<E>) {
556 var_.swap(rhs.var_);
557 }
558
559 // observers
has_value()560 constexpr bool has_value() const noexcept { return var_.index() == 0; }
ok()561 constexpr bool ok() const noexcept { return has_value(); }
562
value()563 constexpr void value() const& { if (!has_value()) std::get<0>(var_); }
564
error()565 constexpr const E& error() const& { return std::get<unexpected_type>(var_).value(); }
error()566 constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
error()567 constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
error()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
582 template<class E1, class E2>
583 constexpr 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
589 template<class T1, class E1, class E2>
590 constexpr 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
596 template<class E1, class T2, class E2>
597 constexpr 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
603 template<class E>
604 class 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)
unexpected(Err && e)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 )>
unexpected(std::in_place_t,std::initializer_list<U> il,Args &&...args)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)
unexpected(const unexpected<Err> & rhs)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 )>
unexpected(const unexpected<Err> & rhs)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)
unexpected(unexpected<Err> && rhs)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 )>
unexpected(unexpected<Err> && rhs)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
value()701 constexpr const E& value() const& noexcept { return val_; }
value()702 constexpr E& value() & noexcept { return val_; }
value()703 constexpr const E&& value() const&& noexcept { return std::move(val_); }
value()704 constexpr E&& value() && noexcept { return std::move(val_); }
705
swap(unexpected & other)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
724 template<class E1, class E2>
725 constexpr bool
726 operator==(const unexpected<E1>& e1, const unexpected<E2>& e2) {
727 return e1.value() == e2.value();
728 }
729
730 template<class E1, class E2>
731 constexpr bool
732 operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2) {
733 return e1.value() != e2.value();
734 }
735
736 template<class E1>
swap(unexpected<E1> & x,unexpected<E1> & y)737 void 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
748