mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
upd: [imp] optimized log interface implementation
This commit is contained in:
parent
19cb391624
commit
ca78e3511b
@ -6,14 +6,14 @@
|
||||
namespace {
|
||||
|
||||
void imp_log_no_output(benchmark::State &state) {
|
||||
imp::log::grip log {__func__, {}};
|
||||
LIBIMP_LOG_([](auto &&) {});
|
||||
for (auto _ : state) {
|
||||
log.debug("hello log.");
|
||||
}
|
||||
}
|
||||
|
||||
void imp_log_gripper(benchmark::State &state) {
|
||||
imp::log::grip log {__func__, {}};
|
||||
void imp_log_info(benchmark::State &state) {
|
||||
LIBIMP_LOG_([](auto &&) {});
|
||||
for (auto _ : state) {
|
||||
log.info("hello log.");
|
||||
}
|
||||
@ -22,4 +22,4 @@ void imp_log_gripper(benchmark::State &state) {
|
||||
} // namespace
|
||||
|
||||
BENCHMARK(imp_log_no_output);
|
||||
BENCHMARK(imp_log_gripper);
|
||||
BENCHMARK(imp_log_info);
|
||||
@ -13,6 +13,7 @@
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <chrono> // std::chrono::time_point
|
||||
#include <tuple>
|
||||
#include <cstddef>
|
||||
#include <ctime> // std::tm, std::localtime
|
||||
|
||||
@ -163,5 +164,15 @@ bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, span<T> s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Tp, std::size_t... I>
|
||||
bool unfold_tuple_fmt_to(fmt_context &ctx, Tp const &tp, std::index_sequence<I...>) {
|
||||
return fmt_to(ctx, std::get<I>(tp)...);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, std::tuple<T...> const &tp) {
|
||||
return unfold_tuple_fmt_to(ctx, tp, std::index_sequence_for<T...>{});
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
LIBIMP_NAMESPACE_END_
|
||||
|
||||
@ -71,9 +71,9 @@ struct is_same_first<T, T> : std::true_type {};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename... A>
|
||||
using is_not_match =
|
||||
using not_match =
|
||||
typename std::enable_if<!detail::is_same_first<T,
|
||||
typename std::decay<A>::type...>::value>::type;
|
||||
typename std::decay<A>::type...>::value, bool>::type;
|
||||
|
||||
/**
|
||||
* \brief Determines whether a type is specialized from a particular template.
|
||||
|
||||
@ -83,115 +83,55 @@ std::string context_to_string(context<T...> const &l_ctx) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
enum out_type : unsigned {
|
||||
out_none = 0x0,
|
||||
out_string = 0x1,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class has_fn_output {
|
||||
static std::integral_constant<out_type, out_none> check(...);
|
||||
|
||||
template <typename U, typename = decltype(std::declval<U &>().output(log::level::trace, std::declval<std::string>()))>
|
||||
static std::integral_constant<out_type, out_string> check(U *u);
|
||||
|
||||
public:
|
||||
using type = decltype(check(static_cast<T *>(nullptr)));
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr out_type has_fn_output_v = has_fn_output<T>::type::value;
|
||||
|
||||
struct vtable_t {
|
||||
void (*output)(void *, log::level, std::string &&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class traits {
|
||||
template <typename U>
|
||||
static auto make_fn_output() noexcept
|
||||
-> std::enable_if_t<(has_fn_output_v<U> == out_none), decltype(vtable_t{}.output)> {
|
||||
return [](void *, log::level, std::string &&) {};
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static auto make_fn_output() noexcept
|
||||
-> std::enable_if_t<(has_fn_output_v<U> == out_string), decltype(vtable_t{}.output)> {
|
||||
return [](void *p, log::level lev, std::string &&str) {
|
||||
static_cast<U *>(p)->output(lev, std::move(str));
|
||||
};
|
||||
}
|
||||
|
||||
public:
|
||||
static auto make_vtable() noexcept {
|
||||
static vtable_t vt { make_fn_output<T>() };
|
||||
return &vt;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class printer {
|
||||
void *objp_ {nullptr};
|
||||
detail::vtable_t *vtable_ {nullptr};
|
||||
|
||||
public:
|
||||
printer() noexcept = default;
|
||||
|
||||
template <typename T,
|
||||
typename = is_not_match<printer, T>>
|
||||
printer(T &p) noexcept
|
||||
: objp_ (static_cast<void *>(&p))
|
||||
, vtable_(detail::traits<T>::make_vtable()) {}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return (objp_ != nullptr) && (vtable_ != nullptr);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void output(context<T...> const &ctx) noexcept {
|
||||
if (!*this) return;
|
||||
LIBIMP_TRY {
|
||||
vtable_->output(objp_, ctx.level, context_to_string(ctx));
|
||||
} LIBIMP_CATCH(...) {}
|
||||
}
|
||||
};
|
||||
|
||||
/// \class class LIBIMP_EXPORT std_t
|
||||
/// \brief Standard console output.
|
||||
class LIBIMP_EXPORT std_t {
|
||||
public:
|
||||
void output(log::level, std::string &&) noexcept;
|
||||
};
|
||||
|
||||
/// \brief Standard console output object.
|
||||
LIBIMP_EXPORT extern std_t std_out;
|
||||
inline auto &make_std_out() noexcept {
|
||||
static auto std_out = [](auto const &ctx) {
|
||||
auto s = context_to_string(ctx);
|
||||
switch (ctx.level) {
|
||||
case level::trace:
|
||||
case level::debug:
|
||||
case level::info:
|
||||
std::fprintf(stdout, "%s\n", s.c_str());
|
||||
break;
|
||||
case level::warning:
|
||||
case level::error:
|
||||
case level::failed:
|
||||
std::fprintf(stderr, "%s\n", s.c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
return std_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Log information grips.
|
||||
*/
|
||||
template <typename Outputer>
|
||||
class grip {
|
||||
printer printer_;
|
||||
Outputer out_;
|
||||
char const *func_;
|
||||
level level_limit_;
|
||||
|
||||
template <typename... A>
|
||||
grip &output(log::level l, A &&... args) noexcept {
|
||||
if (!printer_ || (underlyof(l) < underlyof(level_limit_))) {
|
||||
if (underlyof(l) < underlyof(level_limit_)) {
|
||||
return *this;
|
||||
}
|
||||
printer_.output(context<A &&...> {
|
||||
l, std::chrono::system_clock::now(), func_,
|
||||
std::forward_as_tuple(std::forward<A>(args)...),
|
||||
});
|
||||
LIBIMP_TRY {
|
||||
out_(context<A &&...> {
|
||||
l, std::chrono::system_clock::now(), func_,
|
||||
std::forward_as_tuple(std::forward<A>(args)...),
|
||||
});
|
||||
} LIBIMP_CATCH(...) {}
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
grip(char const *func, printer printer = std_out, level level_limit = level::info) noexcept
|
||||
: printer_ (printer)
|
||||
template <typename O>
|
||||
grip(char const *func, O &&out, level level_limit) noexcept
|
||||
: out_ (std::forward<O>(out))
|
||||
, func_ (func)
|
||||
, level_limit_(level_limit) {}
|
||||
|
||||
@ -203,7 +143,20 @@ public:
|
||||
template <typename... A> grip &failed (A &&...args) noexcept { return output(log::level::failed , std::forward<A>(args)...); }
|
||||
};
|
||||
|
||||
template <typename O>
|
||||
inline auto make_grip(char const *func, O &&out, level level_limit = level::info) noexcept {
|
||||
return grip<std::decay_t<O>>(func, std::forward<O>(out), level_limit);
|
||||
}
|
||||
|
||||
inline auto make_grip(char const *func, level level_limit = level::info) noexcept {
|
||||
return make_grip(func, make_std_out(), level_limit);
|
||||
}
|
||||
|
||||
inline auto make_grip(char const */*ignore*/, char const *func, level level_limit = level::info) noexcept {
|
||||
return make_grip(func, make_std_out(), level_limit);
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
LIBIMP_NAMESPACE_END_
|
||||
|
||||
#define LIBIMP_LOG_(...) ::LIBIMP::log::grip log(__func__,##__VA_ARGS__)
|
||||
#define LIBIMP_LOG_(...) auto log = ::LIBIMP::log::make_grip(__func__,##__VA_ARGS__)
|
||||
@ -139,7 +139,7 @@ private:
|
||||
|
||||
public:
|
||||
template <typename... A,
|
||||
typename = is_not_match<result, A...>,
|
||||
typename = not_match<result, A...>,
|
||||
typename = decltype(type_traits_t::init_code(std::declval<storage_t &>()
|
||||
, std::declval<A>()...))>
|
||||
result(A &&... args) noexcept {
|
||||
@ -168,7 +168,7 @@ private:
|
||||
|
||||
public:
|
||||
template <typename... A,
|
||||
typename = is_not_match<result, A...>,
|
||||
typename = not_match<result, A...>,
|
||||
typename = decltype(type_traits_t::init_code(std::declval<storage_t &>()
|
||||
, std::declval<A>()...))>
|
||||
result(A &&... args) noexcept {
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
#include "libimp/log.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
namespace log {
|
||||
|
||||
std_t std_out;
|
||||
|
||||
void std_t::output(log::level l, std::string &&s) noexcept {
|
||||
switch (l) {
|
||||
case level::trace:
|
||||
case level::debug:
|
||||
case level::info:
|
||||
std::fprintf(stdout, "%s\n", s.c_str());
|
||||
break;
|
||||
case level::warning:
|
||||
case level::error:
|
||||
case level::failed:
|
||||
std::fprintf(stderr, "%s\n", s.c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
LIBIMP_NAMESPACE_END_
|
||||
@ -28,7 +28,7 @@ inline LPSECURITY_ATTRIBUTES get_sa() {
|
||||
|
||||
initiator() {
|
||||
using namespace ::LIBIMP;
|
||||
log::grip log {"get_sa"};
|
||||
LIBIMP_LOG_("get_sa");
|
||||
if (!::InitializeSecurityDescriptor(&sd_, SECURITY_DESCRIPTOR_REVISION)) {
|
||||
log.error("failed: InitializeSecurityDescriptor(SECURITY_DESCRIPTOR_REVISION). "
|
||||
"error = ", sys::error());
|
||||
|
||||
@ -13,12 +13,11 @@ namespace {
|
||||
/**
|
||||
* \brief Check that bytes is not 0 and that the alignment is a power of two.
|
||||
*/
|
||||
bool verify_args(::LIBIMP::log::grip &log, std::size_t bytes, std::size_t alignment) noexcept {
|
||||
bool verify_args(std::size_t bytes, std::size_t alignment) noexcept {
|
||||
if (bytes == 0) {
|
||||
return false;
|
||||
}
|
||||
if ((alignment == 0) || (alignment & (alignment - 1)) != 0) {
|
||||
log.error("invalid bytes = ", bytes, ", alignment = ", alignment);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -47,7 +46,8 @@ new_delete_resource *new_delete_resource::get() noexcept {
|
||||
*/
|
||||
void *new_delete_resource::allocate(std::size_t bytes, std::size_t alignment) noexcept {
|
||||
LIBIMP_LOG_();
|
||||
if (!verify_args(log, bytes, alignment)) {
|
||||
if (!verify_args(bytes, alignment)) {
|
||||
log.error("invalid bytes = ", bytes, ", alignment = ", alignment);
|
||||
return nullptr;
|
||||
}
|
||||
#if defined(LIBIMP_CPP_17)
|
||||
@ -89,7 +89,8 @@ void new_delete_resource::deallocate(void *p, std::size_t bytes, std::size_t ali
|
||||
if (p == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!verify_args(log, bytes, alignment)) {
|
||||
if (!verify_args(bytes, alignment)) {
|
||||
log.error("invalid bytes = ", bytes, ", alignment = ", alignment);
|
||||
return;
|
||||
}
|
||||
#if defined(LIBIMP_CPP_17)
|
||||
|
||||
@ -6,76 +6,9 @@
|
||||
|
||||
#include "libimp/log.h"
|
||||
|
||||
TEST(log, detail) {
|
||||
EXPECT_EQ(imp::log::detail::has_fn_output_v<int>, imp::log::detail::out_none);
|
||||
|
||||
struct foo {
|
||||
int info(std::string);
|
||||
};
|
||||
EXPECT_EQ(imp::log::detail::has_fn_output_v<foo>, imp::log::detail::out_none);
|
||||
|
||||
struct bar {
|
||||
int info(char const *);
|
||||
void output(imp::log::level, std::string &&);
|
||||
};
|
||||
EXPECT_EQ(imp::log::detail::has_fn_output_v<bar>, imp::log::detail::out_string);
|
||||
|
||||
struct str {
|
||||
str(std::string const &);
|
||||
};
|
||||
struct foo_bar {
|
||||
void output(imp::log::level, str);
|
||||
};
|
||||
EXPECT_EQ(imp::log::detail::has_fn_output_v<foo_bar>, imp::log::detail::out_string);
|
||||
|
||||
auto vt_int = imp::log::detail::traits<int>::make_vtable();
|
||||
EXPECT_NE(vt_int, nullptr);
|
||||
EXPECT_NO_THROW(vt_int->output(nullptr, imp::log::level::error, ""));
|
||||
|
||||
struct log {
|
||||
std::string what;
|
||||
void output(imp::log::level l, std::string &&s) {
|
||||
if (l == imp::log::level::error) what += s + '\n';
|
||||
}
|
||||
} ll;
|
||||
auto vt_log = imp::log::detail::traits<log>::make_vtable();
|
||||
EXPECT_NE(vt_log, nullptr);
|
||||
|
||||
vt_log->output(&ll, imp::log::level::info, "123");
|
||||
vt_log->output(&ll, imp::log::level::info, "321");
|
||||
vt_log->output(&ll, imp::log::level::info, "654");
|
||||
vt_log->output(&ll, imp::log::level::info, "456");
|
||||
std::cout << ll.what << "\n";
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(log, log_printer) {
|
||||
struct log {
|
||||
std::string i;
|
||||
std::string e;
|
||||
|
||||
void output(imp::log::level l, std::string &&s) {
|
||||
if (l == imp::log::level::error) e += s + "\n";
|
||||
else if (l == imp::log::level::info) i += s + "\n";
|
||||
}
|
||||
} ll;
|
||||
|
||||
imp::log::printer pt = ll;
|
||||
pt.output(imp::log::context<char const *>{imp::log::level::info , std::chrono::system_clock::now(), __func__, "hello "});
|
||||
pt.output(imp::log::context<char const *>{imp::log::level::error, std::chrono::system_clock::now(), __func__, "failed: "});
|
||||
pt.output(imp::log::context<char const *>{imp::log::level::info , std::chrono::system_clock::now(), __func__, "log-pt"});
|
||||
pt.output(imp::log::context<char const *>{imp::log::level::error, std::chrono::system_clock::now(), __func__, "whatever"});
|
||||
std::cout << ll.i << "\n";
|
||||
std::cout << ll.e << "\n";
|
||||
|
||||
imp::log::printer ps = imp::log::std_out;
|
||||
ps.output(imp::log::context<char const *>{imp::log::level::info, std::chrono::system_clock::now(), __func__, "hello world"});
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(log, gripper) {
|
||||
{
|
||||
imp::log::grip log {__func__};
|
||||
LIBIMP_LOG_();
|
||||
log.info("hello");
|
||||
}
|
||||
{
|
||||
@ -84,3 +17,26 @@ TEST(log, gripper) {
|
||||
}
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(log, custom) {
|
||||
struct log {
|
||||
std::string i;
|
||||
std::string e;
|
||||
} ll_data;
|
||||
auto ll = [&ll_data](auto &&ctx) mutable {
|
||||
auto s = imp::fmt(ctx.params);
|
||||
if (ctx.level == imp::log::level::error) ll_data.e += s + " ";
|
||||
else
|
||||
if (ctx.level == imp::log::level::info ) ll_data.i += s + " ";
|
||||
};
|
||||
|
||||
LIBIMP_LOG_(ll);
|
||||
|
||||
log.info ("hello");
|
||||
log.error("failed:");
|
||||
log.info ("log-pt");
|
||||
log.error("whatever");
|
||||
|
||||
EXPECT_EQ(ll_data.i, "hello log-pt ");
|
||||
EXPECT_EQ(ll_data.e, "failed: whatever ");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user