mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
add: [log] implement simple log function (TBD)
This commit is contained in:
parent
c1557a72ac
commit
fcca475076
@ -18,10 +18,10 @@ LIBIMP_NAMESPACE_BEG_
|
||||
* @see https://en.cppreference.com/w/cpp/iterator/size
|
||||
*/
|
||||
|
||||
namespace detail {
|
||||
namespace detail_countof {
|
||||
|
||||
template <typename T>
|
||||
struct countof_trait_has_size {
|
||||
struct trait_has_size {
|
||||
private:
|
||||
template <typename Type>
|
||||
static std::true_type check(decltype(std::declval<Type>().size())*);
|
||||
@ -33,7 +33,7 @@ public:
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct countof_trait_has_Size {
|
||||
struct trait_has_Size {
|
||||
private:
|
||||
template <typename Type>
|
||||
static std::true_type check(decltype(std::declval<Type>().Size())*);
|
||||
@ -44,34 +44,34 @@ public:
|
||||
constexpr static auto value = type::value;
|
||||
};
|
||||
|
||||
template <typename C, bool = countof_trait_has_size<C>::value
|
||||
, bool = countof_trait_has_Size<C>::value>
|
||||
struct countof_trait;
|
||||
template <typename C, bool = trait_has_size<C>::value
|
||||
, bool = trait_has_Size<C>::value>
|
||||
struct trait;
|
||||
|
||||
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 {
|
||||
return N;
|
||||
}
|
||||
};
|
||||
|
||||
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())) {
|
||||
return c.size();
|
||||
}
|
||||
};
|
||||
|
||||
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())) {
|
||||
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))) {
|
||||
return R::countof(c);
|
||||
}
|
||||
|
||||
144
include/libimp/log.h
Normal file
144
include/libimp/log.h
Normal 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_
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
|
||||
33
src/libimp/log.cpp
Normal file
33
src/libimp/log.cpp
Normal 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
7
src/libipc/mmap.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "libipc/mmap.h"
|
||||
|
||||
LIBIPC_NAMESPACE_BEG_
|
||||
|
||||
|
||||
|
||||
LIBIPC_NAMESPACE_END_
|
||||
27
src/libipc/platform/posix/mmap.h
Normal file
27
src/libipc/platform/posix/mmap.h
Normal 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
90
test/test_imp_log.cpp
Normal 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]");
|
||||
}
|
||||
@ -94,8 +94,8 @@ TEST(utility, countof) {
|
||||
struct {
|
||||
constexpr int Size() const noexcept { return 3; }
|
||||
} sv;
|
||||
EXPECT_FALSE(imp::detail::countof_trait_has_size<decltype(sv)>::value);
|
||||
EXPECT_TRUE (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);
|
||||
|
||||
std::vector<int> vec {1, 2, 3, 4, 5};
|
||||
int arr[] {7, 6, 5, 4, 3, 2, 1};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user