add: [result] an additional status code can be returned on failure to return a pointer

This commit is contained in:
mutouyun 2022-05-15 19:20:30 +08:00
parent 9e170999a1
commit e21da4fe2d
5 changed files with 79 additions and 31 deletions

View File

@ -9,10 +9,9 @@
#include <cstddef>
#include <cstdint>
#if !defined(LIBIMP_NAMESPACE)
# define LIBIMP_NAMESPACE imp
#endif
#define LIBIMP_NAMESPACE_BEG_ namespace LIBIMP_NAMESPACE {
#define LIBIMP_ imp
#define LIBIMP_NAMESPACE_ LIBIMP_
#define LIBIMP_NAMESPACE_BEG_ namespace LIBIMP_NAMESPACE_ {
#define LIBIMP_NAMESPACE_END_ }
LIBIMP_NAMESPACE_BEG_

View File

@ -12,6 +12,7 @@
#include "fmt/format.h"
#include "libimp/def.h"
#include "libimp/detect_plat.h"
#include "libimp/export.h"
LIBIMP_NAMESPACE_BEG_
@ -26,7 +27,7 @@ class LIBIMP_EXPORT result_code {
public:
result_code() noexcept;
result_code(bool ok, std::uint64_t value = 0) noexcept;
result_code(bool ok, std::uint64_t value = {}) noexcept;
std::uint64_t value() const noexcept;
bool ok() const noexcept;
@ -42,6 +43,11 @@ public:
friend bool operator!=(result_code const &lhs, result_code const &rhs) noexcept;
};
template <typename T,
typename DefTraits = detail_result::default_traits<T>,
typename = void>
class result;
namespace detail_result {
template <typename T, typename = void>
@ -57,8 +63,9 @@ struct default_traits<T, std::enable_if_t<std::is_integral<T>::value>> {
static T cast_from_code(std::uint64_t code) noexcept {
return static_cast<T>(code);
}
static T regularize(T value) noexcept {
return value;
template <typename Out>
static auto format(result<T> const &r, Out &&out) noexcept {
return format_to(out, "{}", *r);
}
};
@ -72,16 +79,19 @@ struct default_traits<T, std::enable_if_t<std::is_pointer<T>::value>> {
static T cast_from_code(std::uint64_t code) noexcept {
return reinterpret_cast<T>(code);
}
static void *regularize(T value) noexcept {
return value;
template <typename Out>
static auto format(result<T> const &r, Out &&out) noexcept {
if LIBIMP_LIKELY(r) {
return format_to(out, "{}", static_cast<void *>(*r));
}
return format_to(out, "{}, code = {}", static_cast<void *>(*r), r.code());
}
};
} // namespace detail_result
template <typename T,
typename DefTraits = detail_result::default_traits<T>>
class result {
template <typename T, typename DefTraits>
class result<T, DefTraits, std::enable_if_t<std::is_integral<T>::value>> {
result_code code_;
@ -89,7 +99,7 @@ public:
using default_traits_t = DefTraits;
result() noexcept = default;
result(bool ok, T value = default_traits_t::value())
result(bool ok, T value = default_traits_t::value()) noexcept
: code_(ok, default_traits_t::cast_to_code(value)) {}
T value() const noexcept { return default_traits_t::cast_from_code(code_.value()); }
@ -104,31 +114,58 @@ public:
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_; }
template <typename T, typename DefTraits>
class result<T, DefTraits, std::enable_if_t<std::is_pointer<T>::value>> {
result_code code_;
public:
using default_traits_t = DefTraits;
result(T value = default_traits_t::value()) noexcept
: code_(default_traits_t::value() != value,
default_traits_t::cast_to_code(value)) {}
result(std::nullptr_t, std::uint64_t code) noexcept
: code_(false, code) {}
T value() const noexcept { return code_.ok() ? default_traits_t::cast_from_code(code_.value()) : nullptr; }
bool ok() const noexcept { return code_.ok(); }
std::uint64_t code() const noexcept { return code_.value(); }
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_; }
};
LIBIMP_NAMESPACE_END_
template <typename T>
struct fmt::formatter<::LIBIMP_NAMESPACE::result<T>> {
template <typename T, typename D>
struct fmt::formatter<::LIBIMP_::result<T, D>> {
constexpr auto parse(format_parse_context& ctx) {
return ctx.end();
}
template <typename FormatContext>
auto format(::LIBIMP_NAMESPACE::result<T> r, FormatContext &ctx) {
return format_to(ctx.out(), "[{}, value = {}]",
(r ? "succ" : "fail"),
::LIBIMP_NAMESPACE::result<T>::default_traits_t::regularize(*r));
auto format(::LIBIMP_::result<T, D> r, FormatContext &ctx) {
return format_to(::LIBIMP_::result<T, D>::default_traits_t::format(r,
format_to(ctx.out(), "[{}, value = ", r ? "succ" : "fail")), "]");
}
};
template <>
struct fmt::formatter<::LIBIMP_NAMESPACE::result_code>
: formatter<::LIBIMP_NAMESPACE::result<std::uint64_t>> {
struct fmt::formatter<::LIBIMP_::result_code>
: formatter<::LIBIMP_::result<std::uint64_t>> {
template <typename FormatContext>
auto format(::LIBIMP_NAMESPACE::result_code r, FormatContext &ctx) {
auto format(::LIBIMP_::result_code r, FormatContext &ctx) {
return format_to(ctx.out(), "[{}, value = {}]", (r ? "succ" : "fail"), *r);
}
};

View File

@ -9,14 +9,21 @@
#include <cstddef>
#include <cstdint>
#if !defined(LIBIPC_NAMESPACE)
# define LIBIPC_NAMESPACE ipc
#endif
#define LIBIPC_NAMESPACE_BEG_ namespace LIBIPC_NAMESPACE {
#define LIBIPC_ ipc
#define LIBIPC_NAMESPACE_ LIBIPC_
#define LIBIPC_NAMESPACE_BEG_ namespace LIBIPC_NAMESPACE_ {
#define LIBIPC_NAMESPACE_END_ }
LIBIPC_NAMESPACE_BEG_
// constants
struct prot {
enum : std::uint32_t {
none = 0x00,
read = 0x01,
write = 0x02,
};
};
LIBIPC_NAMESPACE_END_

View File

@ -8,6 +8,7 @@
#include "libimp/export.h"
#include "libimp/result.h"
#include "libipc/def.h"
LIBIPC_NAMESPACE_BEG_
@ -18,6 +19,6 @@ using mmap_t = mmap_handle *;
/**
* @brief Creates a new mapping in the virtual address space of the calling process.
*/
LIBIMP_EXPORT mmap_t mmap_open();
LIBIMP_EXPORT ::LIBIMP_::result<mmap_t> mmap_open();
LIBIPC_NAMESPACE_END_

View File

@ -68,10 +68,14 @@ TEST(result, fmt) {
{
imp::result<int> r1 {false, -123};
EXPECT_EQ(fmt::format("{}", r1), fmt::format("[fail, value = {}]", -123));
imp::result<void *> r2 {true, &r1};
imp::result<void *> r2 {&r1};
EXPECT_EQ(fmt::format("{}", r2), fmt::format("[succ, value = {}]", (void *)&r1));
int aaa {};
imp::result<int *> r3 {false, &aaa};
EXPECT_EQ(fmt::format("{}", r3), fmt::format("[fail, value = {}]", (void *)&aaa));
imp::result<int *> r3 {&aaa};
EXPECT_EQ(fmt::format("{}", r3), fmt::format("[succ, value = {}]", (void *)&aaa));
imp::result<int *> r4 {nullptr};
EXPECT_EQ(fmt::format("{}", r4), fmt::format("[fail, value = {}, code = 0]", nullptr));
r4 = {nullptr, 1234};
EXPECT_EQ(fmt::format("{}", r4), fmt::format("[fail, value = {}, code = 1234]", nullptr));
}
}