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
333 constexpr explicit operator bool() const noexcept { return has_value(); }
has_value()334 constexpr bool has_value() const noexcept { return var_.index() == 0; }
ok()335 constexpr bool ok() const noexcept { return has_value(); }
336
value()337 constexpr const T& value() const& { return std::get<T>(var_); }
value()338 constexpr T& value() & { return std::get<T>(var_); }
value()339 constexpr const T&& value() const&& { return std::move(std::get<T>(var_)); }
value()340 constexpr T&& value() && { return std::move(std::get<T>(var_)); }
341
error()342 constexpr const E& error() const& { return std::get<unexpected_type>(var_).value(); }
error()343 constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
error()344 constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
error()345 constexpr E&& error() && { return std::move(std::get<unexpected_type>(var_)).value(); }
346
347 template<class U _ENABLE_IF(
348 std::is_copy_constructible_v<T> &&
349 std::is_convertible_v<U, T>
350 )>
value_or(U && v)351 constexpr T value_or(U&& v) const& {
352 if (has_value()) return value();
353 else return static_cast<T>(std::forward<U>(v));
354 }
355
356 template<class U _ENABLE_IF(
357 std::is_move_constructible_v<T> &&
358 std::is_convertible_v<U, T>
359 )>
value_or(U && v)360 constexpr T value_or(U&& v) && {
361 if (has_value()) return std::move(value());
362 else return static_cast<T>(std::forward<U>(v));
363 }
364
365 // expected equality operators
366 template<class T1, class E1, class T2, class E2>
367 friend constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y);
368 template<class T1, class E1, class T2, class E2>
369 friend constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y);
370
371 // Comparison with unexpected<E>
372 template<class T1, class E1, class E2>
373 friend constexpr bool operator==(const expected<T1, E1>&, const unexpected<E2>&);
374 template<class T1, class E1, class E2>
375 friend constexpr bool operator==(const unexpected<E2>&, const expected<T1, E1>&);
376 template<class T1, class E1, class E2>
377 friend constexpr bool operator!=(const expected<T1, E1>&, const unexpected<E2>&);
378 template<class T1, class E1, class E2>
379 friend constexpr bool operator!=(const unexpected<E2>&, const expected<T1, E1>&);
380
381 // Specialized algorithms
382 template<class T1, class E1>
383 friend void swap(expected<T1, E1>&, expected<T1, E1>&) noexcept;
384
385 private:
386 std::variant<value_type, unexpected_type> var_;
387 };
388
389 template<class T1, class E1, class T2, class E2>
390 constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y) {
391 if (x.has_value() != y.has_value()) return false;
392 if (!x.has_value()) return x.error() == y.error();
393 return *x == *y;
394 }
395
396 template<class T1, class E1, class T2, class E2>
397 constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y) {
398 return !(x == y);
399 }
400
401 // Comparison with unexpected<E>
402 template<class T1, class E1, class E2>
403 constexpr bool operator==(const expected<T1, E1>& x, const unexpected<E2>& y) {
404 return !x.has_value() && (x.error() == y.value());
405 }
406 template<class T1, class E1, class E2>
407 constexpr bool operator==(const unexpected<E2>& x, const expected<T1, E1>& y) {
408 return !y.has_value() && (x.value() == y.error());
409 }
410 template<class T1, class E1, class E2>
411 constexpr bool operator!=(const expected<T1, E1>& x, const unexpected<E2>& y) {
412 return x.has_value() || (x.error() != y.value());
413 }
414 template<class T1, class E1, class E2>
415 constexpr bool operator!=(const unexpected<E2>& x, const expected<T1, E1>& y) {
416 return y.has_value() || (x.value() != y.error());
417 }
418
419 template<class E>
420 class _NODISCARD_ expected<void, E> {
421 public:
422 using value_type = void;
423 using error_type = E;
424 using unexpected_type = unexpected<E>;
425
426 // constructors
427 constexpr expected() = default;
428 constexpr expected(const expected& rhs) = default;
429 constexpr expected(expected&& rhs) noexcept = default;
430
431 template<class U, class G _ENABLE_IF(
432 std::is_void_v<U> &&
433 std::is_convertible_v<const G&, E> /* non-explicit */
434 )>
435 // NOLINTNEXTLINE(google-explicit-constructor)
expected(const expected<U,G> & rhs)436 constexpr expected(const expected<U, G>& rhs) {
437 if (!rhs.has_value()) var_ = unexpected(rhs.error());
438 }
439
440 template<class U, class G _ENABLE_IF(
441 std::is_void_v<U> &&
442 !std::is_convertible_v<const G&, E> /* explicit */
443 )>
expected(const expected<U,G> & rhs)444 constexpr explicit expected(const expected<U, G>& rhs) {
445 if (!rhs.has_value()) var_ = unexpected(rhs.error());
446 }
447
448 template<class U, class G _ENABLE_IF(
449 std::is_void_v<U> &&
450 std::is_convertible_v<const G&&, E> /* non-explicit */
451 )>
452 // NOLINTNEXTLINE(google-explicit-constructor)
expected(expected<U,G> && rhs)453 constexpr expected(expected<U, G>&& rhs) {
454 if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error()));
455 }
456
457 template<class U, class G _ENABLE_IF(
458 std::is_void_v<U> &&
459 !std::is_convertible_v<const G&&, E> /* explicit */
460 )>
expected(expected<U,G> && rhs)461 constexpr explicit expected(expected<U, G>&& rhs) {
462 if (!rhs.has_value()) var_ = unexpected(std::move(rhs.error()));
463 }
464
465 template<class G = E _ENABLE_IF(
466 std::is_constructible_v<E, const G&> &&
467 std::is_convertible_v<const G&, E> /* non-explicit */
468 )>
469 // NOLINTNEXTLINE(google-explicit-constructor)
expected(const unexpected<G> & e)470 constexpr expected(const unexpected<G>& e)
471 : var_(std::in_place_index<1>, e.value()) {}
472
473 template<class G = E _ENABLE_IF(
474 std::is_constructible_v<E, const G&> &&
475 !std::is_convertible_v<const G&, E> /* explicit */
476 )>
expected(const unexpected<G> & e)477 constexpr explicit expected(const unexpected<G>& e)
478 : var_(std::in_place_index<1>, E(e.value())) {}
479
480 template<class G = E _ENABLE_IF(
481 std::is_constructible_v<E, G&&> &&
482 std::is_convertible_v<G&&, E> /* non-explicit */
483 )>
484 // NOLINTNEXTLINE(google-explicit-constructor)
expected(unexpected<G> && e)485 constexpr expected(unexpected<G>&& e)
486 : var_(std::in_place_index<1>, std::move(e.value())) {}
487
488 template<class G = E _ENABLE_IF(
489 std::is_constructible_v<E, G&&> &&
490 !std::is_convertible_v<G&&, E> /* explicit */
491 )>
expected(unexpected<G> && e)492 constexpr explicit expected(unexpected<G>&& e)
493 : var_(std::in_place_index<1>, E(std::move(e.value()))) {}
494
495 template<class... Args _ENABLE_IF(
496 sizeof...(Args) == 0
497 )>
expected(std::in_place_t,Args &&...)498 constexpr explicit expected(std::in_place_t, Args&&...) {}
499
500 template<class... Args _ENABLE_IF(
501 std::is_constructible_v<E, Args...>
502 )>
expected(unexpect_t,Args &&...args)503 constexpr explicit expected(unexpect_t, Args&&... args)
504 : var_(unexpected_type(std::forward<Args>(args)...)) {}
505
506 template<class U, class... Args _ENABLE_IF(
507 std::is_constructible_v<E, std::initializer_list<U>&, Args...>
508 )>
expected(unexpect_t,std::initializer_list<U> il,Args &&...args)509 constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&&... args)
510 : var_(unexpected_type(il, std::forward<Args>(args)...)) {}
511
512 // destructor
513 ~expected() = default;
514
515 // assignment
516 // Note: SFNAIE doesn't work here because assignment operator should be
517 // non-template. We could workaround this by defining a templated parent class
518 // having the assignment operator. This incomplete implementation however
519 // doesn't allow us to copy assign expected<T,E> even when T is non-copy
520 // assignable. The copy assignment will fail by the underlying std::variant
521 // anyway though the error message won't be clear.
522 expected& operator=(const expected& rhs) = default;
523
524 // Note for SFNAIE above applies to here as well
525 expected& operator=(expected&& rhs) noexcept(std::is_nothrow_move_assignable_v<E>) = default;
526
527 template<class G = E>
528 expected& operator=(const unexpected<G>& rhs) {
529 var_ = rhs;
530 return *this;
531 }
532
533 template<class G = E _ENABLE_IF(
534 std::is_nothrow_move_constructible_v<G> &&
535 std::is_move_assignable_v<G>
536 )>
537 expected& operator=(unexpected<G>&& rhs) {
538 var_ = std::move(rhs);
539 return *this;
540 }
541
542 // modifiers
emplace()543 void emplace() {
544 var_ = std::monostate();
545 }
546
547 // swap
548 template<typename = std::enable_if_t<
549 std::is_swappable_v<E>>
550 >
swap(expected & rhs)551 void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible_v<E>) {
552 var_.swap(rhs.var_);
553 }
554
555 // observers
556 constexpr explicit operator bool() const noexcept { return has_value(); }
has_value()557 constexpr bool has_value() const noexcept { return var_.index() == 0; }
ok()558 constexpr bool ok() const noexcept { return has_value(); }
559
value()560 constexpr void value() const& { if (!has_value()) std::get<0>(var_); }
561
error()562 constexpr const E& error() const& { return std::get<unexpected_type>(var_).value(); }
error()563 constexpr E& error() & { return std::get<unexpected_type>(var_).value(); }
error()564 constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).value(); }
error()565 constexpr E&& error() && { return std::move(std::get<unexpected_type>(var_)).value(); }
566
567 // expected equality operators
568 template<class E1, class E2>
569 friend constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y);
570
571 // Specialized algorithms
572 template<class T1, class E1>
573 friend void swap(expected<T1, E1>&, expected<T1, E1>&) noexcept;
574
575 private:
576 std::variant<std::monostate, unexpected_type> var_;
577 };
578
579 template<class E1, class E2>
580 constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y) {
581 if (x.has_value() != y.has_value()) return false;
582 if (!x.has_value()) return x.error() == y.error();
583 return true;
584 }
585
586 template<class T1, class E1, class E2>
587 constexpr bool operator==(const expected<T1, E1>& x, const expected<void, E2>& y) {
588 if (x.has_value() != y.has_value()) return false;
589 if (!x.has_value()) return x.error() == y.error();
590 return false;
591 }
592
593 template<class E1, class T2, class E2>
594 constexpr bool operator==(const expected<void, E1>& x, const expected<T2, E2>& y) {
595 if (x.has_value() != y.has_value()) return false;
596 if (!x.has_value()) return x.error() == y.error();
597 return false;
598 }
599
600 template<class E>
601 class unexpected {
602 public:
603 // constructors
604 constexpr unexpected(const unexpected&) = default;
605 constexpr unexpected(unexpected&&) noexcept(std::is_nothrow_move_constructible_v<E>) = default;
606
607 template <class Err = E _ENABLE_IF(
608 std::is_constructible_v<E, Err> &&
609 !std::is_same_v<std::remove_cv_t<std::remove_reference_t<E>>, std::in_place_t> &&
610 !std::is_same_v<std::remove_cv_t<std::remove_reference_t<E>>, unexpected>)>
611 // NOLINTNEXTLINE(google-explicit-constructor,bugprone-forwarding-reference-overload)
unexpected(Err && e)612 constexpr unexpected(Err&& e) : val_(std::forward<Err>(e)) {}
613
614 template<class U, class... Args _ENABLE_IF(
615 std::is_constructible_v<E, std::initializer_list<U>&, Args...>
616 )>
unexpected(std::in_place_t,std::initializer_list<U> il,Args &&...args)617 constexpr explicit unexpected(std::in_place_t, std::initializer_list<U> il, Args&&... args)
618 : val_(il, std::forward<Args>(args)...) {}
619
620 template<class Err _ENABLE_IF(
621 std::is_constructible_v<E, Err> &&
622 !std::is_constructible_v<E, unexpected<Err>&> &&
623 !std::is_constructible_v<E, unexpected<Err>> &&
624 !std::is_constructible_v<E, const unexpected<Err>&> &&
625 !std::is_constructible_v<E, const unexpected<Err>> &&
626 !std::is_convertible_v<unexpected<Err>&, E> &&
627 !std::is_convertible_v<unexpected<Err>, E> &&
628 !std::is_convertible_v<const unexpected<Err>&, E> &&
629 !std::is_convertible_v<const unexpected<Err>, E> &&
630 std::is_convertible_v<Err, E> /* non-explicit */
631 )>
632 // NOLINTNEXTLINE(google-explicit-constructor)
unexpected(const unexpected<Err> & rhs)633 constexpr unexpected(const unexpected<Err>& rhs)
634 : val_(rhs.value()) {}
635
636 template<class Err _ENABLE_IF(
637 std::is_constructible_v<E, Err> &&
638 !std::is_constructible_v<E, unexpected<Err>&> &&
639 !std::is_constructible_v<E, unexpected<Err>> &&
640 !std::is_constructible_v<E, const unexpected<Err>&> &&
641 !std::is_constructible_v<E, const unexpected<Err>> &&
642 !std::is_convertible_v<unexpected<Err>&, E> &&
643 !std::is_convertible_v<unexpected<Err>, E> &&
644 !std::is_convertible_v<const unexpected<Err>&, E> &&
645 !std::is_convertible_v<const unexpected<Err>, E> &&
646 !std::is_convertible_v<Err, E> /* explicit */
647 )>
unexpected(const unexpected<Err> & rhs)648 constexpr explicit unexpected(const unexpected<Err>& rhs)
649 : val_(E(rhs.value())) {}
650
651 template<class Err _ENABLE_IF(
652 std::is_constructible_v<E, Err> &&
653 !std::is_constructible_v<E, unexpected<Err>&> &&
654 !std::is_constructible_v<E, unexpected<Err>> &&
655 !std::is_constructible_v<E, const unexpected<Err>&> &&
656 !std::is_constructible_v<E, const unexpected<Err>> &&
657 !std::is_convertible_v<unexpected<Err>&, E> &&
658 !std::is_convertible_v<unexpected<Err>, E> &&
659 !std::is_convertible_v<const unexpected<Err>&, E> &&
660 !std::is_convertible_v<const unexpected<Err>, E> &&
661 std::is_convertible_v<Err, E> /* non-explicit */
662 )>
663 // NOLINTNEXTLINE(google-explicit-constructor)
unexpected(unexpected<Err> && rhs)664 constexpr unexpected(unexpected<Err>&& rhs)
665 : val_(std::move(rhs.value())) {}
666
667 template<class Err _ENABLE_IF(
668 std::is_constructible_v<E, Err> &&
669 !std::is_constructible_v<E, unexpected<Err>&> &&
670 !std::is_constructible_v<E, unexpected<Err>> &&
671 !std::is_constructible_v<E, const unexpected<Err>&> &&
672 !std::is_constructible_v<E, const unexpected<Err>> &&
673 !std::is_convertible_v<unexpected<Err>&, E> &&
674 !std::is_convertible_v<unexpected<Err>, E> &&
675 !std::is_convertible_v<const unexpected<Err>&, E> &&
676 !std::is_convertible_v<const unexpected<Err>, E> &&
677 !std::is_convertible_v<Err, E> /* explicit */
678 )>
unexpected(unexpected<Err> && rhs)679 constexpr explicit unexpected(unexpected<Err>&& rhs)
680 : val_(E(std::move(rhs.value()))) {}
681
682 // assignment
683 constexpr unexpected& operator=(const unexpected&) = default;
684 constexpr unexpected& operator=(unexpected&&) noexcept(std::is_nothrow_move_assignable_v<E>) =
685 default;
686 template<class Err = E>
687 constexpr unexpected& operator=(const unexpected<Err>& rhs) {
688 val_ = rhs.value();
689 return *this;
690 }
691 template<class Err = E>
692 constexpr unexpected& operator=(unexpected<Err>&& rhs) {
693 val_ = std::forward<E>(rhs.value());
694 return *this;
695 }
696
697 // observer
value()698 constexpr const E& value() const& noexcept { return val_; }
value()699 constexpr E& value() & noexcept { return val_; }
value()700 constexpr const E&& value() const&& noexcept { return std::move(val_); }
value()701 constexpr E&& value() && noexcept { return std::move(val_); }
702
swap(unexpected & other)703 void swap(unexpected& other) noexcept(std::is_nothrow_swappable_v<E>) {
704 std::swap(val_, other.val_);
705 }
706
707 template<class E1, class E2>
708 friend constexpr bool
709 operator==(const unexpected<E1>& e1, const unexpected<E2>& e2);
710 template<class E1, class E2>
711 friend constexpr bool
712 operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2);
713
714 template<class E1>
715 friend void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y)));
716
717 private:
718 E val_;
719 };
720
721 template<class E1, class E2>
722 constexpr bool
723 operator==(const unexpected<E1>& e1, const unexpected<E2>& e2) {
724 return e1.value() == e2.value();
725 }
726
727 template<class E1, class E2>
728 constexpr bool
729 operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2) {
730 return e1.value() != e2.value();
731 }
732
733 template<class E1>
swap(unexpected<E1> & x,unexpected<E1> & y)734 void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y))) {
735 x.swap(y);
736 }
737
738 // TODO: bad_expected_access class
739
740 #undef _ENABLE_IF
741 #undef _NODISCARD_
742
743 } // namespace base
744 } // namespace android
745