From 4ce006fb6edfccfa81b7fb4cf4596c61036a5ff2 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 25 Aug 2019 07:48:09 -0700 Subject: [PATCH] Simplify format string compilation --- include/fmt/compile.h | 117 ++++++--------------------- test/compile-test.cc | 180 ------------------------------------------ 2 files changed, 24 insertions(+), 273 deletions(-) diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 5fff7020..266644e4 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -113,28 +113,26 @@ class format_preparation_handler : public internal::error_handler { if (begin == end) return; const auto offset = begin - format_.data(); const auto size = end - begin; - parts_.add(part(string_view_metadata(offset, size))); + parts_.push_back(part(string_view_metadata(offset, size))); } FMT_CONSTEXPR void on_arg_id() { - parts_.add(part(parse_context_.next_arg_id())); + parts_.push_back(part(parse_context_.next_arg_id())); } FMT_CONSTEXPR void on_arg_id(unsigned id) { parse_context_.check_arg_id(id); - parts_.add(part(id)); + parts_.push_back(part(id)); } FMT_CONSTEXPR void on_arg_id(basic_string_view id) { const auto view = string_view_metadata(format_, id); const auto arg_id = typename part::named_argument_id(view); - parts_.add(part(arg_id)); + parts_.push_back(part(arg_id)); } FMT_CONSTEXPR void on_replacement_field(const Char* ptr) { - auto last_part = parts_.last(); - last_part.end_of_argument_id = ptr - format_.begin(); - parts_.substitute_last(last_part); + parts_.back().end_of_argument_id = ptr - format_.begin(); } FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, @@ -148,19 +146,13 @@ class format_preparation_handler : public internal::error_handler { if (*begin != '}') on_error("missing '}' in format string"); - const auto last_part = parts_.last(); - + auto& last_part = parts_.back(); auto specs = last_part.which == part::which_value::argument_id ? typename part::specification(last_part.val.arg_id) : typename part::specification(last_part.val.named_arg_id); - specs.parsed_specs = parsed_specs; - - auto new_part = part(specs); - new_part.end_of_argument_id = specs_offset; - - parts_.substitute_last(new_part); - + last_part = part(specs); + last_part.end_of_argument_id = specs_offset; return begin; } @@ -346,7 +338,6 @@ template class compiletime_prepared_parts_type_provider { FMT_CONSTEXPR value_type& operator[](unsigned ind) { return arr[ind]; } FMT_CONSTEXPR const value_type* begin() const { return arr; } - FMT_CONSTEXPR const value_type* end() const { return begin() + N; } private: @@ -370,13 +361,9 @@ template class compiletime_prepared_parts_collector { FMT_CONSTEXPR explicit compiletime_prepared_parts_collector(Parts& parts) : parts_{parts}, counter_{0u} {} - FMT_CONSTEXPR void add(format_part part) { parts_[counter_++] = part; } + FMT_CONSTEXPR void push_back(format_part part) { parts_[counter_++] = part; } - FMT_CONSTEXPR void substitute_last(format_part part) { - parts_[counter_ - 1] = part; - } - - FMT_CONSTEXPR format_part last() { return parts_[counter_ - 1]; } + FMT_CONSTEXPR format_part& back() { return parts_[counter_ - 1]; } private: Parts& parts_; @@ -431,87 +418,31 @@ struct compiletime_parts_provider { } }; -template -struct parts_provider_type { - using type = compiletime_parts_provider< - Format, typename compiletime_prepared_parts_type_provider::type>; -}; - -template -struct parts_provider_type { - using type = runtime_parts_provider; -}; - template -struct basic_prepared_format { - using type = - internal::prepared_format::value, Format, - PreparedPartsContainer>::type, - Args...>; -}; - -template -std::basic_string to_runtime_format(basic_string_view format) { - return std::basic_string(format.begin(), format.size()); -} - -template -std::basic_string to_runtime_format(const Char* format) { - return std::basic_string(format); -} - -template >> -class parts_container { - public: - using format_part_type = format_part; - - 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().end()) { - return parts_.end(); - } - - auto end() const -> decltype(std::declval().end()) { - return parts_.end(); - } - - private: - Container parts_; -}; +using basic_prepared_format = internal::prepared_format< + Format, + conditional_t::value, + compiletime_parts_provider< + Format, typename compiletime_prepared_parts_type_provider< + Format>::type>, + runtime_parts_provider>, + Args...>; } // namespace internal #if FMT_USE_CONSTEXPR template ::value)> FMT_CONSTEXPR auto compile(S format_str) { - return typename internal::basic_prepared_format::type( - format_str); + return internal::basic_prepared_format(format_str); } #endif template -auto compile(const Char (&format_str)[N]) -> - typename internal::basic_prepared_format, - internal::parts_container, - Args...>::type { - const auto view = basic_string_view(format_str, N - 1); - return internal::to_runtime_format(view); +auto compile(const Char (&format_str)[N]) + -> internal::basic_prepared_format, + std::vector>, + Args...> { + return std::basic_string(format_str, N - 1); } template )); - MOCK_METHOD1(substitute_last, void(fmt::internal::format_part)); - MOCK_METHOD0(last, fmt::internal::format_part()); -}; - FMT_BEGIN_NAMESPACE namespace internal { bool operator==(const internal::string_view_metadata& lhs, @@ -227,179 +220,6 @@ TEST(CompileTest, FormatPart_ComparisonOperators) { } } -TEST(CompileTest, FormatPreparationHandler_OnText_AddsPartWithText) { - typedef fmt::internal::format_part format_part; - typedef StrictMock parts_mock; - - parts_mock parts; - const auto format = fmt::internal::to_string_view("text"); - fmt::internal::format_preparation_handler handler(format, - parts); - - const auto expected_text = fmt::internal::string_view_metadata( - 0u, static_cast(format.size())); - EXPECT_CALL(parts, add(format_part(expected_text))); - - handler.on_text(format.begin(), format.end()); -} - -TEST(CompileTest, FormatPreparationHandler_OnArgId_AddsPartWithIncrementedId) { - typedef fmt::internal::format_part format_part; - typedef StrictMock parts_mock; - - parts_mock parts; - const auto format = fmt::internal::to_string_view(""); - fmt::internal::format_preparation_handler handler(format, - parts); - - const auto expected_first_arg_id = 0u; - const auto expected_second_arg_id = 1u; - EXPECT_CALL(parts, add(format_part(expected_first_arg_id))); - EXPECT_CALL(parts, add(format_part(expected_second_arg_id))); - - handler.on_arg_id(); - handler.on_arg_id(); -} - -TEST(CompileTest, FormatPreparationHandler_OnArgId_AddsPartWithPassedId) { - typedef fmt::internal::format_part format_part; - typedef StrictMock parts_mock; - - parts_mock parts; - const auto format = fmt::internal::to_string_view(""); - fmt::internal::format_preparation_handler handler(format, - parts); - - const auto expected_first_arg_id = 2u; - const auto expected_second_arg_id = 0u; - const auto expected_third_arg_id = 1u; - EXPECT_CALL(parts, add(format_part(expected_first_arg_id))); - EXPECT_CALL(parts, add(format_part(expected_second_arg_id))); - EXPECT_CALL(parts, add(format_part(expected_third_arg_id))); - - handler.on_arg_id(expected_first_arg_id); - handler.on_arg_id(expected_second_arg_id); - handler.on_arg_id(expected_third_arg_id); -} - -TEST(CompileTest, FormatPreparationHandler_OnArgId_AddsPartWithPassedNamedId) { - typedef fmt::internal::format_part format_part; - typedef format_part::named_argument_id named_argument_id; - typedef StrictMock parts_mock; - - parts_mock parts; - const auto format = fmt::internal::to_string_view("0123456789"); - fmt::internal::format_preparation_handler handler(format, - parts); - - const auto expected_first_arg_id = fmt::string_view(format.data(), 1); - const auto expected_first_arg_view_metadata = - fmt::internal::string_view_metadata(0, 1); - const auto expected_second_arg_id = fmt::string_view(format.data() + 3, 2); - const auto expected_second_arg_view_metadata = - fmt::internal::string_view_metadata(3, 2); - const auto expected_third_arg_id = fmt::string_view(format.data() + 6, 3); - const auto expected_third_arg_view_metadata = - fmt::internal::string_view_metadata(6, 3); - EXPECT_CALL( - parts, - add(format_part(named_argument_id(expected_first_arg_view_metadata)))); - EXPECT_CALL( - parts, - add(format_part(named_argument_id(expected_second_arg_view_metadata)))); - EXPECT_CALL( - parts, - add(format_part(named_argument_id(expected_third_arg_view_metadata)))); - - handler.on_arg_id(expected_first_arg_id); - handler.on_arg_id(expected_second_arg_id); - handler.on_arg_id(expected_third_arg_id); -} - -TEST(CompileTest, - FormatPreparationHandler_OnReplacementField_SetsEndOfArgumentId) { - typedef fmt::internal::format_part format_part; - typedef StrictMock parts_mock; - - const auto format = fmt::internal::to_string_view("{:<}"); - parts_mock parts; - - const auto last_part = format_part(0u); - EXPECT_CALL(parts, last()).WillOnce(Return(last_part)); - - auto expected_substitution_part = last_part; - expected_substitution_part.end_of_argument_id = 1; - EXPECT_CALL(parts, substitute_last(expected_substitution_part)); - - fmt::internal::format_preparation_handler handler(format, - parts); - - handler.on_replacement_field(format.data() + 1); -} - -TEST( - CompileTest, - FormatPreparationHandlerLastPartArgIndex_OnFormatSpecs_UpdatesLastAddedPart) { - typedef fmt::internal::format_part format_part; - typedef StrictMock parts_mock; - - parts_mock parts; - const auto specification_test_text = fmt::internal::to_string_view("{:<10}"); - const auto specification_offset = 2u; - const auto specification_begin_it = - specification_test_text.begin() + specification_offset; - fmt::internal::format_preparation_handler handler( - specification_test_text, parts); - - const auto last_part = format_part(0u); - format_part::specification expected_specification(0u); - fmt::internal::dynamic_format_specs specs{}; - specs.align = fmt::align::left; - specs.width = 10; - expected_specification.parsed_specs = specs; - - auto expected_substitution_part = format_part(expected_specification); - expected_substitution_part.end_of_argument_id = specification_offset; - - EXPECT_CALL(parts, last()).WillOnce(Return(last_part)); - EXPECT_CALL(parts, substitute_last(expected_substitution_part)); - - handler.on_format_specs(specification_begin_it, - specification_test_text.end()); -} - -TEST( - CompileTest, - FormatPreparationHandlerLastPartNamedArgIndex_OnFormatSpecs_UpdatesLastAddedPart) { - typedef fmt::internal::format_part format_part; - typedef StrictMock parts_mock; - - parts_mock parts; - const auto specification_test_text = fmt::internal::to_string_view("{:<10}"); - const auto specification_offset = 2u; - const auto specification_begin_it = - specification_test_text.begin() + specification_offset; - fmt::internal::format_preparation_handler handler( - specification_test_text, parts); - - const auto arg_id = fmt::internal::string_view_metadata(0, 42); - const auto last_part = format_part(format_part::named_argument_id(arg_id)); - format_part::specification expected_specification(arg_id); - fmt::internal::dynamic_format_specs specs{}; - specs.align = fmt::align::left; - specs.width = 10; - expected_specification.parsed_specs = specs; - - auto expected_substitution_part = format_part(expected_specification); - expected_substitution_part.end_of_argument_id = specification_offset; - - EXPECT_CALL(parts, last()).WillOnce(Return(last_part)); - EXPECT_CALL(parts, substitute_last(expected_substitution_part)); - - handler.on_format_specs(specification_begin_it, - specification_test_text.end()); -} - // compiletime_prepared_parts_type_provider is useful only with relaxed // constexpr. #if FMT_USE_CONSTEXPR