From 91c5d66003bf746d504a97a210a8870b7326187e Mon Sep 17 00:00:00 2001 From: yumeyao Date: Mon, 1 Mar 2021 10:31:26 +0800 Subject: [PATCH] rip to fmtlog.h --- include/fmt/fmtlog.h | 247 +++++++++++++++++++++++++++++++++ include/fmt/test.cpp | 315 +------------------------------------------ 2 files changed, 249 insertions(+), 313 deletions(-) create mode 100644 include/fmt/fmtlog.h diff --git a/include/fmt/fmtlog.h b/include/fmt/fmtlog.h new file mode 100644 index 00000000..16b94341 --- /dev/null +++ b/include/fmt/fmtlog.h @@ -0,0 +1,247 @@ +#ifndef FMT_FMTLOG_H_ +#define FMT_FMTLOG_H_ + +#include "format.h" +#include + +namespace fmtlog { +using namespace fmt; + +template struct basic_format_entry { + using char_type = typename Context::char_type; + using format_arg = basic_format_arg; + 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) {} +}; + +template struct format_entry : basic_format_entry { + using entry = basic_format_entry; + + format_arg_store arg_store_; + + template + 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; + } +}; + +// +// A stored entry looks like: +// ----------------------------------------------------------------------- +// | basic_format_entry | arg_store | stored_objs... | stored_buffers... | +// ----------------------------------------------------------------------- +// + +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) + buffer, // string/hexdump, store the string/binary trivially as buffer. + constexpr_str // compile-time string, can be stored as pointer directly (requires c++20 is_constant_evaluated()) +}; + +template using store_method_constant = std::integral_constant; +using store_as_object = store_method_constant; +using store_as_buffer = store_method_constant; + +template +using stored_as_numeric = std::integral_constant; +template +using stored_as_string = std::integral_constant; +template struct is_basic_string : std::false_type {}; +template struct is_basic_string> : std::true_type {}; +template +using stored_as_string_object = std::integral_constant::value && is_basic_string>::value && std::is_rvalue_reference::value>; + +struct custom_store_method_checker { + template , typename Formatter = typename Context::template formatter_type> + static std::enable_if_t::value, std::tuple(), std::declval()))>> test(int); + template + static std::tuple test(...); +}; + +template +struct custom_store_method { + using transformed_type = typename std::tuple_element<1, decltype(custom_store_method_checker::template test(0))>::type; + static constexpr bool custom_store = std::tuple_element<0, decltype(custom_store_method_checker::template test(0))>::type::value && !std::is_same_v; + using store_type = std::conditional_t, store_as_object, store_as_buffer>; +}; + +template , Context>> +struct stored_method_constant : std::integral_constant::value ? store_method::numeric : + stored_as_string::value ? (stored_as_string_object::value ? store_method::object : store_method::buffer) : + // store_method::object> {}; + custom_store_method::store_type::value> {}; + +struct stored_objs_dtor_base : std::integral_constant { + static void destruct(void* p) {} +}; + +template +struct stored_objs_dtor_gen : std::integral_constant { + static void destruct(void* p) { + reinterpret_cast((reinterpret_cast(p) + offset))->~RawT(); + Base::destruct(p); + } +}; + +template +struct stored_objs_dtor_select { + using RawT = std::remove_reference_t; + using type = std::conditional_t::value == store_method::object, + typename stored_objs_dtor_select, Args...>::type, + typename stored_objs_dtor_select::type>; +}; + +template +struct stored_objs_dtor_select { using type = Base; }; + +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 {}; + + // Induction step + template + struct range_builder : public range_builder {}; + + // Base step + template struct range_builder { typedef index_list type; }; +} + +// Meta-function that returns a [MIN, MAX) index range +template +using index_range = typename range_builder::type; + +template +struct arg_transformer { + using arg_tuple = std::tuple; + template using arg_at = typename std::tuple_element::type; + using type_tuple = std::tuple...>; + template using type_at = typename std::tuple_element::type; + template using size_at = std::integral_constant)>; + template using objsize_at = std::conditional_t, Context>::value == store_method::object, size_at, std::integral_constant>; + template struct objsizesum_at : std::integral_constant, objsizesum_at>::value + objsize_at::value> {}; + template using objoffset_at = std::conditional_t, objsizesum_at>; +}; + +template , Context>> +using transformed_arg_type = std::conditional_t::custom_store, typename custom_store_method::transformed_type, + std::conditional_t::value && !stored_as_string_object::value, basic_string_view, std::add_const_t>&> + >; + +template +struct format_entry_constructor { + using Entry = format_entry>...>; + using Dtor = stored_objs_dtor; + using Trans = arg_transformer; + + template + static size_t construct(void* buf, const S& format_str, Args... args) { + return format_entry_constructor(buf, format_str, range(), std::forward(args)...).get_total_size(); + } + +private: + using range = typename range_builder<0, sizeof...(Args)>::type; + 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; + } + + template using arg_at = typename Trans::template arg_at; + template transformed_arg_type, Context> store(typename Trans::template arg_at arg) { + using Arg = typename Trans::template arg_at; + using select_store_method = custom_store_method; + using MappedType = fmt::detail::mapped_type_constant, Context>; + if constexpr (select_store_method::custom_store == true) { + using Formatter = typename Context::template formatter_type>; + + // fmt::print("store custom arg {} @ {}\n", N, (void*)pBuffer); + return Formatter::store(pBuffer, std::forward(arg)); + } + else if constexpr (stored_as_string::value && !stored_as_string_object::value) { + // fmt::print("store string arg {} @ {}({})\n", N, (void*)pBuffer, fmt::detail::arg_mapper().map(std::forward(arg))); + return copy_string(pBuffer, fmt::detail::arg_mapper().map(std::forward(arg))); + } + else if constexpr (stored_as_numeric::value) { + return std::forward(arg); + } + else { + char* const pobjs = pEntry + sizeof(Entry); + char* const pobj = pobjs + Trans::template objoffset_at::value; + using Type = typename Trans::template type_at; + auto p = new(pobj) Type(std::forward(arg)); + return *p; + } + } + + static basic_string_view copy_string(char*& pBuffer, const typename Context::char_type* cstr) { + if constexpr (std::is_same_v) { + wchar_t* pStart = reinterpret_cast(pBuffer); + wchar_t* pEnd = wcpcpy(pStart, cstr); + pBuffer = reinterpret_cast(pEnd); + // fmt::print("copied wstring ({}) @ {}\n", basic_string_view(pStart, pEnd - pStart), (void*)pStart); + return basic_string_view(pStart, pEnd - pStart); + } + else { + char* pStart = pBuffer; + char* pEnd = stpcpy(pStart, cstr); + pBuffer = pEnd; + // fmt::print("copied string ({}) @ {}\n", basic_string_view(pStart, pEnd - pStart), (void*)pStart); + return basic_string_view(pStart, pEnd - pStart); + } + } + static basic_string_view copy_string(char*& pBuffer, basic_string_view sv) { + typename Context::char_type* pStart = reinterpret_cast(pBuffer); + size_t size = sizeof(typename Context::char_type) * sv.size(); + std::memcpy(pStart, sv.data(), size); + pBuffer += size; + return basic_string_view(pStart, sv.size()); + } + + static constexpr char* get_buffer_store(void* buf) { + char* const pentry = reinterpret_cast(buf); // entry will be constructed here + char* const pobjs = pentry + sizeof(Entry); // objects will be stored starting here + char* const pbufs = pobjs + get_obj_size(); // buffers will be stored starting here + // fmt::print("creating custom arg entry @ {}, {}, {}\n", (void*)pentry, (void*)pobjs, (void*)pbufs); + return pbufs; + } + static constexpr size_t get_obj_size() { return Trans::template objsizesum_at::value; } + constexpr size_t get_total_size() const { return pBuffer - pEntry; } + char* const pEntry; + char* pBuffer; +}; + +template > +inline size_t store_format_entry(void* buf, const S& format_str, Args&&... args) { + using Context = buffer_context; + using Constructor = 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(); +} + +} +#endif \ No newline at end of file diff --git a/include/fmt/test.cpp b/include/fmt/test.cpp index 631166fb..b7fdc05f 100644 --- a/include/fmt/test.cpp +++ b/include/fmt/test.cpp @@ -1,324 +1,13 @@ #define FMT_HEADER_ONLY -#include "format.h" -#include +#include "fmtlog.h" -namespace fmtlog { -using namespace fmt; - -template struct basic_format_entry { - using char_type = typename Context::char_type; - using format_arg = basic_format_arg; - 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) {} -}; - -template struct format_entry : basic_format_entry { - using entry = basic_format_entry; - - format_arg_store arg_store_; - - template - 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; - } -}; - -// -// A stored entry looks like: -// ----------------------------------------------------------------------- -// | basic_format_entry | arg_store | stored_objs... | stored_buffers... | -// ----------------------------------------------------------------------- -// - -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) - buffer, // string/hexdump, store the string/binary trivially as buffer. - constexpr_str // compile-time string, can be stored as pointer directly (requires c++20 is_constant_evaluated()) -}; - -template using store_method_constant = std::integral_constant; -using store_as_object = store_method_constant; -using store_as_buffer = store_method_constant; - -template -using stored_as_numeric = std::integral_constant; -template -using stored_as_string = std::integral_constant; -template struct is_basic_string : std::false_type {}; -template struct is_basic_string> : std::true_type {}; -template -using stored_as_string_object = std::integral_constant::value && is_basic_string>::value && std::is_rvalue_reference::value>; - -struct custom_store_method_checker { - template , typename Formatter = typename Context::template formatter_type> - static std::enable_if_t::value, std::tuple(), std::declval()))>> test(int); - template - static std::tuple test(...); -}; - -template -struct custom_store_method { - using transformed_type = typename std::tuple_element<1, decltype(custom_store_method_checker::template test(0))>::type; - static constexpr bool custom_store = std::tuple_element<0, decltype(custom_store_method_checker::template test(0))>::type::value && !std::is_same_v; - using store_type = std::conditional_t, store_as_object, store_as_buffer>; -}; - -template , Context>> -struct stored_method_constant : std::integral_constant::value ? store_method::numeric : - stored_as_string::value ? (stored_as_string_object::value ? store_method::object : store_method::buffer) : - // store_method::object> {}; - custom_store_method::store_type::value> {}; - -struct stored_objs_dtor_base : std::integral_constant { - static void destruct(void* p) {} -}; - -template -struct stored_objs_dtor_gen : std::integral_constant { - static void destruct(void* p) { - reinterpret_cast((reinterpret_cast(p) + offset))->~RawT(); - Base::destruct(p); - } -}; - -template -struct stored_objs_dtor_select { - using RawT = std::remove_reference_t; - using type = std::conditional_t::value == store_method::object, - typename stored_objs_dtor_select, Args...>::type, - typename stored_objs_dtor_select::type>; -}; - -template -struct stored_objs_dtor_select { using type = Base; }; - -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 {}; - - // Induction step - template - struct range_builder : public range_builder {}; - - // Base step - template struct range_builder { typedef index_list type; }; -} - -// Meta-function that returns a [MIN, MAX) index range -template -using index_range = typename range_builder::type; - -template -struct arg_transformer { - using arg_tuple = std::tuple; - template using arg_at = typename std::tuple_element::type; - using type_tuple = std::tuple...>; - template using type_at = typename std::tuple_element::type; - template using size_at = std::integral_constant)>; - template using objsize_at = std::conditional_t, Context>::value == store_method::object, size_at, std::integral_constant>; - template struct objsizesum_at : std::integral_constant, objsizesum_at>::value + objsize_at::value> {}; - template using objoffset_at = std::conditional_t, objsizesum_at>; -}; - -template , Context>> -using transformed_arg_type = std::conditional_t::custom_store, typename custom_store_method::transformed_type, - std::conditional_t::value && !stored_as_string_object::value, basic_string_view, std::add_const_t>&> - >; - -template -struct format_entry_constructor { - using Entry = format_entry>...>; - using Dtor = stored_objs_dtor; - using Trans = arg_transformer; - - template - static size_t construct(void* buf, const S& format_str, Args... args) { - return format_entry_constructor(buf, format_str, range(), std::forward(args)...).get_total_size(); - } - -private: - using range = typename range_builder<0, sizeof...(Args)>::type; - 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; - } - - template using arg_at = typename Trans::template arg_at; - template transformed_arg_type, Context> store(typename Trans::template arg_at arg) { - using Arg = typename Trans::template arg_at; - using select_store_method = custom_store_method; - using MappedType = fmt::detail::mapped_type_constant, Context>; - if constexpr (select_store_method::custom_store == true) { - using Formatter = typename Context::template formatter_type>; - - // fmt::print("store custom arg {} @ {}\n", N, (void*)pBuffer); - return Formatter::store(pBuffer, std::forward(arg)); - } - else if constexpr (stored_as_string::value && !stored_as_string_object::value) { - // fmt::print("store string arg {} @ {}({})\n", N, (void*)pBuffer, fmt::detail::arg_mapper().map(std::forward(arg))); - return copy_string(pBuffer, fmt::detail::arg_mapper().map(std::forward(arg))); - } - else if constexpr (stored_as_numeric::value) { - return std::forward(arg); - } - else { - char* const pobjs = pEntry + sizeof(Entry); - char* const pobj = pobjs + Trans::template objoffset_at::value; - using Type = typename Trans::template type_at; - auto p = new(pobj) Type(std::forward(arg)); - return *p; - } - } - - static basic_string_view copy_string(char*& pBuffer, const typename Context::char_type* cstr) { - if constexpr (std::is_same_v) { - wchar_t* pStart = reinterpret_cast(pBuffer); - wchar_t* pEnd = wcpcpy(pStart, cstr); - pBuffer = reinterpret_cast(pEnd); - // fmt::print("copied wstring ({}) @ {}\n", basic_string_view(pStart, pEnd - pStart), (void*)pStart); - return basic_string_view(pStart, pEnd - pStart); - } - else { - char* pStart = pBuffer; - char* pEnd = stpcpy(pStart, cstr); - pBuffer = pEnd; - // fmt::print("copied string ({}) @ {}\n", basic_string_view(pStart, pEnd - pStart), (void*)pStart); - return basic_string_view(pStart, pEnd - pStart); - } - } - static basic_string_view copy_string(char*& pBuffer, basic_string_view sv) { - typename Context::char_type* pStart = reinterpret_cast(pBuffer); - size_t size = sizeof(typename Context::char_type) * sv.size(); - std::memcpy(pStart, sv.data(), size); - pBuffer += size; - return basic_string_view(pStart, sv.size()); - } - - static constexpr char* get_buffer_store(void* buf) { - char* const pentry = reinterpret_cast(buf); // entry will be constructed here - char* const pobjs = pentry + sizeof(Entry); // objects will be stored starting here - char* const pbufs = pobjs + get_obj_size(); // buffers will be stored starting here - // fmt::print("creating custom arg entry @ {}, {}, {}\n", (void*)pentry, (void*)pobjs, (void*)pbufs); - return pbufs; - } - static constexpr size_t get_obj_size() { return Trans::template objsizesum_at::value; } - constexpr size_t get_total_size() const { return pBuffer - pEntry; } - char* const pEntry; - char* pBuffer; -}; - -template > -inline size_t store_format_entry(void* buf, const S& format_str, Args&&... args) { - using Context = buffer_context; - using Constructor = format_entry_constructor; - return Constructor::construct(buf, format_str, std::forward(args)...); -} - -#if 0 -template -inline char* store_objs(void** stored_args, char* p) { return p; } - -template -inline char* store_objs(void** stored_args, char* p, T t, Args... args) { - using RawT = std::remove_reference_t; - if constexpr (stored_method_constant::value == store_method::object) { - new(p) RawT(static_cast(t)); - *stored_args = p; - p += sizeof(RawT); - } - ++stored_args; - return store_objs(stored_args, p, static_cast(args)...); -} - -template -inline char* store_bufs(void** stored_args, char* p) { return p; } - -template -inline char* store_bufs(void** stored_args, char* p, T t, Args... args) { - using RawT = std::remove_reference_t; - if constexpr (stored_method_constant::value == store_method::buffer) { - *stored_args = p; - //p = copy_buffer(p, t); - } - ++stored_args; - return store_bufs(stored_args, p, static_cast(args)...); -} - -template -inline auto make_format_entry(void* buf, const S& format_str, void* const (&stored_args)[sizeof...(Args)], index_list, Args&&... args) { - using Char = char_t; - using Context = buffer_context; - using entry = format_entry...>; - return new(buf) entry { format_str, std::forward(stored_args[Indice] == 0 ? args : *reinterpret_cast*>(stored_args[Indice]))... }; -} - -template > -inline size_t store_format_entry(void* buf, const S& format_str, Args&&... args) { - using Context = buffer_context; - using entry = format_entry...>; - using dtor = stored_objs_dtor; - char* pentry = reinterpret_cast(buf); - char* pobjs = pentry + sizeof(entry); // objects will be stored starting here - void* stored_args[sizeof...(Args)] = {0}; // if an object is stored, it has a pointer other than 0 - char* pbufs = store_objs(stored_args, pobjs, std::forward(args)...); - char* pend = store_bufs(stored_args, pbufs, std::forward(args)...); - - //auto p = new(buf) entry{ format_str, args... }; - auto p = make_format_entry(buf, format_str, stored_args, index_range<0, sizeof...(Args)>(), std::forward(args)...); - p->dtor_ = dtor::value ? dtor::destruct : nullptr; - return pend - pentry; -} -#endif - -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(); -} - - -struct format_queue { - -}; +using namespace fmtlog; template > inline auto mk_format_entry(const S& format_str, Args&&... args) -> format_entry, remove_reference_t...> { return { format_str, args... }; } -template > -inline size_t write_format_entry(void* buf, const S& format_str, Args&&... args) { - using entry = format_entry, remove_reference_t...>; - auto p = new(buf) entry{ format_str, args... }; - (void) p; - return sizeof(entry); -} - - -} -using namespace fmtlog; - #include