/** * @file libimp/result.h * @author mutouyun (orz@orzz.org) * @brief Define the return value type with a status code * @date 2022-04-17 */ #pragma once #include #include #include "fmt/format.h" #include "libimp/def.h" #include "libimp/export.h" LIBIMP_NAMESPACE_BEG_ class LIBIMP_EXPORT result_code { std::uint64_t status_; public: result_code() noexcept; result_code(bool ok, std::uint64_t value = 0) noexcept; std::uint64_t value() const noexcept; bool ok() const noexcept; std::uint64_t operator*() const noexcept { return value(); } explicit operator bool() const noexcept { return ok(); } friend bool operator==(result_code const &lhs, result_code const &rhs) noexcept; friend bool operator!=(result_code const &lhs, result_code const &rhs) noexcept; }; namespace detail_result { template struct default_traits; template struct default_traits::value>> { constexpr static T value() noexcept { return 0; } static std::uint64_t cast_to_code(T value) noexcept { return static_cast(value); } static T cast_from_code(std::uint64_t code) noexcept { return static_cast(code); } static T regularize(T value) noexcept { return value; } }; template struct default_traits::value>> { constexpr static T value() noexcept { return nullptr; } static std::uint64_t cast_to_code(T value) noexcept { return reinterpret_cast(value); } static T cast_from_code(std::uint64_t code) noexcept { return reinterpret_cast(code); } static void *regularize(T value) noexcept { return value; } }; } // namespace detail_result template > class result { result_code code_; public: using default_traits_t = DefTraits; result() noexcept = default; result(bool ok, T value = default_traits_t::value()) : code_(ok, default_traits_t::cast_to_code(value)) {} T value() const noexcept { return default_traits_t::cast_from_code(code_.value()); } bool ok() const noexcept { return code_.ok(); } T operator*() const noexcept { return value(); } explicit operator bool() const noexcept { return ok(); } friend bool operator==(result const &lhs, result const &rhs) noexcept { return lhs.code_ == rhs.code_; } friend bool operator!=(result const &lhs, result const &rhs) noexcept { return lhs.code_ != rhs.code_; } friend std::ostream &operator<<(std::ostream &o, result const &r) noexcept { return o << r.code_; } }; LIBIMP_NAMESPACE_END_ template struct fmt::formatter<::LIBIMP_NAMESPACE::result> { constexpr auto parse(format_parse_context& ctx) { return ctx.end(); } template auto format(::LIBIMP_NAMESPACE::result r, FormatContext &ctx) { return format_to(ctx.out(), "[{}, value = {}]", (r ? "succ" : "fail"), ::LIBIMP_NAMESPACE::result::default_traits_t::regularize(*r)); } }; template <> struct fmt::formatter<::LIBIMP_NAMESPACE::result_code> : formatter<::LIBIMP_NAMESPACE::result> { template auto format(::LIBIMP_NAMESPACE::result_code r, FormatContext &ctx) { return format_to(ctx.out(), "[{}, value = {}]", (r ? "succ" : "fail"), *r); } };