From 61b4c923d78077c100a11bcf55d73c69c3e115a2 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 19 May 2021 16:08:56 -0700 Subject: [PATCH] Reduce code bloat --- include/fmt/format.h | 213 +++++++++++++++++------------------- include/fmt/printf.h | 4 +- src/format.cc | 25 ----- test/core-test.cc | 204 +++++++++++++++++++++++++++++++++++ test/format-test.cc | 249 ------------------------------------------- 5 files changed, 305 insertions(+), 390 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 898ddaea..0478ba0c 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -874,7 +874,7 @@ template struct basic_data { FMT_API static constexpr const char hex_digits[] = "0123456789abcdef"; FMT_API static constexpr const char signs[] = {0, '-', '+', ' '}; FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', - 0x1000000u | ' '}; + 0x1000000u | ' '}; FMT_API static constexpr const char left_padding_shifts[] = {31, 31, 0, 1, 0}; FMT_API static constexpr const char right_padding_shifts[] = {0, 31, 0, 1, 0}; }; @@ -1919,58 +1919,52 @@ auto write(OutputIt out, const T& value) -> typename std::enable_if< // An argument visitor that formats the argument and writes it via the output // iterator. It's a class and not a generic lambda for compatibility with C++11. -template struct default_arg_formatter { - using context = basic_format_context; +template struct default_arg_formatter { + using iterator = buffer_appender; + using context = buffer_context; - OutputIt out; + iterator out; basic_format_args args; locale_ref loc; - template auto operator()(T value) -> OutputIt { + template auto operator()(T value) -> iterator { return write(out, value); } - auto operator()(typename basic_format_arg::handle h) -> OutputIt { + auto operator()(typename basic_format_arg::handle h) -> iterator { basic_format_parse_context parse_ctx({}); - basic_format_context format_ctx(out, args, loc); + context format_ctx(out, args, loc); h.format(parse_ctx, format_ctx); return format_ctx.out(); } }; -template struct arg_formatter { - using context = basic_format_context; +template struct arg_formatter { + using iterator = buffer_appender; + using context = buffer_context; - OutputIt out; + iterator out; const basic_format_specs& specs; locale_ref locale; template - FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> OutputIt { + FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { return detail::write(out, value, specs, locale); } - auto operator()(typename basic_format_arg::handle) -> OutputIt { + auto operator()(typename basic_format_arg::handle) -> iterator { // User-defined types are handled separately because they require access // to the parse context. return out; } }; -template class custom_formatter { - private: - using char_type = typename Context::char_type; +template struct custom_formatter { + basic_format_parse_context& parse_ctx; + buffer_context& ctx; - basic_format_parse_context& parse_ctx_; - Context& ctx_; - - public: - explicit custom_formatter(basic_format_parse_context& parse_ctx, - Context& ctx) - : parse_ctx_(parse_ctx), ctx_(ctx) {} - - void operator()(typename basic_format_arg::handle h) const { - h.format(parse_ctx_, ctx_); + void operator()( + typename basic_format_arg>::handle h) const { + h.format(parse_ctx, ctx); } - template void operator()(T) const {} }; @@ -2036,16 +2030,33 @@ FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, ID id) { } // The standard format specifier handler with checking. -template -class specs_handler : public specs_setter { - public: - using char_type = typename Context::char_type; +template class specs_handler : public specs_setter { + private: + basic_format_parse_context& parse_context_; + buffer_context& context_; - FMT_CONSTEXPR specs_handler(basic_format_specs& specs, - ParseContext& parse_ctx, Context& ctx) - : specs_setter(specs), - parse_context_(parse_ctx), - context_(ctx) {} + // This is only needed for compatibility with gcc 4.4. + using format_arg = basic_format_arg>; + + FMT_CONSTEXPR format_arg get_arg(auto_id) { + return detail::get_arg(context_, parse_context_.next_arg_id()); + } + + FMT_CONSTEXPR format_arg get_arg(int arg_id) { + parse_context_.check_arg_id(arg_id); + return detail::get_arg(context_, arg_id); + } + + FMT_CONSTEXPR format_arg get_arg(basic_string_view arg_id) { + parse_context_.check_arg_id(arg_id); + return detail::get_arg(context_, arg_id); + } + + public: + FMT_CONSTEXPR specs_handler(basic_format_specs& specs, + basic_format_parse_context& parse_ctx, + buffer_context& ctx) + : specs_setter(specs), parse_context_(parse_ctx), context_(ctx) {} template FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { this->specs_.width = get_dynamic_spec( @@ -2058,79 +2069,6 @@ class specs_handler : public specs_setter { } void on_error(const char* message) { context_.on_error(message); } - - private: - // This is only needed for compatibility with gcc 4.4. - using format_arg = typename Context::format_arg; - - FMT_CONSTEXPR format_arg get_arg(auto_id) { - return detail::get_arg(context_, parse_context_.next_arg_id()); - } - - FMT_CONSTEXPR format_arg get_arg(int arg_id) { - parse_context_.check_arg_id(arg_id); - return detail::get_arg(context_, arg_id); - } - - FMT_CONSTEXPR format_arg get_arg(basic_string_view arg_id) { - parse_context_.check_arg_id(arg_id); - return detail::get_arg(context_, arg_id); - } - - ParseContext& parse_context_; - Context& context_; -}; - -template -struct format_handler : detail::error_handler { - basic_format_parse_context parse_context; - Context context; - - format_handler(OutputIt out, basic_string_view str, - basic_format_args format_args, detail::locale_ref loc) - : parse_context(str), context(out, format_args, loc) {} - - void on_text(const Char* begin, const Char* end) { - auto text = basic_string_view(begin, to_unsigned(end - begin)); - context.advance_to(write(context.out(), text)); - } - - int on_arg_id() { return parse_context.next_arg_id(); } - int on_arg_id(int id) { return parse_context.check_arg_id(id), id; } - int on_arg_id(basic_string_view id) { - int arg_id = context.arg_id(id); - if (arg_id < 0) on_error("argument not found"); - return arg_id; - } - - FMT_INLINE void on_replacement_field(int id, const Char*) { - auto arg = get_arg(context, id); - context.advance_to(visit_format_arg( - default_arg_formatter{context.out(), context.args(), - context.locale()}, - arg)); - } - - const Char* on_format_specs(int id, const Char* begin, const Char* end) { - auto arg = get_arg(context, id); - if (arg.type() == type::custom_type) { - parse_context.advance_to(parse_context.begin() + - (begin - &*parse_context.begin())); - visit_format_arg(custom_formatter(parse_context, context), arg); - return parse_context.begin(); - } - auto specs = basic_format_specs(); - using parse_context_t = basic_format_parse_context; - specs_checker> handler( - specs_handler(specs, parse_context, context), - arg.type()); - begin = parse_format_specs(begin, end, handler); - if (begin == end || *begin != '}') on_error("missing '}' in format string"); - auto f = detail::arg_formatter{context.out(), specs, - context.locale()}; - context.advance_to(visit_format_arg(f, arg)); - return begin; - } }; template