Martin Stjernholm | 4fb5111 | 2021-04-30 11:53:52 +0100 | [diff] [blame] | 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); |
Martin Stjernholm | 413b2b5 | 2021-11-15 13:56:19 +0000 | [diff] [blame] | 40 | // if (q.ok()) { printf("%f\n", q.value()); } |
Martin Stjernholm | 4fb5111 | 2021-04-30 11:53:52 +0100 | [diff] [blame] | 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) |
| 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 | |
| 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> |
| 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) |
| 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 | |
| 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) |
| 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 | |
| 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> |
| 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 |