From 466128de00f4cfbcf45f076edb1db0f451a3fa9b Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 1 Sep 2019 12:12:19 -0700 Subject: [PATCH] Remove unused code and refactor --- include/fmt/chrono.h | 6 +- include/fmt/compile.h | 211 ++++++++++++++++++++---------------------- include/fmt/format.h | 15 ++- test/compile-test.cc | 38 +------- test/format | 4 +- 5 files changed, 114 insertions(+), 160 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 934f49f6..9c4c8b3b 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -805,10 +805,10 @@ struct formatter, Char> { auto out = std::back_inserter(buf); using range = internal::output_range; internal::basic_writer w(range(ctx.out())); - internal::handle_dynamic_spec( - specs.width, width_ref, ctx, format_str.begin()); + internal::handle_dynamic_spec(specs.width, + width_ref, ctx); internal::handle_dynamic_spec( - precision, precision_ref, ctx, format_str.begin()); + precision, precision_ref, ctx); if (begin == end || *begin == '}') { out = internal::format_chrono_duration_value(out, d.count(), precision); internal::format_chrono_duration_unit(out); diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 475c584d..da2ad874 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -34,7 +34,8 @@ template struct format_part { FMT_CONSTEXPR value(basic_string_view s) : str(s) {} FMT_CONSTEXPR value(replacement r) : repl(r) {} } val; - std::size_t arg_id_end = 0; // Position past the end of the argument id. + // Position past the end of the argument id. + const Char* arg_id_end = nullptr; FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {}) : part_kind(k), val(v) {} @@ -97,6 +98,11 @@ class format_string_compiler : public error_handler { private: using part = format_part; + PartHandler handler_; + part part_; + basic_string_view format_str_; + basic_parse_context parse_context_; + public: FMT_CONSTEXPR format_string_compiler(basic_string_view format_str, PartHandler handler) @@ -123,34 +129,25 @@ class format_string_compiler : public error_handler { } FMT_CONSTEXPR void on_replacement_field(const Char* ptr) { - part_.arg_id_end = ptr - format_str_.begin(); + part_.arg_id_end = ptr; handler_(part_); } FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, const Char* end) { - const auto specs_offset = to_unsigned(begin - format_str_.begin()); - auto repl = typename part::replacement(); dynamic_specs_handler> handler(repl.specs, parse_context_); - begin = parse_format_specs(begin, end, handler); - if (*begin != '}') on_error("missing '}' in format string"); - + auto it = parse_format_specs(begin, end, handler); + if (*it != '}') on_error("missing '}' in format string"); repl.arg_id = part_.part_kind == part::kind::arg_index ? arg_ref(part_.val.arg_index) : arg_ref(part_.val.str); auto part = part::make_replacement(repl); - part.arg_id_end = specs_offset; + part.arg_id_end = begin; handler_(part); - return begin; + return it; } - - private: - PartHandler handler_; - part part_; - basic_string_view format_str_; - basic_parse_context parse_context_; }; // Compiles a format string and invokes handler(part) for each parsed part. @@ -162,101 +159,93 @@ FMT_CONSTEXPR void compile_format_string(basic_string_view format_str, format_string_compiler(format_str, handler)); } -template -class compiled_format { - public: - using char_type = char_t; - using format_part_t = format_part; +template +void format_arg(basic_parse_context& parse_ctx, + Context& ctx, Id arg_id) { + ctx.advance_to( + visit_format_arg(arg_formatter(ctx, &parse_ctx), ctx.arg(arg_id))); +} - constexpr compiled_format(Format f) - : format_(std::move(f)), parts_provider_(to_string_view(format_)) {} +// vformat_to is defined in a subnamespace to prevent ADL. +namespace cf { +template +auto vformat_to(Range out, CompiledFormat& cf, basic_format_args args) + -> typename Context::iterator { + using char_type = typename Context::char_type; + basic_parse_context parse_ctx(to_string_view(cf.format_)); + Context ctx(out.begin(), args); + + const auto& parts = cf.parts_provider_.parts(); + for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) { + const auto& part = *part_it; + const auto& value = part.val; + + using format_part_t = format_part; + switch (part.part_kind) { + case format_part_t::kind::text: { + const auto text = value.str; + auto output = ctx.out(); + auto&& it = reserve(output, text.size()); + it = std::copy_n(text.begin(), text.size(), it); + ctx.advance_to(output); + } break; + + case format_part_t::kind::arg_index: + advance_to(parse_ctx, part.arg_id_end); + internal::format_arg(parse_ctx, ctx, value.arg_index); + break; + + case format_part_t::kind::arg_name: + advance_to(parse_ctx, part.arg_id_end); + internal::format_arg(parse_ctx, ctx, value.str); + break; + + case format_part_t::kind::replacement: { + const auto& arg_id_value = value.repl.arg_id.val; + const auto arg = value.repl.arg_id.kind == arg_id_kind::index + ? ctx.arg(arg_id_value.index) + : ctx.arg(arg_id_value.name); + + auto specs = value.repl.specs; + + handle_dynamic_spec(specs.width, specs.width_ref, ctx); + handle_dynamic_spec(specs.precision, + specs.precision_ref, ctx); + + error_handler h; + numeric_specs_checker checker(h, arg.type()); + if (specs.align == align::numeric) checker.require_numeric_argument(); + if (specs.sign != sign::none) checker.check_sign(); + if (specs.alt) checker.require_numeric_argument(); + if (specs.precision >= 0) checker.check_precision(); + + advance_to(parse_ctx, part.arg_id_end); + ctx.advance_to( + visit_format_arg(arg_formatter(ctx, nullptr, &specs), arg)); + } break; + } + } + return ctx.out(); +} +} // namespace cf + +template +class compiled_format { + private: + S format_; + PreparedPartsProvider parts_provider_; + + template + friend auto cf::vformat_to(Range out, CompiledFormat& cf, + basic_format_args args) -> + typename Context::iterator; + + public: + using char_type = char_t; compiled_format() = delete; - - template - auto vformat_to(Range out, basic_format_args args) const -> - typename Context::iterator { - const auto format_view = internal::to_string_view(format_); - basic_parse_context parse_ctx(format_view); - Context ctx(out.begin(), args); - - const auto& parts = parts_provider_.parts(); - for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) { - const auto& part = *part_it; - const auto& value = part.val; - - switch (part.part_kind) { - case format_part_t::kind::text: { - const auto text = value.str; - auto output = ctx.out(); - auto&& it = internal::reserve(output, text.size()); - it = std::copy_n(text.begin(), text.size(), it); - ctx.advance_to(output); - } break; - - case format_part_t::kind::arg_index: { - advance_parse_context_to_specification(parse_ctx, part); - format_arg(parse_ctx, ctx, value.arg_index); - } break; - - case format_part_t::kind::arg_name: { - advance_parse_context_to_specification(parse_ctx, part); - format_arg(parse_ctx, ctx, value.str); - } break; - case format_part_t::kind::replacement: { - const auto& arg_id_value = value.repl.arg_id.val; - const auto arg = value.repl.arg_id.kind == arg_id_kind::index - ? ctx.arg(arg_id_value.index) - : ctx.arg(arg_id_value.name); - - auto specs = value.repl.specs; - - handle_dynamic_spec( - specs.width, specs.width_ref, ctx, format_view.begin()); - handle_dynamic_spec( - specs.precision, specs.precision_ref, ctx, format_view.begin()); - - check_prepared_specs(specs, arg.type()); - advance_parse_context_to_specification(parse_ctx, part); - ctx.advance_to( - visit_format_arg(arg_formatter(ctx, nullptr, &specs), arg)); - } break; - } - } - - return ctx.out(); - } - - private: - void advance_parse_context_to_specification( - basic_parse_context& parse_ctx, - const format_part_t& part) const { - const auto view = to_string_view(format_); - const auto specification_begin = view.data() + part.arg_id_end; - advance_to(parse_ctx, specification_begin); - } - - template - void format_arg(basic_parse_context& parse_ctx, Context& ctx, - Id arg_id) const { - ctx.advance_to(visit_format_arg(arg_formatter(ctx, &parse_ctx), - ctx.arg(arg_id))); - } - - template - void check_prepared_specs(const basic_format_specs& specs, - internal::type arg_type) const { - internal::error_handler h; - numeric_specs_checker checker(h, arg_type); - if (specs.align == align::numeric) checker.require_numeric_argument(); - if (specs.sign != sign::none) checker.check_sign(); - if (specs.alt) checker.require_numeric_argument(); - if (specs.precision >= 0) checker.check_precision(); - } - - private: - Format format_; - PreparedPartsProvider parts_provider_; + constexpr compiled_format(S f) + : format_(std::move(f)), parts_provider_(to_string_view(format_)) {} }; template class compiletime_prepared_parts_type_provider { @@ -367,8 +356,8 @@ std::basic_string format(const CompiledFormat& cf, const Args&... args) { basic_memory_buffer buffer; using range = buffer_range; using context = buffer_context; - cf.template vformat_to(range(buffer), - {make_format_args(args...)}); + internal::cf::vformat_to(range(buffer), cf, + {make_format_args(args...)}); return to_string(buffer); } @@ -378,8 +367,8 @@ OutputIt format_to(OutputIt out, const CompiledFormat& cf, using char_type = typename CompiledFormat::char_type; using range = internal::output_range; using context = format_context_t; - return cf.template vformat_to( - range(out), {make_format_args(args...)}); + return internal::cf::vformat_to( + range(out), cf, {make_format_args(args...)}); } template class Handler, typename Spec, typename Context> void handle_dynamic_spec(Spec& value, arg_ref ref, - Context& ctx, - const typename Context::char_type* format_str) { + Context& ctx) { switch (ref.kind) { case arg_id_kind::none: break; @@ -2935,13 +2934,12 @@ template struct formatter::value != internal::custom_type>> { - FMT_CONSTEXPR formatter() : format_str_(nullptr) {} + FMT_CONSTEXPR formatter() {} // Parses format specifiers stopping either at the end of the range or at the // terminating '}'. template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - format_str_ = ctx.begin(); using handler_type = internal::dynamic_specs_handler; auto type = internal::type_constant::value; internal::specs_checker handler(handler_type(specs_, ctx), @@ -2991,9 +2989,9 @@ struct formatter auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { internal::handle_dynamic_spec( - specs_.width, specs_.width_ref, ctx, format_str_); + specs_.width, specs_.width_ref, ctx); internal::handle_dynamic_spec( - specs_.precision, specs_.precision_ref, ctx, format_str_); + specs_.precision, specs_.precision_ref, ctx); using range_type = internal::output_range; @@ -3003,7 +3001,6 @@ struct formatter specs_; - const Char* format_str_; }; #define FMT_FORMAT_AS(Type, Base) \ @@ -3104,9 +3101,9 @@ template class dynamic_formatter { private: template void handle_specs(Context& ctx) { internal::handle_dynamic_spec( - specs_.width, specs_.width_ref, ctx, format_str_); + specs_.width, specs_.width_ref, ctx); internal::handle_dynamic_spec( - specs_.precision, specs_.precision_ref, ctx, format_str_); + specs_.precision, specs_.precision_ref, ctx); } internal::dynamic_format_specs specs_; diff --git a/test/compile-test.cc b/test/compile-test.cc index 91559858..15ee7a28 100644 --- a/test/compile-test.cc +++ b/test/compile-test.cc @@ -67,40 +67,6 @@ TEST(CompileTest, CompileTimePreparedPartsTypeProvider) { } #endif -class custom_parts_container { - public: - typedef fmt::internal::format_part format_part_type; - - private: - typedef std::deque parts; - - public: - void add(format_part_type part) { parts_.push_back(std::move(part)); } - - void substitute_last(format_part_type part) { - parts_.back() = std::move(part); - } - - format_part_type last() { return parts_.back(); } - - auto begin() -> decltype(std::declval().begin()) { - return parts_.begin(); - } - - auto begin() const -> decltype(std::declval().begin()) { - return parts_.begin(); - } - - auto end() -> decltype(std::declval().begin()) { return parts_.end(); } - - auto end() const -> decltype(std::declval().begin()) { - return parts_.end(); - } - - private: - parts parts_; -}; - TEST(CompileTest, PassStringLiteralFormat) { const auto prepared = fmt::compile("test {}"); EXPECT_EQ("test 42", fmt::format(prepared, 42)); @@ -155,12 +121,14 @@ TEST(CompileTest, FormattedSize) { struct formattable {}; +FMT_BEGIN_NAMESPACE template <> -struct fmt::formatter : formatter { +struct formatter : formatter { auto format(formattable, format_context& ctx) -> decltype(ctx.out()) { return formatter::format("foo", ctx); } }; +FMT_END_NAMESPACE TEST(CompileTest, FormatUserDefinedType) { auto f = fmt::compile("{}"); diff --git a/test/format b/test/format index f775022f..dba3bf48 100644 --- a/test/format +++ b/test/format @@ -690,9 +690,9 @@ struct formatter { template auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { fmt::internal::handle_dynamic_spec( - specs_.width, specs_.width_ref, ctx, nullptr); + specs_.width, specs_.width_ref, ctx); fmt::internal::handle_dynamic_spec( - specs_.precision, specs_.precision_ref, ctx, nullptr); + specs_.precision, specs_.precision_ref, ctx); using range_type = fmt::internal::output_range; return visit_format_arg(arg_formatter(ctx, nullptr, &specs_),