1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TYPES_EXPECTED_INTERNAL_H_ 6 #define BASE_TYPES_EXPECTED_INTERNAL_H_ 7 8 // IWYU pragma: private, include "base/types/expected.h" 9 #include <type_traits> 10 #include <utility> 11 12 #include "base/check.h" 13 #include "base/template_util.h" 14 #include "third_party/abseil-cpp/absl/types/variant.h" 15 #include "third_party/abseil-cpp/absl/utility/utility.h" 16 17 // This header defines type traits and aliases used for the implementation of 18 // base::expected. 19 namespace base { 20 21 template <typename T, bool = std::is_void_v<T>> 22 class ok; 23 24 template <typename E> 25 class unexpected; 26 27 struct unexpect_t { 28 explicit unexpect_t() = default; 29 }; 30 31 // in-place construction of unexpected values 32 inline constexpr unexpect_t unexpect{}; 33 34 template <typename T, typename E, bool = std::is_void_v<T>> 35 class expected; 36 37 namespace internal { 38 39 template <typename T> 40 struct IsOk : std::false_type {}; 41 42 template <typename T> 43 struct IsOk<ok<T>> : std::true_type {}; 44 45 template <typename T> 46 struct IsUnexpected : std::false_type {}; 47 48 template <typename E> 49 struct IsUnexpected<unexpected<E>> : std::true_type {}; 50 51 template <typename T> 52 struct IsExpected : std::false_type {}; 53 54 template <typename T, typename E> 55 struct IsExpected<expected<T, E>> : std::true_type {}; 56 57 template <typename T, typename U> 58 struct IsConstructibleOrConvertible 59 : std::disjunction<std::is_constructible<T, U>, std::is_convertible<U, T>> { 60 }; 61 62 template <typename T, typename U> 63 struct IsAnyConstructibleOrConvertible 64 : std::disjunction<IsConstructibleOrConvertible<T, U&>, 65 IsConstructibleOrConvertible<T, U&&>, 66 IsConstructibleOrConvertible<T, const U&>, 67 IsConstructibleOrConvertible<T, const U&&>> {}; 68 69 // Checks whether a given expected<U, G> can be converted into another 70 // expected<T, E>. Used inside expected's conversion constructors. UF and GF are 71 // the forwarded versions of U and G, e.g. UF is const U& for the converting 72 // copy constructor and U for the converting move constructor. Similarly for GF. 73 // ExUG is used for convenience, and not expected to be passed explicitly. 74 // See https://eel.is/c++draft/expected#lib:expected,constructor___ 75 template <typename T, 76 typename E, 77 typename UF, 78 typename GF, 79 typename ExUG = expected<remove_cvref_t<UF>, remove_cvref_t<GF>>> 80 struct IsValidConversion 81 : std::conjunction< 82 std::is_constructible<T, UF>, 83 std::is_constructible<E, GF>, 84 std::negation<IsAnyConstructibleOrConvertible<T, ExUG>>, 85 std::negation<IsAnyConstructibleOrConvertible<unexpected<E>, ExUG>>> { 86 }; 87 88 // Checks whether a given expected<U, G> can be converted into another 89 // expected<T, E> when T is a void type. Used inside expected<void>'s conversion 90 // constructors. GF is the forwarded versions of G, e.g. GF is const G& for the 91 // converting copy constructor and G for the converting move constructor. ExUG 92 // is used for convenience, and not expected to be passed explicitly. See 93 // https://eel.is/c++draft/expected#lib:expected%3cvoid%3e,constructor___ 94 template <typename E, 95 typename U, 96 typename GF, 97 typename ExUG = expected<U, remove_cvref_t<GF>>> 98 struct IsValidVoidConversion 99 : std::conjunction< 100 std::is_void<U>, 101 std::is_constructible<E, GF>, 102 std::negation<IsAnyConstructibleOrConvertible<unexpected<E>, ExUG>>> { 103 }; 104 105 // Checks whether expected<T, E> can be constructed from a value of type U. 106 template <typename T, typename E, typename U> 107 struct IsValidValueConstruction 108 : std::conjunction< 109 std::is_constructible<T, U>, 110 std::negation<std::is_same<remove_cvref_t<U>, absl::in_place_t>>, 111 std::negation<std::is_same<remove_cvref_t<U>, expected<T, E>>>, 112 std::negation<IsOk<remove_cvref_t<U>>>, 113 std::negation<IsUnexpected<remove_cvref_t<U>>>> {}; 114 115 template <typename T, typename E, typename UF, typename GF> 116 struct AreValueAndErrorConvertible 117 : std::conjunction<std::is_convertible<UF, T>, std::is_convertible<GF, E>> { 118 }; 119 120 template <typename T> 121 using EnableIfDefaultConstruction = 122 std::enable_if_t<std::is_default_constructible_v<T>, int>; 123 124 template <typename T, typename E, typename UF, typename GF> 125 using EnableIfExplicitConversion = std::enable_if_t< 126 std::conjunction_v< 127 IsValidConversion<T, E, UF, GF>, 128 std::negation<AreValueAndErrorConvertible<T, E, UF, GF>>>, 129 int>; 130 131 template <typename T, typename E, typename UF, typename GF> 132 using EnableIfImplicitConversion = std::enable_if_t< 133 std::conjunction_v<IsValidConversion<T, E, UF, GF>, 134 AreValueAndErrorConvertible<T, E, UF, GF>>, 135 int>; 136 137 template <typename E, typename U, typename GF> 138 using EnableIfExplicitVoidConversion = std::enable_if_t< 139 std::conjunction_v<IsValidVoidConversion<E, U, GF>, 140 std::negation<std::is_convertible<GF, E>>>, 141 int>; 142 143 template <typename E, typename U, typename GF> 144 using EnableIfImplicitVoidConversion = 145 std::enable_if_t<std::conjunction_v<IsValidVoidConversion<E, U, GF>, 146 std::is_convertible<GF, E>>, 147 int>; 148 149 template <typename T, typename U> 150 using EnableIfOkValueConstruction = std::enable_if_t< 151 std::conjunction_v< 152 std::negation<std::is_same<remove_cvref_t<U>, ok<T>>>, 153 std::negation<std::is_same<remove_cvref_t<U>, absl::in_place_t>>, 154 std::is_constructible<T, U>>, 155 int>; 156 157 template <typename T, typename U> 158 using EnableIfUnexpectedValueConstruction = std::enable_if_t< 159 std::conjunction_v< 160 std::negation<std::is_same<remove_cvref_t<U>, unexpected<T>>>, 161 std::negation<std::is_same<remove_cvref_t<U>, absl::in_place_t>>, 162 std::is_constructible<T, U>>, 163 int>; 164 165 template <typename T, typename E, typename U> 166 using EnableIfExplicitValueConstruction = std::enable_if_t< 167 std::conjunction_v< 168 IsValidValueConstruction<T, E, U>, 169 std::disjunction<std::negation<std::is_convertible<U, T>>, 170 std::is_convertible<U, E>>>, 171 int>; 172 173 template <typename T, typename E, typename U> 174 using EnableIfImplicitValueConstruction = std::enable_if_t< 175 std::conjunction_v< 176 IsValidValueConstruction<T, E, U>, 177 std::conjunction<std::is_convertible<U, T>, 178 std::negation<std::is_convertible<U, E>>>>, 179 int>; 180 181 template <typename T, typename U> 182 using EnableIfExplicitConstruction = std::enable_if_t< 183 std::conjunction_v<std::is_constructible<T, U>, 184 std::negation<std::is_convertible<U, T>>>, 185 int>; 186 187 template <typename T, typename U> 188 using EnableIfImplicitConstruction = std::enable_if_t< 189 std::conjunction_v<std::is_constructible<T, U>, std::is_convertible<U, T>>, 190 int>; 191 192 template <typename T, typename E, typename U> 193 using EnableIfValueAssignment = std::enable_if_t< 194 std::conjunction_v< 195 std::negation<std::is_same<expected<T, E>, remove_cvref_t<U>>>, 196 std::negation<IsOk<remove_cvref_t<U>>>, 197 std::negation<IsUnexpected<remove_cvref_t<U>>>, 198 std::is_constructible<T, U>, 199 std::is_assignable<T&, U>>, 200 int>; 201 202 template <typename T> 203 using EnableIfCopyConstructible = 204 std::enable_if_t<std::is_copy_constructible_v<T>, int>; 205 206 template <typename T> 207 using EnableIfMoveConstructible = 208 std::enable_if_t<std::is_move_constructible_v<T>, int>; 209 210 template <typename T> 211 using EnableIfNotVoid = std::enable_if_t<std::negation_v<std::is_void<T>>, int>; 212 213 template <typename T, typename E> 214 class ExpectedImpl { 215 public: 216 static constexpr size_t kValIdx = 1; 217 static constexpr size_t kErrIdx = 2; 218 static constexpr absl::in_place_index_t<1> kValTag{}; 219 static constexpr absl::in_place_index_t<2> kErrTag{}; 220 221 template <typename U, typename G> 222 friend class ExpectedImpl; 223 224 template <typename LazyT = T, EnableIfDefaultConstruction<LazyT> = 0> 225 constexpr ExpectedImpl() noexcept : data_(kValTag) {} 226 constexpr ExpectedImpl(const ExpectedImpl& rhs) noexcept : data_(rhs.data_) { 227 CHECK(!rhs.is_moved_from()); 228 } 229 constexpr ExpectedImpl(ExpectedImpl&& rhs) noexcept 230 : data_(std::move(rhs.data_)) { 231 CHECK(!rhs.is_moved_from()); 232 rhs.set_is_moved_from(); 233 } 234 235 template <typename U, typename G> 236 constexpr explicit ExpectedImpl(const ExpectedImpl<U, G>& rhs) noexcept { 237 if (rhs.has_value()) { 238 emplace_value(rhs.value()); 239 } else { 240 emplace_error(rhs.error()); 241 } 242 } 243 244 template <typename U, typename G> 245 constexpr explicit ExpectedImpl(ExpectedImpl<U, G>&& rhs) noexcept { 246 if (rhs.has_value()) { 247 emplace_value(std::move(rhs.value())); 248 } else { 249 emplace_error(std::move(rhs.error())); 250 } 251 rhs.set_is_moved_from(); 252 } 253 254 template <typename... Args> 255 constexpr explicit ExpectedImpl(decltype(kValTag), Args&&... args) noexcept 256 : data_(kValTag, std::forward<Args>(args)...) {} 257 258 template <typename U, typename... Args> 259 constexpr explicit ExpectedImpl(decltype(kValTag), 260 std::initializer_list<U> il, 261 Args&&... args) noexcept 262 : data_(kValTag, il, std::forward<Args>(args)...) {} 263 264 template <typename... Args> 265 constexpr explicit ExpectedImpl(decltype(kErrTag), Args&&... args) noexcept 266 : data_(kErrTag, std::forward<Args>(args)...) {} 267 268 template <typename U, typename... Args> 269 constexpr explicit ExpectedImpl(decltype(kErrTag), 270 std::initializer_list<U> il, 271 Args&&... args) noexcept 272 : data_(kErrTag, il, std::forward<Args>(args)...) {} 273 274 constexpr ExpectedImpl& operator=(const ExpectedImpl& rhs) noexcept { 275 CHECK(!rhs.is_moved_from()); 276 data_ = rhs.data_; 277 return *this; 278 } 279 280 constexpr ExpectedImpl& operator=(ExpectedImpl&& rhs) noexcept { 281 CHECK(!rhs.is_moved_from()); 282 data_ = std::move(rhs.data_); 283 rhs.set_is_moved_from(); 284 return *this; 285 } 286 287 template <typename... Args> 288 constexpr T& emplace_value(Args&&... args) noexcept { 289 return data_.template emplace<kValIdx>(std::forward<Args>(args)...); 290 } 291 292 template <typename U, typename... Args> 293 constexpr T& emplace_value(std::initializer_list<U> il, 294 Args&&... args) noexcept { 295 return data_.template emplace<kValIdx>(il, std::forward<Args>(args)...); 296 } 297 298 template <typename... Args> 299 constexpr E& emplace_error(Args&&... args) noexcept { 300 return data_.template emplace<kErrIdx>(std::forward<Args>(args)...); 301 } 302 303 template <typename U, typename... Args> 304 constexpr E& emplace_error(std::initializer_list<U> il, 305 Args&&... args) noexcept { 306 return data_.template emplace<kErrIdx>(il, std::forward<Args>(args)...); 307 } 308 309 void swap(ExpectedImpl& rhs) noexcept { 310 CHECK(!is_moved_from()); 311 CHECK(!rhs.is_moved_from()); 312 data_.swap(rhs.data_); 313 } 314 315 constexpr bool has_value() const noexcept { 316 CHECK(!is_moved_from()); 317 return data_.index() == kValIdx; 318 } 319 320 // Note: No `CHECK()` here and below, since absl::get already checks that 321 // the passed in index is active. 322 constexpr T& value() noexcept { return absl::get<kValIdx>(data_); } 323 constexpr const T& value() const noexcept { 324 return absl::get<kValIdx>(data_); 325 } 326 327 constexpr E& error() noexcept { return absl::get<kErrIdx>(data_); } 328 constexpr const E& error() const noexcept { 329 return absl::get<kErrIdx>(data_); 330 } 331 332 private: 333 static constexpr size_t kNulIdx = 0; 334 static_assert(kNulIdx != kValIdx); 335 static_assert(kNulIdx != kErrIdx); 336 337 constexpr bool is_moved_from() const noexcept { 338 return data_.index() == kNulIdx; 339 } 340 341 constexpr void set_is_moved_from() noexcept { 342 data_.template emplace<kNulIdx>(); 343 } 344 345 absl::variant<absl::monostate, T, E> data_; 346 }; 347 348 template <typename Exp, typename F> 349 constexpr auto AndThen(Exp&& exp, F&& f) noexcept { 350 using T = remove_cvref_t<decltype(exp.value())>; 351 using E = remove_cvref_t<decltype(exp.error())>; 352 353 auto invoke_f = [&]() -> decltype(auto) { 354 if constexpr (!std::is_void_v<T>) { 355 return std::invoke(std::forward<F>(f), std::forward<Exp>(exp).value()); 356 } else { 357 return std::invoke(std::forward<F>(f)); 358 } 359 }; 360 361 using U = remove_cvref_t<decltype(invoke_f())>; 362 static_assert(internal::IsExpected<U>::value, 363 "expected<T, E>::and_then: Result of f() must be a " 364 "specialization of expected"); 365 static_assert( 366 std::is_same_v<typename U::error_type, E>, 367 "expected<T, E>::and_then: Result of f() must have E as error_type"); 368 369 return exp.has_value() ? invoke_f() 370 : U(unexpect, std::forward<Exp>(exp).error()); 371 } 372 373 template <typename Exp, typename F> 374 constexpr auto OrElse(Exp&& exp, F&& f) noexcept { 375 using T = remove_cvref_t<decltype(exp.value())>; 376 using G = remove_cvref_t< 377 std::invoke_result_t<F, decltype(std::forward<Exp>(exp).error())>>; 378 379 static_assert(internal::IsExpected<G>::value, 380 "expected<T, E>::or_else: Result of f() must be a " 381 "specialization of expected"); 382 static_assert( 383 std::is_same_v<typename G::value_type, T>, 384 "expected<T, E>::or_else: Result of f() must have T as value_type"); 385 386 if (!exp.has_value()) { 387 return std::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()); 388 } 389 390 if constexpr (!std::is_void_v<T>) { 391 return G(absl::in_place, std::forward<Exp>(exp).value()); 392 } else { 393 return G(); 394 } 395 } 396 397 template <typename Exp, typename F> 398 constexpr auto Transform(Exp&& exp, F&& f) noexcept { 399 using T = remove_cvref_t<decltype(exp.value())>; 400 using E = remove_cvref_t<decltype(exp.error())>; 401 402 auto invoke_f = [&]() -> decltype(auto) { 403 if constexpr (!std::is_void_v<T>) { 404 return std::invoke(std::forward<F>(f), std::forward<Exp>(exp).value()); 405 } else { 406 return std::invoke(std::forward<F>(f)); 407 } 408 }; 409 410 using U = std::remove_cv_t<decltype(invoke_f())>; 411 if constexpr (!std::is_void_v<U>) { 412 static_assert(!std::is_array_v<U>, 413 "expected<T, E>::transform: Result of f() should " 414 "not be an Array"); 415 static_assert(!std::is_same_v<U, absl::in_place_t>, 416 "expected<T, E>::transform: Result of f() should " 417 "not be absl::in_place_t"); 418 static_assert(!std::is_same_v<U, unexpect_t>, 419 "expected<T, E>::transform: Result of f() should " 420 "not be unexpect_t"); 421 static_assert(!internal::IsOk<U>::value, 422 "expected<T, E>::transform: Result of f() should " 423 "not be a specialization of ok"); 424 static_assert(!internal::IsUnexpected<U>::value, 425 "expected<T, E>::transform: Result of f() should " 426 "not be a specialization of unexpected"); 427 static_assert(std::is_object_v<U>, 428 "expected<T, E>::transform: Result of f() should be " 429 "an object type"); 430 } 431 432 if (!exp.has_value()) { 433 return expected<U, E>(unexpect, std::forward<Exp>(exp).error()); 434 } 435 436 if constexpr (!std::is_void_v<U>) { 437 return expected<U, E>(absl::in_place, invoke_f()); 438 } else { 439 invoke_f(); 440 return expected<U, E>(); 441 } 442 } 443 444 template <typename Exp, typename F> 445 constexpr auto TransformError(Exp&& exp, F&& f) noexcept { 446 using T = remove_cvref_t<decltype(exp.value())>; 447 using G = std::remove_cv_t< 448 std::invoke_result_t<F, decltype(std::forward<Exp>(exp).error())>>; 449 450 static_assert( 451 !std::is_array_v<G>, 452 "expected<T, E>::transform_error: Result of f() should not be an Array"); 453 static_assert(!std::is_same_v<G, absl::in_place_t>, 454 "expected<T, E>::transform_error: Result of f() should not be " 455 "absl::in_place_t"); 456 static_assert(!std::is_same_v<G, unexpect_t>, 457 "expected<T, E>::transform_error: Result of f() should not be " 458 "unexpect_t"); 459 static_assert(!internal::IsOk<G>::value, 460 "expected<T, E>::transform_error: Result of f() should not be " 461 "a specialization of ok"); 462 static_assert(!internal::IsUnexpected<G>::value, 463 "expected<T, E>::transform_error: Result of f() should not be " 464 "a specialization of unexpected"); 465 static_assert(std::is_object_v<G>, 466 "expected<T, E>::transform_error: Result of f() should be an " 467 "object type"); 468 469 if (!exp.has_value()) { 470 return expected<T, G>( 471 unexpect, 472 std::invoke(std::forward<F>(f), std::forward<Exp>(exp).error())); 473 } 474 475 if constexpr (std::is_void_v<T>) { 476 return expected<T, G>(); 477 } else { 478 return expected<T, G>(absl::in_place, std::forward<Exp>(exp).value()); 479 } 480 } 481 482 } // namespace internal 483 484 } // namespace base 485 486 #endif // BASE_TYPES_EXPECTED_INTERNAL_H_ 487