From fcca475076c699d56e1ea39eb056a9517b887d62 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 22 May 2022 18:29:18 +0800 Subject: [PATCH] add: [log] implement simple log function (TBD) --- include/libimp/countof.h | 22 ++--- include/libimp/log.h | 144 +++++++++++++++++++++++++++++++ include/libimp/result.h | 1 + src/libimp/log.cpp | 33 +++++++ src/libipc/mmap.cpp | 7 ++ src/libipc/platform/posix/mmap.h | 27 ++++++ test/test_imp_log.cpp | 90 +++++++++++++++++++ test/test_imp_utility.cpp | 4 +- 8 files changed, 315 insertions(+), 13 deletions(-) create mode 100644 include/libimp/log.h create mode 100644 src/libimp/log.cpp create mode 100644 src/libipc/mmap.cpp create mode 100644 src/libipc/platform/posix/mmap.h create mode 100644 test/test_imp_log.cpp diff --git a/include/libimp/countof.h b/include/libimp/countof.h index 59c0d39..91f0e08 100644 --- a/include/libimp/countof.h +++ b/include/libimp/countof.h @@ -18,10 +18,10 @@ LIBIMP_NAMESPACE_BEG_ * @see https://en.cppreference.com/w/cpp/iterator/size */ -namespace detail { +namespace detail_countof { template -struct countof_trait_has_size { +struct trait_has_size { private: template static std::true_type check(decltype(std::declval().size())*); @@ -33,7 +33,7 @@ public: }; template -struct countof_trait_has_Size { +struct trait_has_Size { private: template static std::true_type check(decltype(std::declval().Size())*); @@ -44,34 +44,34 @@ public: constexpr static auto value = type::value; }; -template ::value - , bool = countof_trait_has_Size::value> -struct countof_trait; +template ::value + , bool = trait_has_Size::value> +struct trait; template -struct countof_trait { +struct trait { constexpr static auto countof(T const (&)[N]) noexcept { return N; } }; template -struct countof_trait { +struct trait { constexpr static auto countof(C const &c) noexcept(noexcept(c.size())) { return c.size(); } }; template -struct countof_trait { +struct trait { constexpr static auto countof(C const &c) noexcept(noexcept(c.Size())) { return c.Size(); } }; -} // namespace detail +} // namespace detail_countof -template > +template > constexpr auto countof(C const &c) noexcept(noexcept(R::countof(c))) { return R::countof(c); } diff --git a/include/libimp/log.h b/include/libimp/log.h new file mode 100644 index 0000000..0ced440 --- /dev/null +++ b/include/libimp/log.h @@ -0,0 +1,144 @@ +/** + * @file libimp/log.h + * @author mutouyun (orz@orzz.org) + * @brief Simple log output component + * @date 2022-05-22 + */ +#pragma once + +#include +#include + +#include "fmt/format.h" + +#include "libimp/def.h" +#include "libimp/detect_plat.h" +#include "libimp/export.h" + +LIBIMP_NAMESPACE_BEG_ + +namespace detail_log { + +template +class has_fn_info { + static std::false_type check(...); + template + static auto check(U *u) -> decltype(u->info(std::declval()), std::true_type{}); + +public: + using type = decltype(check(static_cast(nullptr))); +}; + +template +constexpr bool has_fn_info_v = typename has_fn_info::type::value; + +template +class has_fn_error { + static std::false_type check(...); + template + static auto check(U *u) -> decltype(u->error(std::declval()), std::true_type{}); + +public: + using type = decltype(check(static_cast(nullptr))); +}; + +template +constexpr bool has_fn_error_v = typename has_fn_error::type::value; + +struct vtable_t { + void (*info )(void *, std::string &&); + void (*error)(void *, std::string &&); +}; + +template +class traits { + template + static auto make_fn_info() noexcept + -> std::enable_if_t, void (*)(void *, std::string &&)> { + return [](void *p, std::string &&s) { + static_cast(p)->info(std::move(s)); + }; + } + template + static auto make_fn_info() noexcept + -> std::enable_if_t, void (*)(void *, std::string &&)> { + return [](void *, std::string &&) {}; + } + + template + static auto make_fn_error() noexcept + -> std::enable_if_t, void (*)(void *, std::string &&)> { + return [](void *p, std::string &&s) { + static_cast(p)->error(std::move(s)); + }; + } + template + static auto make_fn_error() noexcept + -> std::enable_if_t, void (*)(void *, std::string &&)> { + return [](void *, std::string &&) {}; + } + +public: + static auto make_vtable() noexcept { + static vtable_t vt { + make_fn_info (), + make_fn_error(), + }; + return &vt; + } +}; + +class prefix { + std::string px_; + +public: + template + prefix(A &&... args) { + LIBIMP_UNUSED auto unfold = { + 0, ((px_ += ::fmt::format("[{}]", std::forward(args))), 0)... + }; + } + + operator std::string() const noexcept { + return px_; + } +}; + +} // namespace detail_log + +class LIBIMP_EXPORT log_printer { + void *objp_ {nullptr}; + detail_log::vtable_t *vtable_ {nullptr}; + +public: + log_printer() noexcept = default; + + template + log_printer(T &p) noexcept + : objp_ (static_cast(&p)) + , vtable_(detail_log::traits::make_vtable()) {} + + explicit operator bool() const noexcept; + + void info (std::string &&); + void error(std::string &&); +}; + +class LIBIMP_EXPORT log_std_t { +public: + void info (std::string &&) const; + void error(std::string &&) const; +}; + +LIBIMP_EXPORT extern log_std_t log_std; + +namespace log { + +template +std::string fmt(Fmt &&ft, A &&... args) { + return ::fmt::format(std::forward(ft), std::forward(args)...); +} + +} // namespace log + +LIBIMP_NAMESPACE_END_ diff --git a/include/libimp/result.h b/include/libimp/result.h index 81f94c8..0bff001 100644 --- a/include/libimp/result.h +++ b/include/libimp/result.h @@ -8,6 +8,7 @@ #include #include +#include #include "fmt/format.h" diff --git a/src/libimp/log.cpp b/src/libimp/log.cpp new file mode 100644 index 0000000..dc37e33 --- /dev/null +++ b/src/libimp/log.cpp @@ -0,0 +1,33 @@ + +#include +#include + +#include "libimp/log.h" + +LIBIMP_NAMESPACE_BEG_ + +log_printer::operator bool() const noexcept { + return (objp_ != nullptr) && (vtable_ != nullptr); +} + +void log_printer::info(std::string && s) { + if (!*this) return; + vtable_->info(objp_, std::move(s)); +} + +void log_printer::error(std::string && s) { + if (!*this) return; + vtable_->error(objp_, std::move(s)); +} + +log_std_t log_std; + +void log_std_t::info(std::string && s) const { + std::cout << std::move(s); +} + +void log_std_t::error(std::string && s) const { + std::cerr << std::move(s); +} + +LIBIMP_NAMESPACE_END_ diff --git a/src/libipc/mmap.cpp b/src/libipc/mmap.cpp new file mode 100644 index 0000000..06fb539 --- /dev/null +++ b/src/libipc/mmap.cpp @@ -0,0 +1,7 @@ +#include "libipc/mmap.h" + +LIBIPC_NAMESPACE_BEG_ + + + +LIBIPC_NAMESPACE_END_ diff --git a/src/libipc/platform/posix/mmap.h b/src/libipc/platform/posix/mmap.h new file mode 100644 index 0000000..8aef07b --- /dev/null +++ b/src/libipc/platform/posix/mmap.h @@ -0,0 +1,27 @@ +/** + * @file libimp/platform/posix/mmap.h + * @author mutouyun (orz@orzz.org) + */ +#pragma once + +#include +#include + +#include "libipc/mmap.h" + +LIBIPC_NAMESPACE_BEG_ + +struct mmap_handle { + std::string file; + std::size_t f_sz; + std::size_t f_of; + void *memp; +}; + +inline int mmap_open_(mmap_t *h_out, std::string const &file, int fd, int flags, std::size_t f_sz, std::size_t f_of) noexcept { + if (h_out == nullptr) { + return -1; + } +} + +LIBIPC_NAMESPACE_END_ diff --git a/test/test_imp_log.cpp b/test/test_imp_log.cpp new file mode 100644 index 0000000..cc171f1 --- /dev/null +++ b/test/test_imp_log.cpp @@ -0,0 +1,90 @@ + +#include "gtest/gtest.h" + +#include "libimp/log.h" + +TEST(log, detail) { + EXPECT_FALSE(imp::detail_log::has_fn_info_v); + EXPECT_FALSE(imp::detail_log::has_fn_error_v); + + struct foo { + int info(std::string); + }; + EXPECT_TRUE (imp::detail_log::has_fn_info_v); + EXPECT_FALSE(imp::detail_log::has_fn_error_v); + + struct bar { + int info(char const *); + void error(std::string &&); + }; + EXPECT_FALSE(imp::detail_log::has_fn_info_v); + EXPECT_TRUE (imp::detail_log::has_fn_error_v); + + struct str { + str(std::string const &); + }; + struct foo_bar { + void info(std::string const &); + void error(str); + }; + EXPECT_TRUE(imp::detail_log::has_fn_info_v); + EXPECT_TRUE(imp::detail_log::has_fn_error_v); + + auto vt_int = imp::detail_log::traits::make_vtable(); + EXPECT_NE(vt_int, nullptr); + vt_int->info (nullptr, "123"); + vt_int->error(nullptr, "321"); + + struct log { + std::string what; + void error(std::string &&s) { + what += s; + } + } ll; + auto vt_log = imp::detail_log::traits::make_vtable(); + EXPECT_NE(vt_log, nullptr); + vt_log->info (&ll, "123"); + vt_log->error(&ll, "321"); + vt_log->info (&ll, "654"); + vt_log->error(&ll, "456"); + EXPECT_EQ(ll.what, "321456"); +} + +TEST(log, log_printer) { + struct log { + std::string i; + std::string e; + void info(std::string &&s) { + i += s; + } + void error(std::string &&s) { + e += s; + } + } ll; + + imp::log_printer pt = ll; + pt.info("hello "); + pt.error("failed: "); + pt.info("log-pt"); + pt.error("whatever"); + EXPECT_EQ(ll.i, "hello log-pt"); + EXPECT_EQ(ll.e, "failed: whatever"); + + imp::log_printer ps = imp::log_std; + ps.info("hello world\n"); +} + +#include +#include + +TEST(log, prefix) { + imp::detail_log::prefix prefix; + EXPECT_EQ(std::string{prefix}, ""); + + prefix = {"hello", "world"}; + EXPECT_EQ(std::string{prefix}, "[hello][world]"); + + using namespace std::literals::chrono_literals; + prefix = {"time", imp::log::fmt("{:%H:%M:%S}", 3h + 15min + 30s)}; + EXPECT_EQ(std::string{prefix}, "[time][03:15:30]"); +} \ No newline at end of file diff --git a/test/test_imp_utility.cpp b/test/test_imp_utility.cpp index c16def4..e7c2527 100644 --- a/test/test_imp_utility.cpp +++ b/test/test_imp_utility.cpp @@ -94,8 +94,8 @@ TEST(utility, countof) { struct { constexpr int Size() const noexcept { return 3; } } sv; - EXPECT_FALSE(imp::detail::countof_trait_has_size::value); - EXPECT_TRUE (imp::detail::countof_trait_has_Size::value); + EXPECT_FALSE(imp::detail_countof::trait_has_size::value); + EXPECT_TRUE (imp::detail_countof::trait_has_Size::value); std::vector vec {1, 2, 3, 4, 5}; int arr[] {7, 6, 5, 4, 3, 2, 1};