mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
Add result
This commit is contained in:
parent
09a304161f
commit
453f964bdd
@ -98,9 +98,10 @@ LIBIPC_EXPORT bool to_string(fmt_context &ctx, long double a, span<char const> f
|
|||||||
|
|
||||||
/// \brief Pointer.
|
/// \brief Pointer.
|
||||||
LIBIPC_EXPORT bool to_string(fmt_context &ctx, std::nullptr_t) noexcept;
|
LIBIPC_EXPORT bool to_string(fmt_context &ctx, std::nullptr_t) noexcept;
|
||||||
|
LIBIPC_EXPORT bool to_string(fmt_context &ctx, void const volatile *a) noexcept;
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename = std::enable_if_t<std::is_same<T, void>::value>>
|
typename = std::enable_if_t<!std::is_same<T, char>::value>>
|
||||||
LIBIPC_EXPORT bool to_string(fmt_context &ctx, T const volatile *a) noexcept;
|
inline bool to_string(fmt_context &ctx, T const volatile *a) noexcept { return to_string(ctx, (void *)a); }
|
||||||
|
|
||||||
/// \brief Date and time.
|
/// \brief Date and time.
|
||||||
LIBIPC_EXPORT bool to_string(fmt_context &ctx, std::tm const &a, span<char const> fstr = {}) noexcept;
|
LIBIPC_EXPORT bool to_string(fmt_context &ctx, std::tm const &a, span<char const> fstr = {}) noexcept;
|
||||||
|
|||||||
138
include/libipc/imp/result.h
Normal file
138
include/libipc/imp/result.h
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/**
|
||||||
|
* \file libipc/result.h
|
||||||
|
* \author mutouyun (orz@orzz.org)
|
||||||
|
* \brief Define the return value type with an error status code.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "libipc/imp/expected.h"
|
||||||
|
#include "libipc/imp/error.h"
|
||||||
|
#include "libipc/imp/generic.h"
|
||||||
|
#include "libipc/imp/fmt.h"
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
namespace detail_result {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct generic_initializer {
|
||||||
|
using storage_t = expected<T, std::error_code>;
|
||||||
|
|
||||||
|
/// \brief Custom initialization.
|
||||||
|
static constexpr storage_t init_code() noexcept {
|
||||||
|
return {unexpected, std::error_code(-1, std::generic_category())};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr storage_t init_code(T value) noexcept {
|
||||||
|
return {in_place, value};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr storage_t init_code(std::error_code const &ec) noexcept {
|
||||||
|
return {unexpected, ec};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct result_base;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct result_base<T, std::enable_if_t<std::is_pointer<T>::value>>
|
||||||
|
: generic_initializer<T> {
|
||||||
|
|
||||||
|
using storage_t = typename generic_initializer<T>::storage_t;
|
||||||
|
using generic_initializer<T>::init_code;
|
||||||
|
|
||||||
|
static constexpr storage_t init_code(std::nullptr_t, std::error_code const &ec) noexcept {
|
||||||
|
return {unexpected, ec};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr storage_t init_code(std::nullptr_t) noexcept {
|
||||||
|
return {unexpected, std::error_code(-1, std::generic_category())};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct result_base<T, std::enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value>>
|
||||||
|
: generic_initializer<T> {
|
||||||
|
|
||||||
|
using storage_t = typename generic_initializer<T>::storage_t;
|
||||||
|
using generic_initializer<T>::init_code;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail_result
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class class result
|
||||||
|
* \brief The generic wrapper for the result type.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
class result : public detail_result::result_base<T> {
|
||||||
|
private:
|
||||||
|
using base_t = detail_result::result_base<T>;
|
||||||
|
using storage_t = typename base_t::storage_t;
|
||||||
|
|
||||||
|
storage_t ret_; ///< internal data
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename... A,
|
||||||
|
typename = not_match<result, A...>,
|
||||||
|
typename = decltype(base_t::init_code(std::declval<A>()...))>
|
||||||
|
result(A &&...args) noexcept
|
||||||
|
: ret_(base_t::init_code(std::forward<A>(args)...)) {}
|
||||||
|
|
||||||
|
std::string format_string() const {
|
||||||
|
if LIBIPC_LIKELY(ret_) {
|
||||||
|
return fmt("value = ", ret_.value());
|
||||||
|
} else {
|
||||||
|
return fmt("error = ", ret_.error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T value() const noexcept { return ret_ ? ret_.value() : T{}; }
|
||||||
|
bool ok () const noexcept { return ret_.has_value(); }
|
||||||
|
std::error_code error() const noexcept { return ret_.error(); }
|
||||||
|
|
||||||
|
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.ret_ == rhs.ret_; }
|
||||||
|
friend bool operator!=(result const &lhs, result const &rhs) noexcept { return !(lhs == rhs); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class result<void> {
|
||||||
|
private:
|
||||||
|
std::error_code ret_; ///< internal data
|
||||||
|
|
||||||
|
public:
|
||||||
|
result() noexcept
|
||||||
|
: ret_(-1, std::generic_category()) {}
|
||||||
|
|
||||||
|
result(std::error_code const &ec) noexcept
|
||||||
|
: ret_(ec) {}
|
||||||
|
|
||||||
|
std::string format_string() const {
|
||||||
|
return fmt("error = ", error());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok () const noexcept { return !ret_; }
|
||||||
|
std::error_code error() const noexcept { return ret_; }
|
||||||
|
explicit operator bool () const noexcept { return ok(); }
|
||||||
|
|
||||||
|
friend bool operator==(result const &lhs, result const &rhs) noexcept { return lhs.ret_ == rhs.ret_; }
|
||||||
|
friend bool operator!=(result const &lhs, result const &rhs) noexcept { return !(lhs == rhs); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Custom defined fmt_to method for imp::fmt
|
||||||
|
namespace detail_tag_invoke {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool tag_invoke(decltype(ipc::fmt_to), fmt_context &ctx, result<T> const &r) {
|
||||||
|
return fmt_to(ctx, (r ? "succ" : "fail"), ", ", r.format_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail_tag_invoke
|
||||||
|
} // namespace ipc
|
||||||
@ -302,8 +302,7 @@ bool to_string(fmt_context &ctx, std::nullptr_t) noexcept {
|
|||||||
return ctx.append("null");
|
return ctx.append("null");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
bool to_string(fmt_context &ctx, void const volatile *a) noexcept {
|
||||||
bool to_string<void, void>(fmt_context &ctx, void const volatile *a) noexcept {
|
|
||||||
if (a == nullptr) {
|
if (a == nullptr) {
|
||||||
return to_string(ctx, nullptr);
|
return to_string(ctx, nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,10 +28,10 @@ TEST(log, custom) {
|
|||||||
std::string e;
|
std::string e;
|
||||||
} ll_data;
|
} ll_data;
|
||||||
auto ll = [&ll_data](auto &&ctx) {
|
auto ll = [&ll_data](auto &&ctx) {
|
||||||
auto s = imp::fmt(ctx.params);
|
auto s = ipc::fmt(ctx.params);
|
||||||
if (ctx.level == imp::log::level::error) ll_data.e += s + " ";
|
if (ctx.level == ipc::log::level::error) ll_data.e += s + " ";
|
||||||
else
|
else
|
||||||
if (ctx.level == imp::log::level::info ) ll_data.i += s + " ";
|
if (ctx.level == ipc::log::level::info ) ll_data.i += s + " ";
|
||||||
};
|
};
|
||||||
|
|
||||||
LIBIPC_LOG(ll);
|
LIBIPC_LOG(ll);
|
||||||
|
|||||||
109
test/imp/test_imp_result.cpp
Normal file
109
test/imp/test_imp_result.cpp
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#include "libipc/imp/result.h"
|
||||||
|
#include "libipc/imp/fmt.h"
|
||||||
|
|
||||||
|
TEST(result, ok) {
|
||||||
|
ipc::result<std::uint64_t> ret;
|
||||||
|
EXPECT_FALSE(ret);
|
||||||
|
EXPECT_FALSE(ret.ok());
|
||||||
|
EXPECT_EQ(ret.value(), 0);
|
||||||
|
|
||||||
|
ret = {0};
|
||||||
|
EXPECT_TRUE(ret);
|
||||||
|
EXPECT_TRUE(ret.ok());
|
||||||
|
EXPECT_EQ(ret.value(), 0);
|
||||||
|
|
||||||
|
ret = ipc::result<std::uint64_t>(1234);
|
||||||
|
EXPECT_TRUE(ret);
|
||||||
|
EXPECT_TRUE(ret.ok());
|
||||||
|
EXPECT_EQ(ret.value(), 1234);
|
||||||
|
|
||||||
|
ret = std::error_code{9999, std::generic_category()};
|
||||||
|
EXPECT_FALSE(ret);
|
||||||
|
EXPECT_FALSE(ret.ok());
|
||||||
|
EXPECT_EQ(ret.value(), 0);
|
||||||
|
|
||||||
|
ret = 4321;
|
||||||
|
EXPECT_TRUE(ret);
|
||||||
|
EXPECT_TRUE(ret.ok());
|
||||||
|
EXPECT_EQ(ret.value(), 4321);
|
||||||
|
|
||||||
|
ipc::result<void> r1;
|
||||||
|
EXPECT_FALSE(r1);
|
||||||
|
r1 = std::error_code{};
|
||||||
|
EXPECT_TRUE(r1);
|
||||||
|
r1 = {};
|
||||||
|
EXPECT_FALSE(r1);
|
||||||
|
r1 = std::error_code{9999, std::generic_category()};
|
||||||
|
EXPECT_FALSE(r1);
|
||||||
|
EXPECT_EQ(r1.error().value(), 9999);
|
||||||
|
|
||||||
|
ipc::result<int *> r2 {nullptr, std::error_code{4321, std::generic_category()}};
|
||||||
|
EXPECT_NE(r2, nullptr); // ipc::result<int *>{nullptr}
|
||||||
|
EXPECT_EQ(*r2, nullptr);
|
||||||
|
EXPECT_FALSE(r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(result, compare) {
|
||||||
|
ipc::result<std::uint64_t> r1, r2;
|
||||||
|
EXPECT_EQ(r1, r2);
|
||||||
|
|
||||||
|
ipc::result<std::uint64_t> r3(0);
|
||||||
|
EXPECT_NE(r1, r3);
|
||||||
|
|
||||||
|
ipc::result<std::uint64_t> r4(222222);
|
||||||
|
EXPECT_NE(r3, r4);
|
||||||
|
|
||||||
|
ipc::result<std::uint64_t> r5(std::error_code{9999, std::generic_category()});
|
||||||
|
EXPECT_NE(r4, r5);
|
||||||
|
EXPECT_NE(r3, r5);
|
||||||
|
|
||||||
|
r3 = r5;
|
||||||
|
EXPECT_EQ(r3, r5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(result, fmt) {
|
||||||
|
{
|
||||||
|
ipc::result<std::uint64_t> r1;
|
||||||
|
EXPECT_EQ(ipc::fmt(r1), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category())));
|
||||||
|
ipc::result<std::uint64_t> r2(65537);
|
||||||
|
EXPECT_EQ(ipc::fmt(r2), "succ, value = 65537");
|
||||||
|
ipc::result<std::uint64_t> r3(0);
|
||||||
|
EXPECT_EQ(ipc::fmt(r3), "succ, value = 0");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ipc::result<int> r0;
|
||||||
|
EXPECT_EQ(ipc::fmt(r0), ipc::fmt(ipc::result<std::uint64_t>()));
|
||||||
|
ipc::result<int> r1 {std::error_code(-1, std::generic_category())};
|
||||||
|
EXPECT_EQ(ipc::fmt(r1), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category())));
|
||||||
|
|
||||||
|
ipc::result<void *> r2 {&r1};
|
||||||
|
EXPECT_EQ(ipc::fmt(r2), ipc::fmt("succ, value = ", (void *)&r1));
|
||||||
|
|
||||||
|
int aaa {};
|
||||||
|
ipc::result<int *> r3 {&aaa};
|
||||||
|
EXPECT_EQ(ipc::fmt(r3), ipc::fmt("succ, value = ", (void *)&aaa));
|
||||||
|
ipc::result<int *> r4 {nullptr};
|
||||||
|
EXPECT_EQ(ipc::fmt(r4), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category())));
|
||||||
|
r4 = std::error_code(1234, std::generic_category());
|
||||||
|
EXPECT_EQ(ipc::fmt(r4), ipc::fmt("fail, error = ", std::error_code(1234, std::generic_category())));
|
||||||
|
ipc::result<int *> r5;
|
||||||
|
EXPECT_EQ(ipc::fmt(r5), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category())));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ipc::result<std::int64_t> r1 {-123};
|
||||||
|
EXPECT_EQ(ipc::fmt(r1), ipc::fmt("succ, value = ", -123));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ipc::result<void> r1;
|
||||||
|
EXPECT_EQ(ipc::fmt(r1), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category())));
|
||||||
|
r1 = std::error_code{};
|
||||||
|
EXPECT_TRUE(r1);
|
||||||
|
EXPECT_EQ(ipc::fmt(r1), ipc::fmt("succ, error = ", std::error_code()));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user