Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-31 09:33:37

0001 // Copyright 2020 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 #ifndef ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
0015 #define ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
0016 
0017 #include <cstdint>
0018 #include <type_traits>
0019 #include <utility>
0020 
0021 #include "absl/base/attributes.h"
0022 #include "absl/base/nullability.h"
0023 #include "absl/meta/type_traits.h"
0024 #include "absl/status/status.h"
0025 #include "absl/strings/string_view.h"
0026 #include "absl/utility/utility.h"
0027 
0028 namespace absl {
0029 ABSL_NAMESPACE_BEGIN
0030 
0031 template <typename T>
0032 class ABSL_MUST_USE_RESULT StatusOr;
0033 
0034 namespace internal_statusor {
0035 
0036 // Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator
0037 // StatusOr<T>()`.
0038 template <typename T, typename U, typename = void>
0039 struct HasConversionOperatorToStatusOr : std::false_type {};
0040 
0041 template <typename T, typename U>
0042 void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]);
0043 
0044 template <typename T, typename U>
0045 struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
0046     : std::true_type {};
0047 
0048 // Detects whether `T` is constructible or convertible from `StatusOr<U>`.
0049 template <typename T, typename U>
0050 using IsConstructibleOrConvertibleFromStatusOr =
0051     absl::disjunction<std::is_constructible<T, StatusOr<U>&>,
0052                       std::is_constructible<T, const StatusOr<U>&>,
0053                       std::is_constructible<T, StatusOr<U>&&>,
0054                       std::is_constructible<T, const StatusOr<U>&&>,
0055                       std::is_convertible<StatusOr<U>&, T>,
0056                       std::is_convertible<const StatusOr<U>&, T>,
0057                       std::is_convertible<StatusOr<U>&&, T>,
0058                       std::is_convertible<const StatusOr<U>&&, T>>;
0059 
0060 // Detects whether `T` is constructible or convertible or assignable from
0061 // `StatusOr<U>`.
0062 template <typename T, typename U>
0063 using IsConstructibleOrConvertibleOrAssignableFromStatusOr =
0064     absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>,
0065                       std::is_assignable<T&, StatusOr<U>&>,
0066                       std::is_assignable<T&, const StatusOr<U>&>,
0067                       std::is_assignable<T&, StatusOr<U>&&>,
0068                       std::is_assignable<T&, const StatusOr<U>&&>>;
0069 
0070 // Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e.
0071 // when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`.
0072 template <typename T, typename U>
0073 struct IsDirectInitializationAmbiguous
0074     : public absl::conditional_t<
0075           std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type,
0076           IsDirectInitializationAmbiguous<T, absl::remove_cvref_t<U>>> {};
0077 
0078 template <typename T, typename V>
0079 struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>
0080     : public IsConstructibleOrConvertibleFromStatusOr<T, V> {};
0081 
0082 // Checks against the constraints of the direction initialization, i.e. when
0083 // `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution.
0084 template <typename T, typename U>
0085 using IsDirectInitializationValid = absl::disjunction<
0086     // Short circuits if T is basically U.
0087     std::is_same<T, absl::remove_cvref_t<U>>,
0088     absl::negation<absl::disjunction<
0089         std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
0090         std::is_same<absl::Status, absl::remove_cvref_t<U>>,
0091         std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
0092         IsDirectInitializationAmbiguous<T, U>>>>;
0093 
0094 // This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which
0095 // is equivalent to whether all the following conditions are met:
0096 // 1. `U` is `StatusOr<V>`.
0097 // 2. `T` is constructible and assignable from `V`.
0098 // 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`).
0099 // For example, the following code is considered ambiguous:
0100 // (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`)
0101 //   StatusOr<bool> s1 = true;  // s1.ok() && s1.ValueOrDie() == true
0102 //   StatusOr<bool> s2 = false;  // s2.ok() && s2.ValueOrDie() == false
0103 //   s1 = s2;  // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`?
0104 template <typename T, typename U>
0105 struct IsForwardingAssignmentAmbiguous
0106     : public absl::conditional_t<
0107           std::is_same<absl::remove_cvref_t<U>, U>::value, std::false_type,
0108           IsForwardingAssignmentAmbiguous<T, absl::remove_cvref_t<U>>> {};
0109 
0110 template <typename T, typename U>
0111 struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>>
0112     : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {};
0113 
0114 // Checks against the constraints of the forwarding assignment, i.e. whether
0115 // `StatusOr<T>::operator(U&&)` should participate in overload resolution.
0116 template <typename T, typename U>
0117 using IsForwardingAssignmentValid = absl::disjunction<
0118     // Short circuits if T is basically U.
0119     std::is_same<T, absl::remove_cvref_t<U>>,
0120     absl::negation<absl::disjunction<
0121         std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>,
0122         std::is_same<absl::Status, absl::remove_cvref_t<U>>,
0123         std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
0124         IsForwardingAssignmentAmbiguous<T, U>>>>;
0125 
0126 template <bool Value, typename T>
0127 using Equality = std::conditional_t<Value, T, absl::negation<T>>;
0128 
0129 template <bool Explicit, typename T, typename U, bool Lifetimebound>
0130 using IsConstructionValid = absl::conjunction<
0131     Equality<Lifetimebound,
0132              type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
0133     IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>,
0134     Equality<!Explicit, std::is_convertible<U&&, T>>,
0135     absl::disjunction<
0136         std::is_same<T, absl::remove_cvref_t<U>>,
0137         absl::conjunction<
0138             std::conditional_t<
0139                 Explicit,
0140                 absl::negation<std::is_constructible<absl::Status, U&&>>,
0141                 absl::negation<std::is_convertible<U&&, absl::Status>>>,
0142             absl::negation<
0143                 internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>;
0144 
0145 template <typename T, typename U, bool Lifetimebound>
0146 using IsAssignmentValid = absl::conjunction<
0147     Equality<Lifetimebound,
0148              type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
0149     std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
0150     absl::disjunction<
0151         std::is_same<T, absl::remove_cvref_t<U>>,
0152         absl::conjunction<
0153             absl::negation<std::is_convertible<U&&, absl::Status>>,
0154             absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>,
0155     IsForwardingAssignmentValid<T, U&&>>;
0156 
0157 template <bool Explicit, typename T, typename U>
0158 using IsConstructionFromStatusValid = absl::conjunction<
0159     absl::negation<std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>>,
0160     absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
0161     absl::negation<std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>>,
0162     Equality<!Explicit, std::is_convertible<U, absl::Status>>,
0163     std::is_constructible<absl::Status, U>,
0164     absl::negation<HasConversionOperatorToStatusOr<T, U>>>;
0165 
0166 template <bool Explicit, typename T, typename U, bool Lifetimebound,
0167           typename UQ>
0168 using IsConstructionFromStatusOrValid = absl::conjunction<
0169     absl::negation<std::is_same<T, U>>,
0170     Equality<Lifetimebound,
0171              type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
0172     std::is_constructible<T, UQ>,
0173     Equality<!Explicit, std::is_convertible<UQ, T>>,
0174     absl::negation<IsConstructibleOrConvertibleFromStatusOr<T, U>>>;
0175 
0176 template <typename T, typename U, bool Lifetimebound>
0177 using IsStatusOrAssignmentValid = absl::conjunction<
0178     absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
0179     Equality<Lifetimebound,
0180              type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
0181     std::is_constructible<T, U>, std::is_assignable<T, U>,
0182     absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr<
0183         T, absl::remove_cvref_t<U>>>>;
0184 
0185 class Helper {
0186  public:
0187   // Move type-agnostic error handling to the .cc.
0188   static void HandleInvalidStatusCtorArg(absl::Nonnull<Status*>);
0189   [[noreturn]] static void Crash(const absl::Status& status);
0190 };
0191 
0192 // Construct an instance of T in `p` through placement new, passing Args... to
0193 // the constructor.
0194 // This abstraction is here mostly for the gcc performance fix.
0195 template <typename T, typename... Args>
0196 ABSL_ATTRIBUTE_NONNULL(1)
0197 void PlacementNew(absl::Nonnull<void*> p, Args&&... args) {
0198   new (p) T(std::forward<Args>(args)...);
0199 }
0200 
0201 // Helper base class to hold the data and all operations.
0202 // We move all this to a base class to allow mixing with the appropriate
0203 // TraitsBase specialization.
0204 template <typename T>
0205 class StatusOrData {
0206   template <typename U>
0207   friend class StatusOrData;
0208 
0209  public:
0210   StatusOrData() = delete;
0211 
0212   StatusOrData(const StatusOrData& other) {
0213     if (other.ok()) {
0214       MakeValue(other.data_);
0215       MakeStatus();
0216     } else {
0217       MakeStatus(other.status_);
0218     }
0219   }
0220 
0221   StatusOrData(StatusOrData&& other) noexcept {
0222     if (other.ok()) {
0223       MakeValue(std::move(other.data_));
0224       MakeStatus();
0225     } else {
0226       MakeStatus(std::move(other.status_));
0227     }
0228   }
0229 
0230   template <typename U>
0231   explicit StatusOrData(const StatusOrData<U>& other) {
0232     if (other.ok()) {
0233       MakeValue(other.data_);
0234       MakeStatus();
0235     } else {
0236       MakeStatus(other.status_);
0237     }
0238   }
0239 
0240   template <typename U>
0241   explicit StatusOrData(StatusOrData<U>&& other) {
0242     if (other.ok()) {
0243       MakeValue(std::move(other.data_));
0244       MakeStatus();
0245     } else {
0246       MakeStatus(std::move(other.status_));
0247     }
0248   }
0249 
0250   template <typename... Args>
0251   explicit StatusOrData(absl::in_place_t, Args&&... args)
0252       : data_(std::forward<Args>(args)...) {
0253     MakeStatus();
0254   }
0255 
0256   explicit StatusOrData(const T& value) : data_(value) {
0257     MakeStatus();
0258   }
0259   explicit StatusOrData(T&& value) : data_(std::move(value)) {
0260     MakeStatus();
0261   }
0262 
0263   template <typename U,
0264             absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value,
0265                               int> = 0>
0266   explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) {
0267     EnsureNotOk();
0268   }
0269 
0270   StatusOrData& operator=(const StatusOrData& other) {
0271     if (this == &other) return *this;
0272     if (other.ok())
0273       Assign(other.data_);
0274     else
0275       AssignStatus(other.status_);
0276     return *this;
0277   }
0278 
0279   StatusOrData& operator=(StatusOrData&& other) {
0280     if (this == &other) return *this;
0281     if (other.ok())
0282       Assign(std::move(other.data_));
0283     else
0284       AssignStatus(std::move(other.status_));
0285     return *this;
0286   }
0287 
0288   ~StatusOrData() {
0289     if (ok()) {
0290       status_.~Status();
0291       data_.~T();
0292     } else {
0293       status_.~Status();
0294     }
0295   }
0296 
0297   template <typename U>
0298   void Assign(U&& value) {
0299     if (ok()) {
0300       data_ = std::forward<U>(value);
0301     } else {
0302       MakeValue(std::forward<U>(value));
0303       status_ = OkStatus();
0304     }
0305   }
0306 
0307   template <typename U>
0308   void AssignStatus(U&& v) {
0309     Clear();
0310     status_ = static_cast<absl::Status>(std::forward<U>(v));
0311     EnsureNotOk();
0312   }
0313 
0314   bool ok() const { return status_.ok(); }
0315 
0316  protected:
0317   // status_ will always be active after the constructor.
0318   // We make it a union to be able to initialize exactly how we need without
0319   // waste.
0320   // Eg. in the copy constructor we use the default constructor of Status in
0321   // the ok() path to avoid an extra Ref call.
0322   union {
0323     Status status_;
0324   };
0325 
0326   // data_ is active iff status_.ok()==true
0327   struct Dummy {};
0328   union {
0329     // When T is const, we need some non-const object we can cast to void* for
0330     // the placement new. dummy_ is that object.
0331     Dummy dummy_;
0332     T data_;
0333   };
0334 
0335   void Clear() {
0336     if (ok()) data_.~T();
0337   }
0338 
0339   void EnsureOk() const {
0340     if (ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_);
0341   }
0342 
0343   void EnsureNotOk() {
0344     if (ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_);
0345   }
0346 
0347   // Construct the value (ie. data_) through placement new with the passed
0348   // argument.
0349   template <typename... Arg>
0350   void MakeValue(Arg&&... arg) {
0351     internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...);
0352   }
0353 
0354   // Construct the status (ie. status_) through placement new with the passed
0355   // argument.
0356   template <typename... Args>
0357   void MakeStatus(Args&&... args) {
0358     internal_statusor::PlacementNew<Status>(&status_,
0359                                             std::forward<Args>(args)...);
0360   }
0361 };
0362 
0363 // Helper base classes to allow implicitly deleted constructors and assignment
0364 // operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete
0365 // the copy constructor when T is not copy constructible and `StatusOr` will
0366 // inherit that behavior implicitly.
0367 template <typename T, bool = std::is_copy_constructible<T>::value>
0368 struct CopyCtorBase {
0369   CopyCtorBase() = default;
0370   CopyCtorBase(const CopyCtorBase&) = default;
0371   CopyCtorBase(CopyCtorBase&&) = default;
0372   CopyCtorBase& operator=(const CopyCtorBase&) = default;
0373   CopyCtorBase& operator=(CopyCtorBase&&) = default;
0374 };
0375 
0376 template <typename T>
0377 struct CopyCtorBase<T, false> {
0378   CopyCtorBase() = default;
0379   CopyCtorBase(const CopyCtorBase&) = delete;
0380   CopyCtorBase(CopyCtorBase&&) = default;
0381   CopyCtorBase& operator=(const CopyCtorBase&) = default;
0382   CopyCtorBase& operator=(CopyCtorBase&&) = default;
0383 };
0384 
0385 template <typename T, bool = std::is_move_constructible<T>::value>
0386 struct MoveCtorBase {
0387   MoveCtorBase() = default;
0388   MoveCtorBase(const MoveCtorBase&) = default;
0389   MoveCtorBase(MoveCtorBase&&) = default;
0390   MoveCtorBase& operator=(const MoveCtorBase&) = default;
0391   MoveCtorBase& operator=(MoveCtorBase&&) = default;
0392 };
0393 
0394 template <typename T>
0395 struct MoveCtorBase<T, false> {
0396   MoveCtorBase() = default;
0397   MoveCtorBase(const MoveCtorBase&) = default;
0398   MoveCtorBase(MoveCtorBase&&) = delete;
0399   MoveCtorBase& operator=(const MoveCtorBase&) = default;
0400   MoveCtorBase& operator=(MoveCtorBase&&) = default;
0401 };
0402 
0403 template <typename T, bool = std::is_copy_constructible<T>::value&&
0404                           std::is_copy_assignable<T>::value>
0405 struct CopyAssignBase {
0406   CopyAssignBase() = default;
0407   CopyAssignBase(const CopyAssignBase&) = default;
0408   CopyAssignBase(CopyAssignBase&&) = default;
0409   CopyAssignBase& operator=(const CopyAssignBase&) = default;
0410   CopyAssignBase& operator=(CopyAssignBase&&) = default;
0411 };
0412 
0413 template <typename T>
0414 struct CopyAssignBase<T, false> {
0415   CopyAssignBase() = default;
0416   CopyAssignBase(const CopyAssignBase&) = default;
0417   CopyAssignBase(CopyAssignBase&&) = default;
0418   CopyAssignBase& operator=(const CopyAssignBase&) = delete;
0419   CopyAssignBase& operator=(CopyAssignBase&&) = default;
0420 };
0421 
0422 template <typename T, bool = std::is_move_constructible<T>::value&&
0423                           std::is_move_assignable<T>::value>
0424 struct MoveAssignBase {
0425   MoveAssignBase() = default;
0426   MoveAssignBase(const MoveAssignBase&) = default;
0427   MoveAssignBase(MoveAssignBase&&) = default;
0428   MoveAssignBase& operator=(const MoveAssignBase&) = default;
0429   MoveAssignBase& operator=(MoveAssignBase&&) = default;
0430 };
0431 
0432 template <typename T>
0433 struct MoveAssignBase<T, false> {
0434   MoveAssignBase() = default;
0435   MoveAssignBase(const MoveAssignBase&) = default;
0436   MoveAssignBase(MoveAssignBase&&) = default;
0437   MoveAssignBase& operator=(const MoveAssignBase&) = default;
0438   MoveAssignBase& operator=(MoveAssignBase&&) = delete;
0439 };
0440 
0441 [[noreturn]] void ThrowBadStatusOrAccess(absl::Status status);
0442 
0443 // Used to introduce jitter into the output of printing functions for
0444 // `StatusOr` (i.e. `AbslStringify` and `operator<<`).
0445 class StringifyRandom {
0446   enum BracesType {
0447     kBareParens = 0,
0448     kSpaceParens,
0449     kBareBrackets,
0450     kSpaceBrackets,
0451   };
0452 
0453   // Returns a random `BracesType` determined once per binary load.
0454   static BracesType RandomBraces() {
0455     static const BracesType kRandomBraces = static_cast<BracesType>(
0456         (reinterpret_cast<uintptr_t>(&kRandomBraces) >> 4) % 4);
0457     return kRandomBraces;
0458   }
0459 
0460  public:
0461   static inline absl::string_view OpenBrackets() {
0462     switch (RandomBraces()) {
0463       case kBareParens:
0464         return "(";
0465       case kSpaceParens:
0466         return "( ";
0467       case kBareBrackets:
0468         return "[";
0469       case kSpaceBrackets:
0470         return "[ ";
0471     }
0472     return "(";
0473   }
0474 
0475   static inline absl::string_view CloseBrackets() {
0476     switch (RandomBraces()) {
0477       case kBareParens:
0478         return ")";
0479       case kSpaceParens:
0480         return " )";
0481       case kBareBrackets:
0482         return "]";
0483       case kSpaceBrackets:
0484         return " ]";
0485     }
0486     return ")";
0487   }
0488 };
0489 
0490 }  // namespace internal_statusor
0491 ABSL_NAMESPACE_END
0492 }  // namespace absl
0493 
0494 #endif  // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_