mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
upd: [imp] optimized log interface implementation
This commit is contained in:
parent
19cb391624
commit
ca78e3511b
@ -6,14 +6,14 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void imp_log_no_output(benchmark::State &state) {
|
void imp_log_no_output(benchmark::State &state) {
|
||||||
imp::log::grip log {__func__, {}};
|
LIBIMP_LOG_([](auto &&) {});
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
log.debug("hello log.");
|
log.debug("hello log.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void imp_log_gripper(benchmark::State &state) {
|
void imp_log_info(benchmark::State &state) {
|
||||||
imp::log::grip log {__func__, {}};
|
LIBIMP_LOG_([](auto &&) {});
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
log.info("hello log.");
|
log.info("hello log.");
|
||||||
}
|
}
|
||||||
@ -22,4 +22,4 @@ void imp_log_gripper(benchmark::State &state) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
BENCHMARK(imp_log_no_output);
|
BENCHMARK(imp_log_no_output);
|
||||||
BENCHMARK(imp_log_gripper);
|
BENCHMARK(imp_log_info);
|
||||||
@ -13,6 +13,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <chrono> // std::chrono::time_point
|
#include <chrono> // std::chrono::time_point
|
||||||
|
#include <tuple>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <ctime> // std::tm, std::localtime
|
#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;
|
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
|
} // namespace detail
|
||||||
LIBIMP_NAMESPACE_END_
|
LIBIMP_NAMESPACE_END_
|
||||||
|
|||||||
@ -71,9 +71,9 @@ struct is_same_first<T, T> : std::true_type {};
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename T, typename... A>
|
template <typename T, typename... A>
|
||||||
using is_not_match =
|
using not_match =
|
||||||
typename std::enable_if<!detail::is_same_first<T,
|
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.
|
* \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.
|
/// \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.
|
* \brief Log information grips.
|
||||||
*/
|
*/
|
||||||
|
template <typename Outputer>
|
||||||
class grip {
|
class grip {
|
||||||
printer printer_;
|
Outputer out_;
|
||||||
char const *func_;
|
char const *func_;
|
||||||
level level_limit_;
|
level level_limit_;
|
||||||
|
|
||||||
template <typename... A>
|
template <typename... A>
|
||||||
grip &output(log::level l, A &&... args) noexcept {
|
grip &output(log::level l, A &&... args) noexcept {
|
||||||
if (!printer_ || (underlyof(l) < underlyof(level_limit_))) {
|
if (underlyof(l) < underlyof(level_limit_)) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
printer_.output(context<A &&...> {
|
LIBIMP_TRY {
|
||||||
|
out_(context<A &&...> {
|
||||||
l, std::chrono::system_clock::now(), func_,
|
l, std::chrono::system_clock::now(), func_,
|
||||||
std::forward_as_tuple(std::forward<A>(args)...),
|
std::forward_as_tuple(std::forward<A>(args)...),
|
||||||
});
|
});
|
||||||
|
} LIBIMP_CATCH(...) {}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
grip(char const *func, printer printer = std_out, level level_limit = level::info) noexcept
|
template <typename O>
|
||||||
: printer_ (printer)
|
grip(char const *func, O &&out, level level_limit) noexcept
|
||||||
|
: out_ (std::forward<O>(out))
|
||||||
, func_ (func)
|
, func_ (func)
|
||||||
, level_limit_(level_limit) {}
|
, 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... 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
|
} // namespace log
|
||||||
LIBIMP_NAMESPACE_END_
|
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:
|
public:
|
||||||
template <typename... A,
|
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 &>()
|
typename = decltype(type_traits_t::init_code(std::declval<storage_t &>()
|
||||||
, std::declval<A>()...))>
|
, std::declval<A>()...))>
|
||||||
result(A &&... args) noexcept {
|
result(A &&... args) noexcept {
|
||||||
@ -168,7 +168,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename... A,
|
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 &>()
|
typename = decltype(type_traits_t::init_code(std::declval<storage_t &>()
|
||||||
, std::declval<A>()...))>
|
, std::declval<A>()...))>
|
||||||
result(A &&... args) noexcept {
|
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() {
|
initiator() {
|
||||||
using namespace ::LIBIMP;
|
using namespace ::LIBIMP;
|
||||||
log::grip log {"get_sa"};
|
LIBIMP_LOG_("get_sa");
|
||||||
if (!::InitializeSecurityDescriptor(&sd_, SECURITY_DESCRIPTOR_REVISION)) {
|
if (!::InitializeSecurityDescriptor(&sd_, SECURITY_DESCRIPTOR_REVISION)) {
|
||||||
log.error("failed: InitializeSecurityDescriptor(SECURITY_DESCRIPTOR_REVISION). "
|
log.error("failed: InitializeSecurityDescriptor(SECURITY_DESCRIPTOR_REVISION). "
|
||||||
"error = ", sys::error());
|
"error = ", sys::error());
|
||||||
|
|||||||
@ -13,12 +13,11 @@ namespace {
|
|||||||
/**
|
/**
|
||||||
* \brief Check that bytes is not 0 and that the alignment is a power of two.
|
* \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) {
|
if (bytes == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((alignment == 0) || (alignment & (alignment - 1)) != 0) {
|
if ((alignment == 0) || (alignment & (alignment - 1)) != 0) {
|
||||||
log.error("invalid bytes = ", bytes, ", alignment = ", alignment);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
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 {
|
void *new_delete_resource::allocate(std::size_t bytes, std::size_t alignment) noexcept {
|
||||||
LIBIMP_LOG_();
|
LIBIMP_LOG_();
|
||||||
if (!verify_args(log, bytes, alignment)) {
|
if (!verify_args(bytes, alignment)) {
|
||||||
|
log.error("invalid bytes = ", bytes, ", alignment = ", alignment);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#if defined(LIBIMP_CPP_17)
|
#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) {
|
if (p == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!verify_args(log, bytes, alignment)) {
|
if (!verify_args(bytes, alignment)) {
|
||||||
|
log.error("invalid bytes = ", bytes, ", alignment = ", alignment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if defined(LIBIMP_CPP_17)
|
#if defined(LIBIMP_CPP_17)
|
||||||
|
|||||||
@ -6,76 +6,9 @@
|
|||||||
|
|
||||||
#include "libimp/log.h"
|
#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) {
|
TEST(log, gripper) {
|
||||||
{
|
{
|
||||||
imp::log::grip log {__func__};
|
LIBIMP_LOG_();
|
||||||
log.info("hello");
|
log.info("hello");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -84,3 +17,26 @@ TEST(log, gripper) {
|
|||||||
}
|
}
|
||||||
SUCCEED();
|
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