diff --git a/include/fmt/fmtlog.h b/include/fmt/fmtlog.h index 2ffe6654..d5b2e23e 100644 --- a/include/fmt/fmtlog.h +++ b/include/fmt/fmtlog.h @@ -8,23 +8,44 @@ namespace fmtlog { using namespace fmt; template struct basic_format_entry { +protected: using char_type = typename Context::char_type; - using format_arg = basic_format_arg; + using format_arg = fmt::detail::value; using arg_destructor = void (*)(void *p); basic_string_view format_; unsigned long long desc_; arg_destructor dtor_; - void destruct() { - if (dtor_) { - fmt::print("calling dtor\n"); - dtor_(this); - } else { - fmt::print("dtor is empty\n"); - } - } FMT_CONSTEXPR basic_format_entry(basic_string_view format) : format_(format), desc_(0), dtor_(0) {} + const format_arg* get_format_args() const; + + template + using enable_out = std::enable_if_t::value, T>; +public: + void destruct() { if (dtor_) dtor_(this); } + + // libfmt public APIs + std::basic_string format() const { return fmt::vformat(format_, {desc_, get_format_args()}); } + + template + auto format_to(OutIt out) const -> enable_out { + return fmt::vformat_to(out, format_, {desc_, get_format_args()}); + } + + template + auto format_to_n(OutIt out, size_t n) const -> enable_out> { + return fmt::vformat_to(fmt::detail::truncating_iterator(out, n), format_, {desc_, get_format_args()}); + } + + size_t formatted_size() const { + fmt::detail::counting_buffer<> buf; + format_to(buf); + return buf.count(); + } + + void print(std::FILE* file = stdout) const { return fmt::vprint(file, format_, {desc_, get_format_args()}); } + }; template struct format_entry : basic_format_entry { @@ -36,8 +57,15 @@ template struct format_entry : basic_format FMT_CONSTEXPR format_entry(const S& format_str, const Args&... args) : entry(to_string_view(format_str)), arg_store_(args...) { entry::desc_ = arg_store_.desc; } + FMT_CONSTEXPR void set_dtor(typename entry::arg_destructor dtor) { this->dtor_ = dtor; } }; +template +inline const typename basic_format_entry::format_arg* basic_format_entry::get_format_args() const { + auto& entry = static_cast&>(*this); + return &entry.arg_store_.data_.args_[entry.desc_ & fmt::detail::has_named_args_bit ? 1 : 0]; +} + // // A stored entry looks like: // ----------------------------------------------------------------------- @@ -45,6 +73,8 @@ template struct format_entry : basic_format // ----------------------------------------------------------------------- // +namespace detail { + enum class store_method { numeric, // stored by libfmt as numeric value, no need for extra storage object, // stored by libfmt as object, copy/move construct the object manually (requires properly calling destructor) @@ -115,17 +145,14 @@ template using stored_objs_dtor = typename stored_objs_dtor_select::type; // Collects internal details for generating index ranges [MIN, MAX) -inline namespace detail -{ - template struct index_list {}; +template struct index_list {}; - // Induction step - template - struct range_builder : public range_builder {}; +// Induction step +template +struct range_builder : public range_builder {}; - // Base step - template struct range_builder { typedef index_list type; }; -} +// Base step +template struct range_builder { typedef index_list type; }; // Meta-function that returns a [MIN, MAX) index range template @@ -164,7 +191,7 @@ private: template constexpr format_entry_constructor(void* buf, const S& format_str, index_list, Args... args) : pEntry(reinterpret_cast(buf)), pBuffer(get_buffer_store(buf)) { auto p = new(buf) Entry(format_str, store(std::forward(args))...); - p->dtor_ = Dtor::value ? Dtor::destruct : nullptr; + p->set_dtor(Dtor::value ? Dtor::destruct : nullptr); } template using arg_at = typename Trans::template arg_at; @@ -231,19 +258,48 @@ private: char* pBuffer; }; +template +struct entry_destruct_sentry { + using Entry = basic_format_entry; + entry_destruct_sentry(Entry& entry) : entry_(entry) {} + ~entry_destruct_sentry() { entry_.destruct(); } + Entry& entry_; +}; + +} + template > inline size_t store_format_entry(void* buf, const S& format_str, Args&&... args) { using Context = buffer_context; - using Constructor = format_entry_constructor; + using Constructor = detail::format_entry_constructor; return Constructor::construct(buf, format_str, std::forward(args)...); } -template inline -void print_format_entry(basic_format_entry& entry) { - auto& full_entry = static_cast&>(entry); - vprint(entry.format_, {entry.desc_, &full_entry.arg_store_.data_.args_[entry.desc_ & fmt::detail::has_named_args_bit ? 1 : 0]}); - entry.destruct(); +template +inline auto format_entry_to_string(basic_format_entry& entry) -> decltype(entry.format()) { + detail::entry_destruct_sentry _(entry); + return entry.format(); } +template +inline auto format_entry_to(OutIt out, basic_format_entry& entry) -> decltype(entry.format_to(out)) { + detail::entry_destruct_sentry _(entry); + return entry.format_to(out); +} + +template +inline auto format_entry_to_n(OutIt out, size_t n, basic_format_entry& entry) -> decltype(entry.format_to_n(out, n)) { + detail::entry_destruct_sentry _(entry); + return entry.format_to(out, n); +} + +template +inline void print_format_entry(std::FILE* f, basic_format_entry& entry) { + detail::entry_destruct_sentry _(entry); + entry.print(f); +} + +template inline void print_format_entry(basic_format_entry& entry) { print_format_entry(stdout, entry); } + } #endif \ No newline at end of file