Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-08-27 08:47:19

0001 //
0002 // Copyright 2017 Asylo authors
0003 //
0004 // Licensed under the Apache License, Version 2.0 (the "License");
0005 // you may not use this file except in compliance with the License.
0006 // You may obtain a copy of the License at
0007 //
0008 //     http://www.apache.org/licenses/LICENSE-2.0
0009 //
0010 // Unless required by applicable law or agreed to in writing, software
0011 // distributed under the License is distributed on an "AS IS" BASIS,
0012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013 // See the License for the specific language governing permissions and
0014 // limitations under the License.
0015 //
0016 
0017 // Adapted from Asylo
0018 
0019 #pragma once
0020 
0021 #include <cstddef>
0022 #include <new>
0023 #include <string>
0024 #include <type_traits>
0025 #include <utility>
0026 
0027 #include "arrow/status.h"
0028 #include "arrow/util/aligned_storage.h"
0029 #include "arrow/util/compare.h"
0030 
0031 namespace arrow {
0032 
0033 template <typename>
0034 struct EnsureResult;
0035 
0036 namespace internal {
0037 
0038 ARROW_EXPORT void DieWithMessage(const std::string& msg);
0039 
0040 ARROW_EXPORT void InvalidValueOrDie(const Status& st);
0041 
0042 ARROW_EXPORT Status UninitializedResult();
0043 
0044 }  // namespace internal
0045 
0046 /// A class for representing either a usable value, or an error.
0047 ///
0048 /// A Result object either contains a value of type `T` or a Status object
0049 /// explaining why such a value is not present. The type `T` must be
0050 /// copy-constructible and/or move-constructible.
0051 ///
0052 /// The state of a Result object may be determined by calling ok() or
0053 /// status(). The ok() method returns true if the object contains a valid value.
0054 /// The status() method returns the internal Status object. A Result object
0055 /// that contains a valid value will return an OK Status for a call to status().
0056 ///
0057 /// A value of type `T` may be extracted from a Result object through a call
0058 /// to ValueOrDie(). This function should only be called if a call to ok()
0059 /// returns true. Sample usage:
0060 ///
0061 /// ```
0062 ///   arrow::Result<Foo> result = CalculateFoo();
0063 ///   if (result.ok()) {
0064 ///     Foo foo = result.ValueOrDie();
0065 ///     foo.DoSomethingCool();
0066 ///   } else {
0067 ///     ARROW_LOG(ERROR) << result.status();
0068 ///  }
0069 /// ```
0070 ///
0071 /// If `T` is a move-only type, like `std::unique_ptr<>`, then the value should
0072 /// only be extracted after invoking `std::move()` on the Result object.
0073 /// Sample usage:
0074 ///
0075 /// ```
0076 ///   arrow::Result<std::unique_ptr<Foo>> result = CalculateFoo();
0077 ///   if (result.ok()) {
0078 ///     std::unique_ptr<Foo> foo = std::move(result).ValueOrDie();
0079 ///     foo->DoSomethingCool();
0080 ///   } else {
0081 ///     ARROW_LOG(ERROR) << result.status();
0082 ///   }
0083 /// ```
0084 ///
0085 /// Result is provided for the convenience of implementing functions that
0086 /// return some value but may fail during execution. For instance, consider a
0087 /// function with the following signature:
0088 ///
0089 /// ```
0090 ///   arrow::Status CalculateFoo(int *output);
0091 /// ```
0092 ///
0093 /// This function may instead be written as:
0094 ///
0095 /// ```
0096 ///   arrow::Result<int> CalculateFoo();
0097 /// ```
0098 template <class T>
0099 class [[nodiscard]] Result : public util::EqualityComparable<Result<T>> {
0100   template <typename U>
0101   friend class Result;
0102 
0103   static_assert(!std::is_same<T, Status>::value,
0104                 "this assert indicates you have probably made a metaprogramming error");
0105 
0106  public:
0107   using ValueType = T;
0108 
0109   /// Constructs a Result object that contains a non-OK status.
0110   ///
0111   /// This constructor is marked `explicit` to prevent attempts to `return {}`
0112   /// from a function with a return type of, for example,
0113   /// `Result<std::vector<int>>`. While `return {}` seems like it would return
0114   /// an empty vector, it will actually invoke the default constructor of
0115   /// Result.
0116   explicit Result() noexcept  // NOLINT(runtime/explicit)
0117       : status_(internal::UninitializedResult()) {}
0118 
0119   ~Result() noexcept { Destroy(); }
0120 
0121   /// Constructs a Result object with the given non-OK Status object. All
0122   /// calls to ValueOrDie() on this object will abort. The given `status` must
0123   /// not be an OK status, otherwise this constructor will abort.
0124   ///
0125   /// This constructor is not declared explicit so that a function with a return
0126   /// type of `Result<T>` can return a Status object, and the status will be
0127   /// implicitly converted to the appropriate return type as a matter of
0128   /// convenience.
0129   ///
0130   /// \param status The non-OK Status object to initialize to.
0131   Result(const Status& status) noexcept  // NOLINT(runtime/explicit)
0132       : status_(status) {
0133     if (ARROW_PREDICT_FALSE(status.ok())) {
0134       internal::DieWithMessage(std::string("Constructed with a non-error status: ") +
0135                                status.ToString());
0136     }
0137   }
0138 
0139   /// Constructs a Result object that contains `value`. The resulting object
0140   /// is considered to have an OK status. The wrapped element can be accessed
0141   /// with ValueOrDie().
0142   ///
0143   /// This constructor is made implicit so that a function with a return type of
0144   /// `Result<T>` can return an object of type `U &&`, implicitly converting
0145   /// it to a `Result<T>` object.
0146   ///
0147   /// Note that `T` must be implicitly constructible from `U`, and `U` must not
0148   /// be a (cv-qualified) Status or Status-reference type. Due to C++
0149   /// reference-collapsing rules and perfect-forwarding semantics, this
0150   /// constructor matches invocations that pass `value` either as a const
0151   /// reference or as an rvalue reference. Since Result needs to work for both
0152   /// reference and rvalue-reference types, the constructor uses perfect
0153   /// forwarding to avoid invalidating arguments that were passed by reference.
0154   /// See http://thbecker.net/articles/rvalue_references/section_08.html for
0155   /// additional details.
0156   ///
0157   /// \param value The value to initialize to.
0158   template <typename U,
0159             typename E = typename std::enable_if<
0160                 std::is_constructible<T, U>::value && std::is_convertible<U, T>::value &&
0161                 !std::is_same<typename std::remove_reference<
0162                                   typename std::remove_cv<U>::type>::type,
0163                               Status>::value>::type>
0164   Result(U&& value) noexcept {  // NOLINT(runtime/explicit)
0165     ConstructValue(std::forward<U>(value));
0166   }
0167 
0168   /// Constructs a Result object that contains `value`. The resulting object
0169   /// is considered to have an OK status. The wrapped element can be accessed
0170   /// with ValueOrDie().
0171   ///
0172   /// This constructor is made implicit so that a function with a return type of
0173   /// `Result<T>` can return an object of type `T`, implicitly converting
0174   /// it to a `Result<T>` object.
0175   ///
0176   /// \param value The value to initialize to.
0177   // NOTE `Result(U&& value)` above should be sufficient, but some compilers
0178   // fail matching it.
0179   Result(T&& value) noexcept {  // NOLINT(runtime/explicit)
0180     ConstructValue(std::move(value));
0181   }
0182 
0183   /// Copy constructor.
0184   ///
0185   /// This constructor needs to be explicitly defined because the presence of
0186   /// the move-assignment operator deletes the default copy constructor. In such
0187   /// a scenario, since the deleted copy constructor has stricter binding rules
0188   /// than the templated copy constructor, the templated constructor cannot act
0189   /// as a copy constructor, and any attempt to copy-construct a `Result`
0190   /// object results in a compilation error.
0191   ///
0192   /// \param other The value to copy from.
0193   Result(const Result& other) noexcept : status_(other.status_) {
0194     if (ARROW_PREDICT_TRUE(status_.ok())) {
0195       ConstructValue(other.ValueUnsafe());
0196     }
0197   }
0198 
0199   /// Templatized constructor that constructs a `Result<T>` from a const
0200   /// reference to a `Result<U>`.
0201   ///
0202   /// `T` must be implicitly constructible from `const U &`.
0203   ///
0204   /// \param other The value to copy from.
0205   template <typename U, typename E = typename std::enable_if<
0206                             std::is_constructible<T, const U&>::value &&
0207                             std::is_convertible<U, T>::value>::type>
0208   Result(const Result<U>& other) noexcept : status_(other.status_) {
0209     if (ARROW_PREDICT_TRUE(status_.ok())) {
0210       ConstructValue(other.ValueUnsafe());
0211     }
0212   }
0213 
0214   /// Copy-assignment operator.
0215   ///
0216   /// \param other The Result object to copy.
0217   Result& operator=(const Result& other) noexcept {
0218     // Check for self-assignment.
0219     if (ARROW_PREDICT_FALSE(this == &other)) {
0220       return *this;
0221     }
0222     Destroy();
0223     status_ = other.status_;
0224     if (ARROW_PREDICT_TRUE(status_.ok())) {
0225       ConstructValue(other.ValueUnsafe());
0226     }
0227     return *this;
0228   }
0229 
0230   /// Templatized constructor which constructs a `Result<T>` by moving the
0231   /// contents of a `Result<U>`. `T` must be implicitly constructible from `U
0232   /// &&`.
0233   ///
0234   /// Sets `other` to contain a non-OK status with a`StatusError::Invalid`
0235   /// error code.
0236   ///
0237   /// \param other The Result object to move from and set to a non-OK status.
0238   template <typename U,
0239             typename E = typename std::enable_if<std::is_constructible<T, U&&>::value &&
0240                                                  std::is_convertible<U, T>::value>::type>
0241   Result(Result<U>&& other) noexcept {
0242     if (ARROW_PREDICT_TRUE(other.status_.ok())) {
0243       status_ = std::move(other.status_);
0244       ConstructValue(other.MoveValueUnsafe());
0245     } else {
0246       // If we moved the status, the other status may become ok but the other
0247       // value hasn't been constructed => crash on other destructor.
0248       status_ = other.status_;
0249     }
0250   }
0251 
0252   /// Move-assignment operator.
0253   ///
0254   /// Sets `other` to an invalid state..
0255   ///
0256   /// \param other The Result object to assign from and set to a non-OK
0257   /// status.
0258   Result& operator=(Result&& other) noexcept {
0259     // Check for self-assignment.
0260     if (ARROW_PREDICT_FALSE(this == &other)) {
0261       return *this;
0262     }
0263     Destroy();
0264     if (ARROW_PREDICT_TRUE(other.status_.ok())) {
0265       status_ = std::move(other.status_);
0266       ConstructValue(other.MoveValueUnsafe());
0267     } else {
0268       // If we moved the status, the other status may become ok but the other
0269       // value hasn't been constructed => crash on other destructor.
0270       status_ = other.status_;
0271     }
0272     return *this;
0273   }
0274 
0275   /// Compare to another Result.
0276   bool Equals(const Result& other) const {
0277     if (ARROW_PREDICT_TRUE(status_.ok())) {
0278       return other.status_.ok() && ValueUnsafe() == other.ValueUnsafe();
0279     }
0280     return status_ == other.status_;
0281   }
0282 
0283   /// Indicates whether the object contains a `T` value.  Generally instead
0284   /// of accessing this directly you will want to use ASSIGN_OR_RAISE defined
0285   /// below.
0286   ///
0287   /// \return True if this Result object's status is OK (i.e. a call to ok()
0288   /// returns true). If this function returns true, then it is safe to access
0289   /// the wrapped element through a call to ValueOrDie().
0290   constexpr bool ok() const { return status_.ok(); }
0291 
0292   /// \brief Equivalent to ok().
0293   // operator bool() const { return ok(); }
0294 
0295   /// Gets the stored status object, or an OK status if a `T` value is stored.
0296   ///
0297   /// \return The stored non-OK status object, or an OK status if this object
0298   ///         has a value.
0299   constexpr const Status& status() const& { return status_; }
0300 
0301   /// Gets the stored status object, or an OK status if a `T` value is stored.
0302   ///
0303   /// \return The stored non-OK status object, or an OK status if this object
0304   ///         has a value.
0305   Status status() && {
0306     if (ARROW_PREDICT_TRUE(ok())) return Status::OK();
0307     auto tmp = internal::UninitializedResult();
0308     std::swap(status_, tmp);
0309     return tmp;
0310   }
0311 
0312   /// Gets the stored `T` value.
0313   ///
0314   /// This method should only be called if this Result object's status is OK
0315   /// (i.e. a call to ok() returns true), otherwise this call will abort.
0316   ///
0317   /// \return The stored `T` value.
0318   const T& ValueOrDie() const& {
0319     if (ARROW_PREDICT_FALSE(!ok())) {
0320       internal::InvalidValueOrDie(status_);
0321     }
0322     return ValueUnsafe();
0323   }
0324   const T& operator*() const& { return ValueOrDie(); }
0325   const T* operator->() const { return &ValueOrDie(); }
0326 
0327   /// Gets a mutable reference to the stored `T` value.
0328   ///
0329   /// This method should only be called if this Result object's status is OK
0330   /// (i.e. a call to ok() returns true), otherwise this call will abort.
0331   ///
0332   /// \return The stored `T` value.
0333   T& ValueOrDie() & {
0334     if (ARROW_PREDICT_FALSE(!ok())) {
0335       internal::InvalidValueOrDie(status_);
0336     }
0337     return ValueUnsafe();
0338   }
0339   T& operator*() & { return ValueOrDie(); }
0340   T* operator->() { return &ValueOrDie(); }
0341 
0342   /// Moves and returns the internally-stored `T` value.
0343   ///
0344   /// This method should only be called if this Result object's status is OK
0345   /// (i.e. a call to ok() returns true), otherwise this call will abort. The
0346   /// Result object is invalidated after this call and will be updated to
0347   /// contain a non-OK status.
0348   ///
0349   /// \return The stored `T` value.
0350   T ValueOrDie() && {
0351     if (ARROW_PREDICT_FALSE(!ok())) {
0352       internal::InvalidValueOrDie(status_);
0353     }
0354     return MoveValueUnsafe();
0355   }
0356   T operator*() && { return std::move(*this).ValueOrDie(); }
0357 
0358   /// Helper method for implementing Status returning functions in terms of semantically
0359   /// equivalent Result returning functions. For example:
0360   ///
0361   /// Status GetInt(int *out) { return GetInt().Value(out); }
0362   template <typename U, typename E = typename std::enable_if<
0363                             std::is_constructible<U, T>::value>::type>
0364   Status Value(U* out) && {
0365     if (!ok()) {
0366       return std::move(*this).status();
0367     }
0368     *out = U(MoveValueUnsafe());
0369     return Status::OK();
0370   }
0371 
0372   /// Move and return the internally stored value or alternative if an error is stored.
0373   T ValueOr(T alternative) && {
0374     if (!ok()) {
0375       return alternative;
0376     }
0377     return MoveValueUnsafe();
0378   }
0379 
0380   /// Retrieve the value if ok(), falling back to an alternative generated by the provided
0381   /// factory
0382   template <typename G>
0383   T ValueOrElse(G&& generate_alternative) && {
0384     if (ok()) {
0385       return MoveValueUnsafe();
0386     }
0387     return std::forward<G>(generate_alternative)();
0388   }
0389 
0390   /// Apply a function to the internally stored value to produce a new result or propagate
0391   /// the stored error.
0392   template <typename M>
0393   typename EnsureResult<decltype(std::declval<M&&>()(std::declval<T&&>()))>::type Map(
0394       M&& m) && {
0395     if (!ok()) {
0396       return std::move(*this).status();
0397     }
0398     return std::forward<M>(m)(MoveValueUnsafe());
0399   }
0400 
0401   /// Apply a function to the internally stored value to produce a new result or propagate
0402   /// the stored error.
0403   template <typename M>
0404   typename EnsureResult<decltype(std::declval<M&&>()(std::declval<const T&>()))>::type
0405   Map(M&& m) const& {
0406     if (!ok()) {
0407       return status();
0408     }
0409     return std::forward<M>(m)(ValueUnsafe());
0410   }
0411 
0412   /// Cast the internally stored value to produce a new result or propagate the stored
0413   /// error.
0414   template <typename U, typename E = typename std::enable_if<
0415                             std::is_constructible<U, T>::value>::type>
0416   Result<U> As() && {
0417     if (!ok()) {
0418       return std::move(*this).status();
0419     }
0420     return U(MoveValueUnsafe());
0421   }
0422 
0423   /// Cast the internally stored value to produce a new result or propagate the stored
0424   /// error.
0425   template <typename U, typename E = typename std::enable_if<
0426                             std::is_constructible<U, const T&>::value>::type>
0427   Result<U> As() const& {
0428     if (!ok()) {
0429       return status();
0430     }
0431     return U(ValueUnsafe());
0432   }
0433 
0434   constexpr const T& ValueUnsafe() const& { return *storage_.get(); }
0435 
0436   constexpr T& ValueUnsafe() & { return *storage_.get(); }
0437 
0438   T ValueUnsafe() && { return MoveValueUnsafe(); }
0439 
0440   T MoveValueUnsafe() { return std::move(*storage_.get()); }
0441 
0442  private:
0443   Status status_;  // pointer-sized
0444   internal::AlignedStorage<T> storage_;
0445 
0446   template <typename U>
0447   void ConstructValue(U&& u) noexcept {
0448     storage_.construct(std::forward<U>(u));
0449   }
0450 
0451   void Destroy() noexcept {
0452     if (ARROW_PREDICT_TRUE(status_.ok())) {
0453       static_assert(offsetof(Result<T>, status_) == 0,
0454                     "Status is guaranteed to be at the start of Result<>");
0455       storage_.destroy();
0456     }
0457   }
0458 };
0459 
0460 #define ARROW_ASSIGN_OR_RAISE_IMPL(result_name, lhs, rexpr)                              \
0461   auto&& result_name = (rexpr);                                                          \
0462   ARROW_RETURN_IF_(!(result_name).ok(), (result_name).status(), ARROW_STRINGIFY(rexpr)); \
0463   lhs = std::move(result_name).ValueUnsafe();
0464 
0465 #define ARROW_ASSIGN_OR_RAISE_NAME(x, y) ARROW_CONCAT(x, y)
0466 
0467 /// \brief Execute an expression that returns a Result, extracting its value
0468 /// into the variable defined by `lhs` (or returning a Status on error).
0469 ///
0470 /// Example: Assigning to a new value:
0471 ///   ARROW_ASSIGN_OR_RAISE(auto value, MaybeGetValue(arg));
0472 ///
0473 /// Example: Assigning to an existing value:
0474 ///   ValueType value;
0475 ///   ARROW_ASSIGN_OR_RAISE(value, MaybeGetValue(arg));
0476 ///
0477 /// WARNING: ARROW_ASSIGN_OR_RAISE expands into multiple statements;
0478 /// it cannot be used in a single statement (e.g. as the body of an if
0479 /// statement without {})!
0480 ///
0481 /// WARNING: ARROW_ASSIGN_OR_RAISE `std::move`s its right operand. If you have
0482 /// an lvalue Result which you *don't* want to move out of cast appropriately.
0483 ///
0484 /// WARNING: ARROW_ASSIGN_OR_RAISE is not a single expression; it will not
0485 /// maintain lifetimes of all temporaries in `rexpr` (e.g.
0486 /// `ARROW_ASSIGN_OR_RAISE(auto x, MakeTemp().GetResultRef());`
0487 /// will most likely segfault)!
0488 #define ARROW_ASSIGN_OR_RAISE(lhs, rexpr)                                              \
0489   ARROW_ASSIGN_OR_RAISE_IMPL(ARROW_ASSIGN_OR_RAISE_NAME(_error_or_value, __COUNTER__), \
0490                              lhs, rexpr);
0491 
0492 namespace internal {
0493 
0494 template <typename T>
0495 inline const Status& GenericToStatus(const Result<T>& res) {
0496   return res.status();
0497 }
0498 
0499 template <typename T>
0500 inline Status GenericToStatus(Result<T>&& res) {
0501   return std::move(res).status();
0502 }
0503 
0504 }  // namespace internal
0505 
0506 template <typename T, typename R = typename EnsureResult<T>::type>
0507 R ToResult(T t) {
0508   return R(std::move(t));
0509 }
0510 
0511 template <typename T>
0512 struct EnsureResult {
0513   using type = Result<T>;
0514 };
0515 
0516 template <typename T>
0517 struct EnsureResult<Result<T>> {
0518   using type = Result<T>;
0519 };
0520 
0521 }  // namespace arrow