add: [log] implement simple log function (TBD)

This commit is contained in:
mutouyun 2022-05-22 18:29:18 +08:00
parent c1557a72ac
commit fcca475076
8 changed files with 315 additions and 13 deletions

View File

@ -18,10 +18,10 @@ LIBIMP_NAMESPACE_BEG_
* @see https://en.cppreference.com/w/cpp/iterator/size * @see https://en.cppreference.com/w/cpp/iterator/size
*/ */
namespace detail { namespace detail_countof {
template <typename T> template <typename T>
struct countof_trait_has_size { struct trait_has_size {
private: private:
template <typename Type> template <typename Type>
static std::true_type check(decltype(std::declval<Type>().size())*); static std::true_type check(decltype(std::declval<Type>().size())*);
@ -33,7 +33,7 @@ public:
}; };
template <typename T> template <typename T>
struct countof_trait_has_Size { struct trait_has_Size {
private: private:
template <typename Type> template <typename Type>
static std::true_type check(decltype(std::declval<Type>().Size())*); static std::true_type check(decltype(std::declval<Type>().Size())*);
@ -44,34 +44,34 @@ public:
constexpr static auto value = type::value; constexpr static auto value = type::value;
}; };
template <typename C, bool = countof_trait_has_size<C>::value template <typename C, bool = trait_has_size<C>::value
, bool = countof_trait_has_Size<C>::value> , bool = trait_has_Size<C>::value>
struct countof_trait; struct trait;
template <typename T, std::size_t N> template <typename T, std::size_t N>
struct countof_trait<T[N], false, false> { struct trait<T[N], false, false> {
constexpr static auto countof(T const (&)[N]) noexcept { constexpr static auto countof(T const (&)[N]) noexcept {
return N; return N;
} }
}; };
template <typename C, bool B> template <typename C, bool B>
struct countof_trait<C, true, B> { struct trait<C, true, B> {
constexpr static auto countof(C const &c) noexcept(noexcept(c.size())) { constexpr static auto countof(C const &c) noexcept(noexcept(c.size())) {
return c.size(); return c.size();
} }
}; };
template <typename C> template <typename C>
struct countof_trait<C, false, true> { struct trait<C, false, true> {
constexpr static auto countof(C const &c) noexcept(noexcept(c.Size())) { constexpr static auto countof(C const &c) noexcept(noexcept(c.Size())) {
return c.Size(); return c.Size();
} }
}; };
} // namespace detail } // namespace detail_countof
template <typename C, typename R = detail::countof_trait<C>> template <typename C, typename R = detail_countof::trait<C>>
constexpr auto countof(C const &c) noexcept(noexcept(R::countof(c))) { constexpr auto countof(C const &c) noexcept(noexcept(R::countof(c))) {
return R::countof(c); return R::countof(c);
} }

144
include/libimp/log.h Normal file
View File

@ -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 <string>
#include <type_traits>
#include "fmt/format.h"
#include "libimp/def.h"
#include "libimp/detect_plat.h"
#include "libimp/export.h"
LIBIMP_NAMESPACE_BEG_
namespace detail_log {
template <typename T>
class has_fn_info {
static std::false_type check(...);
template <typename U>
static auto check(U *u) -> decltype(u->info(std::declval<std::string>()), std::true_type{});
public:
using type = decltype(check(static_cast<T *>(nullptr)));
};
template <typename T>
constexpr bool has_fn_info_v = typename has_fn_info<T>::type::value;
template <typename T>
class has_fn_error {
static std::false_type check(...);
template <typename U>
static auto check(U *u) -> decltype(u->error(std::declval<std::string>()), std::true_type{});
public:
using type = decltype(check(static_cast<T *>(nullptr)));
};
template <typename T>
constexpr bool has_fn_error_v = typename has_fn_error<T>::type::value;
struct vtable_t {
void (*info )(void *, std::string &&);
void (*error)(void *, std::string &&);
};
template <typename T>
class traits {
template <typename U>
static auto make_fn_info() noexcept
-> std::enable_if_t<has_fn_info_v<U>, void (*)(void *, std::string &&)> {
return [](void *p, std::string &&s) {
static_cast<U *>(p)->info(std::move(s));
};
}
template <typename U>
static auto make_fn_info() noexcept
-> std::enable_if_t<!has_fn_info_v<U>, void (*)(void *, std::string &&)> {
return [](void *, std::string &&) {};
}
template <typename U>
static auto make_fn_error() noexcept
-> std::enable_if_t<has_fn_error_v<U>, void (*)(void *, std::string &&)> {
return [](void *p, std::string &&s) {
static_cast<U *>(p)->error(std::move(s));
};
}
template <typename U>
static auto make_fn_error() noexcept
-> std::enable_if_t<!has_fn_error_v<U>, void (*)(void *, std::string &&)> {
return [](void *, std::string &&) {};
}
public:
static auto make_vtable() noexcept {
static vtable_t vt {
make_fn_info <T>(),
make_fn_error<T>(),
};
return &vt;
}
};
class prefix {
std::string px_;
public:
template <typename... A>
prefix(A &&... args) {
LIBIMP_UNUSED auto unfold = {
0, ((px_ += ::fmt::format("[{}]", std::forward<A>(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 <typename T>
log_printer(T &p) noexcept
: objp_ (static_cast<void *>(&p))
, vtable_(detail_log::traits<T>::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 <typename Fmt, typename... A>
std::string fmt(Fmt &&ft, A &&... args) {
return ::fmt::format(std::forward<Fmt>(ft), std::forward<A>(args)...);
}
} // namespace log
LIBIMP_NAMESPACE_END_

View File

@ -8,6 +8,7 @@
#include <type_traits> #include <type_traits>
#include <cstdint> #include <cstdint>
#include <span>
#include "fmt/format.h" #include "fmt/format.h"

33
src/libimp/log.cpp Normal file
View File

@ -0,0 +1,33 @@
#include <utility>
#include <iostream>
#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_

7
src/libipc/mmap.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "libipc/mmap.h"
LIBIPC_NAMESPACE_BEG_
LIBIPC_NAMESPACE_END_

View File

@ -0,0 +1,27 @@
/**
* @file libimp/platform/posix/mmap.h
* @author mutouyun (orz@orzz.org)
*/
#pragma once
#include <string>
#include <cstddef>
#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_

90
test/test_imp_log.cpp Normal file
View File

@ -0,0 +1,90 @@
#include "gtest/gtest.h"
#include "libimp/log.h"
TEST(log, detail) {
EXPECT_FALSE(imp::detail_log::has_fn_info_v<int>);
EXPECT_FALSE(imp::detail_log::has_fn_error_v<int>);
struct foo {
int info(std::string);
};
EXPECT_TRUE (imp::detail_log::has_fn_info_v<foo>);
EXPECT_FALSE(imp::detail_log::has_fn_error_v<foo>);
struct bar {
int info(char const *);
void error(std::string &&);
};
EXPECT_FALSE(imp::detail_log::has_fn_info_v<bar>);
EXPECT_TRUE (imp::detail_log::has_fn_error_v<bar>);
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<foo_bar>);
EXPECT_TRUE(imp::detail_log::has_fn_error_v<foo_bar>);
auto vt_int = imp::detail_log::traits<int>::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<log>::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 <chrono>
#include <fmt/chrono.h>
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]");
}

View File

@ -94,8 +94,8 @@ TEST(utility, countof) {
struct { struct {
constexpr int Size() const noexcept { return 3; } constexpr int Size() const noexcept { return 3; }
} sv; } sv;
EXPECT_FALSE(imp::detail::countof_trait_has_size<decltype(sv)>::value); EXPECT_FALSE(imp::detail_countof::trait_has_size<decltype(sv)>::value);
EXPECT_TRUE (imp::detail::countof_trait_has_Size<decltype(sv)>::value); EXPECT_TRUE (imp::detail_countof::trait_has_Size<decltype(sv)>::value);
std::vector<int> vec {1, 2, 3, 4, 5}; std::vector<int> vec {1, 2, 3, 4, 5};
int arr[] {7, 6, 5, 4, 3, 2, 1}; int arr[] {7, 6, 5, 4, 3, 2, 1};