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