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 a partial implementation of C++23's std::expected 26 // for Android. 27 // 28 // Usage: 29 // using android::base::expected; 30 // using android::base::unexpected; 31 // 32 // expected<double,std::string> safe_divide(double i, double j) { 33 // if (j == 0) return unexpected("divide by zero"); 34 // else return i / j; 35 // } 36 // 37 // void test() { 38 // auto q = safe_divide(10, 0); 39 // if (q.ok()) { printf("%f\n", q.value()); } 40 // else { printf("%s\n", q.error().c_str()); } 41 // } 42 // 43 // Once the Android platform has moved to C++23, this will be removed and 44 // android::base::expected will be type aliased to std::expected. 45 // 46 47 namespace android { 48 namespace base { 49 50 // Synopsis 51 template <class T, class E> 52 class expected; 53 54 template <class E> 55 class unexpected; 56 template <class E> 57 unexpected(E) -> unexpected<E>; 58 59 template <class E> 60 class bad_expected_access; 61 62 template <> 63 class bad_expected_access<void>; 64 65 struct unexpect_t { 66 explicit unexpect_t() = default; 67 }; 68 inline constexpr unexpect_t unexpect{}; 69 70 // macros for SFINAE 71 #define _ENABLE_IF(...) \ 72 , std::enable_if_t<(__VA_ARGS__)>* = nullptr 73 74 // Define NODISCARD_EXPECTED to prevent expected<T,E> from being 75 // ignored when used as a return value. This is off by default. 76 #ifdef NODISCARD_EXPECTED 77 #define _NODISCARD_ [[nodiscard]] 78 #else 79 #define _NODISCARD_ 80 #endif 81 82 #define _EXPLICIT(cond) \ 83 _Pragma("clang diagnostic push") \ 84 _Pragma("clang diagnostic ignored \"-Wc++20-extensions\"") explicit(cond) \ 85 _Pragma("clang diagnostic pop") 86 87 #define _COMMA , 88 89 namespace expected_internal { 90 91 template <class T> 92 struct remove_cvref { 93 using type = std::remove_cv_t<std::remove_reference_t<T>>; 94 }; 95 96 template <class T> 97 using remove_cvref_t = typename remove_cvref<T>::type; 98 99 // Can T be constructed from W (or W converted to T)? W can be lvalue or rvalue, 100 // const or not. 101 template <class T, class W> 102 inline constexpr bool converts_from_any_cvref = 103 std::disjunction_v<std::is_constructible<T, W&>, std::is_convertible<W&, T>, 104 std::is_constructible<T, W>, std::is_convertible<W, T>, 105 std::is_constructible<T, const W&>, std::is_convertible<const W&, T>, 106 std::is_constructible<T, const W>, std::is_convertible<const W, T>>; 107 108 template <class T> 109 struct is_expected : std::false_type {}; 110 111 template <class T, class E> 112 struct is_expected<expected<T, E>> : std::true_type {}; 113 114 template <class T> 115 inline constexpr bool is_expected_v = is_expected<T>::value; 116 117 template <class T> 118 struct is_unexpected : std::false_type {}; 119 120 template <class E> 121 struct is_unexpected<unexpected<E>> : std::true_type {}; 122 123 template <class T> 124 inline constexpr bool is_unexpected_v = is_unexpected<T>::value; 125 126 // Constraints on constructing an expected<T, ...> from an expected<U, G> 127 // related to T and U. UF is either "const U&" or "U". 128 template <class T, class U, class G, class UF> 129 inline constexpr bool convert_value_constraints = 130 std::is_constructible_v<T, UF> && 131 (std::is_same_v<std::remove_cv_t<T>, bool> || !converts_from_any_cvref<T, expected<U, G>>); 132 133 // Constraints on constructing an expected<..., E> from an expected<U, G> 134 // related to E, G, and expected<U, G>. GF is either "const G&" or "G". 135 template <class E, class U, class G, class GF> 136 inline constexpr bool convert_error_constraints = 137 std::is_constructible_v<E, GF> && 138 !std::is_constructible_v<unexpected<E>, expected<U, G>&> && 139 !std::is_constructible_v<unexpected<E>, expected<U, G>> && 140 !std::is_constructible_v<unexpected<E>, const expected<U, G>&> && 141 !std::is_constructible_v<unexpected<E>, const expected<U, G>>; 142 143 // If an exception is thrown in expected::operator=, while changing the expected 144 // object between a value and an error, the expected object is supposed to 145 // retain its original value, which is only possible if certain constructors 146 // are noexcept. This implementation doesn't try to be exception-safe, but 147 // enforce these constraints anyway because std::expected also will enforce 148 // them, and we intend to switch to it eventually. 149 template <class T, class E, class Self, class Value> 150 inline constexpr bool eh_assign_constraints = 151 std::is_nothrow_constructible_v<Self, Value> || 152 std::is_nothrow_move_constructible_v<T> || 153 std::is_nothrow_move_constructible_v<E>; 154 155 // Implement expected<..., E>::expected([const] unexpected<G> [&/&&]). 156 #define _CONSTRUCT_EXPECTED_FROM_UNEXPECTED(GF, ParamType, forward_func) \ 157 template <class G _ENABLE_IF(std::is_constructible_v<E, GF>)> \ 158 constexpr _EXPLICIT((!std::is_convertible_v<GF, E>)) \ 159 expected(ParamType e) noexcept(std::is_nothrow_constructible_v<E, GF>) \ 160 : var_(std::in_place_index<1>, forward_func(e.error())) {} 161 162 // Implement expected<..., E>::operator=([const] unexpected<G> [&/&&]). 163 #define _ASSIGN_UNEXPECTED_TO_EXPECTED(GF, ParamType, forward_func, extra_constraints) \ 164 template <class G _ENABLE_IF(std::is_constructible_v<E, GF> && \ 165 std::is_assignable_v<E&, GF>) && \ 166 extra_constraints> \ 167 constexpr expected& operator=(ParamType e) noexcept(std::is_nothrow_constructible_v<E, GF> && \ 168 std::is_nothrow_assignable_v<E&, GF>) { \ 169 if (has_value()) { \ 170 var_.template emplace<1>(forward_func(e.error())); \ 171 } else { \ 172 error() = forward_func(e.error()); \ 173 } \ 174 return *this; \ 175 } 176 177 } // namespace expected_internal 178 179 // Class expected 180 template <class T, class E> 181 class _NODISCARD_ expected { 182 static_assert(std::is_object_v<T> && !std::is_array_v<T> && 183 !std::is_same_v<std::remove_cv_t<T>, std::in_place_t> && 184 !std::is_same_v<std::remove_cv_t<T>, unexpect_t> && 185 !expected_internal::is_unexpected_v<std::remove_cv_t<T>>, 186 "expected value type cannot be a reference, a function, an array, in_place_t, " 187 "unexpect_t, or unexpected"); 188 189 public: 190 using value_type = T; 191 using error_type = E; 192 using unexpected_type = unexpected<E>; 193 194 template <class U> 195 using rebind = expected<U, error_type>; 196 197 // Delegate simple operations to the underlying std::variant. std::variant 198 // doesn't set noexcept well, at least for copy ctor/assign, so set it 199 // explicitly. Technically the copy/move assignment operators should also be 200 // deleted if neither T nor E satisfies is_nothrow_move_constructible_v, but 201 // that would require making these operator= methods into template functions. 202 constexpr expected() = default; 203 constexpr expected(const expected& rhs) noexcept( 204 std::is_nothrow_copy_constructible_v<T> && std::is_nothrow_copy_constructible_v<E>) = default; 205 constexpr expected(expected&& rhs) noexcept(std::is_nothrow_move_constructible_v<T> && 206 std::is_nothrow_move_constructible_v<E>) = default; 207 constexpr expected& operator=(const expected& rhs) noexcept( 208 std::is_nothrow_copy_constructible_v<T> && std::is_nothrow_copy_assignable_v<T> && 209 std::is_nothrow_copy_constructible_v<E> && std::is_nothrow_copy_assignable_v<E>) = default; 210 constexpr expected& operator=(expected&& rhs) noexcept( 211 std::is_nothrow_move_constructible_v<T> && std::is_nothrow_move_assignable_v<T> && 212 std::is_nothrow_move_constructible_v<E> && std::is_nothrow_move_assignable_v<E>) = default; 213 214 // Construct this expected<T, E> from a different expected<U, G> type. 215 #define _CONVERTING_CTOR(UF, GF, ParamType, forward_func) \ 216 template <class U, \ 217 class G _ENABLE_IF(expected_internal::convert_value_constraints<T, U, G, UF> && \ 218 expected_internal::convert_error_constraints<E, U, G, GF>)> \ 219 constexpr _EXPLICIT((!std::is_convertible_v<UF, T> || !std::is_convertible_v<GF, E>)) \ 220 expected(ParamType rhs) noexcept(std::is_nothrow_constructible_v<T, UF> && \ 221 std::is_nothrow_constructible_v<E, GF>) \ 222 : var_(rhs.has_value() ? variant_type(std::in_place_index<0>, forward_func(rhs.value())) \ 223 : variant_type(std::in_place_index<1>, forward_func(rhs.error()))) {} 224 225 // NOLINTNEXTLINE(google-explicit-constructor) 226 _CONVERTING_CTOR(const U&, const G&, const expected<U _COMMA G>&, ) 227 // NOLINTNEXTLINE(google-explicit-constructor) 228 _CONVERTING_CTOR(U, G, expected<U _COMMA G>&&, std::move) 229 230 #undef _CONVERTING_CTOR 231 232 // Construct from (converted) success value, using a forwarding reference. 233 template <class U = T _ENABLE_IF( 234 !std::is_same_v<expected_internal::remove_cvref_t<U>, std::in_place_t> && 235 !std::is_same_v<expected_internal::remove_cvref_t<U>, expected> && 236 !expected_internal::is_unexpected_v<expected_internal::remove_cvref_t<U>> && 237 std::is_constructible_v<T, U> && 238 (!std::is_same_v<std::remove_cv_t<T>, bool> || 239 !expected_internal::is_expected_v<expected_internal::remove_cvref_t<U>>))> 240 constexpr _EXPLICIT((!std::is_convertible_v<U, T>)) 241 // NOLINTNEXTLINE(google-explicit-constructor) 242 expected(U&& v) noexcept(std::is_nothrow_constructible_v<T, U>) 243 : var_(std::in_place_index<0>, std::forward<U>(v)) {} 244 245 // NOLINTNEXTLINE(google-explicit-constructor) 246 _CONSTRUCT_EXPECTED_FROM_UNEXPECTED(const G&, const unexpected<G>&, ) 247 // NOLINTNEXTLINE(google-explicit-constructor) 248 _CONSTRUCT_EXPECTED_FROM_UNEXPECTED(G, unexpected<G>&&, std::move) 249 250 // in_place_t construction 251 template <class... Args _ENABLE_IF(std::is_constructible_v<T, Args...>)> 252 constexpr explicit expected(std::in_place_t, Args&&... args) 253 noexcept(std::is_nothrow_constructible_v<T, Args...>) 254 : var_(std::in_place_index<0>, std::forward<Args>(args)...) {} 255 256 // in_place_t with initializer_list construction 257 template <class U, class... Args _ENABLE_IF( 258 std::is_constructible_v<T, std::initializer_list<U>&, Args...>)> 259 constexpr explicit expected(std::in_place_t, std::initializer_list<U> il, Args&&... args) 260 noexcept(std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>) 261 : var_(std::in_place_index<0>, il, std::forward<Args>(args)...) {} 262 263 // unexpect_t construction 264 template <class... Args _ENABLE_IF(std::is_constructible_v<E, Args...>)> 265 constexpr explicit expected(unexpect_t, Args&&... args) 266 noexcept(std::is_nothrow_constructible_v<E, Args...>) 267 : var_(std::in_place_index<1>, unexpected_type(std::forward<Args>(args)...)) {} 268 269 // unexpect_t with initializer_list construction 270 template <class U, class... Args _ENABLE_IF( 271 std::is_constructible_v<E, std::initializer_list<U>&, Args...>)> 272 constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&&... args) 273 noexcept(std::is_nothrow_constructible_v<E, std::initializer_list<U>&, Args...>) 274 : var_(std::in_place_index<1>, unexpected_type(il, std::forward<Args>(args)...)) {} 275 276 // Assignment from (converted) success value, using a forwarding reference. 277 template <class U = T _ENABLE_IF( 278 !std::is_same_v<expected, expected_internal::remove_cvref_t<U>> && 279 !expected_internal::is_unexpected_v<expected_internal::remove_cvref_t<U>> && 280 std::is_constructible_v<T, U> && std::is_assignable_v<T&, U> && 281 expected_internal::eh_assign_constraints<T, E, T, U>)> 282 constexpr expected& operator=(U&& v) noexcept(std::is_nothrow_constructible_v<T, U> && 283 std::is_nothrow_assignable_v<T&, U>) { 284 if (has_value()) { 285 value() = std::forward<U>(v); 286 } else { 287 var_.template emplace<0>(std::forward<U>(v)); 288 } 289 return *this; 290 } 291 292 _ASSIGN_UNEXPECTED_TO_EXPECTED(const G&, const unexpected<G>&, , 293 (expected_internal::eh_assign_constraints<T, E, E, const G&>)) 294 _ASSIGN_UNEXPECTED_TO_EXPECTED(G, unexpected<G>&&, std::move, 295 (expected_internal::eh_assign_constraints<T, E, E, G>)) 296 297 // modifiers 298 template <class... Args _ENABLE_IF(std::is_nothrow_constructible_v<T, Args...>)> 299 constexpr T& emplace(Args&&... args) noexcept { 300 var_.template emplace<0>(std::forward<Args>(args)...); 301 return value(); 302 } 303 304 template <class U, class... Args _ENABLE_IF( 305 std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>)> 306 constexpr T& emplace(std::initializer_list<U> il, Args&&... args) noexcept { 307 var_.template emplace<0>(il, std::forward<Args>(args)...); 308 return value(); 309 } 310 311 // Swap. This function takes a template argument so that _ENABLE_IF works. 312 template <class U = T _ENABLE_IF( 313 std::is_same_v<U, T> && 314 std::is_swappable_v<T> && std::is_swappable_v<E> && 315 std::is_move_constructible_v<T> && std::is_move_constructible_v<E> && 316 (std::is_nothrow_move_constructible_v<T> || 317 std::is_nothrow_move_constructible_v<E>))> 318 constexpr void swap(expected& rhs) noexcept(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 constexpr explicit operator bool() const noexcept { return has_value(); } 336 337 constexpr const T& value() const& { return std::get<T>(var_); } 338 constexpr T& value() & { return std::get<T>(var_); } 339 constexpr const T&& value() const&& { return std::move(std::get<T>(var_)); } 340 constexpr T&& value() && { return std::move(std::get<T>(var_)); } 341 342 constexpr const E& error() const& { return std::get<unexpected_type>(var_).error(); } 343 constexpr E& error() & { return std::get<unexpected_type>(var_).error(); } 344 constexpr const E&& error() const&& { return std::move(std::get<unexpected_type>(var_)).error(); } 345 constexpr E&& error() && { return std::move(std::get<unexpected_type>(var_)).error(); } 346 347 template<class U _ENABLE_IF( 348 std::is_copy_constructible_v<T> && 349 std::is_convertible_v<U, T> 350 )> 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 )> 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 private: 382 using variant_type = std::variant<value_type, unexpected_type>; 383 variant_type var_; 384 }; 385 386 template<class T1, class E1, class T2, class E2> 387 constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y) { 388 if (x.has_value() != y.has_value()) return false; 389 if (!x.has_value()) return x.error() == y.error(); 390 return *x == *y; 391 } 392 393 template<class T1, class E1, class T2, class E2> 394 constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y) { 395 return !(x == y); 396 } 397 398 // Comparison with unexpected<E> 399 template<class T1, class E1, class E2> 400 constexpr bool operator==(const expected<T1, E1>& x, const unexpected<E2>& y) { 401 return !x.has_value() && (x.error() == y.error()); 402 } 403 template<class T1, class E1, class E2> 404 constexpr bool operator==(const unexpected<E2>& x, const expected<T1, E1>& y) { 405 return !y.has_value() && (x.error() == y.error()); 406 } 407 template<class T1, class E1, class E2> 408 constexpr bool operator!=(const expected<T1, E1>& x, const unexpected<E2>& y) { 409 return x.has_value() || (x.error() != y.error()); 410 } 411 template<class T1, class E1, class E2> 412 constexpr bool operator!=(const unexpected<E2>& x, const expected<T1, E1>& y) { 413 return y.has_value() || (x.error() != y.error()); 414 } 415 416 template<class E> 417 class _NODISCARD_ expected<void, E> { 418 public: 419 using value_type = void; 420 using error_type = E; 421 using unexpected_type = unexpected<E>; 422 423 template <class U> 424 using rebind = expected<U, error_type>; 425 426 // Delegate simple operations to the underlying std::variant. 427 constexpr expected() = default; 428 constexpr expected(const expected& rhs) noexcept(std::is_nothrow_copy_constructible_v<E>) = 429 default; 430 constexpr expected(expected&& rhs) noexcept(std::is_nothrow_move_constructible_v<E>) = default; 431 constexpr expected& operator=(const expected& rhs) noexcept( 432 std::is_nothrow_copy_constructible_v<E> && std::is_nothrow_copy_assignable_v<E>) = default; 433 constexpr expected& operator=(expected&& rhs) noexcept( 434 std::is_nothrow_move_constructible_v<E> && std::is_nothrow_move_assignable_v<E>) = default; 435 436 // Construct this expected<void, E> from a different expected<U, G> type. 437 #define _CONVERTING_CTOR(GF, ParamType, forward_func) \ 438 template <class U, class G _ENABLE_IF(std::is_void_v<U> && \ 439 expected_internal::convert_error_constraints<E, U, G, GF>)> \ 440 constexpr _EXPLICIT((!std::is_convertible_v<GF, E>)) \ 441 expected(ParamType rhs) noexcept(std::is_nothrow_constructible_v<E, GF>) \ 442 : var_(rhs.has_value() ? variant_type(std::in_place_index<0>, std::monostate()) \ 443 : variant_type(std::in_place_index<1>, forward_func(rhs.error()))) {} 444 445 // NOLINTNEXTLINE(google-explicit-constructor) 446 _CONVERTING_CTOR(const G&, const expected<U _COMMA G>&, ) 447 // NOLINTNEXTLINE(google-explicit-constructor) 448 _CONVERTING_CTOR(G, expected<U _COMMA G>&&, std::move) 449 450 #undef _CONVERTING_CTOR 451 452 // NOLINTNEXTLINE(google-explicit-constructor) 453 _CONSTRUCT_EXPECTED_FROM_UNEXPECTED(const G&, const unexpected<G>&, ) 454 // NOLINTNEXTLINE(google-explicit-constructor) 455 _CONSTRUCT_EXPECTED_FROM_UNEXPECTED(G, unexpected<G>&&, std::move) 456 457 // in_place_t construction 458 constexpr explicit expected(std::in_place_t) noexcept {} 459 460 // unexpect_t construction 461 template <class... Args _ENABLE_IF(std::is_constructible_v<E, Args...>)> 462 constexpr explicit expected(unexpect_t, Args&&... args) 463 noexcept(std::is_nothrow_constructible_v<E, Args...>) 464 : var_(std::in_place_index<1>, unexpected_type(std::forward<Args>(args)...)) {} 465 466 // unexpect_t with initializer_list construction 467 template <class U, class... Args _ENABLE_IF( 468 std::is_constructible_v<E, std::initializer_list<U>&, Args...>)> 469 constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&&... args) 470 noexcept(std::is_nothrow_constructible_v<E, std::initializer_list<U>&, Args...>) 471 : var_(std::in_place_index<1>, unexpected_type(il, std::forward<Args>(args)...)) {} 472 473 _ASSIGN_UNEXPECTED_TO_EXPECTED(const G&, const unexpected<G>&, , true) 474 _ASSIGN_UNEXPECTED_TO_EXPECTED(G, unexpected<G>&&, std::move, true) 475 476 // modifiers 477 constexpr void emplace() noexcept { var_.template emplace<0>(std::monostate()); } 478 479 // Swap. This function takes a template argument so that _ENABLE_IF works. 480 template <class G = E _ENABLE_IF(std::is_same_v<G, E> && 481 std::is_swappable_v<E> && std::is_move_constructible_v<E>)> 482 constexpr void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible_v<E> && 483 std::is_nothrow_swappable_v<E>) { 484 var_.swap(rhs.var_); 485 } 486 487 // observers 488 constexpr bool has_value() const noexcept { return var_.index() == 0; } 489 constexpr bool ok() const noexcept { return has_value(); } 490 constexpr explicit operator bool() const noexcept { return has_value(); } 491 492 constexpr void value() const& { if (!has_value()) std::get<0>(var_); } 493 494 constexpr const E& error() const& { return std::get<1>(var_).error(); } 495 constexpr E& error() & { return std::get<1>(var_).error(); } 496 constexpr const E&& error() const&& { return std::move(std::get<1>(var_)).error(); } 497 constexpr E&& error() && { return std::move(std::get<1>(var_)).error(); } 498 499 // expected equality operators 500 template<class E1, class E2> 501 friend constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y); 502 503 private: 504 using variant_type = std::variant<std::monostate, unexpected_type>; 505 variant_type var_; 506 }; 507 508 template<class E1, class E2> 509 constexpr bool operator==(const expected<void, E1>& x, const expected<void, E2>& y) { 510 if (x.has_value() != y.has_value()) return false; 511 if (!x.has_value()) return x.error() == y.error(); 512 return true; 513 } 514 515 template<class T1, class E1, class E2> 516 constexpr bool operator==(const expected<T1, E1>& x, const expected<void, E2>& y) { 517 if (x.has_value() != y.has_value()) return false; 518 if (!x.has_value()) return x.error() == y.error(); 519 return false; 520 } 521 522 template<class E1, class T2, class E2> 523 constexpr bool operator==(const expected<void, E1>& x, const expected<T2, E2>& y) { 524 if (x.has_value() != y.has_value()) return false; 525 if (!x.has_value()) return x.error() == y.error(); 526 return false; 527 } 528 529 template <class T, class E, typename = decltype( 530 std::declval<expected<T, E>&>().swap(std::declval<expected<T, E>&>()))> 531 constexpr void swap(expected<T, E>& x, expected<T, E>& y) noexcept(noexcept(x.swap(y))) { 532 x.swap(y); 533 } 534 535 template<class E> 536 class unexpected { 537 static_assert(std::is_object_v<E> && !std::is_array_v<E> && !std::is_const_v<E> && 538 !std::is_volatile_v<E> && !expected_internal::is_unexpected_v<E>, 539 "unexpected error type cannot be a reference, a function, an array, cv-qualified, " 540 "or unexpected"); 541 542 public: 543 // constructors 544 constexpr unexpected(const unexpected&) = default; 545 constexpr unexpected(unexpected&&) = default; 546 547 template <class Err = E _ENABLE_IF( 548 !std::is_same_v<expected_internal::remove_cvref_t<Err>, unexpected> && 549 !std::is_same_v<expected_internal::remove_cvref_t<Err>, std::in_place_t> && 550 std::is_constructible_v<E, Err>)> 551 constexpr explicit unexpected(Err&& e) noexcept(std::is_nothrow_constructible_v<E, Err>) 552 : val_(std::forward<Err>(e)) {} 553 554 template <class... Args _ENABLE_IF(std::is_constructible_v<E, Args...>)> 555 constexpr explicit unexpected(std::in_place_t, Args&&... args) 556 noexcept(std::is_nothrow_constructible_v<E, Args...>) 557 : val_(std::forward<Args>(args)...) {} 558 559 template <class U, class... Args _ENABLE_IF( 560 std::is_constructible_v<E, std::initializer_list<U>&, Args...>)> 561 constexpr explicit unexpected(std::in_place_t, std::initializer_list<U> il, Args&&... args) 562 noexcept(std::is_nothrow_constructible_v<E, std::initializer_list<U>&, Args...>) 563 : val_(il, std::forward<Args>(args)...) {} 564 565 constexpr unexpected& operator=(const unexpected&) = default; 566 constexpr unexpected& operator=(unexpected&&) = default; 567 568 // observer 569 constexpr const E& error() const& noexcept { return val_; } 570 constexpr E& error() & noexcept { return val_; } 571 constexpr const E&& error() const&& noexcept { return std::move(val_); } 572 constexpr E&& error() && noexcept { return std::move(val_); } 573 574 // Swap. This function takes a template argument so that _ENABLE_IF works. 575 template <typename G = E _ENABLE_IF(std::is_same_v<G, E> && std::is_swappable_v<E>)> 576 void swap(unexpected& other) noexcept(std::is_nothrow_swappable_v<E>) { 577 // Make std::swap visible to provide swap for STL and builtin types, but use 578 // an unqualified swap to invoke argument-dependent lookup to find the swap 579 // functions for user-declared types. 580 using std::swap; 581 swap(val_, other.val_); 582 } 583 584 template<class E1, class E2> 585 friend constexpr bool 586 operator==(const unexpected<E1>& e1, const unexpected<E2>& e2); 587 template<class E1, class E2> 588 friend constexpr bool 589 operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2); 590 591 private: 592 E val_; 593 }; 594 595 template<class E1, class E2> 596 constexpr bool 597 operator==(const unexpected<E1>& e1, const unexpected<E2>& e2) { 598 return e1.error() == e2.error(); 599 } 600 601 template<class E1, class E2> 602 constexpr bool 603 operator!=(const unexpected<E1>& e1, const unexpected<E2>& e2) { 604 return e1.error() != e2.error(); 605 } 606 607 template <class E1 _ENABLE_IF(std::is_swappable_v<E1>)> 608 void swap(unexpected<E1>& x, unexpected<E1>& y) noexcept(noexcept(x.swap(y))) { 609 x.swap(y); 610 } 611 612 // TODO: bad_expected_access class 613 614 #undef _ENABLE_IF 615 #undef _NODISCARD_ 616 #undef _EXPLICIT 617 #undef _COMMA 618 #undef _CONSTRUCT_EXPECTED_FROM_UNEXPECTED 619 #undef _ASSIGN_UNEXPECTED_TO_EXPECTED 620 621 } // namespace base 622 } // namespace android 623