refactor fmtlog with libfmt compatible public apis for format_entry

This commit is contained in:
yumeyao 2021-03-03 11:30:43 +08:00
parent 36d14b8ce3
commit c4a6d48584

View File

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