| // |
| // Copyright 2017 Asylo authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| // Adapted from Asylo |
| |
| #pragma once |
| |
| #include <new> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "arrow/status.h" |
| #include "arrow/util/compare.h" |
| |
| namespace arrow { |
| |
| namespace internal { |
| |
| #if __cplusplus >= 201703L |
| using std::launder; |
| #else |
| template <class T> |
| constexpr T* launder(T* p) noexcept { |
| return p; |
| } |
| #endif |
| |
| ARROW_EXPORT void DieWithMessage(const std::string& msg); |
| |
| ARROW_EXPORT void InvalidValueOrDie(const Status& st); |
| |
| } // namespace internal |
| |
| /// A class for representing either a usable value, or an error. |
| /// |
| /// A Result object either contains a value of type `T` or a Status object |
| /// explaining why such a value is not present. The type `T` must be |
| /// copy-constructible and/or move-constructible. |
| /// |
| /// The state of a Result object may be determined by calling ok() or |
| /// status(). The ok() method returns true if the object contains a valid value. |
| /// The status() method returns the internal Status object. A Result object |
| /// that contains a valid value will return an OK Status for a call to status(). |
| /// |
| /// A value of type `T` may be extracted from a Result object through a call |
| /// to ValueOrDie(). This function should only be called if a call to ok() |
| /// returns true. Sample usage: |
| /// |
| /// ``` |
| /// arrow::Result<Foo> result = CalculateFoo(); |
| /// if (result.ok()) { |
| /// Foo foo = result.ValueOrDie(); |
| /// foo.DoSomethingCool(); |
| /// } else { |
| /// ARROW_LOG(ERROR) << result.status(); |
| /// } |
| /// ``` |
| /// |
| /// If `T` is a move-only type, like `std::unique_ptr<>`, then the value should |
| /// only be extracted after invoking `std::move()` on the Result object. |
| /// Sample usage: |
| /// |
| /// ``` |
| /// arrow::Result<std::unique_ptr<Foo>> result = CalculateFoo(); |
| /// if (result.ok()) { |
| /// std::unique_ptr<Foo> foo = std::move(result).ValueOrDie(); |
| /// foo->DoSomethingCool(); |
| /// } else { |
| /// ARROW_LOG(ERROR) << result.status(); |
| /// } |
| /// ``` |
| /// |
| /// Result is provided for the convenience of implementing functions that |
| /// return some value but may fail during execution. For instance, consider a |
| /// function with the following signature: |
| /// |
| /// ``` |
| /// arrow::Status CalculateFoo(int *output); |
| /// ``` |
| /// |
| /// This function may instead be written as: |
| /// |
| /// ``` |
| /// arrow::Result<int> CalculateFoo(); |
| /// ``` |
| template <class T> |
| class ARROW_MUST_USE_TYPE Result : public util::EqualityComparable<Result<T>> { |
| template <typename U> |
| friend class Result; |
| |
| static_assert(!std::is_same<T, Status>::value, |
| "this assert indicates you have probably made a metaprogramming error"); |
| |
| public: |
| using ValueType = T; |
| |
| /// Constructs a Result object that contains a non-OK status. |
| /// |
| /// This constructor is marked `explicit` to prevent attempts to `return {}` |
| /// from a function with a return type of, for example, |
| /// `Result<std::vector<int>>`. While `return {}` seems like it would return |
| /// an empty vector, it will actually invoke the default constructor of |
| /// Result. |
| explicit Result() // NOLINT(runtime/explicit) |
| : status_(Status::UnknownError("Uninitialized Result<T>")) {} |
| |
| ~Result() noexcept { Destroy(); } |
| |
| /// Constructs a Result object with the given non-OK Status object. All |
| /// calls to ValueOrDie() on this object will abort. The given `status` must |
| /// not be an OK status, otherwise this constructor will abort. |
| /// |
| /// This constructor is not declared explicit so that a function with a return |
| /// type of `Result<T>` can return a Status object, and the status will be |
| /// implicitly converted to the appropriate return type as a matter of |
| /// convenience. |
| /// |
| /// \param status The non-OK Status object to initialize to. |
| Result(const Status& status) // NOLINT(runtime/explicit) |
| : status_(status) { |
| if (ARROW_PREDICT_FALSE(status.ok())) { |
| internal::DieWithMessage(std::string("Constructed with a non-error status: ") + |
| status.ToString()); |
| } |
| } |
| |
| /// Constructs a Result object that contains `value`. The resulting object |
| /// is considered to have an OK status. The wrapped element can be accessed |
| /// with ValueOrDie(). |
| /// |
| /// This constructor is made implicit so that a function with a return type of |
| /// `Result<T>` can return an object of type `U &&`, implicitly converting |
| /// it to a `Result<T>` object. |
| /// |
| /// Note that `T` must be implicitly constructible from `U`, and `U` must not |
| /// be a (cv-qualified) Status or Status-reference type. Due to C++ |
| /// reference-collapsing rules and perfect-forwarding semantics, this |
| /// constructor matches invocations that pass `value` either as a const |
| /// reference or as an rvalue reference. Since Result needs to work for both |
| /// reference and rvalue-reference types, the constructor uses perfect |
| /// forwarding to avoid invalidating arguments that were passed by reference. |
| /// See http://thbecker.net/articles/rvalue_references/section_08.html for |
| /// additional details. |
| /// |
| /// \param value The value to initialize to. |
| template <typename U, |
| typename E = typename std::enable_if< |
| std::is_constructible<T, U>::value && std::is_convertible<U, T>::value && |
| !std::is_same<typename std::remove_reference< |
| typename std::remove_cv<U>::type>::type, |
| Status>::value>::type> |
| Result(U&& value) noexcept { // NOLINT(runtime/explicit) |
| ConstructValue(std::forward<U>(value)); |
| } |
| |
| /// Constructs a Result object that contains `value`. The resulting object |
| /// is considered to have an OK status. The wrapped element can be accessed |
| /// with ValueOrDie(). |
| /// |
| /// This constructor is made implicit so that a function with a return type of |
| /// `Result<T>` can return an object of type `T`, implicitly converting |
| /// it to a `Result<T>` object. |
| /// |
| /// \param value The value to initialize to. |
| // NOTE `Result(U&& value)` above should be sufficient, but some compilers |
| // fail matching it. |
| Result(T&& value) noexcept { // NOLINT(runtime/explicit) |
| ConstructValue(std::move(value)); |
| } |
| |
| /// Copy constructor. |
| /// |
| /// This constructor needs to be explicitly defined because the presence of |
| /// the move-assignment operator deletes the default copy constructor. In such |
| /// a scenario, since the deleted copy constructor has stricter binding rules |
| /// than the templated copy constructor, the templated constructor cannot act |
| /// as a copy constructor, and any attempt to copy-construct a `Result` |
| /// object results in a compilation error. |
| /// |
| /// \param other The value to copy from. |
| Result(const Result& other) : status_(other.status_) { |
| if (ARROW_PREDICT_TRUE(status_.ok())) { |
| ConstructValue(other.ValueUnsafe()); |
| } |
| } |
| |
| /// Templatized constructor that constructs a `Result<T>` from a const |
| /// reference to a `Result<U>`. |
| /// |
| /// `T` must be implicitly constructible from `const U &`. |
| /// |
| /// \param other The value to copy from. |
| template <typename U, typename E = typename std::enable_if< |
| std::is_constructible<T, const U&>::value && |
| std::is_convertible<U, T>::value>::type> |
| Result(const Result<U>& other) : status_(other.status_) { |
| if (ARROW_PREDICT_TRUE(status_.ok())) { |
| ConstructValue(other.ValueUnsafe()); |
| } |
| } |
| |
| /// Copy-assignment operator. |
| /// |
| /// \param other The Result object to copy. |
| Result& operator=(const Result& other) { |
| // Check for self-assignment. |
| if (this == &other) { |
| return *this; |
| } |
| Destroy(); |
| status_ = other.status_; |
| if (ARROW_PREDICT_TRUE(status_.ok())) { |
| ConstructValue(other.ValueUnsafe()); |
| } |
| return *this; |
| } |
| |
| /// Templatized constructor which constructs a `Result<T>` by moving the |
| /// contents of a `Result<U>`. `T` must be implicitly constructible from `U |
| /// &&`. |
| /// |
| /// Sets `other` to contain a non-OK status with a`StatusError::Invalid` |
| /// error code. |
| /// |
| /// \param other The Result object to move from and set to a non-OK status. |
| template <typename U, |
| typename E = typename std::enable_if<std::is_constructible<T, U&&>::value && |
| std::is_convertible<U, T>::value>::type> |
| Result(Result<U>&& other) noexcept { |
| if (ARROW_PREDICT_TRUE(other.status_.ok())) { |
| status_ = std::move(other.status_); |
| ConstructValue(other.MoveValueUnsafe()); |
| } else { |
| // If we moved the status, the other status may become ok but the other |
| // value hasn't been constructed => crash on other destructor. |
| status_ = other.status_; |
| } |
| } |
| |
| /// Move-assignment operator. |
| /// |
| /// Sets `other` to an invalid state.. |
| /// |
| /// \param other The Result object to assign from and set to a non-OK |
| /// status. |
| Result& operator=(Result&& other) noexcept { |
| // Check for self-assignment. |
| if (this == &other) { |
| return *this; |
| } |
| Destroy(); |
| if (ARROW_PREDICT_TRUE(other.status_.ok())) { |
| status_ = std::move(other.status_); |
| ConstructValue(other.MoveValueUnsafe()); |
| } else { |
| // If we moved the status, the other status may become ok but the other |
| // value hasn't been constructed => crash on other destructor. |
| status_ = other.status_; |
| } |
| return *this; |
| } |
| |
| /// Compare to another Result. |
| bool Equals(const Result& other) const { |
| if (ARROW_PREDICT_TRUE(status_.ok())) { |
| return other.status_.ok() && ValueUnsafe() == other.ValueUnsafe(); |
| } |
| return status_ == other.status_; |
| } |
| |
| /// Indicates whether the object contains a `T` value. Generally instead |
| /// of accessing this directly you will want to use ASSIGN_OR_RAISE defined |
| /// below. |
| /// |
| /// \return True if this Result object's status is OK (i.e. a call to ok() |
| /// returns true). If this function returns true, then it is safe to access |
| /// the wrapped element through a call to ValueOrDie(). |
| bool ok() const { return status_.ok(); } |
| |
| /// \brief Equivalent to ok(). |
| // operator bool() const { return ok(); } |
| |
| /// Gets the stored status object, or an OK status if a `T` value is stored. |
| /// |
| /// \return The stored non-OK status object, or an OK status if this object |
| /// has a value. |
| Status status() const { return status_; } |
| |
| /// Gets the stored `T` value. |
| /// |
| /// This method should only be called if this Result object's status is OK |
| /// (i.e. a call to ok() returns true), otherwise this call will abort. |
| /// |
| /// \return The stored `T` value. |
| const T& ValueOrDie() const& { |
| if (ARROW_PREDICT_FALSE(!ok())) { |
| internal::InvalidValueOrDie(status_); |
| } |
| return ValueUnsafe(); |
| } |
| const T& operator*() const& { return ValueOrDie(); } |
| |
| /// Gets a mutable reference to the stored `T` value. |
| /// |
| /// This method should only be called if this Result object's status is OK |
| /// (i.e. a call to ok() returns true), otherwise this call will abort. |
| /// |
| /// \return The stored `T` value. |
| T& ValueOrDie() & { |
| if (ARROW_PREDICT_FALSE(!ok())) { |
| internal::InvalidValueOrDie(status_); |
| } |
| return ValueUnsafe(); |
| } |
| T& operator*() & { return ValueOrDie(); } |
| |
| /// Moves and returns the internally-stored `T` value. |
| /// |
| /// This method should only be called if this Result object's status is OK |
| /// (i.e. a call to ok() returns true), otherwise this call will abort. The |
| /// Result object is invalidated after this call and will be updated to |
| /// contain a non-OK status. |
| /// |
| /// \return The stored `T` value. |
| T ValueOrDie() && { |
| if (ARROW_PREDICT_FALSE(!ok())) { |
| internal::InvalidValueOrDie(status_); |
| } |
| return MoveValueUnsafe(); |
| } |
| T operator*() && { return std::move(*this).ValueOrDie(); } |
| |
| /// Helper method for implementing Status returning functions in terms of semantically |
| /// equivalent Result returning functions. For example: |
| /// |
| /// Status GetInt(int *out) { return GetInt().Value(out); } |
| template <typename U, typename E = typename std::enable_if< |
| std::is_constructible<U, T>::value>::type> |
| Status Value(U* out) && { |
| if (!ok()) { |
| return status(); |
| } |
| *out = U(MoveValueUnsafe()); |
| return Status::OK(); |
| } |
| |
| /// Move and return the internally stored value or alternative if an error is stored. |
| T ValueOr(T alternative) && { |
| if (!ok()) { |
| return alternative; |
| } |
| return MoveValueUnsafe(); |
| } |
| |
| /// Retrieve the value if ok(), falling back to an alternative generated by the provided |
| /// factory |
| template <typename G> |
| T ValueOrElse(G&& generate_alternative) && { |
| if (ok()) { |
| return MoveValueUnsafe(); |
| } |
| return generate_alternative(); |
| } |
| |
| /// Apply a function to the internally stored value to produce a new result or propagate |
| /// the stored error. |
| template <typename M> |
| typename std::result_of<M && (T)>::type Map(M&& m) && { |
| if (!ok()) { |
| return status(); |
| } |
| return std::forward<M>(m)(MoveValueUnsafe()); |
| } |
| |
| /// Apply a function to the internally stored value to produce a new result or propagate |
| /// the stored error. |
| template <typename M> |
| typename std::result_of<M && (const T&)>::type Map(M&& m) const& { |
| if (!ok()) { |
| return status(); |
| } |
| return std::forward<M>(m)(ValueUnsafe()); |
| } |
| |
| const T& ValueUnsafe() const& { |
| return *internal::launder(reinterpret_cast<const T*>(&data_)); |
| } |
| |
| T& ValueUnsafe() & { return *internal::launder(reinterpret_cast<T*>(&data_)); } |
| |
| T ValueUnsafe() && { return MoveValueUnsafe(); } |
| |
| T MoveValueUnsafe() { |
| return std::move(*internal::launder(reinterpret_cast<T*>(&data_))); |
| } |
| |
| private: |
| Status status_; // pointer-sized |
| typename std::aligned_storage<sizeof(T), alignof(T)>::type data_; |
| |
| template <typename U> |
| void ConstructValue(U&& u) { |
| new (&data_) T(std::forward<U>(u)); |
| } |
| |
| void Destroy() { |
| if (ARROW_PREDICT_TRUE(status_.ok())) { |
| internal::launder(reinterpret_cast<const T*>(&data_))->~T(); |
| } |
| } |
| }; |
| |
| #define ARROW_ASSIGN_OR_RAISE_IMPL(result_name, lhs, rexpr) \ |
| auto result_name = (rexpr); \ |
| ARROW_RETURN_NOT_OK((result_name).status()); \ |
| lhs = std::move(result_name).MoveValueUnsafe(); |
| |
| #define ARROW_ASSIGN_OR_RAISE_NAME(x, y) ARROW_CONCAT(x, y) |
| |
| /// \brief Execute an expression that returns a Result, extracting its value |
| /// into the variable defined by `lhs` (or returning a Status on error). |
| /// |
| /// Example: Assigning to a new value: |
| /// ARROW_ASSIGN_OR_RAISE(auto value, MaybeGetValue(arg)); |
| /// |
| /// Example: Assigning to an existing value: |
| /// ValueType value; |
| /// ARROW_ASSIGN_OR_RAISE(value, MaybeGetValue(arg)); |
| /// |
| /// WARNING: ARROW_ASSIGN_OR_RAISE expands into multiple statements; |
| /// it cannot be used in a single statement (e.g. as the body of an if |
| /// statement without {})! |
| #define ARROW_ASSIGN_OR_RAISE(lhs, rexpr) \ |
| ARROW_ASSIGN_OR_RAISE_IMPL(ARROW_ASSIGN_OR_RAISE_NAME(_error_or_value, __COUNTER__), \ |
| lhs, rexpr); |
| |
| namespace internal { |
| |
| template <typename T> |
| inline Status GenericToStatus(const Result<T>& res) { |
| return res.status(); |
| } |
| |
| template <typename T> |
| inline Status GenericToStatus(Result<T>&& res) { |
| return std::move(res).status(); |
| } |
| |
| } // namespace internal |
| |
| } // namespace arrow |