From ca78e3511bdbe648a1bcf07b270c691084dfe726 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 27 May 2023 21:19:25 +0800 Subject: [PATCH] upd: [imp] optimized log interface implementation --- benchmark/benchmark_log.cpp | 8 +- include/libimp/fmt.h | 11 +++ include/libimp/generic.h | 4 +- include/libimp/log.h | 139 ++++++++++--------------------- include/libimp/result.h | 4 +- src/libimp/log.cpp | 28 ------- src/libipc/platform/win/get_sa.h | 2 +- src/libpmr/memory_resource.cpp | 9 +- test/imp/test_imp_log.cpp | 92 ++++++-------------- 9 files changed, 95 insertions(+), 202 deletions(-) delete mode 100644 src/libimp/log.cpp diff --git a/benchmark/benchmark_log.cpp b/benchmark/benchmark_log.cpp index 9f5fe09..87f918c 100644 --- a/benchmark/benchmark_log.cpp +++ b/benchmark/benchmark_log.cpp @@ -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); \ No newline at end of file +BENCHMARK(imp_log_info); \ No newline at end of file diff --git a/include/libimp/fmt.h b/include/libimp/fmt.h index 373fe12..06d5374 100644 --- a/include/libimp/fmt.h +++ b/include/libimp/fmt.h @@ -13,6 +13,7 @@ #include #include #include // std::chrono::time_point +#include #include #include // std::tm, std::localtime @@ -163,5 +164,15 @@ bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, span s) { return true; } +template +bool unfold_tuple_fmt_to(fmt_context &ctx, Tp const &tp, std::index_sequence) { + return fmt_to(ctx, std::get(tp)...); +} + +template +bool tag_invoke(decltype(::LIBIMP::fmt_to), fmt_context &ctx, std::tuple const &tp) { + return unfold_tuple_fmt_to(ctx, tp, std::index_sequence_for{}); +} + } // namespace detail LIBIMP_NAMESPACE_END_ diff --git a/include/libimp/generic.h b/include/libimp/generic.h index 54d1288..e030181 100644 --- a/include/libimp/generic.h +++ b/include/libimp/generic.h @@ -71,9 +71,9 @@ struct is_same_first : std::true_type {}; } // namespace detail template -using is_not_match = +using not_match = typename std::enable_if::type...>::value>::type; + typename std::decay::type...>::value, bool>::type; /** * \brief Determines whether a type is specialized from a particular template. diff --git a/include/libimp/log.h b/include/libimp/log.h index 05fe998..e2aaa3e 100644 --- a/include/libimp/log.h +++ b/include/libimp/log.h @@ -83,115 +83,55 @@ std::string context_to_string(context const &l_ctx) noexcept { } } -namespace detail { - -enum out_type : unsigned { - out_none = 0x0, - out_string = 0x1, -}; - -template -class has_fn_output { - static std::integral_constant check(...); - - template ().output(log::level::trace, std::declval()))> - static std::integral_constant check(U *u); - -public: - using type = decltype(check(static_cast(nullptr))); -}; - -template -constexpr out_type has_fn_output_v = has_fn_output::type::value; - -struct vtable_t { - void (*output)(void *, log::level, std::string &&); -}; - -template -class traits { - template - static auto make_fn_output() noexcept - -> std::enable_if_t<(has_fn_output_v == out_none), decltype(vtable_t{}.output)> { - return [](void *, log::level, std::string &&) {}; - } - - template - static auto make_fn_output() noexcept - -> std::enable_if_t<(has_fn_output_v == out_string), decltype(vtable_t{}.output)> { - return [](void *p, log::level lev, std::string &&str) { - static_cast(p)->output(lev, std::move(str)); - }; - } - -public: - static auto make_vtable() noexcept { - static vtable_t vt { make_fn_output() }; - return &vt; - } -}; - -} // namespace detail - -class printer { - void *objp_ {nullptr}; - detail::vtable_t *vtable_ {nullptr}; - -public: - printer() noexcept = default; - - template > - printer(T &p) noexcept - : objp_ (static_cast(&p)) - , vtable_(detail::traits::make_vtable()) {} - - explicit operator bool() const noexcept { - return (objp_ != nullptr) && (vtable_ != nullptr); - } - - template - void output(context 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 class grip { - printer printer_; + Outputer out_; char const *func_; level level_limit_; template 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 { - l, std::chrono::system_clock::now(), func_, - std::forward_as_tuple(std::forward(args)...), - }); + LIBIMP_TRY { + out_(context { + l, std::chrono::system_clock::now(), func_, + std::forward_as_tuple(std::forward(args)...), + }); + } LIBIMP_CATCH(...) {} return *this; } public: - grip(char const *func, printer printer = std_out, level level_limit = level::info) noexcept - : printer_ (printer) + template + grip(char const *func, O &&out, level level_limit) noexcept + : out_ (std::forward(out)) , func_ (func) , level_limit_(level_limit) {} @@ -203,7 +143,20 @@ public: template grip &failed (A &&...args) noexcept { return output(log::level::failed , std::forward(args)...); } }; +template +inline auto make_grip(char const *func, O &&out, level level_limit = level::info) noexcept { + return grip>(func, std::forward(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__) \ No newline at end of file +#define LIBIMP_LOG_(...) auto log = ::LIBIMP::log::make_grip(__func__,##__VA_ARGS__) \ No newline at end of file diff --git a/include/libimp/result.h b/include/libimp/result.h index dd95d95..aea6738 100644 --- a/include/libimp/result.h +++ b/include/libimp/result.h @@ -139,7 +139,7 @@ private: public: template , + typename = not_match, typename = decltype(type_traits_t::init_code(std::declval() , std::declval()...))> result(A &&... args) noexcept { @@ -168,7 +168,7 @@ private: public: template , + typename = not_match, typename = decltype(type_traits_t::init_code(std::declval() , std::declval()...))> result(A &&... args) noexcept { diff --git a/src/libimp/log.cpp b/src/libimp/log.cpp deleted file mode 100644 index de535bb..0000000 --- a/src/libimp/log.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "libimp/log.h" - -#include - -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_ diff --git a/src/libipc/platform/win/get_sa.h b/src/libipc/platform/win/get_sa.h index 4fa2229..91ec7d3 100644 --- a/src/libipc/platform/win/get_sa.h +++ b/src/libipc/platform/win/get_sa.h @@ -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()); diff --git a/src/libpmr/memory_resource.cpp b/src/libpmr/memory_resource.cpp index 951768c..726fc02 100644 --- a/src/libpmr/memory_resource.cpp +++ b/src/libpmr/memory_resource.cpp @@ -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) diff --git a/test/imp/test_imp_log.cpp b/test/imp/test_imp_log.cpp index 631d661..93e89a7 100644 --- a/test/imp/test_imp_log.cpp +++ b/test/imp/test_imp_log.cpp @@ -6,76 +6,9 @@ #include "libimp/log.h" -TEST(log, detail) { - EXPECT_EQ(imp::log::detail::has_fn_output_v, imp::log::detail::out_none); - - struct foo { - int info(std::string); - }; - EXPECT_EQ(imp::log::detail::has_fn_output_v, 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, 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, imp::log::detail::out_string); - - auto vt_int = imp::log::detail::traits::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::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{imp::log::level::info , std::chrono::system_clock::now(), __func__, "hello "}); - pt.output(imp::log::context{imp::log::level::error, std::chrono::system_clock::now(), __func__, "failed: "}); - pt.output(imp::log::context{imp::log::level::info , std::chrono::system_clock::now(), __func__, "log-pt"}); - pt.output(imp::log::context{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{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 "); +}