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