diff options
| author | Morph <39850852+Morph1984@users.noreply.github.com> | 2021-11-01 10:09:37 -0400 | 
|---|---|---|
| committer | Morph <39850852+Morph1984@users.noreply.github.com> | 2021-11-02 15:20:35 -0400 | 
| commit | 52e52924bb00723b6fd4536419cbbae39ee86b35 (patch) | |
| tree | 8eb8359bf82adde70386c06e536a8b3f2454fa96 | |
| parent | a41e9e93dd0786dc0fbdbe0fe61b7294490129ef (diff) | |
hle/result: Reimplement ResultVal using Common::Expected
Common::Expected effectively provides the same functions as ResultVal, so we can implement it with this.
This can be replaced with std::expected with minimal effort should it be standardized in the C++ Standard Template Library.
| -rw-r--r-- | src/core/hle/result.h | 180 | 
1 files changed, 63 insertions, 117 deletions
| diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 2c6b24848..29fa4eed2 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -4,11 +4,10 @@  #pragma once -#include <new> -#include <utility>  #include "common/assert.h"  #include "common/bit_field.h"  #include "common/common_types.h" +#include "common/expected.h"  // All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes @@ -189,150 +188,97 @@ constexpr ResultCode ResultUnknown(UINT32_MAX);  template <typename T>  class ResultVal {  public: -    /// Constructs an empty `ResultVal` with the given error code. The code must not be a success -    /// code. -    ResultVal(ResultCode error_code = ResultUnknown) : result_code(error_code) { -        ASSERT(error_code.IsError()); -    } +    constexpr ResultVal() : expected{} {} + +    constexpr ResultVal(ResultCode code) : expected{Common::Unexpected(code)} {} + +    template <typename U> +    constexpr ResultVal(U&& val) : expected{std::forward<U>(val)} {} -    /** -     * Similar to the non-member function `MakeResult`, with the exception that you can manually -     * specify the success code. `success_code` must not be an error code. -     */      template <typename... Args> -    [[nodiscard]] static ResultVal WithCode(ResultCode success_code, Args&&... args) { -        ResultVal<T> result; -        result.emplace(success_code, std::forward<Args>(args)...); -        return result; -    } +    constexpr ResultVal(Args&&... args) : expected{std::in_place, std::forward<Args>(args)...} {} -    ResultVal(const ResultVal& o) noexcept : result_code(o.result_code) { -        if (!o.empty()) { -            new (&object) T(o.object); -        } -    } +    ~ResultVal() = default; -    ResultVal(ResultVal&& o) noexcept : result_code(o.result_code) { -        if (!o.empty()) { -            new (&object) T(std::move(o.object)); -        } -    } +    constexpr ResultVal(const ResultVal&) = default; +    constexpr ResultVal(ResultVal&&) = default; -    ~ResultVal() { -        if (!empty()) { -            object.~T(); -        } -    } +    ResultVal& operator=(const ResultVal&) = default; +    ResultVal& operator=(ResultVal&&) = default; -    ResultVal& operator=(const ResultVal& o) noexcept { -        if (this == &o) { -            return *this; -        } -        if (!empty()) { -            if (!o.empty()) { -                object = o.object; -            } else { -                object.~T(); -            } -        } else { -            if (!o.empty()) { -                new (&object) T(o.object); -            } -        } -        result_code = o.result_code; - -        return *this; +    [[nodiscard]] constexpr explicit operator bool() const noexcept { +        return expected.has_value();      } -    ResultVal& operator=(ResultVal&& o) noexcept { -        if (this == &o) { -            return *this; -        } -        if (!empty()) { -            if (!o.empty()) { -                object = std::move(o.object); -            } else { -                object.~T(); -            } -        } else { -            if (!o.empty()) { -                new (&object) T(std::move(o.object)); -            } -        } -        result_code = o.result_code; - -        return *this; +    [[nodiscard]] constexpr ResultCode Code() const { +        return expected.has_value() ? ResultSuccess : expected.error();      } -    /** -     * Replaces the current result with a new constructed result value in-place. The code must not -     * be an error code. -     */ -    template <typename... Args> -    void emplace(ResultCode success_code, Args&&... args) { -        ASSERT(success_code.IsSuccess()); -        if (!empty()) { -            object.~T(); -        } -        new (&object) T(std::forward<Args>(args)...); -        result_code = success_code; +    [[nodiscard]] constexpr bool Succeeded() const { +        return expected.has_value();      } -    /// Returns true if the `ResultVal` contains an error code and no value. -    [[nodiscard]] bool empty() const { -        return result_code.IsError(); +    [[nodiscard]] constexpr bool Failed() const { +        return !expected.has_value();      } -    /// Returns true if the `ResultVal` contains a return value. -    [[nodiscard]] bool Succeeded() const { -        return result_code.IsSuccess(); +    [[nodiscard]] constexpr T* operator->() { +        return std::addressof(expected.value());      } -    /// Returns true if the `ResultVal` contains an error code and no value. -    [[nodiscard]] bool Failed() const { -        return empty(); + +    [[nodiscard]] constexpr const T* operator->() const { +        return std::addressof(expected.value());      } -    [[nodiscard]] ResultCode Code() const { -        return result_code; +    [[nodiscard]] constexpr T& operator*() & { +        return *expected;      } -    [[nodiscard]] const T& operator*() const { -        return object; +    [[nodiscard]] constexpr const T& operator*() const& { +        return *expected;      } -    [[nodiscard]] T& operator*() { -        return object; + +    [[nodiscard]] constexpr T&& operator*() && { +        return *expected;      } -    [[nodiscard]] const T* operator->() const { -        return &object; + +    [[nodiscard]] constexpr const T&& operator*() const&& { +        return *expected;      } -    [[nodiscard]] T* operator->() { -        return &object; + +    [[nodiscard]] constexpr T& Unwrap() & { +        ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); +        return expected.value();      } -    /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. -    template <typename U> -    [[nodiscard]] T ValueOr(U&& value) const { -        return !empty() ? object : std::move(value); +    [[nodiscard]] constexpr const T& Unwrap() const& { +        ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); +        return expected.value();      } -    /// Asserts that the result succeeded and returns a reference to it. -    [[nodiscard]] T& Unwrap() & { +    [[nodiscard]] constexpr T&& Unwrap() && {          ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); -        return **this; +        return std::move(expected.value());      } -    [[nodiscard]] T&& Unwrap() && { +    [[nodiscard]] constexpr const T&& Unwrap() const&& {          ASSERT_MSG(Succeeded(), "Tried to Unwrap empty ResultVal"); -        return std::move(**this); +        return std::move(expected.value()); +    } + +    template <typename U> +    [[nodiscard]] constexpr T ValueOr(U&& v) const& { +        return expected.value_or(v); +    } + +    template <typename U> +    [[nodiscard]] constexpr T ValueOr(U&& v) && { +        return expected.value_or(v);      }  private: -    // A union is used to allocate the storage for the value, while allowing us to construct and -    // destruct it at will. -    union { -        T object; -    }; -    ResultCode result_code; +    // TODO: Replace this with std::expected once it is standardized in the STL. +    Common::Expected<T, ResultCode> expected;  };  /** @@ -341,16 +287,16 @@ private:   */  template <typename T, typename... Args>  [[nodiscard]] ResultVal<T> MakeResult(Args&&... args) { -    return ResultVal<T>::WithCode(ResultSuccess, std::forward<Args>(args)...); +    return ResultVal<T>{std::forward<Args>(args)...};  }  /**   * Deducible overload of MakeResult, allowing the template parameter to be ommited if you're just   * copy or move constructing.   */ -template <typename Arg> -[[nodiscard]] ResultVal<std::remove_cvref_t<Arg>> MakeResult(Arg&& arg) { -    return ResultVal<std::remove_cvref_t<Arg>>::WithCode(ResultSuccess, std::forward<Arg>(arg)); +template <typename T> +[[nodiscard]] ResultVal<std::remove_cvref_t<T>> MakeResult(T&& val) { +    return ResultVal<std::remove_cvref_t<T>>{std::forward<T>(val)};  }  /** | 
