// license:GPL-2.0+ // copyright-holders:Couriersud /// /// \file pfmtlog.h /// #ifndef PFMT_H_ #define PFMT_H_ #include "pstring.h" #include "ptypes.h" #include "putil.h" #include #include #include namespace plib { P_ENUM(plog_level, DEBUG, VERBOSE, INFO, WARNING, ERROR, FATAL) template struct ptype_traits_base { static constexpr const bool is_signed = std::numeric_limits::is_signed; static char32_t fmt_spec() { return 'u'; } static inline void streamify(std::ostream &s, const T &v) { s << v; } }; #if (PUSE_FLOAT128) template <> struct ptype_traits_base<__float128> { // FIXME: need native support at some time static constexpr const bool is_signed = true; static char32_t fmt_spec() { return 'f'; } static inline void streamify(std::ostream &s, const __float128 &v) { s << static_cast(v); } }; #endif template struct ptype_traits; template<> struct ptype_traits : ptype_traits_base { }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return is_signed ? 'd' : 'u'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'd'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'd'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'd'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'd'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'd'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'u'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'u'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'u'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'u'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'u'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'f'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'f'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'f'; } }; #if (PUSE_FLOAT128) template<> struct ptype_traits<__float128> : ptype_traits_base<__float128> { static char32_t fmt_spec() { return 'f'; } }; #endif template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 's'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 's'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 's'; } }; template<> struct ptype_traits : ptype_traits_base { static char32_t fmt_spec() { return 'p'; } }; class pfmt { public: explicit pfmt(const pstring &fmt) : m_str(fmt), m_locale(std::locale::classic()), m_arg(0) { } explicit pfmt(const std::locale &loc, const pstring &fmt) : m_str(fmt), m_locale(loc), m_arg(0) { } COPYASSIGNMOVE(pfmt, default) ~pfmt() noexcept = default; operator pstring() const { return m_str; } template typename std::enable_if::value, pfmt &>::type f(const T &x) {return format_element('f', x); } template typename std::enable_if::value, pfmt &>::type e(const T &x) {return format_element('e', x); } #if PUSE_FLOAT128 // FIXME: should use quadmath_snprintf pfmt & e(const __float128 &x) {return format_element('e', static_cast(x)); } #endif template typename std::enable_if::value, pfmt &>::type g(const T &x) {return format_element('g', x); } pfmt &operator ()(const void *x) {return format_element('p', x); } pfmt &operator ()(const pstring &x) {return format_element('s', x.c_str() ); } template pfmt &operator ()(const T &x) { return format_element(x); } template pfmt &operator ()(const T *x) { return format_element(x); } pfmt &operator ()() { return *this; } template pfmt &operator()(X&& x, Y && y, Args&&... args) { return ((*this)(std::forward(x)))(std::forward(y), std::forward(args)...); } template typename std::enable_if::value, pfmt &>::type x(const T &x) { return format_element('x', x); } template typename std::enable_if::value, pfmt &>::type o(const T &x) { return format_element('o', x); } friend std::ostream& operator<<(std::ostream &ostrm, const pfmt &fmt) { ostrm << fmt.m_str; return ostrm; } protected: struct rtype { rtype() : ret(0), p(0), sl(0) {} int ret; pstring::size_type p; pstring::size_type sl; }; rtype setfmt(std::stringstream &strm, char32_t cfmt_spec); template pfmt &format_element(T &&v) { return format_element(ptype_traits::type>::fmt_spec(), std::forward(v)); } template pfmt &format_element(const char32_t cfmt_spec, T &&v) { rtype ret; m_arg++; do { std::stringstream strm; strm.imbue(m_locale); ret = setfmt(strm, cfmt_spec); if (ret.ret>=0) { ptype_traits::type>::streamify(strm, std::forward(v)); const pstring ps(strm.str()); m_str = m_str.substr(0, ret.p) + ps + m_str.substr(ret.p + ret.sl); } } while (ret.ret == 1); return *this; } private: pstring m_str; std::locale m_locale; unsigned m_arg; }; template class pfmt_writer_t { public: explicit pfmt_writer_t() : m_enabled(true) { } COPYASSIGNMOVE(pfmt_writer_t, delete) // runtime enable template void log(const pstring & fmt, Args&&... args) const noexcept { if (build_enabled && enabled && m_enabled) { pfmt pf(fmt); static_cast(this)->vdowrite(xlog(pf, std::forward(args)...)); } } template void operator ()(const pstring &fmt, Args&&... args) const noexcept { if (build_enabled && m_enabled) { pfmt pf(fmt); static_cast(this)->vdowrite(xlog(pf, std::forward(args)...)); } } void set_enabled(const bool v) { m_enabled = v; } bool is_enabled() const { return m_enabled; } protected: ~pfmt_writer_t() noexcept = default; private: pfmt &xlog(pfmt &fmt) const { return fmt; } template pfmt &xlog(pfmt &fmt, X&& x, Args&&... args) const { return xlog(fmt(std::forward(x)), std::forward(args)...); } bool m_enabled; }; template class plog_channel : public pfmt_writer_t, build_enabled> { friend class pfmt_writer_t, build_enabled>; public: explicit plog_channel(T &b) : pfmt_writer_t(), m_base(b) { } COPYASSIGNMOVE(plog_channel, delete) ~plog_channel() noexcept = default; protected: void vdowrite(const pstring &ls) const noexcept { m_base.vlog(L, ls); } private: T &m_base; }; template class plog_base { public: explicit plog_base(T &proxy) : debug(proxy), info(proxy), verbose(proxy), warning(proxy), error(proxy), fatal(proxy) {} COPYASSIGNMOVE(plog_base, default) virtual ~plog_base() noexcept = default; plog_channel debug; plog_channel info; plog_channel verbose; plog_channel warning; plog_channel error; plog_channel fatal; }; } // namespace plib template plib::pfmt& operator<<(plib::pfmt &p, T&& val) { return p(std::forward(val)); } #endif // PSTRING_H_