expected_internal.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_TYPES_EXPECTED_INTERNAL_H_
  5. #define BASE_TYPES_EXPECTED_INTERNAL_H_
  6. // IWYU pragma: private, include "base/types/expected.h"
  7. #include <type_traits>
  8. #include <utility>
  9. #include "base/check.h"
  10. #include "base/template_util.h"
  11. #include "third_party/abseil-cpp/absl/types/variant.h"
  12. #include "third_party/abseil-cpp/absl/utility/utility.h"
  13. // This header defines type traits and aliases used for the implementation of
  14. // base::expected.
  15. namespace base {
  16. template <typename E>
  17. class unexpected;
  18. template <typename T, typename E, bool = std::is_void_v<T>>
  19. class expected;
  20. namespace internal {
  21. template <typename T>
  22. struct IsUnexpected : std::false_type {};
  23. template <typename E>
  24. struct IsUnexpected<unexpected<E>> : std::true_type {};
  25. template <typename T, typename U>
  26. struct IsConstructibleOrConvertible
  27. : std::disjunction<std::is_constructible<T, U>, std::is_convertible<U, T>> {
  28. };
  29. template <typename T, typename U>
  30. struct IsAnyConstructibleOrConvertible
  31. : std::disjunction<IsConstructibleOrConvertible<T, U&>,
  32. IsConstructibleOrConvertible<T, U&&>,
  33. IsConstructibleOrConvertible<T, const U&>,
  34. IsConstructibleOrConvertible<T, const U&&>> {};
  35. // Checks whether a given expected<U, G> can be converted into another
  36. // expected<T, E>. Used inside expected's conversion constructors. UF and GF are
  37. // the forwarded versions of U and G, e.g. UF is const U& for the converting
  38. // copy constructor and U for the converting move constructor. Similarly for GF.
  39. // ExUG is used for convenience, and not expected to be passed explicitly.
  40. // See https://eel.is/c++draft/expected#lib:expected,constructor___
  41. template <typename T,
  42. typename E,
  43. typename UF,
  44. typename GF,
  45. typename ExUG = expected<remove_cvref_t<UF>, remove_cvref_t<GF>>>
  46. struct IsValidConversion
  47. : std::conjunction<
  48. std::is_constructible<T, UF>,
  49. std::is_constructible<E, GF>,
  50. std::negation<IsAnyConstructibleOrConvertible<T, ExUG>>,
  51. std::negation<IsAnyConstructibleOrConvertible<unexpected<E>, ExUG>>> {
  52. };
  53. // Checks whether a given expected<U, G> can be converted into another
  54. // expected<T, E> when T is a void type. Used inside expected<void>'s conversion
  55. // constructors. GF is the forwarded versions of G, e.g. GF is const G& for the
  56. // converting copy constructor and G for the converting move constructor. ExUG
  57. // is used for convenience, and not expected to be passed explicitly. See
  58. // https://eel.is/c++draft/expected#lib:expected%3cvoid%3e,constructor___
  59. template <typename E,
  60. typename U,
  61. typename GF,
  62. typename ExUG = expected<U, remove_cvref_t<GF>>>
  63. struct IsValidVoidConversion
  64. : std::conjunction<
  65. std::is_void<U>,
  66. std::is_constructible<E, GF>,
  67. std::negation<IsAnyConstructibleOrConvertible<unexpected<E>, ExUG>>> {
  68. };
  69. template <typename T, typename E, typename U>
  70. struct IsValidValueConstruction
  71. : std::conjunction<
  72. std::is_constructible<T, U>,
  73. std::negation<std::is_same<remove_cvref_t<U>, absl::in_place_t>>,
  74. std::negation<std::is_same<remove_cvref_t<U>, expected<T, E>>>,
  75. std::negation<IsUnexpected<remove_cvref_t<U>>>> {};
  76. template <typename T, typename E, typename UF, typename GF>
  77. struct AreValueAndErrorConvertible
  78. : std::conjunction<std::is_convertible<UF, T>, std::is_convertible<GF, E>> {
  79. };
  80. template <typename T>
  81. using EnableIfDefaultConstruction =
  82. std::enable_if_t<std::is_default_constructible_v<T>, int>;
  83. template <typename T, typename E, typename UF, typename GF>
  84. using EnableIfExplicitConversion = std::enable_if_t<
  85. std::conjunction_v<
  86. IsValidConversion<T, E, UF, GF>,
  87. std::negation<AreValueAndErrorConvertible<T, E, UF, GF>>>,
  88. int>;
  89. template <typename T, typename E, typename UF, typename GF>
  90. using EnableIfImplicitConversion = std::enable_if_t<
  91. std::conjunction_v<IsValidConversion<T, E, UF, GF>,
  92. AreValueAndErrorConvertible<T, E, UF, GF>>,
  93. int>;
  94. template <typename E, typename U, typename GF>
  95. using EnableIfExplicitVoidConversion = std::enable_if_t<
  96. std::conjunction_v<IsValidVoidConversion<E, U, GF>,
  97. std::negation<std::is_convertible<GF, E>>>,
  98. int>;
  99. template <typename E, typename U, typename GF>
  100. using EnableIfImplicitVoidConversion =
  101. std::enable_if_t<std::conjunction_v<IsValidVoidConversion<E, U, GF>,
  102. std::is_convertible<GF, E>>,
  103. int>;
  104. template <typename T, typename U>
  105. using EnableIfUnexpectedValueConstruction = std::enable_if_t<
  106. std::conjunction_v<
  107. std::negation<std::is_same<remove_cvref_t<U>, unexpected<T>>>,
  108. std::negation<std::is_same<remove_cvref_t<U>, absl::in_place_t>>,
  109. std::is_constructible<T, U>>,
  110. int>;
  111. template <typename T, typename E, typename U>
  112. using EnableIfExplicitValueConstruction = std::enable_if_t<
  113. std::conjunction_v<IsValidValueConstruction<T, E, U>,
  114. std::negation<std::is_convertible<U, T>>>,
  115. int>;
  116. template <typename T, typename E, typename U>
  117. using EnableIfImplicitValueConstruction =
  118. std::enable_if_t<std::conjunction_v<IsValidValueConstruction<T, E, U>,
  119. std::is_convertible<U, T>>,
  120. int>;
  121. template <typename T, typename U>
  122. using EnableIfExplicitUnexpectedConstruction = std::enable_if_t<
  123. std::conjunction_v<std::is_constructible<T, U>,
  124. std::negation<std::is_convertible<U, T>>>,
  125. int>;
  126. template <typename T, typename U>
  127. using EnableIfImplicitUnexpectedConstruction = std::enable_if_t<
  128. std::conjunction_v<std::is_constructible<T, U>, std::is_convertible<U, T>>,
  129. int>;
  130. template <typename T, typename E, typename U>
  131. using EnableIfValueAssignment = std::enable_if_t<
  132. std::conjunction_v<
  133. std::negation<std::is_same<expected<T, E>, remove_cvref_t<U>>>,
  134. std::negation<IsUnexpected<remove_cvref_t<U>>>,
  135. std::is_constructible<T, U>,
  136. std::is_assignable<T&, U>>,
  137. int>;
  138. template <typename T>
  139. using EnableIfNotVoid = std::enable_if_t<std::negation_v<std::is_void<T>>, int>;
  140. template <typename T, typename E>
  141. class ExpectedImpl {
  142. public:
  143. static constexpr size_t kValIdx = 1;
  144. static constexpr size_t kErrIdx = 2;
  145. static constexpr absl::in_place_index_t<1> kValTag{};
  146. static constexpr absl::in_place_index_t<2> kErrTag{};
  147. template <typename U, typename G>
  148. friend class ExpectedImpl;
  149. template <typename LazyT = T, EnableIfDefaultConstruction<LazyT> = 0>
  150. constexpr ExpectedImpl() noexcept : data_(kValTag) {}
  151. constexpr ExpectedImpl(const ExpectedImpl& rhs) noexcept : data_(rhs.data_) {
  152. CHECK(!rhs.is_moved_from());
  153. }
  154. constexpr ExpectedImpl(ExpectedImpl&& rhs) noexcept
  155. : data_(std::move(rhs.data_)) {
  156. CHECK(!rhs.is_moved_from());
  157. rhs.set_is_moved_from();
  158. }
  159. template <typename U, typename G>
  160. constexpr explicit ExpectedImpl(const ExpectedImpl<U, G>& rhs) noexcept {
  161. if (rhs.has_value()) {
  162. emplace_value(rhs.value());
  163. } else {
  164. emplace_error(rhs.error());
  165. }
  166. }
  167. template <typename U, typename G>
  168. constexpr explicit ExpectedImpl(ExpectedImpl<U, G>&& rhs) noexcept {
  169. if (rhs.has_value()) {
  170. emplace_value(std::move(rhs.value()));
  171. } else {
  172. emplace_error(std::move(rhs.error()));
  173. }
  174. rhs.set_is_moved_from();
  175. }
  176. template <typename... Args>
  177. constexpr explicit ExpectedImpl(decltype(kValTag), Args&&... args) noexcept
  178. : data_(kValTag, std::forward<Args>(args)...) {}
  179. template <typename U, typename... Args>
  180. constexpr explicit ExpectedImpl(decltype(kValTag),
  181. std::initializer_list<U> il,
  182. Args&&... args) noexcept
  183. : data_(kValTag, il, std::forward<Args>(args)...) {}
  184. template <typename... Args>
  185. constexpr explicit ExpectedImpl(decltype(kErrTag), Args&&... args) noexcept
  186. : data_(kErrTag, std::forward<Args>(args)...) {}
  187. template <typename U, typename... Args>
  188. constexpr explicit ExpectedImpl(decltype(kErrTag),
  189. std::initializer_list<U> il,
  190. Args&&... args) noexcept
  191. : data_(kErrTag, il, std::forward<Args>(args)...) {}
  192. constexpr ExpectedImpl& operator=(const ExpectedImpl& rhs) noexcept {
  193. CHECK(!rhs.is_moved_from());
  194. data_ = rhs.data_;
  195. return *this;
  196. }
  197. constexpr ExpectedImpl& operator=(ExpectedImpl&& rhs) noexcept {
  198. CHECK(!rhs.is_moved_from());
  199. data_ = std::move(rhs.data_);
  200. rhs.set_is_moved_from();
  201. return *this;
  202. }
  203. template <typename... Args>
  204. constexpr T& emplace_value(Args&&... args) noexcept {
  205. return data_.template emplace<kValIdx>(std::forward<Args>(args)...);
  206. }
  207. template <typename U, typename... Args>
  208. constexpr T& emplace_value(std::initializer_list<U> il,
  209. Args&&... args) noexcept {
  210. return data_.template emplace<kValIdx>(il, std::forward<Args>(args)...);
  211. }
  212. template <typename... Args>
  213. constexpr E& emplace_error(Args&&... args) noexcept {
  214. return data_.template emplace<kErrIdx>(std::forward<Args>(args)...);
  215. }
  216. template <typename U, typename... Args>
  217. constexpr E& emplace_error(std::initializer_list<U> il,
  218. Args&&... args) noexcept {
  219. return data_.template emplace<kErrIdx>(il, std::forward<Args>(args)...);
  220. }
  221. void swap(ExpectedImpl& rhs) noexcept {
  222. CHECK(!is_moved_from());
  223. CHECK(!rhs.is_moved_from());
  224. data_.swap(rhs.data_);
  225. }
  226. constexpr bool has_value() const noexcept {
  227. CHECK(!is_moved_from());
  228. return data_.index() == kValIdx;
  229. }
  230. // Note: No `CHECK()` here and below, since absl::get already checks that
  231. // the passed in index is active.
  232. constexpr T& value() noexcept { return absl::get<kValIdx>(data_); }
  233. constexpr const T& value() const noexcept {
  234. return absl::get<kValIdx>(data_);
  235. }
  236. constexpr E& error() noexcept { return absl::get<kErrIdx>(data_); }
  237. constexpr const E& error() const noexcept {
  238. return absl::get<kErrIdx>(data_);
  239. }
  240. private:
  241. static constexpr size_t kNulIdx = 0;
  242. static_assert(kNulIdx != kValIdx);
  243. static_assert(kNulIdx != kErrIdx);
  244. constexpr bool is_moved_from() const noexcept {
  245. return data_.index() == kNulIdx;
  246. }
  247. constexpr void set_is_moved_from() noexcept {
  248. data_.template emplace<kNulIdx>();
  249. }
  250. absl::variant<absl::monostate, T, E> data_;
  251. };
  252. } // namespace internal
  253. } // namespace base
  254. #endif // BASE_TYPES_EXPECTED_INTERNAL_H_