From 9c6004535acfe1cfbe2533b77970eec2dde7cb35 Mon Sep 17 00:00:00 2001 From: yumeyao Date: Fri, 26 Feb 2021 19:39:55 +0800 Subject: [PATCH] essential fmtlog done --- include/fmt/test.cpp | 244 +++++++++++++++++++++++++++++++------------ 1 file changed, 179 insertions(+), 65 deletions(-) diff --git a/include/fmt/test.cpp b/include/fmt/test.cpp index 42b89857..405299fb 100644 --- a/include/fmt/test.cpp +++ b/include/fmt/test.cpp @@ -1,5 +1,6 @@ #define FMT_HEADER_ONLY #include "format.h" +#include namespace fmtlog { using namespace fmt; @@ -28,42 +29,19 @@ template struct format_entry : basic_format using entry = basic_format_entry; format_arg_store arg_store_; - // char stored_objs_[0]; - // char stored_bufs_[]; 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; } - - }; - - -template struct obj_store; - - - - - - -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); -} - - - - +// +// 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 @@ -72,6 +50,10 @@ enum class store_method { 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 @@ -81,25 +63,39 @@ template struct is_basic_string using stored_as_string_object = std::integral_constant::value && is_basic_string>::value && std::is_rvalue_reference::value>; -template , Context>> +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> {}; + 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::false_type { +struct stored_objs_dtor_base : std::integral_constant { static void destruct(void* p) {} }; -template -struct stored_objs_dtor_gen : std::true_type { +template +struct stored_objs_dtor_gen : std::integral_constant { static void destruct(void* p) { + reinterpret_cast((reinterpret_cast(p) + offset))->~RawT(); Base::destruct(p); - reinterpret_cast((reinterpret_cast(p) + offset))->~T(); } }; - template struct stored_objs_dtor_select { using RawT = std::remove_reference_t; @@ -111,11 +107,134 @@ struct stored_objs_dtor_select { 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; } @@ -145,24 +264,6 @@ inline char* store_bufs(void** stored_args, char* p, T t, Args... args) { return store_bufs(stored_args, p, static_cast(args)...); } - -template struct index_list {}; - -// Collects internal details for generating index ranges [MIN, MAX) -inline namespace detail -{ - // 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 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; @@ -171,7 +272,6 @@ inline auto make_format_entry(void* buf, const S& format_str, void* const (&stor 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; @@ -188,8 +288,7 @@ inline size_t store_format_entry(void* buf, const S& format_str, Args&&... args) p->dtor_ = dtor::value ? dtor::destruct : nullptr; return pend - pentry; } - - +#endif template inline void print_format_entry(basic_format_entry& entry) { @@ -203,6 +302,20 @@ struct format_queue { }; +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; @@ -212,15 +325,16 @@ using namespace fmtlog; int main() { - std::cout << sizeof(basic_format_entry) << std::endl; + fmt::print("entry header: {}\n", sizeof(basic_format_entry)); auto entry = mk_format_entry("The answer is {}\n", 42); print_format_entry(entry); char buf[2000]; - size_t size = store_format_entry(buf, "The answer is {}{}\n", std::to_string(4), 2); - std::cout << size << std::endl; - auto& entryref = entry; - print_format_entry(reinterpret_cast(buf[0])); + size_t size = store_format_entry(buf, "This {} is {}{}\n", "answer", std::to_string(4), 2); + fmt::print("entry size: {}\n", size); + auto& entryref1 = entry; + auto& entryref = reinterpret_cast(buf[0]); + print_format_entry(entryref); - std::cout << &entry << "\n" << &(entry.arg_store_) << "\n" << sizeof(entry.arg_store_) << std::endl; + std::cout << &entryref << "\n" << &(entryref.arg_store_) << "\n" << sizeof(entryref.arg_store_) << std::endl; }