From d17aeaae1e8815a9860930d42e8b66e0d999194f Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 25 Dec 2022 13:48:06 +0800 Subject: [PATCH] add: [imp] `result` --- include/libimp/error.h | 1 + include/libimp/result.h | 65 ++++++++++++++++++++++++++++++++++-- src/libimp/error.cpp | 2 +- test/imp/test_imp_result.cpp | 17 ++++++++++ 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/include/libimp/error.h b/include/libimp/error.h index af35bde..351ae66 100644 --- a/include/libimp/error.h +++ b/include/libimp/error.h @@ -16,6 +16,7 @@ LIBIMP_NAMESPACE_BEG_ using error_code_t = std::uint64_t; +constexpr error_code_t error_number_limit = error_code_t(-1); /** * \brief Serves as the base class for specific error category types. diff --git a/include/libimp/result.h b/include/libimp/result.h index 7ac6fa7..1fcd614 100644 --- a/include/libimp/result.h +++ b/include/libimp/result.h @@ -42,7 +42,7 @@ struct generic_traits { /// \brief Custom initialization. constexpr static void init_code(storage_t &code) noexcept { - code = {0, -1/*make a default error code*/}; + code = {0, error_number_limit/*make a default error code*/}; } constexpr static void init_code(storage_t &code, T value, error_code const &ec) noexcept { code = {value, ec}; @@ -66,12 +66,39 @@ struct generic_traits { } }; +template +struct default_traits { + /// \typedef Use the `error_code` as the storage type. + using storage_t = error_code; + + /// \brief Custom initialization. + constexpr static void init_code(storage_t &code) noexcept { + code = error_number_limit/*make a default error code*/; + } + constexpr static void init_code(storage_t &code, error_code const &ec) noexcept { + code = ec; + } + + /// \brief Custom type data acquisition. + constexpr static bool get_ok(storage_t const &code) noexcept { + return !code; + } + constexpr static error_code get_error(storage_t const &code) noexcept { + return code; + } + + /// \brief Custom formatted output. + static std::string format(result const &r) noexcept { + return fmt("error = ", r.error()); + } +}; + template struct default_traits::value>> : generic_traits { /// \brief Custom initialization. constexpr static void init_code(storage_t &code, T value, bool ok) noexcept { - code = {value, static_cast(ok ? 0 : - ((value == default_value()) ? -1 : value))}; + code = {value, static_cast(ok ? 0 : + ((value == default_value()) ? error_number_limit : value))}; } using generic_traits::init_code; @@ -146,6 +173,33 @@ public: friend bool operator!=(result const &lhs, result const &rhs) noexcept { return !(lhs == rhs); } }; +template +class result { +public: + using type_traits_t = TypeTraits; + using storage_t = typename type_traits_t::storage_t; + +private: + storage_t code_; ///< internal data + +public: + template , + typename = decltype(type_traits_t::init_code(std::declval() + , std::declval()...))> + result(A &&... args) noexcept { + type_traits_t::init_code(code_, std::forward(args)...); + } + + bool ok () const noexcept { return type_traits_t::get_ok (code_); } + error_code error() const noexcept { return type_traits_t::get_error(code_); } + + 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 == rhs); } +}; + /// \brief Custom defined fmt_to method for imp::fmt namespace detail { @@ -154,5 +208,10 @@ bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, result r) { return fmt_to(ctx, (r ? "succ" : "fail"), ", value = ", result::type_traits_t::format(r)); } +template +bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, result r) { + return fmt_to(ctx, (r ? "succ" : "fail"), ", ", result::type_traits_t::format(r)); +} + } // namespace detail LIBIMP_NAMESPACE_END_ diff --git a/src/libimp/error.cpp b/src/libimp/error.cpp index fccaeba..a90ef2b 100644 --- a/src/libimp/error.cpp +++ b/src/libimp/error.cpp @@ -17,7 +17,7 @@ public: return "generic"; } std::string message(error_code_t const &r) const { - if (r == error_code_t(-1)) { + if (r == error_number_limit) { return "0, \"failure\""; } if (r == error_code_t(0)) { diff --git a/test/imp/test_imp_result.cpp b/test/imp/test_imp_result.cpp index 5f5bf89..2c07a0c 100644 --- a/test/imp/test_imp_result.cpp +++ b/test/imp/test_imp_result.cpp @@ -48,6 +48,16 @@ TEST(result, ok) { EXPECT_TRUE(ret.ok()); EXPECT_EQ(ret.value(), 4321); + imp::result r1; + EXPECT_FALSE(r1); + r1 = 0; + EXPECT_TRUE(r1); + r1 = {}; + EXPECT_FALSE(r1); + r1 = 9999; + EXPECT_FALSE(r1); + EXPECT_EQ(r1.error(), 9999); + imp::result r2 {nullptr, 4321}; EXPECT_NE(r2, nullptr); // imp::result{nullptr} EXPECT_EQ(*r2, nullptr); @@ -102,4 +112,11 @@ TEST(result, fmt) { imp::result r1 {-123}; EXPECT_EQ(imp::fmt(r1), imp::fmt("succ, value = ", -123)); } + { + imp::result r1; + EXPECT_EQ(imp::fmt(r1), "fail, error = [generic: 0, \"failure\"]"); + r1 = 0; + EXPECT_TRUE(r1); + EXPECT_EQ(imp::fmt(r1), "succ, error = [generic: 0, \"success\"]"); + } } \ No newline at end of file