diff --git a/include/fmt/test.cpp b/include/fmt/test.cpp new file mode 100644 index 00000000..42b89857 --- /dev/null +++ b/include/fmt/test.cpp @@ -0,0 +1,226 @@ +#define FMT_HEADER_ONLY +#include "format.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_; + // 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); +} + + + + + +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 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>; + +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> {}; + +struct stored_objs_dtor_base : std::false_type { + static void destruct(void* p) {} +}; + +template +struct stored_objs_dtor_gen : std::true_type { + static void destruct(void* p) { + Base::destruct(p); + reinterpret_cast((reinterpret_cast(p) + offset))->~T(); + } +}; + + +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; + + +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 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; + 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; +} + + + +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_}); ///// args_ or args + 1 depends on desc_ & detail::has_named_args_bit + entry.destruct(); +} + + +struct format_queue { + +}; + +} +using namespace fmtlog; + + +#include + + + +int main() { + std::cout << sizeof(basic_format_entry) << std::endl; + 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])); + + std::cout << &entry << "\n" << &(entry.arg_store_) << "\n" << sizeof(entry.arg_store_) << std::endl; +}