mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
upd: [imp] optimize result interface and fix some bugs
This commit is contained in:
parent
7d8ff13db7
commit
649a5ee02a
@ -54,6 +54,7 @@ class LIBIMP_EXPORT error_code {
|
||||
public:
|
||||
/// \brief constructors
|
||||
error_code() noexcept;
|
||||
error_code(error_code_t const &r) noexcept;
|
||||
error_code(error_code_t const &r, error_category const &ec) noexcept;
|
||||
|
||||
/// \brief observers
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include <array>
|
||||
|
||||
#include "libimp/def.h"
|
||||
#include "libimp/generic.h"
|
||||
@ -18,9 +19,12 @@
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
/**
|
||||
* \class class LIBIMP_EXPORT fmt_context
|
||||
* \brief The context of fmt.
|
||||
*/
|
||||
class LIBIMP_EXPORT fmt_context {
|
||||
std::array<char, 2048U> sbuf_; ///< stack buffer
|
||||
|
||||
std::string &joined_;
|
||||
std::size_t offset_;
|
||||
|
||||
|
||||
@ -16,39 +16,9 @@
|
||||
#include "libimp/export.h"
|
||||
#include "libimp/fmt.h"
|
||||
#include "libimp/generic.h"
|
||||
#include "libimp/error.h"
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
using result_code_t = std::uint64_t;
|
||||
using result_type = std::tuple<result_code_t, bool>;
|
||||
|
||||
/**
|
||||
* \class class LIBIMP_EXPORT result_code
|
||||
* \brief Uses std::uint64_t as the default underlying type of error code.
|
||||
*/
|
||||
class LIBIMP_EXPORT result_code {
|
||||
result_type status_;
|
||||
|
||||
public:
|
||||
result_code() noexcept;
|
||||
result_code(result_code_t value) noexcept;
|
||||
result_code(result_type const &value) noexcept;
|
||||
result_code(bool ok, result_code_t value) noexcept;
|
||||
|
||||
result_code_t value() const noexcept;
|
||||
bool ok() const noexcept;
|
||||
|
||||
result_code_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 <typename T, typename = void>
|
||||
@ -60,31 +30,56 @@ template <typename T,
|
||||
typename TypeTraits = detail_result::default_traits<T>>
|
||||
class result;
|
||||
|
||||
/// \typedef Uses std::uint64_t as the default underlying type of result code.
|
||||
using result_code = result<std::uint64_t>;
|
||||
|
||||
namespace detail_result {
|
||||
|
||||
template <typename T>
|
||||
struct default_traits<T, std::enable_if_t<std::is_integral<T>::value>> {
|
||||
struct generic_traits {
|
||||
/// \typedef Combine data and valid identifiers with a tuple.
|
||||
using storage_t = std::tuple<T, error_code>;
|
||||
|
||||
/// \brief Custom initialization.
|
||||
constexpr static void init_code(result_code &code) noexcept {
|
||||
code = {};
|
||||
constexpr static void init_code(storage_t &code) noexcept {
|
||||
code = {0, -1/*make a default error code*/};
|
||||
}
|
||||
constexpr static void init_code(result_code &code, bool ok, T value) noexcept {
|
||||
code = {ok, static_cast<result_code_t>(value)};
|
||||
constexpr static void init_code(storage_t &code, T value, error_code const &ec) noexcept {
|
||||
code = {value, ec};
|
||||
}
|
||||
constexpr static void init_code(result_code &code, T value) noexcept {
|
||||
init_code(code, true, value);
|
||||
constexpr static void init_code(storage_t &code, T value) noexcept {
|
||||
code = {value, {}};
|
||||
}
|
||||
constexpr static void init_code(storage_t &code, error_code const &ec) noexcept {
|
||||
code = {{}, ec};
|
||||
}
|
||||
|
||||
/// \brief Custom type data acquisition.
|
||||
constexpr static T get_value(storage_t const &code) noexcept {
|
||||
return std::get<0>(code);
|
||||
}
|
||||
constexpr static bool get_ok(storage_t const &code) noexcept {
|
||||
return !std::get<1>(code);
|
||||
}
|
||||
constexpr static error_code get_error(storage_t const &code) noexcept {
|
||||
return std::get<1>(code);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct default_traits<T, std::enable_if_t<std::is_integral<T>::value>> : generic_traits<T> {
|
||||
/// \brief Custom initialization.
|
||||
constexpr static void init_code(storage_t &code, T value, bool ok) noexcept {
|
||||
code = {value, static_cast<error_code_t>(ok ? 0 :
|
||||
((value == default_value()) ? -1 : value))};
|
||||
}
|
||||
using generic_traits<T>::init_code;
|
||||
|
||||
/// \brief Custom default value.
|
||||
constexpr static T default_value() noexcept {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Custom type conversions.
|
||||
constexpr static T cast_from_code(result_code code) noexcept {
|
||||
return static_cast<T>(code.value());
|
||||
}
|
||||
|
||||
/// \brief Custom formatted output.
|
||||
static std::string format(result<T> const &r) noexcept {
|
||||
return fmt(*r);
|
||||
@ -92,34 +87,27 @@ struct default_traits<T, std::enable_if_t<std::is_integral<T>::value>> {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct default_traits<T, std::enable_if_t<std::is_pointer<T>::value>> {
|
||||
struct default_traits<T, std::enable_if_t<std::is_pointer<T>::value>> : generic_traits<T> {
|
||||
/// \brief Custom initialization.
|
||||
constexpr static void init_code(result_code &code, T value = default_value()) noexcept {
|
||||
code = {default_value() != value, reinterpret_cast<result_code_t>(value)};
|
||||
constexpr static void init_code(storage_t &code, std::nullptr_t, error_code const &ec) noexcept {
|
||||
code = {nullptr, ec};
|
||||
}
|
||||
constexpr static void init_code(result_code &code, std::nullptr_t) noexcept {
|
||||
code = {false, {}};
|
||||
}
|
||||
constexpr static void init_code(result_code &code, std::nullptr_t, result_code_t r) noexcept {
|
||||
code = {false, r};
|
||||
constexpr static void init_code(storage_t &code, std::nullptr_t) noexcept {
|
||||
code = {nullptr, -1};
|
||||
}
|
||||
using generic_traits<T>::init_code;
|
||||
|
||||
/// \brief Custom default value.
|
||||
constexpr static T default_value() noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \brief Custom type conversions.
|
||||
constexpr static T cast_from_code(result_code code) noexcept {
|
||||
return code.ok() ? reinterpret_cast<T>(code.value()) : default_value();
|
||||
}
|
||||
|
||||
/// \brief Custom formatted output.
|
||||
static std::string format(result<T> const &r) noexcept {
|
||||
if LIBIMP_LIKELY(r) {
|
||||
return fmt(static_cast<void *>(*r));
|
||||
}
|
||||
return fmt(static_cast<void *>(*r), ", code = ", r.code_value());
|
||||
return fmt(static_cast<void *>(*r), ", error = ", r.error());
|
||||
}
|
||||
};
|
||||
|
||||
@ -127,51 +115,43 @@ struct default_traits<T, std::enable_if_t<std::is_pointer<T>::value>> {
|
||||
|
||||
/**
|
||||
* \class class result
|
||||
* \brief The generic wrapper for the result_code.
|
||||
* \brief The generic wrapper for the result type.
|
||||
*/
|
||||
template <typename T, typename TypeTraits>
|
||||
class result : public TypeTraits {
|
||||
|
||||
/// \brief Internal data is stored using result_code.
|
||||
result_code code_;
|
||||
|
||||
public:
|
||||
using type_traits_t = TypeTraits;
|
||||
using storage_t = typename type_traits_t::storage_t;
|
||||
|
||||
private:
|
||||
storage_t code_; ///< internal data
|
||||
|
||||
public:
|
||||
template <typename... A,
|
||||
typename = is_not_match<result, A...>,
|
||||
typename = decltype(type_traits_t::init_code(std::declval<result_code &>()
|
||||
typename = decltype(type_traits_t::init_code(std::declval<storage_t &>()
|
||||
, std::declval<A>()...))>
|
||||
result(A &&... args) noexcept {
|
||||
type_traits_t::init_code(code_, std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
bool ok() const noexcept { return code_.ok(); }
|
||||
T value() const noexcept { return type_traits_t::cast_from_code(code_); }
|
||||
T value() const noexcept { return type_traits_t::get_value(code_); }
|
||||
bool ok () const noexcept { return type_traits_t::get_ok (code_); }
|
||||
error_code error() const noexcept { return type_traits_t::get_error(code_); }
|
||||
|
||||
result_code_t code_value() const noexcept { return code_.value(); }
|
||||
|
||||
T operator*() const noexcept {
|
||||
return value();
|
||||
}
|
||||
explicit operator bool() const noexcept {
|
||||
return 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 bool operator!=(result const &lhs, result const &rhs) noexcept { return !(lhs == rhs); }
|
||||
};
|
||||
|
||||
/// \brief Custom defined fmt_to method for imp::fmt
|
||||
namespace detail {
|
||||
|
||||
inline bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, result_code r) {
|
||||
return fmt_to(ctx, "[", (r ? "succ" : "fail"), ", value = ", *r, "]");
|
||||
}
|
||||
|
||||
template <typename T, typename D>
|
||||
bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, result<T, D> r) {
|
||||
return fmt_to(ctx, "[", (r ? "succ" : "fail"), ", value = ", result<T, D>::type_traits_t::format(r), "]");
|
||||
return fmt_to(ctx, (r ? "succ" : "fail"), ", value = ", result<T, D>::type_traits_t::format(r));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@ -17,7 +17,13 @@ public:
|
||||
return "generic";
|
||||
}
|
||||
std::string message(error_code_t const &r) const {
|
||||
return fmt(r, ((r == 0) ? ", \"success\"" : ", \"failure\""));
|
||||
if (r == error_code_t(-1)) {
|
||||
return "0, \"failure\"";
|
||||
}
|
||||
if (r == error_code_t(0)) {
|
||||
return "0, \"success\"";
|
||||
}
|
||||
return fmt(r, ", \"failure\"");
|
||||
}
|
||||
};
|
||||
|
||||
@ -31,6 +37,9 @@ error_category const &generic_category() noexcept {
|
||||
error_code::error_code() noexcept
|
||||
: error_code{0, generic_category()} {}
|
||||
|
||||
error_code::error_code(error_code_t const &r) noexcept
|
||||
: error_code{r, generic_category()} {}
|
||||
|
||||
error_code::error_code(error_code_t const &r, error_category const &ec) noexcept
|
||||
: e_code_{r}, ec_{&ec} {}
|
||||
|
||||
|
||||
@ -24,10 +24,6 @@ struct sfmt_policy {
|
||||
constexpr static std::size_t aligned_size = 32U;
|
||||
};
|
||||
|
||||
struct sbuf_policy {
|
||||
constexpr static std::size_t aligned_size = 2048U;
|
||||
};
|
||||
|
||||
template <typename Policy = sfmt_policy>
|
||||
span<char> local_fmt_sbuf() noexcept {
|
||||
thread_local std::array<char, Policy::aligned_size> sbuf;
|
||||
@ -143,10 +139,6 @@ bool sprintf(fmt_context &ctx, F fop, span<char const> const &fstr, span<char co
|
||||
}
|
||||
}
|
||||
|
||||
span<char> fmt_context_sbuf() noexcept {
|
||||
return local_fmt_sbuf<sbuf_policy>();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/// \brief The context of fmt.
|
||||
@ -156,9 +148,7 @@ fmt_context::fmt_context(std::string &j) noexcept
|
||||
, offset_(0) {}
|
||||
|
||||
std::size_t fmt_context::capacity() noexcept {
|
||||
return (offset_ < fmt_context_sbuf().size())
|
||||
? fmt_context_sbuf().size()
|
||||
: joined_.size();
|
||||
return (offset_ < sbuf_.size()) ? sbuf_.size() : joined_.size();
|
||||
}
|
||||
|
||||
void fmt_context::reset() noexcept {
|
||||
@ -167,8 +157,8 @@ void fmt_context::reset() noexcept {
|
||||
|
||||
bool fmt_context::finish() noexcept {
|
||||
LIBIMP_TRY {
|
||||
if (offset_ < fmt_context_sbuf().size()) {
|
||||
joined_.assign(fmt_context_sbuf().data(), offset_);
|
||||
if (offset_ < sbuf_.size()) {
|
||||
joined_.assign(sbuf_.data(), offset_);
|
||||
} else {
|
||||
joined_.resize(offset_);
|
||||
}
|
||||
@ -183,7 +173,7 @@ span<char> fmt_context::buffer(std::size_t sz) noexcept {
|
||||
constexpr std::size_t fmt_context_aligned_size = 512U;
|
||||
return (sz & ~(fmt_context_aligned_size - 1)) + fmt_context_aligned_size;
|
||||
};
|
||||
auto sbuf = fmt_context_sbuf();
|
||||
auto sbuf = make_span(sbuf_);
|
||||
LIBIMP_TRY {
|
||||
if (offset_ < sbuf.size()) {
|
||||
if ((offset_ + sz) < sbuf.size()) {
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
|
||||
#include "libimp/result.h"
|
||||
#include "libimp/horrible_cast.h"
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
result_code::result_code() noexcept
|
||||
: result_code(false, {}) {}
|
||||
|
||||
result_code::result_code(result_code_t value) noexcept
|
||||
: result_code(true, value) {}
|
||||
|
||||
result_code::result_code(result_type const &value) noexcept
|
||||
: result_code(std::get<bool>(value),
|
||||
std::get<result_code_t>(value)) {}
|
||||
|
||||
result_code::result_code(bool ok, std::uint64_t code) noexcept
|
||||
: status_(code, ok) {}
|
||||
|
||||
result_code_t result_code::value() const noexcept {
|
||||
return std::get<result_code_t>(status_);
|
||||
}
|
||||
|
||||
bool result_code::ok() const noexcept {
|
||||
return std::get<bool>(status_);
|
||||
}
|
||||
|
||||
bool operator==(result_code const &lhs, result_code const &rhs) noexcept {
|
||||
return lhs.status_ == rhs.status_;
|
||||
}
|
||||
|
||||
bool operator!=(result_code const &lhs, result_code const &rhs) noexcept {
|
||||
return lhs.status_ != rhs.status_;
|
||||
}
|
||||
|
||||
LIBIMP_NAMESPACE_END_
|
||||
@ -74,9 +74,17 @@ result<int> shm_open_fd(std::string const &name, mode::type type) noexcept {
|
||||
}
|
||||
|
||||
/// \brief Create/Open POSIX shared memory bject
|
||||
return ::shm_open(name.c_str(), flag, S_IRUSR | S_IWUSR |
|
||||
S_IRGRP | S_IWGRP |
|
||||
S_IROTH | S_IWOTH);
|
||||
int fd = ::shm_open(name.c_str(), flag, S_IRUSR | S_IWUSR |
|
||||
S_IRGRP | S_IWGRP |
|
||||
S_IROTH | S_IWOTH);
|
||||
if (fd == posix::failed) {
|
||||
auto err = sys::error();
|
||||
log.error("failed: shm_open(name = ", name,
|
||||
", type = ", type,
|
||||
"). error = ", err);
|
||||
return err;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
result_code ftruncate_fd(int fd, std::size_t size) noexcept {
|
||||
@ -85,9 +93,9 @@ result_code ftruncate_fd(int fd, std::size_t size) noexcept {
|
||||
if (::ftruncate(fd, size) != posix::succ) {
|
||||
auto err = sys::error();
|
||||
log.error("failed: ftruncate(", fd, ", ", size, "). error = ", err);
|
||||
return err.code();
|
||||
return err;
|
||||
}
|
||||
return {posix::succ};
|
||||
return posix::succ;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -100,12 +108,8 @@ result_code ftruncate_fd(int fd, std::size_t size) noexcept {
|
||||
result<shm_t> shm_open(std::string name, std::size_t size, mode::type type) noexcept {
|
||||
LIBIMP_LOG_();
|
||||
auto fd = shm_open_fd(name, type);
|
||||
if (!fd) return {};
|
||||
if (*fd == posix::failed) {
|
||||
log.error("failed: shm_open(name = ", name,
|
||||
", type = ", type,
|
||||
"). error = ", sys::error());
|
||||
return {};
|
||||
if (!fd) {
|
||||
return fd.error();
|
||||
}
|
||||
LIBIMP_UNUSED auto guard = std::unique_ptr<decltype(fd), void (*)(decltype(fd) *)> {
|
||||
&fd, [](decltype(fd) *pfd) {
|
||||
@ -115,26 +119,30 @@ result<shm_t> shm_open(std::string name, std::size_t size, mode::type type) noex
|
||||
/// \brief Try to get the size of this fd
|
||||
struct stat st;
|
||||
if (::fstat(*fd, &st) == posix::failed) {
|
||||
log.error("failed: fstat(fd = ", *fd, "). error = ", sys::error());
|
||||
return {};
|
||||
auto err = sys::error();
|
||||
log.error("failed: fstat(fd = ", *fd, "). error = ", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/// \brief Truncate this fd to a specified length
|
||||
if (size == 0) {
|
||||
size = static_cast<std::size_t>(st.st_size);
|
||||
if (!ftruncate_fd(*fd, size)) return {};
|
||||
auto ret = ftruncate_fd(*fd, size);
|
||||
if (!ret) return ret.error();
|
||||
} else if (st.st_size > 0) {
|
||||
/// \remark Based on the actual size.
|
||||
size = static_cast<std::size_t>(st.st_size);
|
||||
} else { // st.st_size <= 0
|
||||
if (!ftruncate_fd(*fd, size)) return {};
|
||||
auto ret = ftruncate_fd(*fd, size);
|
||||
if (!ret) return ret.error();
|
||||
}
|
||||
|
||||
/// \brief Creates a new mapping in the virtual address space of the calling process.
|
||||
void *mem = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0);
|
||||
if (mem == MAP_FAILED) {
|
||||
log.error("failed: mmap(size = ", size, ", fd = ", *fd, "). error = ", sys::error());
|
||||
return {};
|
||||
auto err = sys::error();
|
||||
log.error("failed: mmap(size = ", size, ", fd = ", *fd, "). error = ", err);
|
||||
return err;
|
||||
}
|
||||
return new shm_handle{std::move(name), size, mem};
|
||||
}
|
||||
@ -149,11 +157,11 @@ result_code shm_close(shm_t h) noexcept {
|
||||
if (::munmap(shm->memp, shm->f_sz) == posix::failed) {
|
||||
auto err = sys::error();
|
||||
log.error("failed: munmap(", shm->memp, ", ", shm->f_sz, "). error = ", err);
|
||||
return err.code();
|
||||
return err;
|
||||
}
|
||||
/// \brief no unlink the file.
|
||||
delete shm;
|
||||
return {posix::succ};
|
||||
return posix::succ;
|
||||
}
|
||||
|
||||
LIBIPC_NAMESPACE_END_
|
||||
|
||||
@ -42,9 +42,9 @@ result_code mmap_close(HANDLE h) {
|
||||
if (!::CloseHandle(h)) {
|
||||
auto err = sys::error();
|
||||
log.error("failed: CloseHandle(", h, "). error = ", err);
|
||||
return err.code();
|
||||
return err;
|
||||
}
|
||||
return {ERROR_SUCCESS};
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,7 +78,7 @@ result<HANDLE> mmap_open(std::string const &file, std::size_t size, mode::type t
|
||||
if (h == NULL) {
|
||||
auto err = sys::error();
|
||||
log.error("failed: OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, ", file, "). error = ", err);
|
||||
return {nullptr, err.code()};
|
||||
return {nullptr, err};
|
||||
}
|
||||
return h;
|
||||
};
|
||||
@ -91,7 +91,7 @@ result<HANDLE> mmap_open(std::string const &file, std::size_t size, mode::type t
|
||||
if (h == NULL) {
|
||||
auto err = sys::error();
|
||||
log.error("failed: CreateFileMapping(PAGE_READWRITE | SEC_COMMIT, ", size, ", ", file, "). error = ", err);
|
||||
return {nullptr, err.code()};
|
||||
return {nullptr, err};
|
||||
}
|
||||
return h;
|
||||
};
|
||||
@ -133,7 +133,7 @@ result<LPVOID> mmap_memof(HANDLE h) {
|
||||
if (mem == NULL) {
|
||||
auto err = sys::error();
|
||||
log.error("failed: MapViewOfFile(", h, ", FILE_MAP_ALL_ACCESS). error = ", err);
|
||||
return {nullptr, err.code()};
|
||||
return {nullptr, err};
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
@ -152,7 +152,7 @@ result<SIZE_T> mmap_sizeof(LPCVOID mem) {
|
||||
if (::VirtualQuery(mem, &mem_info, sizeof(mem_info)) == 0) {
|
||||
auto err = sys::error();
|
||||
log.error("failed: VirtualQuery(", mem, "). error = ", err);
|
||||
return {false, (SIZE_T)err.code()};
|
||||
return {false, err};
|
||||
}
|
||||
return mem_info.RegionSize;
|
||||
}
|
||||
|
||||
@ -22,19 +22,19 @@ result<shm_t> shm_open(std::string name, std::size_t size, mode::type type) noex
|
||||
auto h = mmap_open(name, size, type);
|
||||
if (*h == NULL) {
|
||||
log.error("failed: mmap_open(name = ", name, ", size = ", size, ", type = ", type, ").");
|
||||
return {nullptr, h.code_value()};
|
||||
return {nullptr, h.error()};
|
||||
}
|
||||
auto mem = mmap_memof(*h);
|
||||
if (*mem == NULL) {
|
||||
log.error("failed: mmap_memof(", *h, ").");
|
||||
mmap_close(*h);
|
||||
return {nullptr, mem.code_value()};
|
||||
return {nullptr, mem.error()};
|
||||
}
|
||||
auto sz = mmap_sizeof(*mem);
|
||||
if (!sz) {
|
||||
log.error("failed: mmap_sizeof(", *mem, ").");
|
||||
mmap_close(*h);
|
||||
return {nullptr, static_cast<result_code_t>(sz.value())};
|
||||
return {nullptr, sz.error()};
|
||||
}
|
||||
return new shm_handle{std::move(name), *sz, *mem, *h};
|
||||
}
|
||||
|
||||
@ -13,50 +13,58 @@ TEST(result, ok) {
|
||||
EXPECT_FALSE(ret.ok());
|
||||
EXPECT_EQ(ret.value(), 0);
|
||||
|
||||
ret = {true, 0};
|
||||
ret = {0, true};
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(ret.ok());
|
||||
EXPECT_EQ(ret.value(), 0);
|
||||
|
||||
ret = {false, 1234};
|
||||
ret = {0, false};
|
||||
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 = {1234, false};
|
||||
EXPECT_FALSE(ret);
|
||||
EXPECT_FALSE(ret.ok());
|
||||
EXPECT_EQ(*ret, 1234);
|
||||
|
||||
ret = imp::result_code(1234, true);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(ret.ok());
|
||||
EXPECT_EQ(ret.value(), 1234);
|
||||
|
||||
ret = {0, false};
|
||||
EXPECT_FALSE(ret);
|
||||
EXPECT_FALSE(ret.ok());
|
||||
EXPECT_EQ(ret.value(), 0);
|
||||
|
||||
ret = {4321, true};
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(ret.ok());
|
||||
EXPECT_EQ(ret.value(), 4321);
|
||||
|
||||
imp::result<int *> r2 {nullptr, 4321};
|
||||
EXPECT_NE(r2, nullptr); // imp::result<int *>{nullptr}
|
||||
EXPECT_EQ(*r2, nullptr);
|
||||
EXPECT_FALSE(r2);
|
||||
}
|
||||
|
||||
TEST(result, code) {
|
||||
imp::result_code ret(true, 1234);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(ret.ok());
|
||||
EXPECT_EQ(ret.value(), 1234);
|
||||
|
||||
ret = {false, 0};
|
||||
EXPECT_FALSE(ret);
|
||||
EXPECT_FALSE(ret.ok());
|
||||
EXPECT_EQ(ret.value(), 0);
|
||||
|
||||
ret = {true, 4321};
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(ret.ok());
|
||||
EXPECT_EQ(ret.value(), 4321);
|
||||
}
|
||||
|
||||
TEST(result, compare) {
|
||||
imp::result_code r1, r2;
|
||||
EXPECT_EQ(r1, r2);
|
||||
|
||||
imp::result_code r3(true);
|
||||
imp::result_code r3(0, true);
|
||||
EXPECT_NE(r1, r3);
|
||||
|
||||
imp::result_code r4(true, 222222);
|
||||
imp::result_code r4(222222, true);
|
||||
EXPECT_NE(r3, r4);
|
||||
|
||||
imp::result_code r5(false, 222222);
|
||||
imp::result_code r5(222222, false);
|
||||
EXPECT_NE(r4, r5);
|
||||
r3 = r5;
|
||||
EXPECT_EQ(r3, r5);
|
||||
@ -65,33 +73,33 @@ TEST(result, compare) {
|
||||
TEST(result, fmt) {
|
||||
{
|
||||
imp::result_code r1;
|
||||
EXPECT_EQ(imp::fmt(r1), "[fail, value = 0]");
|
||||
imp::result_code r2(true, 65537);
|
||||
EXPECT_EQ(imp::fmt(r2), "[succ, value = 65537]");
|
||||
EXPECT_EQ(imp::fmt(r1), "fail, value = 0");
|
||||
imp::result_code r2(65537, true);
|
||||
EXPECT_EQ(imp::fmt(r2), "succ, value = 65537");
|
||||
imp::result_code r3(0);
|
||||
EXPECT_EQ(imp::fmt(r3), "[succ, value = 0]");
|
||||
EXPECT_EQ(imp::fmt(r3), "succ, value = 0");
|
||||
}
|
||||
{
|
||||
imp::result<int> r0;
|
||||
EXPECT_EQ(imp::fmt(r0), imp::fmt(imp::result_code()));
|
||||
imp::result<int> r1 {false, -123};
|
||||
EXPECT_EQ(imp::fmt(r1), imp::fmt("[fail, value = ", -123, "]"));
|
||||
imp::result<int> r1 {-123, false};
|
||||
EXPECT_EQ(imp::fmt(r1), imp::fmt("fail, value = ", -123));
|
||||
|
||||
imp::result<void *> r2 {&r1};
|
||||
EXPECT_EQ(imp::fmt(r2), imp::fmt("[succ, value = ", (void *)&r1, "]"));
|
||||
EXPECT_EQ(imp::fmt(r2), imp::fmt("succ, value = ", (void *)&r1));
|
||||
|
||||
int aaa {};
|
||||
imp::result<int *> r3 {&aaa};
|
||||
EXPECT_EQ(imp::fmt(r3), imp::fmt("[succ, value = ", (void *)&aaa, "]"));
|
||||
EXPECT_EQ(imp::fmt(r3), imp::fmt("succ, value = ", (void *)&aaa));
|
||||
imp::result<int *> r4 {nullptr};
|
||||
EXPECT_EQ(imp::fmt(r4), imp::fmt("[fail, value = ", nullptr, ", code = 0]"));
|
||||
EXPECT_EQ(imp::fmt(r4), imp::fmt("fail, value = ", nullptr, ", error = [generic: 0, \"failure\"]"));
|
||||
r4 = {nullptr, 1234};
|
||||
EXPECT_EQ(imp::fmt(r4), imp::fmt("[fail, value = ", nullptr, ", code = 1234]"));
|
||||
EXPECT_EQ(imp::fmt(r4), imp::fmt("fail, value = ", nullptr, ", error = [generic: 1234, \"failure\"]"));
|
||||
imp::result<int *> r5;
|
||||
EXPECT_EQ(imp::fmt(r5), "[fail, value = null, code = 0]");
|
||||
EXPECT_EQ(imp::fmt(r5), "fail, value = null, error = [generic: 0, \"failure\"]");
|
||||
}
|
||||
{
|
||||
imp::result<std::int64_t> r1 {-123};
|
||||
EXPECT_EQ(imp::fmt(r1), imp::fmt("[succ, value = ", -123, "]"));
|
||||
EXPECT_EQ(imp::fmt(r1), imp::fmt("succ, value = ", -123));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user