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