From e8219952c638482e1d539018d70bf120b2c22757 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 10 Aug 2019 13:18:11 -0700 Subject: [PATCH] Restrict fmt::compile to literal strings to make sure we don't break the API too much when making all of this compile-time only. --- include/fmt/compile.h | 40 ++++------- test/compile-test.cc | 157 ------------------------------------------ 2 files changed, 13 insertions(+), 184 deletions(-) diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 5beb6aa5..d80adb73 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -613,44 +613,30 @@ template using prepared_format_t = typename basic_prepared_format, Args...>::type; -} // namespace internal - -#if FMT_USE_CONSTEXPR - -template -FMT_CONSTEXPR auto compile(S format_str) { - return internal::do_compile( - typename internal::format_tag::type{}, std::move(format_str)); -} -#else template auto compile(S format_str) -> typename internal::preparator::prepared_format_type { return internal::preparator::prepare(std::move(format_str)); } +} // namespace internal + +#if FMT_USE_CONSTEXPR + +template ::value)> +FMT_CONSTEXPR auto compile(S format_str) { + return internal::do_compile( + typename internal::format_tag::type{}, std::move(format_str)); +} #endif -template -auto compile(const Char* format_str) -> - typename internal::preparator, - Args...>::prepared_format_type { - return compile(internal::to_runtime_format(format_str)); -} - template -auto compile(const Char(format_str)[N]) -> +auto compile(const Char (&format_str)[N]) -> typename internal::preparator, Args...>::prepared_format_type { - const auto view = basic_string_view(format_str, N); - return compile(internal::to_runtime_format(view)); -} - -template -auto compile(basic_string_view format_str) -> - typename internal::preparator, - Args...>::prepared_format_type { - return compile(internal::to_runtime_format(format_str)); + const auto view = basic_string_view(format_str, N - 1); + return internal::compile(internal::to_runtime_format(view)); } template struct copied_prepared_format_creator { - static decltype(fmt::compile(std::declval())) make( - std::string format_str) { - auto prepared_format = fmt::compile(std::move(format_str)); - auto copied_prepared_format = prepared_format; - prepared_format = fmt::compile(""); - - return copied_prepared_format; - } -}; - -TEST(PrepareTest, CopyPreparedFormat_InternalStringViewsAreNotInvalidated) { - auto prepared = copied_prepared_format_creator::make( - "before {} middle {} after"); - EXPECT_EQ("before 42 middle text after", fmt::format(prepared, 42, "text")); - - prepared = copied_prepared_format_creator::make( - "before {0} middle {1} after"); - EXPECT_EQ("before 42 middle text after", fmt::format(prepared, 42, "text")); - - { - typedef decltype(fmt::arg("first", 42)) argument0; - typedef decltype(fmt::arg("second", "text")) argument1; - auto named_prepared = - copied_prepared_format_creator::make( - "before {first} middle {second} after"); - EXPECT_EQ("before 42 middle text after", - fmt::format(named_prepared, fmt::arg("first", 42), - fmt::arg("second", "text"))); - } - { - typedef decltype(fmt::arg("value", "12345")) argument0; - typedef decltype(fmt::arg("width", 10)) argument1; - auto named_prepared = - copied_prepared_format_creator::make( - ">>>{value:>{width}}<<<"); - EXPECT_EQ(">>> 12345<<<", - fmt::format(named_prepared, fmt::arg("value", "12345"), - fmt::arg("width", 10))); - } -} - -TEST(PrepareTest, ReusedPreparedFormatType) { - using prepared_format = fmt::internal::prepared_format_t; - - prepared_format prepared = fmt::compile("The {} is {}."); - EXPECT_EQ("The answer is 42.", fmt::format(prepared, "answer", 42)); - prepared = fmt::compile("40 {} 2 = {}"); - EXPECT_EQ("40 + 2 = 42", fmt::format(prepared, "+", 42)); -} - -TEST(PrepareTest, UserProvidedPartsContainerUnderlyingContainer) { - typedef fmt::internal::format_part format_part; - typedef fmt::internal::parts_container> - parts_container; - typedef fmt::internal::basic_prepared_format::type prepared_format; - - prepared_format prepared = fmt::compile("The {} is {}."); - EXPECT_EQ("The answer is 42.", fmt::format(prepared, "answer", 42)); - prepared = fmt::compile("40 {} 2 = {}"); - EXPECT_EQ("40 + 2 = 42", fmt::format(prepared, "+", 42)); -} - class custom_parts_container { public: typedef fmt::internal::format_part format_part_type; @@ -533,43 +467,6 @@ class custom_parts_container { parts parts_; }; -TEST(PrepareTest, UserProvidedPartsContainer) { - typedef fmt::internal::basic_prepared_format::type prepared_format; - - prepared_format prepared = fmt::compile("The {} is {}."); - EXPECT_EQ("The answer is 42.", fmt::format(prepared, "answer", 42)); - prepared = fmt::compile("40 {} 2 = {}"); - EXPECT_EQ("40 + 2 = 42", fmt::format(prepared, "+", 42)); -} - -TEST(PrepareTest, PassConstCharPointerFormat) { - const char* c_format = "test {}"; - const auto prepared = fmt::compile(c_format); - EXPECT_EQ("test 42", fmt::format(prepared, 42)); - const wchar_t* wc_format = L"test {}"; - const auto wprepared = fmt::compile(wc_format); - EXPECT_EQ(L"test 42", fmt::format(wprepared, 42)); -} - -TEST(PrepareTest, PassCharArrayFormat) { - char c_format[] = "test {}"; - const auto prepared = fmt::compile(c_format); - EXPECT_EQ("test 42", fmt::format(prepared, 42)); - wchar_t wc_format[] = L"test {}"; - const auto wprepared = fmt::compile(wc_format); - EXPECT_EQ(L"test 42", fmt::format(wprepared, 42)); -} - -TEST(PrepareTest, PassConstCharArrayFormat) { - const char c_format[] = "test {}"; - const auto prepared = fmt::compile(c_format); - EXPECT_EQ("test 42", fmt::format(prepared, 42)); - const wchar_t wc_format[] = L"test {}"; - const auto wprepared = fmt::compile(wc_format); - EXPECT_EQ(L"test 42", fmt::format(wprepared, 42)); -} - TEST(PrepareTest, PassStringLiteralFormat) { const auto prepared = fmt::compile("test {}"); EXPECT_EQ("test 42", fmt::format(prepared, 42)); @@ -577,22 +474,6 @@ TEST(PrepareTest, PassStringLiteralFormat) { EXPECT_EQ(L"test 42", fmt::format(wprepared, 42)); } -TEST(PrepareTest, PassStringViewFormat) { - const auto prepared = - fmt::compile(fmt::basic_string_view("test {}")); - EXPECT_EQ("test 42", fmt::format(prepared, 42)); - const auto wprepared = - fmt::compile(fmt::basic_string_view(L"test {}")); - EXPECT_EQ(L"test 42", fmt::format(wprepared, 42)); -} - -TEST(PrepareTest, PassBasicStringFormat) { - const auto prepared = fmt::compile(std::string("test {}")); - EXPECT_EQ("test 42", fmt::format(prepared, 42)); - const auto wprepared = fmt::compile(std::wstring(L"test {}")); - EXPECT_EQ(L"test 42", fmt::format(wprepared, 42)); -} - #if FMT_USE_CONSTEXPR TEST(PrepareTest, PassCompileString) { const auto prepared = fmt::compile(FMT_STRING("test {}")); @@ -602,44 +483,6 @@ TEST(PrepareTest, PassCompileString) { } #endif -template struct user_allocator { - typedef T value_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - template struct rebind { typedef user_allocator other; }; - - user_allocator() = default; - ~user_allocator() = default; - template user_allocator(const user_allocator&) {} - - pointer allocate( - size_type cnt, - typename std::allocator::const_pointer = nullptr) { - return new value_type[cnt]; - } - - void deallocate(pointer p, size_type) { delete[] p; } - - void construct(pointer p, const value_type& val) { new (p) value_type(val); } - - void destroy(pointer p) { (*p).~value_type(); } - - bool operator==(const user_allocator&) const { return true; } - bool operator!=(const user_allocator&) const { return false; } -}; - -TEST(PrepareTest, PassUserTypeFormat) { - typedef std::basic_string, user_allocator> - user_format; - const auto prepared = fmt::compile(user_format("test {}")); - EXPECT_EQ("test 42", fmt::format(prepared, 42)); -} - TEST(PrepareTest, FormatToArrayOfChars) { char buffer[32] = {0}; const auto prepared = fmt::compile("4{}");