| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #ifndef ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ |
| #define ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_ |
|
|
| #include <cstdint> |
| #include <type_traits> |
| #include <utility> |
|
|
| #include "absl/base/attributes.h" |
| #include "absl/base/nullability.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/status/status.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/utility/utility.h" |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
|
|
| template <typename T> |
| class ABSL_MUST_USE_RESULT StatusOr; |
|
|
| namespace internal_statusor { |
|
|
| |
| |
| template <typename T, typename U, typename = void> |
| struct HasConversionOperatorToStatusOr : std::false_type {}; |
|
|
| template <typename T, typename U> |
| void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]); |
|
|
| template <typename T, typename U> |
| struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))> |
| : std::true_type {}; |
|
|
| |
| template <typename T, typename U> |
| using IsConstructibleOrConvertibleFromStatusOr = |
| absl::disjunction<std::is_constructible<T, StatusOr<U>&>, |
| std::is_constructible<T, const StatusOr<U>&>, |
| std::is_constructible<T, StatusOr<U>&&>, |
| std::is_constructible<T, const StatusOr<U>&&>, |
| std::is_convertible<StatusOr<U>&, T>, |
| std::is_convertible<const StatusOr<U>&, T>, |
| std::is_convertible<StatusOr<U>&&, T>, |
| std::is_convertible<const StatusOr<U>&&, T>>; |
|
|
| |
| |
| template <typename T, typename U> |
| using IsConstructibleOrConvertibleOrAssignableFromStatusOr = |
| absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>, |
| std::is_assignable<T&, StatusOr<U>&>, |
| std::is_assignable<T&, const StatusOr<U>&>, |
| std::is_assignable<T&, StatusOr<U>&&>, |
| std::is_assignable<T&, const StatusOr<U>&&>>; |
|
|
| |
| |
| template <typename T, typename U> |
| struct IsDirectInitializationAmbiguous |
| : public absl::conditional_t< |
| std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type, |
| IsDirectInitializationAmbiguous<T, absl::remove_cvref_t<U>>> {}; |
|
|
| template <typename T, typename V> |
| struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>> |
| : public IsConstructibleOrConvertibleFromStatusOr<T, V> {}; |
|
|
| |
| |
| template <typename T, typename U> |
| using IsDirectInitializationValid = absl::disjunction< |
| |
| std::is_same<T, absl::remove_cvref_t<U>>, |
| absl::negation<absl::disjunction< |
| std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>, |
| std::is_same<absl::Status, absl::remove_cvref_t<U>>, |
| std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>, |
| IsDirectInitializationAmbiguous<T, U>>>>; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename T, typename U> |
| struct IsForwardingAssignmentAmbiguous |
| : public absl::conditional_t< |
| std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type, |
| IsForwardingAssignmentAmbiguous<T, absl::remove_cvref_t<U>>> {}; |
|
|
| template <typename T, typename U> |
| struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>> |
| : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {}; |
|
|
| |
| |
| template <typename T, typename U> |
| using IsForwardingAssignmentValid = absl::disjunction< |
| |
| std::is_same<T, absl::remove_cvref_t<U>>, |
| absl::negation<absl::disjunction< |
| std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>, |
| std::is_same<absl::Status, absl::remove_cvref_t<U>>, |
| std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>, |
| IsForwardingAssignmentAmbiguous<T, U>>>>; |
|
|
| class Helper { |
| public: |
| |
| static void HandleInvalidStatusCtorArg(absl::Nonnull<Status*>); |
| ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status); |
| }; |
|
|
| |
| |
| |
| template <typename T, typename... Args> |
| ABSL_ATTRIBUTE_NONNULL(1) |
| void PlacementNew(absl::Nonnull<void*> p, Args&&... args) { |
| new (p) T(std::forward<Args>(args)...); |
| } |
|
|
| |
| |
| |
| template <typename T> |
| class StatusOrData { |
| template <typename U> |
| friend class StatusOrData; |
|
|
| public: |
| StatusOrData() = delete; |
|
|
| StatusOrData(const StatusOrData& other) { |
| if (other.ok()) { |
| MakeValue(other.data_); |
| MakeStatus(); |
| } else { |
| MakeStatus(other.status_); |
| } |
| } |
|
|
| StatusOrData(StatusOrData&& other) noexcept { |
| if (other.ok()) { |
| MakeValue(std::move(other.data_)); |
| MakeStatus(); |
| } else { |
| MakeStatus(std::move(other.status_)); |
| } |
| } |
|
|
| template <typename U> |
| explicit StatusOrData(const StatusOrData<U>& other) { |
| if (other.ok()) { |
| MakeValue(other.data_); |
| MakeStatus(); |
| } else { |
| MakeStatus(other.status_); |
| } |
| } |
|
|
| template <typename U> |
| explicit StatusOrData(StatusOrData<U>&& other) { |
| if (other.ok()) { |
| MakeValue(std::move(other.data_)); |
| MakeStatus(); |
| } else { |
| MakeStatus(std::move(other.status_)); |
| } |
| } |
|
|
| template <typename... Args> |
| explicit StatusOrData(absl::in_place_t, Args&&... args) |
| : data_(std::forward<Args>(args)...) { |
| MakeStatus(); |
| } |
|
|
| explicit StatusOrData(const T& value) : data_(value) { |
| MakeStatus(); |
| } |
| explicit StatusOrData(T&& value) : data_(std::move(value)) { |
| MakeStatus(); |
| } |
|
|
| template <typename U, |
| absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value, |
| int> = 0> |
| explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) { |
| EnsureNotOk(); |
| } |
|
|
| StatusOrData& operator=(const StatusOrData& other) { |
| if (this == &other) return *this; |
| if (other.ok()) |
| Assign(other.data_); |
| else |
| AssignStatus(other.status_); |
| return *this; |
| } |
|
|
| StatusOrData& operator=(StatusOrData&& other) { |
| if (this == &other) return *this; |
| if (other.ok()) |
| Assign(std::move(other.data_)); |
| else |
| AssignStatus(std::move(other.status_)); |
| return *this; |
| } |
|
|
| ~StatusOrData() { |
| if (ok()) { |
| status_.~Status(); |
| data_.~T(); |
| } else { |
| status_.~Status(); |
| } |
| } |
|
|
| template <typename U> |
| void Assign(U&& value) { |
| if (ok()) { |
| data_ = std::forward<U>(value); |
| } else { |
| MakeValue(std::forward<U>(value)); |
| status_ = OkStatus(); |
| } |
| } |
|
|
| template <typename U> |
| void AssignStatus(U&& v) { |
| Clear(); |
| status_ = static_cast<absl::Status>(std::forward<U>(v)); |
| EnsureNotOk(); |
| } |
|
|
| bool ok() const { return status_.ok(); } |
|
|
| protected: |
| |
| |
| |
| |
| |
| union { |
| Status status_; |
| }; |
|
|
| |
| struct Dummy {}; |
| union { |
| |
| |
| Dummy dummy_; |
| T data_; |
| }; |
|
|
| void Clear() { |
| if (ok()) data_.~T(); |
| } |
|
|
| void EnsureOk() const { |
| if (ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_); |
| } |
|
|
| void EnsureNotOk() { |
| if (ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_); |
| } |
|
|
| |
| |
| template <typename... Arg> |
| void MakeValue(Arg&&... arg) { |
| internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...); |
| } |
|
|
| |
| |
| template <typename... Args> |
| void MakeStatus(Args&&... args) { |
| internal_statusor::PlacementNew<Status>(&status_, |
| std::forward<Args>(args)...); |
| } |
| }; |
|
|
| |
| |
| |
| |
| template <typename T, bool = std::is_copy_constructible<T>::value> |
| struct CopyCtorBase { |
| CopyCtorBase() = default; |
| CopyCtorBase(const CopyCtorBase&) = default; |
| CopyCtorBase(CopyCtorBase&&) = default; |
| CopyCtorBase& operator=(const CopyCtorBase&) = default; |
| CopyCtorBase& operator=(CopyCtorBase&&) = default; |
| }; |
|
|
| template <typename T> |
| struct CopyCtorBase<T, false> { |
| CopyCtorBase() = default; |
| CopyCtorBase(const CopyCtorBase&) = delete; |
| CopyCtorBase(CopyCtorBase&&) = default; |
| CopyCtorBase& operator=(const CopyCtorBase&) = default; |
| CopyCtorBase& operator=(CopyCtorBase&&) = default; |
| }; |
|
|
| template <typename T, bool = std::is_move_constructible<T>::value> |
| struct MoveCtorBase { |
| MoveCtorBase() = default; |
| MoveCtorBase(const MoveCtorBase&) = default; |
| MoveCtorBase(MoveCtorBase&&) = default; |
| MoveCtorBase& operator=(const MoveCtorBase&) = default; |
| MoveCtorBase& operator=(MoveCtorBase&&) = default; |
| }; |
|
|
| template <typename T> |
| struct MoveCtorBase<T, false> { |
| MoveCtorBase() = default; |
| MoveCtorBase(const MoveCtorBase&) = default; |
| MoveCtorBase(MoveCtorBase&&) = delete; |
| MoveCtorBase& operator=(const MoveCtorBase&) = default; |
| MoveCtorBase& operator=(MoveCtorBase&&) = default; |
| }; |
|
|
| template <typename T, bool = std::is_copy_constructible<T>::value&& |
| std::is_copy_assignable<T>::value> |
| struct CopyAssignBase { |
| CopyAssignBase() = default; |
| CopyAssignBase(const CopyAssignBase&) = default; |
| CopyAssignBase(CopyAssignBase&&) = default; |
| CopyAssignBase& operator=(const CopyAssignBase&) = default; |
| CopyAssignBase& operator=(CopyAssignBase&&) = default; |
| }; |
|
|
| template <typename T> |
| struct CopyAssignBase<T, false> { |
| CopyAssignBase() = default; |
| CopyAssignBase(const CopyAssignBase&) = default; |
| CopyAssignBase(CopyAssignBase&&) = default; |
| CopyAssignBase& operator=(const CopyAssignBase&) = delete; |
| CopyAssignBase& operator=(CopyAssignBase&&) = default; |
| }; |
|
|
| template <typename T, bool = std::is_move_constructible<T>::value&& |
| std::is_move_assignable<T>::value> |
| struct MoveAssignBase { |
| MoveAssignBase() = default; |
| MoveAssignBase(const MoveAssignBase&) = default; |
| MoveAssignBase(MoveAssignBase&&) = default; |
| MoveAssignBase& operator=(const MoveAssignBase&) = default; |
| MoveAssignBase& operator=(MoveAssignBase&&) = default; |
| }; |
|
|
| template <typename T> |
| struct MoveAssignBase<T, false> { |
| MoveAssignBase() = default; |
| MoveAssignBase(const MoveAssignBase&) = default; |
| MoveAssignBase(MoveAssignBase&&) = default; |
| MoveAssignBase& operator=(const MoveAssignBase&) = default; |
| MoveAssignBase& operator=(MoveAssignBase&&) = delete; |
| }; |
|
|
| ABSL_ATTRIBUTE_NORETURN void ThrowBadStatusOrAccess(absl::Status status); |
|
|
| |
| |
| class StringifyRandom { |
| enum BracesType { |
| kBareParens = 0, |
| kSpaceParens, |
| kBareBrackets, |
| kSpaceBrackets, |
| }; |
|
|
| |
| static BracesType RandomBraces() { |
| static const BracesType kRandomBraces = static_cast<BracesType>( |
| (reinterpret_cast<uintptr_t>(&kRandomBraces) >> 4) % 4); |
| return kRandomBraces; |
| } |
|
|
| public: |
| static inline absl::string_view OpenBrackets() { |
| switch (RandomBraces()) { |
| case kBareParens: |
| return "("; |
| case kSpaceParens: |
| return "( "; |
| case kBareBrackets: |
| return "["; |
| case kSpaceBrackets: |
| return "[ "; |
| } |
| return "("; |
| } |
|
|
| static inline absl::string_view CloseBrackets() { |
| switch (RandomBraces()) { |
| case kBareParens: |
| return ")"; |
| case kSpaceParens: |
| return " )"; |
| case kBareBrackets: |
| return "]"; |
| case kSpaceBrackets: |
| return " ]"; |
| } |
| return ")"; |
| } |
| }; |
|
|
| } |
| ABSL_NAMESPACE_END |
| } |
|
|
| #endif |
|
|