From 3aac7bea08f2b0842b15c6e4b7d5b04e2602efa9 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 18 Dec 2022 17:38:24 +0800 Subject: [PATCH] add: [imp] `error_code` --- include/libimp/error.h | 68 +++++++++++++++++++++++++++++++++++++ src/libimp/error.cpp | 62 +++++++++++++++++++++++++++++++++ test/imp/test_imp_error.cpp | 31 +++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 include/libimp/error.h create mode 100644 src/libimp/error.cpp create mode 100644 test/imp/test_imp_error.cpp diff --git a/include/libimp/error.h b/include/libimp/error.h new file mode 100644 index 0000000..7762aa0 --- /dev/null +++ b/include/libimp/error.h @@ -0,0 +1,68 @@ +/** + * @file libimp/error.h + * @author mutouyun (orz@orzz.org) + * @brief A platform-dependent error code. + * @date 2022-12-18 + */ +#pragma once + +#include + +#include "libimp/def.h" +#include "libimp/export.h" +#include "libimp/result.h" +#include "libimp/fmt_cpo.h" + +LIBIMP_NAMESPACE_BEG_ + +/** + * @brief Serves as the base class for specific error category types. + * @see https://en.cppreference.com/w/cpp/error/error_category + */ +class LIBIMP_EXPORT error_category { +public: + error_category(error_category const &) = delete; + error_category &operator=(error_category const &) = delete; + + constexpr error_category() noexcept = default; + virtual ~error_category() noexcept = default; + + /// @brief observer + virtual std::string message(result_code r) const = 0; + + /// @brief comparison function + bool operator==(error_category const &rhs) const noexcept; +}; + +/** + * @brief Identifies the generic error category. + * @see https://en.cppreference.com/w/cpp/error/generic_category + */ +LIBIMP_EXPORT error_category const &generic_category() noexcept; + +/** + * @brief The error code object. + * @see https://en.cppreference.com/w/cpp/error/error_code + */ +class LIBIMP_EXPORT error_code { + result_code r_code_; + error_category const *ec_; + +public: + /// @brief constructors + error_code() noexcept; + error_code(result_code r, error_category const &ec) noexcept; + + /// @brief observers + result_code code() const noexcept; + result_type value() const noexcept; + error_category const &category() const noexcept; + std::string message() const; + explicit operator bool() const noexcept; + + /// @brief comparison functions + friend LIBIMP_EXPORT bool operator==(error_code const &lhs, error_code const &rhs) noexcept; + friend LIBIMP_EXPORT bool operator!=(error_code const &lhs, error_code const &rhs) noexcept; +}; + +LIBIMP_NAMESPACE_END_ diff --git a/src/libimp/error.cpp b/src/libimp/error.cpp new file mode 100644 index 0000000..0b10a7f --- /dev/null +++ b/src/libimp/error.cpp @@ -0,0 +1,62 @@ +#include + +#include "libimp/error.h" +#include "libimp/fmt.h" + +LIBIMP_NAMESPACE_BEG_ + +bool error_category::operator==(error_category const &rhs) const noexcept { + return typeid(*this) == typeid(rhs); +} + +namespace { + +class generic_error_category : public error_category { +public: + std::string message(result_code r) const { + return fmt("[", r.value(), (!r ? ", \"success\"]" : ", \"failure\"]")); + } +}; + +} // namespace + +error_category const &generic_category() noexcept { + static generic_error_category ec; + return ec; +} + +error_code::error_code() noexcept + : r_code_{}, ec_{&generic_category()} {} + +error_code::error_code(result_code r, error_category const &ec) noexcept + : r_code_{r}, ec_{&ec} {} + +result_code error_code::code() const noexcept { + return r_code_; +} + +result_type error_code::value() const noexcept { + return r_code_.value(); +} + +error_category const &error_code::category() const noexcept { + return *ec_; +} + +std::string error_code::message() const { + return ec_->message(r_code_); +} + +error_code::operator bool() const noexcept { + return !!r_code_; +} + +bool operator==(error_code const &lhs, error_code const &rhs) noexcept { + return (lhs.r_code_ == rhs.r_code_) && (*lhs.ec_ == *rhs.ec_); +} + +bool operator!=(error_code const &lhs, error_code const &rhs) noexcept { + return !(lhs == rhs); +} + +LIBIMP_NAMESPACE_END_ diff --git a/test/imp/test_imp_error.cpp b/test/imp/test_imp_error.cpp new file mode 100644 index 0000000..08e0d1a --- /dev/null +++ b/test/imp/test_imp_error.cpp @@ -0,0 +1,31 @@ +#include + +#include "gtest/gtest.h" + +#include "libimp/error.h" +#include "libimp/result.h" +#include "libimp/fmt.h" + +namespace { + +class custom_error_category : public imp::error_category { +public: + std::string message(imp::result_code r) const { + return !r ? "success" : "failure"; + } +}; + +} // namespace + +TEST(error, error_code) { + imp::error_code ecode; + EXPECT_FALSE(ecode); + std::cout << ecode.message() << "\n"; + EXPECT_EQ(ecode.message(), "[0, \"success\"]"); + + custom_error_category cec; + ecode = {123, cec}; + EXPECT_TRUE(ecode); + std::cout << ecode.message() << "\n"; + EXPECT_EQ(ecode.message(), cec.message(123)); +} \ No newline at end of file