1 // Copyright 2020 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 #ifndef ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ 15 #define ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ 16 17 #include <cstdint> 18 #include <type_traits> 19 #include <utility> 20 21 #include "absl/base/attributes.h" 22 #include "absl/base/nullability.h" 23 #include "absl/meta/type_traits.h" 24 #include "absl/status/status.h" 25 #include "absl/strings/string_view.h" 26 #include "absl/utility/utility.h" 27 28 namespace absl { 29 ABSL_NAMESPACE_BEGIN 30 31 template <typename T> 32 class ABSL_MUST_USE_RESULT StatusOr; 33 34 namespace internal_statusor { 35 36 // Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator 37 // StatusOr<T>()`. 38 template <typename T, typename U, typename = void> 39 struct HasConversionOperatorToStatusOr : std::false_type {}; 40 41 template <typename T, typename U> 42 void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]); 43 44 template <typename T, typename U> 45 struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))> 46 : std::true_type {}; 47 48 // Detects whether `T` is constructible or convertible from `StatusOr<U>`. 49 template <typename T, typename U> 50 using IsConstructibleOrConvertibleFromStatusOr = 51 absl::disjunction<std::is_constructible<T, StatusOr<U>&>, 52 std::is_constructible<T, const StatusOr<U>&>, 53 std::is_constructible<T, StatusOr<U>&&>, 54 std::is_constructible<T, const StatusOr<U>&&>, 55 std::is_convertible<StatusOr<U>&, T>, 56 std::is_convertible<const StatusOr<U>&, T>, 57 std::is_convertible<StatusOr<U>&&, T>, 58 std::is_convertible<const StatusOr<U>&&, T>>; 59 60 // Detects whether `T` is constructible or convertible or assignable from 61 // `StatusOr<U>`. 62 template <typename T, typename U> 63 using IsConstructibleOrConvertibleOrAssignableFromStatusOr = 64 absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>, 65 std::is_assignable<T&, StatusOr<U>&>, 66 std::is_assignable<T&, const StatusOr<U>&>, 67 std::is_assignable<T&, StatusOr<U>&&>, 68 std::is_assignable<T&, const StatusOr<U>&&>>; 69 70 // Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e. 71 // when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`. 72 template <typename T, typename U> 73 struct IsDirectInitializationAmbiguous 74 : public absl::conditional_t< 75 std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type, 76 IsDirectInitializationAmbiguous<T, absl::remove_cvref_t<U>>> {}; 77 78 template <typename T, typename V> 79 struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>> 80 : public IsConstructibleOrConvertibleFromStatusOr<T, V> {}; 81 82 // Checks against the constraints of the direction initialization, i.e. when 83 // `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution. 84 template <typename T, typename U> 85 using IsDirectInitializationValid = absl::disjunction< 86 // Short circuits if T is basically U. 87 std::is_same<T, absl::remove_cvref_t<U>>, 88 absl::negation<absl::disjunction< 89 std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>, 90 std::is_same<absl::Status, absl::remove_cvref_t<U>>, 91 std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>, 92 IsDirectInitializationAmbiguous<T, U>>>>; 93 94 // This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which 95 // is equivalent to whether all the following conditions are met: 96 // 1. `U` is `StatusOr<V>`. 97 // 2. `T` is constructible and assignable from `V`. 98 // 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`). 99 // For example, the following code is considered ambiguous: 100 // (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`) 101 // StatusOr<bool> s1 = true; // s1.ok() && s1.ValueOrDie() == true 102 // StatusOr<bool> s2 = false; // s2.ok() && s2.ValueOrDie() == false 103 // s1 = s2; // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`? 104 template <typename T, typename U> 105 struct IsForwardingAssignmentAmbiguous 106 : public absl::conditional_t< 107 std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type, 108 IsForwardingAssignmentAmbiguous<T, absl::remove_cvref_t<U>>> {}; 109 110 template <typename T, typename U> 111 struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>> 112 : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {}; 113 114 // Checks against the constraints of the forwarding assignment, i.e. whether 115 // `StatusOr<T>::operator(U&&)` should participate in overload resolution. 116 template <typename T, typename U> 117 using IsForwardingAssignmentValid = absl::disjunction< 118 // Short circuits if T is basically U. 119 std::is_same<T, absl::remove_cvref_t<U>>, 120 absl::negation<absl::disjunction< 121 std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>, 122 std::is_same<absl::Status, absl::remove_cvref_t<U>>, 123 std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>, 124 IsForwardingAssignmentAmbiguous<T, U>>>>; 125 126 template <bool Value, typename T> 127 using Equality = std::conditional_t<Value, T, absl::negation<T>>; 128 129 template <bool Explicit, typename T, typename U, bool Lifetimebound> 130 using IsConstructionValid = absl::conjunction< 131 Equality<Lifetimebound, 132 type_traits_internal::IsLifetimeBoundAssignment<T, U>>, 133 IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>, 134 Equality<!Explicit, std::is_convertible<U&&, T>>, 135 absl::disjunction< 136 std::is_same<T, absl::remove_cvref_t<U>>, 137 absl::conjunction< 138 std::conditional_t< 139 Explicit, 140 absl::negation<std::is_constructible<absl::Status, U&&>>, 141 absl::negation<std::is_convertible<U&&, absl::Status>>>, 142 absl::negation< 143 internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>; 144 145 template <typename T, typename U, bool Lifetimebound> 146 using IsAssignmentValid = absl::conjunction< 147 Equality<Lifetimebound, 148 type_traits_internal::IsLifetimeBoundAssignment<T, U>>, 149 std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>, 150 absl::disjunction< 151 std::is_same<T, absl::remove_cvref_t<U>>, 152 absl::conjunction< 153 absl::negation<std::is_convertible<U&&, absl::Status>>, 154 absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>, 155 IsForwardingAssignmentValid<T, U&&>>; 156 157 template <bool Explicit, typename T, typename U> 158 using IsConstructionFromStatusValid = absl::conjunction< 159 absl::negation<std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>>, 160 absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>, 161 absl::negation<std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>>, 162 Equality<!Explicit, std::is_convertible<U, absl::Status>>, 163 std::is_constructible<absl::Status, U>, 164 absl::negation<HasConversionOperatorToStatusOr<T, U>>>; 165 166 template <bool Explicit, typename T, typename U, bool Lifetimebound, 167 typename UQ> 168 using IsConstructionFromStatusOrValid = absl::conjunction< 169 absl::negation<std::is_same<T, U>>, 170 Equality<Lifetimebound, 171 type_traits_internal::IsLifetimeBoundAssignment<T, U>>, 172 std::is_constructible<T, UQ>, 173 Equality<!Explicit, std::is_convertible<UQ, T>>, 174 absl::negation<IsConstructibleOrConvertibleFromStatusOr<T, U>>>; 175 176 template <typename T, typename U, bool Lifetimebound> 177 using IsStatusOrAssignmentValid = absl::conjunction< 178 absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>, 179 Equality<Lifetimebound, 180 type_traits_internal::IsLifetimeBoundAssignment<T, U>>, 181 std::is_constructible<T, U>, std::is_assignable<T, U>, 182 absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr< 183 T, absl::remove_cvref_t<U>>>>; 184 185 class Helper { 186 public: 187 // Move type-agnostic error handling to the .cc. 188 static void HandleInvalidStatusCtorArg(absl::Nonnull<Status*>); 189 [[noreturn]] static void Crash(const absl::Status& status); 190 }; 191 192 // Construct an instance of T in `p` through placement new, passing Args... to 193 // the constructor. 194 // This abstraction is here mostly for the gcc performance fix. 195 template <typename T, typename... Args> 196 ABSL_ATTRIBUTE_NONNULL(1) 197 void PlacementNew(absl::Nonnull<void*> p, Args&&... args) { 198 new (p) T(std::forward<Args>(args)...); 199 } 200 201 // Helper base class to hold the data and all operations. 202 // We move all this to a base class to allow mixing with the appropriate 203 // TraitsBase specialization. 204 template <typename T> 205 class StatusOrData { 206 template <typename U> 207 friend class StatusOrData; 208 209 public: 210 StatusOrData() = delete; 211 212 StatusOrData(const StatusOrData& other) { 213 if (other.ok()) { 214 MakeValue(other.data_); 215 MakeStatus(); 216 } else { 217 MakeStatus(other.status_); 218 } 219 } 220 221 StatusOrData(StatusOrData&& other) noexcept { 222 if (other.ok()) { 223 MakeValue(std::move(other.data_)); 224 MakeStatus(); 225 } else { 226 MakeStatus(std::move(other.status_)); 227 } 228 } 229 230 template <typename U> 231 explicit StatusOrData(const StatusOrData<U>& other) { 232 if (other.ok()) { 233 MakeValue(other.data_); 234 MakeStatus(); 235 } else { 236 MakeStatus(other.status_); 237 } 238 } 239 240 template <typename U> 241 explicit StatusOrData(StatusOrData<U>&& other) { 242 if (other.ok()) { 243 MakeValue(std::move(other.data_)); 244 MakeStatus(); 245 } else { 246 MakeStatus(std::move(other.status_)); 247 } 248 } 249 250 template <typename... Args> 251 explicit StatusOrData(absl::in_place_t, Args&&... args) 252 : data_(std::forward<Args>(args)...) { 253 MakeStatus(); 254 } 255 256 explicit StatusOrData(const T& value) : data_(value) { 257 MakeStatus(); 258 } 259 explicit StatusOrData(T&& value) : data_(std::move(value)) { 260 MakeStatus(); 261 } 262 263 template <typename U, 264 absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value, 265 int> = 0> 266 explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) { 267 EnsureNotOk(); 268 } 269 270 StatusOrData& operator=(const StatusOrData& other) { 271 if (this == &other) return *this; 272 if (other.ok()) 273 Assign(other.data_); 274 else 275 AssignStatus(other.status_); 276 return *this; 277 } 278 279 StatusOrData& operator=(StatusOrData&& other) { 280 if (this == &other) return *this; 281 if (other.ok()) 282 Assign(std::move(other.data_)); 283 else 284 AssignStatus(std::move(other.status_)); 285 return *this; 286 } 287 288 ~StatusOrData() { 289 if (ok()) { 290 status_.~Status(); 291 data_.~T(); 292 } else { 293 status_.~Status(); 294 } 295 } 296 297 template <typename U> 298 void Assign(U&& value) { 299 if (ok()) { 300 data_ = std::forward<U>(value); 301 } else { 302 MakeValue(std::forward<U>(value)); 303 status_ = OkStatus(); 304 } 305 } 306 307 template <typename U> 308 void AssignStatus(U&& v) { 309 Clear(); 310 status_ = static_cast<absl::Status>(std::forward<U>(v)); 311 EnsureNotOk(); 312 } 313 314 bool ok() const { return status_.ok(); } 315 316 protected: 317 // status_ will always be active after the constructor. 318 // We make it a union to be able to initialize exactly how we need without 319 // waste. 320 // Eg. in the copy constructor we use the default constructor of Status in 321 // the ok() path to avoid an extra Ref call. 322 union { 323 Status status_; 324 }; 325 326 // data_ is active iff status_.ok()==true 327 struct Dummy {}; 328 union { 329 // When T is const, we need some non-const object we can cast to void* for 330 // the placement new. dummy_ is that object. 331 Dummy dummy_; 332 T data_; 333 }; 334 335 void Clear() { 336 if (ok()) data_.~T(); 337 } 338 339 void EnsureOk() const { 340 if (ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_); 341 } 342 343 void EnsureNotOk() { 344 if (ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_); 345 } 346 347 // Construct the value (ie. data_) through placement new with the passed 348 // argument. 349 template <typename... Arg> 350 void MakeValue(Arg&&... arg) { 351 internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...); 352 } 353 354 // Construct the status (ie. status_) through placement new with the passed 355 // argument. 356 template <typename... Args> 357 void MakeStatus(Args&&... args) { 358 internal_statusor::PlacementNew<Status>(&status_, 359 std::forward<Args>(args)...); 360 } 361 }; 362 363 // Helper base classes to allow implicitly deleted constructors and assignment 364 // operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete 365 // the copy constructor when T is not copy constructible and `StatusOr` will 366 // inherit that behavior implicitly. 367 template <typename T, bool = std::is_copy_constructible<T>::value> 368 struct CopyCtorBase { 369 CopyCtorBase() = default; 370 CopyCtorBase(const CopyCtorBase&) = default; 371 CopyCtorBase(CopyCtorBase&&) = default; 372 CopyCtorBase& operator=(const CopyCtorBase&) = default; 373 CopyCtorBase& operator=(CopyCtorBase&&) = default; 374 }; 375 376 template <typename T> 377 struct CopyCtorBase<T, false> { 378 CopyCtorBase() = default; 379 CopyCtorBase(const CopyCtorBase&) = delete; 380 CopyCtorBase(CopyCtorBase&&) = default; 381 CopyCtorBase& operator=(const CopyCtorBase&) = default; 382 CopyCtorBase& operator=(CopyCtorBase&&) = default; 383 }; 384 385 template <typename T, bool = std::is_move_constructible<T>::value> 386 struct MoveCtorBase { 387 MoveCtorBase() = default; 388 MoveCtorBase(const MoveCtorBase&) = default; 389 MoveCtorBase(MoveCtorBase&&) = default; 390 MoveCtorBase& operator=(const MoveCtorBase&) = default; 391 MoveCtorBase& operator=(MoveCtorBase&&) = default; 392 }; 393 394 template <typename T> 395 struct MoveCtorBase<T, false> { 396 MoveCtorBase() = default; 397 MoveCtorBase(const MoveCtorBase&) = default; 398 MoveCtorBase(MoveCtorBase&&) = delete; 399 MoveCtorBase& operator=(const MoveCtorBase&) = default; 400 MoveCtorBase& operator=(MoveCtorBase&&) = default; 401 }; 402 403 template <typename T, bool = std::is_copy_constructible<T>::value&& 404 std::is_copy_assignable<T>::value> 405 struct CopyAssignBase { 406 CopyAssignBase() = default; 407 CopyAssignBase(const CopyAssignBase&) = default; 408 CopyAssignBase(CopyAssignBase&&) = default; 409 CopyAssignBase& operator=(const CopyAssignBase&) = default; 410 CopyAssignBase& operator=(CopyAssignBase&&) = default; 411 }; 412 413 template <typename T> 414 struct CopyAssignBase<T, false> { 415 CopyAssignBase() = default; 416 CopyAssignBase(const CopyAssignBase&) = default; 417 CopyAssignBase(CopyAssignBase&&) = default; 418 CopyAssignBase& operator=(const CopyAssignBase&) = delete; 419 CopyAssignBase& operator=(CopyAssignBase&&) = default; 420 }; 421 422 template <typename T, bool = std::is_move_constructible<T>::value&& 423 std::is_move_assignable<T>::value> 424 struct MoveAssignBase { 425 MoveAssignBase() = default; 426 MoveAssignBase(const MoveAssignBase&) = default; 427 MoveAssignBase(MoveAssignBase&&) = default; 428 MoveAssignBase& operator=(const MoveAssignBase&) = default; 429 MoveAssignBase& operator=(MoveAssignBase&&) = default; 430 }; 431 432 template <typename T> 433 struct MoveAssignBase<T, false> { 434 MoveAssignBase() = default; 435 MoveAssignBase(const MoveAssignBase&) = default; 436 MoveAssignBase(MoveAssignBase&&) = default; 437 MoveAssignBase& operator=(const MoveAssignBase&) = default; 438 MoveAssignBase& operator=(MoveAssignBase&&) = delete; 439 }; 440 441 [[noreturn]] void ThrowBadStatusOrAccess(absl::Status status); 442 443 // Used to introduce jitter into the output of printing functions for 444 // `StatusOr` (i.e. `AbslStringify` and `operator<<`). 445 class StringifyRandom { 446 enum BracesType { 447 kBareParens = 0, 448 kSpaceParens, 449 kBareBrackets, 450 kSpaceBrackets, 451 }; 452 453 // Returns a random `BracesType` determined once per binary load. 454 static BracesType RandomBraces() { 455 static const BracesType kRandomBraces = static_cast<BracesType>( 456 (reinterpret_cast<uintptr_t>(&kRandomBraces) >> 4) % 4); 457 return kRandomBraces; 458 } 459 460 public: 461 static inline absl::string_view OpenBrackets() { 462 switch (RandomBraces()) { 463 case kBareParens: 464 return "("; 465 case kSpaceParens: 466 return "( "; 467 case kBareBrackets: 468 return "["; 469 case kSpaceBrackets: 470 return "[ "; 471 } 472 return "("; 473 } 474 475 static inline absl::string_view CloseBrackets() { 476 switch (RandomBraces()) { 477 case kBareParens: 478 return ")"; 479 case kSpaceParens: 480 return " )"; 481 case kBareBrackets: 482 return "]"; 483 case kSpaceBrackets: 484 return " ]"; 485 } 486 return ")"; 487 } 488 }; 489 490 } // namespace internal_statusor 491 ABSL_NAMESPACE_END 492 } // namespace absl 493 494 #endif // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ 495