• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Fuchsia 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 
5 #ifndef LIB_FIT_INTERNAL_RESULT_H_
6 #define LIB_FIT_INTERNAL_RESULT_H_
7 
8 #include <lib/fit/internal/compiler.h>
9 #include <lib/stdcompat/type_traits.h>
10 
11 #include <cstddef>
12 #include <new>
13 #include <tuple>
14 #include <type_traits>
15 #include <utility>
16 
17 namespace fit {
18 
19 // Forward declarations.
20 template <typename E>
21 class error;
22 
23 template <typename... Ts>
24 class success;
25 
26 template <typename E, typename... Ts>
27 class result;
28 
29 namespace internal {
30 
31 // Determines whether T has an operator-> overload and provides a method that
32 // forwards its argument by reference when T has the overload, or by pointer
33 // otherwise.
34 template <typename T, typename = void>
35 struct arrow_operator {
forwardarrow_operator36   static constexpr T* forward(T& value) { return &value; }
forwardarrow_operator37   static constexpr const T* forward(const T& value) { return &value; }
38 };
39 template <typename T>
40 struct arrow_operator<T, std::enable_if_t<cpp17::is_pointer_v<T>>> {
41   static constexpr T& forward(T& value) { return value; }
42   static constexpr const T& forward(const T& value) { return value; }
43 };
44 template <typename T>
45 struct arrow_operator<T, cpp17::void_t<decltype(std::declval<T>().operator->())>> {
46   static constexpr T& forward(T& value) { return value; }
47   static constexpr const T& forward(const T& value) { return value; }
48 };
49 
50 // Concept helper for constructor, method, and operator overloads.
51 template <typename... Conditions>
52 using requires_conditions = std::enable_if_t<cpp17::conjunction_v<Conditions...>, bool>;
53 
54 // Detects whether the given expression evaluates to an instance of the template T.
55 template <template <typename...> class T>
56 struct template_matcher {
57   template <typename... Args>
58   static constexpr std::true_type match(const T<Args...>&);
59   static constexpr std::false_type match(...);
60 };
61 
62 template <typename T, template <typename...> class U, typename = bool>
63 struct is_match : decltype(template_matcher<U>::match(std::declval<T>())) {};
64 
65 template <typename T, template <typename...> class U>
66 struct is_match<T, U, requires_conditions<std::is_void<T>>> : std::false_type {};
67 
68 template <typename T, template <typename...> class U>
69 static constexpr bool is_match_v = is_match<T, U>::value;
70 
71 // Predicate indicating whether type T is an instantiation of fit::error.
72 template <typename T>
73 struct is_error : is_match<T, ::fit::error>::type {};
74 
75 template <typename T>
76 static constexpr bool is_error_v = is_error<T>::value;
77 
78 // Predicate indicating whether type T is not an instantiation of fit::error.
79 template <typename T>
80 struct not_error_type : cpp17::negation<is_error<T>>::type {};
81 
82 // Predicate indicating whether type T is an instantiation of fit::success.
83 template <typename T>
84 struct is_success : is_match<T, ::fit::success>::type {};
85 
86 template <typename T>
87 static constexpr bool is_success_v = is_success<T>::value;
88 
89 // Predicate indicating whether type T is an instantiation of fit::result.
90 template <typename T>
91 struct is_result : is_match<T, ::fit::result>::type {};
92 
93 template <typename T>
94 static constexpr bool is_result_v = is_result<T>::value;
95 
96 // Predicate indicating whether type T is not an instantiation of fit::result.
97 template <typename T>
98 struct not_result_type : cpp17::negation<is_result<T>>::type {};
99 
100 // Determines whether T += U is well defined.
101 template <typename T, typename U, typename = void>
102 struct has_plus_equals : std::false_type {};
103 template <typename T, typename U>
104 struct has_plus_equals<T, U, cpp17::void_t<decltype(std::declval<T>() += std::declval<U>())>>
105     : std::true_type {};
106 
107 // Enable if relational operator is convertible to bool and the optional
108 // conditions are true.
109 template <typename Op, typename... Conditions>
110 using enable_rel_op =
111     std::enable_if_t<(cpp17::is_convertible_v<Op, bool> && cpp17::conjunction_v<Conditions...>),
112                      bool>;
113 
114 // Specifies whether a type is trivially or non-trivially destructible.
115 enum class storage_class_e {
116   trivial,
117   non_trivial,
118 };
119 
120 // Evaluates to storage_class_e::trivial if all of the types in Ts are trivially
121 // destructible, storage_class_e::non_trivial otherwise.
122 template <typename... Ts>
123 static constexpr storage_class_e storage_class_trait =
124     cpp17::conjunction_v<std::is_trivially_destructible<Ts>...> ? storage_class_e::trivial
125                                                                 : storage_class_e::non_trivial;
126 
127 // Trivial type for the default variant of the union below.
128 struct empty_type {};
129 
130 // Type tags to discriminate between empty, error, and value constructors,
131 // avoiding ambiguity with copy/move constructors.
132 enum empty_t { empty_v };
133 enum error_t { error_v };
134 enum value_t { value_v };
135 
136 // Union that stores either nothing, an error of type E, or a value of type T.
137 // This type is specialized for trivially and non-trivially destructible types
138 // to support multi-register return values for trivial types.
139 template <typename E, typename T, storage_class_e = storage_class_trait<E, T>>
140 union error_or_value_type {
141   constexpr error_or_value_type() : empty{} {}
142 
143   constexpr error_or_value_type(const error_or_value_type&) = default;
144   constexpr error_or_value_type& operator=(const error_or_value_type&) = default;
145   constexpr error_or_value_type(error_or_value_type&&) = default;
146   constexpr error_or_value_type& operator=(error_or_value_type&&) = default;
147 
148   template <typename F>
149   constexpr error_or_value_type(error_t, F&& error) : error(std::forward<F>(error)) {}
150 
151   template <typename U>
152   constexpr error_or_value_type(value_t, U&& value) : value(std::forward<U>(value)) {}
153 
154   ~error_or_value_type() = default;
155 
156   constexpr void destroy(error_t) {}
157   constexpr void destroy(value_t) {}
158 
159   empty_type empty;
160   E error;
161   T value;
162 };
163 template <typename E, typename T>
164 union error_or_value_type<E, T, storage_class_e::non_trivial> {
165   constexpr error_or_value_type() : empty{} {}
166 
167   constexpr error_or_value_type(const error_or_value_type&) = default;
168   constexpr error_or_value_type& operator=(const error_or_value_type&) = default;
169   constexpr error_or_value_type(error_or_value_type&&) = default;
170   constexpr error_or_value_type& operator=(error_or_value_type&&) = default;
171 
172   template <typename F>
173   constexpr error_or_value_type(error_t, F&& error) : error(std::forward<F>(error)) {}
174 
175   template <typename U>
176   constexpr error_or_value_type(value_t, U&& value) : value(std::forward<U>(value)) {}
177 
178   ~error_or_value_type() {}
179 
180   // The caller must manually destroy() if overwriting an existing value.
181   constexpr void copy_from(error_t, const E& e) { new (&error) E(e); }
182   constexpr void copy_from(value_t, const T& t) { new (&value) T(t); }
183   constexpr void move_from(error_t, E&& e) { new (&error) E(std::move(e)); }
184   constexpr void move_from(value_t, T&& t) { new (&value) T(std::move(t)); }
185 
186   constexpr void destroy(error_t) { error.E::~E(); }
187   constexpr void destroy(value_t) { value.T::~T(); }
188 
189   empty_type empty;
190   E error;
191   T value;
192 };
193 
194 // Specifies whether the storage is empty, contains an error, or contains a
195 // a value.
196 enum class state_e {
197   empty,
198   has_error,
199   has_value,
200 };
201 
202 // Storage type is either empty, holds an error, or holds a set of values. This
203 // type is specialized for trivially and non-trivially destructible types. When
204 // E and all of the elements of Ts are trivially destructible, this type
205 // provides a trivial destructor, which is necessary for multi-register return
206 // value optimization.
207 template <storage_class_e storage_class, typename E, typename... Ts>
208 struct storage_type;
209 
210 template <storage_class_e storage_class, typename E, typename T>
211 struct storage_type<storage_class, E, T> {
212   using value_type = error_or_value_type<E, T>;
213 
214   constexpr storage_type() = default;
215 
216   constexpr storage_type(const storage_type&) = default;
217   constexpr storage_type& operator=(const storage_type&) = default;
218   constexpr storage_type(storage_type&&) = default;
219   constexpr storage_type& operator=(storage_type&&) = default;
220 
221   constexpr void destroy() {}
222 
223   constexpr void reset() { state = state_e::empty; }
224 
225   ~storage_type() = default;
226 
227   explicit constexpr storage_type(empty_t) {}
228 
229   template <typename F>
230   constexpr storage_type(error_t, F&& error)
231       : state{state_e::has_error}, error_or_value{error_v, std::forward<F>(error)} {}
232 
233   template <typename U>
234   explicit constexpr storage_type(value_t, U&& value)
235       : state{state_e::has_value}, error_or_value{value_v, std::forward<U>(value)} {}
236 
237   template <storage_class_e other_storage_class, typename F, typename U>
238   explicit constexpr storage_type(storage_type<other_storage_class, F, U>&& other)
239       : state{other.state},
240         error_or_value{other.state == state_e::empty ? value_type{}
241                        : other.state == state_e::has_error
242                            ? value_type{error_v, std::move(other.error_or_value.error)}
243                            : value_type{value_v, std::move(other.error_or_value.value)}} {}
244 
245   state_e state{state_e::empty};
246   value_type error_or_value;
247 };
248 template <typename E, typename T>
249 struct storage_type<storage_class_e::non_trivial, E, T> {
250   using value_type = error_or_value_type<E, T>;
251 
252   constexpr storage_type() = default;
253 
254   constexpr storage_type(const storage_type& other) { copy_from(other); }
255   constexpr storage_type& operator=(const storage_type& other) {
256     destroy();
257     copy_from(other);
258     return *this;
259   }
260 
261   constexpr storage_type(storage_type&& other) noexcept(std::is_nothrow_move_constructible_v<E> &&
262                                                         std::is_nothrow_move_constructible_v<T>) {
263     move_from(std::move(other));
264   }
265   constexpr storage_type& operator=(storage_type&& other) noexcept(
266       std::is_nothrow_move_assignable_v<E> && std::is_nothrow_move_assignable_v<T>) {
267     destroy();
268     move_from(std::move(other));
269     return *this;
270   }
271 
272   // Copy/move-constructs over this object's value. If there could be a previous value, callers must
273   // call destroy() first.
274   constexpr void copy_from(const storage_type& other) {
275     state = other.state;
276     if (state == state_e::has_value) {
277       error_or_value.copy_from(value_v, other.error_or_value.value);
278     } else if (state == state_e::has_error) {
279       error_or_value.copy_from(error_v, other.error_or_value.error);
280     }
281   }
282   constexpr void move_from(storage_type&& other) {
283     state = other.state;
284     if (state == state_e::has_value) {
285       error_or_value.move_from(value_v, std::move(other.error_or_value.value));
286     } else if (state == state_e::has_error) {
287       error_or_value.move_from(error_v, std::move(other.error_or_value.error));
288     }
289   }
290 
291   constexpr void destroy() {
292     if (state == state_e::has_value) {
293       error_or_value.destroy(value_v);
294     } else if (state == state_e::has_error) {
295       error_or_value.destroy(error_v);
296     }
297   }
298 
299   constexpr void reset() {
300     destroy();
301     state = state_e::empty;
302   }
303 
304   ~storage_type() { destroy(); }
305 
306   explicit constexpr storage_type(empty_t) {}
307 
308   template <typename F>
309   constexpr storage_type(error_t, F&& error)
310       : state{state_e::has_error}, error_or_value{error_v, std::forward<F>(error)} {}
311 
312   template <typename U>
313   explicit constexpr storage_type(value_t, U&& value)
314       : state{state_e::has_value}, error_or_value{value_v, std::forward<U>(value)} {}
315 
316   template <storage_class_e other_storage_class, typename F, typename U>
317   explicit constexpr storage_type(storage_type<other_storage_class, F, U>&& other)
318       : state{other.state},
319         error_or_value{other.state == state_e::empty ? value_type{}
320                        : other.state == state_e::has_error
321                            ? value_type{error_v, std::move(other.error_or_value.error)}
322                            : value_type{value_v, std::move(other.error_or_value.value)}} {}
323 
324   state_e state{state_e::empty};
325   value_type error_or_value;
326 };
327 
328 template <storage_class_e storage_class, typename E>
329 struct storage_type<storage_class, E> {
330   using value_type = error_or_value_type<E, empty_type>;
331 
332   constexpr storage_type() = default;
333 
334   constexpr storage_type(const storage_type&) = default;
335   constexpr storage_type& operator=(const storage_type&) = default;
336   constexpr storage_type(storage_type&&) = default;
337   constexpr storage_type& operator=(storage_type&&) = default;
338 
339   constexpr void destroy() {}
340 
341   constexpr void reset() { state = state_e::empty; }
342 
343   ~storage_type() = default;
344 
345   explicit constexpr storage_type(empty_t) {}
346 
347   explicit constexpr storage_type(value_t)
348       : state{state_e::has_value}, error_or_value{value_v, empty_type{}} {}
349 
350   template <typename F>
351   constexpr storage_type(error_t, F&& error)
352       : state{state_e::has_error}, error_or_value{error_v, std::forward<F>(error)} {}
353 
354   template <storage_class_e other_storage_class, typename F>
355   explicit constexpr storage_type(storage_type<other_storage_class, F>&& other)
356       : state{other.state},
357         error_or_value{other.state == state_e::empty ? value_type{}
358                        : other.state == state_e::has_error
359                            ? value_type{error_v, std::move(other.error_or_value.error)}
360                            : value_type{value_v, std::move(other.error_or_value.value)}} {}
361 
362   state_e state{state_e::empty};
363   value_type error_or_value;
364 };
365 template <typename E>
366 struct storage_type<storage_class_e::non_trivial, E> {
367   using value_type = error_or_value_type<E, empty_type>;
368 
369   constexpr storage_type() = default;
370 
371   constexpr storage_type(const storage_type& other) { copy_from(other); }
372   constexpr storage_type& operator=(const storage_type& other) {
373     destroy();
374     copy_from(other);
375     return *this;
376   }
377 
378   constexpr storage_type(storage_type&& other) noexcept(std::is_nothrow_move_constructible_v<E>) {
379     move_from(std::move(other));
380   }
381   constexpr storage_type& operator=(storage_type&& other) noexcept(
382       std::is_nothrow_move_assignable_v<E>) {
383     destroy();
384     move_from(std::move(other));
385     return *this;
386   }
387 
388   // Copy/move-constructs over this object's value. If there could be a previous value, callers must
389   // call destroy() first.
390   constexpr void copy_from(const storage_type& other) {
391     state = other.state;
392     if (state == state_e::has_error) {
393       error_or_value.copy_from(error_v, other.error_or_value.error);
394     }
395   }
396   constexpr void move_from(storage_type&& other) {
397     state = other.state;
398     if (state == state_e::has_error) {
399       error_or_value.move_from(error_v, std::move(other.error_or_value.error));
400     }
401   }
402 
403   constexpr void destroy() {
404     if (state == state_e::has_error) {
405       error_or_value.destroy(error_v);
406     }
407   }
408 
409   constexpr void reset() {
410     destroy();
411     state = state_e::empty;
412   }
413 
414   ~storage_type() { destroy(); }
415 
416   explicit constexpr storage_type(empty_t) {}
417 
418   explicit constexpr storage_type(value_t)
419       : state{state_e::has_value}, error_or_value{value_v, empty_type{}} {}
420 
421   template <typename F>
422   constexpr storage_type(error_t, F&& error)
423       : state{state_e::has_error}, error_or_value{error_v, std::forward<F>(error)} {}
424 
425   template <storage_class_e other_storage_class, typename F>
426   explicit constexpr storage_type(storage_type<other_storage_class, F>&& other)
427       : state{other.state},
428         error_or_value{other.state == state_e::empty ? value_type{}
429                        : other.state == state_e::has_error
430                            ? value_type{error_v, std::move(other.error_or_value.error)}
431                            : value_type{value_v, std::move(other.error_or_value.value)}} {}
432 
433   state_e state{state_e::empty};
434   value_type error_or_value;
435 };
436 
437 // Simplified alias of storage_type.
438 template <typename E, typename... Ts>
439 using storage = storage_type<storage_class_trait<E, Ts...>, E, Ts...>;
440 
441 }  // namespace internal
442 }  // namespace fit
443 
444 #endif  // LIB_FIT_INTERNAL_RESULT_H_
445