/** * @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_