• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <concepts>
10 #include <functional>
11 #include <type_traits>
12 #include <utility>
13 
14 #include "base/check.h"
15 #include "base/template_util.h"
16 #include "third_party/abseil-cpp/absl/types/variant.h"
17 #include "third_party/abseil-cpp/absl/utility/utility.h"
18 
19 // This header defines type traits and aliases used for the implementation of
20 // base::expected.
21 namespace base {
22 
23 template <typename T>
24 class ok;
25 
26 template <typename E>
27 class unexpected;
28 
29 struct unexpect_t {
30   explicit unexpect_t() = default;
31 };
32 
33 // in-place construction of unexpected values
34 inline constexpr unexpect_t unexpect{};
35 
36 template <typename T, typename E>
37 class expected;
38 
39 namespace internal {
40 
41 template <typename T>
42 inline constexpr bool UnderlyingIsOk = false;
43 template <typename T>
44 inline constexpr bool UnderlyingIsOk<ok<T>> = true;
45 template <typename T>
46 inline constexpr bool IsOk = UnderlyingIsOk<remove_cvref_t<T>>;
47 
48 template <typename T>
49 inline constexpr bool UnderlyingIsUnexpected = false;
50 template <typename E>
51 inline constexpr bool UnderlyingIsUnexpected<unexpected<E>> = true;
52 template <typename T>
53 inline constexpr bool IsUnexpected = UnderlyingIsUnexpected<remove_cvref_t<T>>;
54 
55 template <typename T>
56 inline constexpr bool UnderlyingIsExpected = false;
57 template <typename T, typename E>
58 inline constexpr bool UnderlyingIsExpected<expected<T, E>> = true;
59 template <typename T>
60 inline constexpr bool IsExpected = UnderlyingIsExpected<remove_cvref_t<T>>;
61 
62 template <typename T, typename U>
63 inline constexpr bool IsConstructibleOrConvertible =
64     std::is_constructible_v<T, U> || std::is_convertible_v<U, T>;
65 
66 template <typename T, typename U>
67 inline constexpr bool IsAnyConstructibleOrConvertible =
68     IsConstructibleOrConvertible<T, U&> ||
69     IsConstructibleOrConvertible<T, U&&> ||
70     IsConstructibleOrConvertible<T, const U&> ||
71     IsConstructibleOrConvertible<T, const U&&>;
72 
73 // Checks whether a given expected<U, G> can be converted into another
74 // expected<T, E>. Used inside expected's conversion constructors. UF and GF are
75 // the forwarded versions of U and G, e.g. UF is const U& for the converting
76 // copy constructor and U for the converting move constructor. Similarly for GF.
77 // ExUG is used for convenience, and not expected to be passed explicitly.
78 // See https://eel.is/c++draft/expected#lib:expected,constructor___
79 template <typename T,
80           typename E,
81           typename UF,
82           typename GF,
83           typename ExUG = expected<remove_cvref_t<UF>, remove_cvref_t<GF>>>
84 inline constexpr bool IsValidConversion =
85     std::is_constructible_v<T, UF> && std::is_constructible_v<E, GF> &&
86     !IsAnyConstructibleOrConvertible<T, ExUG> &&
87     !IsAnyConstructibleOrConvertible<unexpected<E>, ExUG>;
88 
89 // Checks whether a given expected<U, G> can be converted into another
90 // expected<T, E> when T is a void type. Used inside expected<void>'s conversion
91 // constructors. GF is the forwarded versions of G, e.g. GF is const G& for the
92 // converting copy constructor and G for the converting move constructor. ExUG
93 // is used for convenience, and not expected to be passed explicitly. See
94 // https://eel.is/c++draft/expected#lib:expected%3cvoid%3e,constructor___
95 template <typename E,
96           typename U,
97           typename GF,
98           typename ExUG = expected<U, remove_cvref_t<GF>>>
99 inline constexpr bool IsValidVoidConversion =
100     std::is_void_v<U> && std::is_constructible_v<E, GF> &&
101     !IsAnyConstructibleOrConvertible<unexpected<E>, ExUG>;
102 
103 // Checks whether expected<T, E> can be constructed from a value of type U.
104 template <typename T, typename E, typename U>
105 inline constexpr bool IsValidValueConstruction =
106     std::is_constructible_v<T, U> &&
107     !std::is_same_v<remove_cvref_t<U>, absl::in_place_t> &&
108     !std::is_same_v<remove_cvref_t<U>, expected<T, E>> && !IsOk<U> &&
109     !IsUnexpected<U>;
110 
111 template <typename T, typename U>
112 inline constexpr bool IsOkValueConstruction =
113     !std::is_same_v<remove_cvref_t<U>, ok<T>> &&
114     !std::is_same_v<remove_cvref_t<U>, absl::in_place_t> &&
115     std::is_constructible_v<T, U>;
116 
117 template <typename T, typename U>
118 inline constexpr bool IsUnexpectedValueConstruction =
119     !std::is_same_v<remove_cvref_t<U>, unexpected<T>> &&
120     !std::is_same_v<remove_cvref_t<U>, absl::in_place_t> &&
121     std::is_constructible_v<T, U>;
122 
123 template <typename T, typename E, typename U>
124 inline constexpr bool IsValueAssignment =
125     !std::is_same_v<expected<T, E>, remove_cvref_t<U>> && !IsOk<U> &&
126     !IsUnexpected<U> && std::is_constructible_v<T, U> &&
127     std::is_assignable_v<T&, U>;
128 
129 template <typename T, typename E>
130 class ExpectedImpl {
131  public:
132   static constexpr size_t kValIdx = 1;
133   static constexpr size_t kErrIdx = 2;
134   static constexpr absl::in_place_index_t<1> kValTag{};
135   static constexpr absl::in_place_index_t<2> kErrTag{};
136 
137   template <typename U, typename G>
138   friend class ExpectedImpl;
139 
ExpectedImpl()140   constexpr ExpectedImpl() noexcept
141     requires(std::default_initializable<T>)
142       : data_(kValTag) {}
ExpectedImpl(const ExpectedImpl & rhs)143   constexpr ExpectedImpl(const ExpectedImpl& rhs) noexcept : data_(rhs.data_) {
144     CHECK(!rhs.is_moved_from());
145   }
ExpectedImpl(ExpectedImpl && rhs)146   constexpr ExpectedImpl(ExpectedImpl&& rhs) noexcept
147       : data_(std::move(rhs.data_)) {
148     CHECK(!rhs.is_moved_from());
149     rhs.set_is_moved_from();
150   }
151 
152   template <typename U, typename G>
ExpectedImpl(const ExpectedImpl<U,G> & rhs)153   constexpr explicit ExpectedImpl(const ExpectedImpl<U, G>& rhs) noexcept {
154     if (rhs.has_value()) {
155       emplace_value(rhs.value());
156     } else {
157       emplace_error(rhs.error());
158     }
159   }
160 
161   template <typename U, typename G>
ExpectedImpl(ExpectedImpl<U,G> && rhs)162   constexpr explicit ExpectedImpl(ExpectedImpl<U, G>&& rhs) noexcept {
163     if (rhs.has_value()) {
164       emplace_value(std::move(rhs.value()));
165     } else {
166       emplace_error(std::move(rhs.error()));
167     }
168     rhs.set_is_moved_from();
169   }
170 
171   template <typename... Args>
ExpectedImpl(decltype (kValTag),Args &&...args)172   constexpr explicit ExpectedImpl(decltype(kValTag), Args&&... args) noexcept
173       : data_(kValTag, std::forward<Args>(args)...) {}
174 
175   template <typename U, typename... Args>
ExpectedImpl(decltype (kValTag),std::initializer_list<U> il,Args &&...args)176   constexpr explicit ExpectedImpl(decltype(kValTag),
177                                   std::initializer_list<U> il,
178                                   Args&&... args) noexcept
179       : data_(kValTag, il, std::forward<Args>(args)...) {}
180 
181   template <typename... Args>
ExpectedImpl(decltype (kErrTag),Args &&...args)182   constexpr explicit ExpectedImpl(decltype(kErrTag), Args&&... args) noexcept
183       : data_(kErrTag, std::forward<Args>(args)...) {}
184 
185   template <typename U, typename... Args>
ExpectedImpl(decltype (kErrTag),std::initializer_list<U> il,Args &&...args)186   constexpr explicit ExpectedImpl(decltype(kErrTag),
187                                   std::initializer_list<U> il,
188                                   Args&&... args) noexcept
189       : data_(kErrTag, il, std::forward<Args>(args)...) {}
190 
191   constexpr ExpectedImpl& operator=(const ExpectedImpl& rhs) noexcept {
192     CHECK(!rhs.is_moved_from());
193     data_ = rhs.data_;
194     return *this;
195   }
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 
204   template <typename... Args>
emplace_value(Args &&...args)205   constexpr T& emplace_value(Args&&... args) noexcept {
206     return data_.template emplace<kValIdx>(std::forward<Args>(args)...);
207   }
208 
209   template <typename U, typename... Args>
emplace_value(std::initializer_list<U> il,Args &&...args)210   constexpr T& emplace_value(std::initializer_list<U> il,
211                              Args&&... args) noexcept {
212     return data_.template emplace<kValIdx>(il, std::forward<Args>(args)...);
213   }
214 
215   template <typename... Args>
emplace_error(Args &&...args)216   constexpr E& emplace_error(Args&&... args) noexcept {
217     return data_.template emplace<kErrIdx>(std::forward<Args>(args)...);
218   }
219 
220   template <typename U, typename... Args>
emplace_error(std::initializer_list<U> il,Args &&...args)221   constexpr E& emplace_error(std::initializer_list<U> il,
222                              Args&&... args) noexcept {
223     return data_.template emplace<kErrIdx>(il, std::forward<Args>(args)...);
224   }
225 
swap(ExpectedImpl & rhs)226   void swap(ExpectedImpl& rhs) noexcept {
227     CHECK(!is_moved_from());
228     CHECK(!rhs.is_moved_from());
229     data_.swap(rhs.data_);
230   }
231 
has_value()232   constexpr bool has_value() const noexcept {
233     CHECK(!is_moved_from());
234     return data_.index() == kValIdx;
235   }
236 
237   // Note: No `CHECK()` here and below, since absl::get already checks that
238   // the passed in index is active.
value()239   constexpr T& value() noexcept { return absl::get<kValIdx>(data_); }
value()240   constexpr const T& value() const noexcept {
241     return absl::get<kValIdx>(data_);
242   }
243 
error()244   constexpr E& error() noexcept { return absl::get<kErrIdx>(data_); }
error()245   constexpr const E& error() const noexcept {
246     return absl::get<kErrIdx>(data_);
247   }
248 
249  private:
250   static constexpr size_t kNulIdx = 0;
251   static_assert(kNulIdx != kValIdx);
252   static_assert(kNulIdx != kErrIdx);
253 
is_moved_from()254   constexpr bool is_moved_from() const noexcept {
255     return data_.index() == kNulIdx;
256   }
257 
set_is_moved_from()258   constexpr void set_is_moved_from() noexcept {
259     data_.template emplace<kNulIdx>();
260   }
261 
262   absl::variant<absl::monostate, T, E> data_;
263 };
264 
265 template <typename Exp, typename F>
AndThen(Exp && exp,F && f)266 constexpr auto AndThen(Exp&& exp, F&& f) noexcept {
267   using T = remove_cvref_t<decltype(exp.value())>;
268   using E = remove_cvref_t<decltype(exp.error())>;
269 
270   auto invoke_f = [&]() -> decltype(auto) {
271     if constexpr (!std::is_void_v<T>) {
272       return std::invoke(std::forward<F>(f), std::forward<Exp>(exp).value());
273     } else {
274       return std::invoke(std::forward<F>(f));
275     }
276   };
277 
278   using U = decltype(invoke_f());
279   static_assert(internal::IsExpected<U>,
280                 "expected<T, E>::and_then: Result of f() must be a "
281                 "specialization of expected");
282   static_assert(
283       std::is_same_v<typename U::error_type, E>,
284       "expected<T, E>::and_then: Result of f() must have E as error_type");
285 
286   return exp.has_value() ? invoke_f()
287                          : U(unexpect, std::forward<Exp>(exp).error());
288 }
289 
290 template <typename Exp, typename F>
OrElse(Exp && exp,F && f)291 constexpr auto OrElse(Exp&& exp, F&& f) noexcept {
292   using T = remove_cvref_t<decltype(exp.value())>;
293   using G = std::invoke_result_t<F, decltype(std::forward<Exp>(exp).error())>;
294 
295   static_assert(internal::IsExpected<G>,
296                 "expected<T, E>::or_else: Result of f() must be a "
297                 "specialization of expected");
298   static_assert(
299       std::is_same_v<typename G::value_type, T>,
300       "expected<T, E>::or_else: Result of f() must have T as value_type");
301 
302   if (!exp.has_value()) {
303     return std::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
304   }
305 
306   if constexpr (!std::is_void_v<T>) {
307     return G(absl::in_place, std::forward<Exp>(exp).value());
308   } else {
309     return G();
310   }
311 }
312 
313 template <typename Exp, typename F>
Transform(Exp && exp,F && f)314 constexpr auto Transform(Exp&& exp, F&& f) noexcept {
315   using T = remove_cvref_t<decltype(exp.value())>;
316   using E = remove_cvref_t<decltype(exp.error())>;
317 
318   auto invoke_f = [&]() -> decltype(auto) {
319     if constexpr (!std::is_void_v<T>) {
320       return std::invoke(std::forward<F>(f), std::forward<Exp>(exp).value());
321     } else {
322       return std::invoke(std::forward<F>(f));
323     }
324   };
325 
326   using U = std::remove_cv_t<decltype(invoke_f())>;
327   if constexpr (!std::is_void_v<U>) {
328     static_assert(!std::is_array_v<U>,
329                   "expected<T, E>::transform: Result of f() should "
330                   "not be an Array");
331     static_assert(!std::is_same_v<U, absl::in_place_t>,
332                   "expected<T, E>::transform: Result of f() should "
333                   "not be absl::in_place_t");
334     static_assert(!std::is_same_v<U, unexpect_t>,
335                   "expected<T, E>::transform: Result of f() should "
336                   "not be unexpect_t");
337     static_assert(!internal::IsOk<U>,
338                   "expected<T, E>::transform: Result of f() should "
339                   "not be a specialization of ok");
340     static_assert(!internal::IsUnexpected<U>,
341                   "expected<T, E>::transform: Result of f() should "
342                   "not be a specialization of unexpected");
343     static_assert(std::is_object_v<U>,
344                   "expected<T, E>::transform: Result of f() should be "
345                   "an object type");
346   }
347 
348   if (!exp.has_value()) {
349     return expected<U, E>(unexpect, std::forward<Exp>(exp).error());
350   }
351 
352   if constexpr (!std::is_void_v<U>) {
353     return expected<U, E>(absl::in_place, invoke_f());
354   } else {
355     invoke_f();
356     return expected<U, E>();
357   }
358 }
359 
360 template <typename Exp, typename F>
TransformError(Exp && exp,F && f)361 constexpr auto TransformError(Exp&& exp, F&& f) noexcept {
362   using T = remove_cvref_t<decltype(exp.value())>;
363   using G = std::remove_cv_t<
364       std::invoke_result_t<F, decltype(std::forward<Exp>(exp).error())>>;
365 
366   static_assert(
367       !std::is_array_v<G>,
368       "expected<T, E>::transform_error: Result of f() should not be an Array");
369   static_assert(!std::is_same_v<G, absl::in_place_t>,
370                 "expected<T, E>::transform_error: Result of f() should not be "
371                 "absl::in_place_t");
372   static_assert(!std::is_same_v<G, unexpect_t>,
373                 "expected<T, E>::transform_error: Result of f() should not be "
374                 "unexpect_t");
375   static_assert(!internal::IsOk<G>,
376                 "expected<T, E>::transform_error: Result of f() should not be "
377                 "a specialization of ok");
378   static_assert(!internal::IsUnexpected<G>,
379                 "expected<T, E>::transform_error: Result of f() should not be "
380                 "a specialization of unexpected");
381   static_assert(std::is_object_v<G>,
382                 "expected<T, E>::transform_error: Result of f() should be an "
383                 "object type");
384 
385   if (!exp.has_value()) {
386     return expected<T, G>(
387         unexpect,
388         std::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()));
389   }
390 
391   if constexpr (std::is_void_v<T>) {
392     return expected<T, G>();
393   } else {
394     return expected<T, G>(absl::in_place, std::forward<Exp>(exp).value());
395   }
396 }
397 
398 }  // namespace internal
399 
400 }  // namespace base
401 
402 #endif  // BASE_TYPES_EXPECTED_INTERNAL_H_
403