fix fallback to the runtime API, add FMT_ENABLE_FALLBACK_TO_RUNTIME_API define, add test

This commit is contained in:
Alexey Ochapov 2021-02-21 06:00:18 +03:00
parent ab0f7d7fdc
commit 0c5bb0fcf1
No known key found for this signature in database
GPG Key ID: 9DC52E8F031B8DA8
2 changed files with 70 additions and 10 deletions

View File

@ -22,6 +22,10 @@
# endif
#endif
#ifndef FMT_ENABLE_FALLBACK_TO_RUNTIME_API
# define FMT_ENABLE_FALLBACK_TO_RUNTIME_API 1
#endif
FMT_BEGIN_NAMESPACE
namespace detail {
@ -704,12 +708,13 @@ constexpr auto compile(S format_str) {
constexpr auto result =
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
format_str);
if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
detail::unknown_format>()) {
return detail::compiled_format<S, Args...>(to_string_view(format_str));
} else {
return result;
}
# if !FMT_ENABLE_FALLBACK_TO_RUNTIME_API
static_assert(!std::is_same<remove_cvref_t<decltype(result)>,
detail::unknown_format>(),
"format string is invalid for compile-time API, "
"and fallback to runtime API is disabled");
# endif
return result;
}
}
#else
@ -789,7 +794,17 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
}
#endif
constexpr auto compiled = detail::compile<Args...>(S());
#ifdef __cpp_if_constexpr
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return format(static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return format(compiled, std::forward<Args>(args)...);
}
#else
return format(compiled, std::forward<Args>(args)...);
#endif
}
template <typename OutputIt, typename CompiledFormat, typename... Args,
@ -805,9 +820,20 @@ constexpr OutputIt format_to(OutputIt out, const CompiledFormat& cf,
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, const Args&... args) {
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
constexpr auto compiled = detail::compile<Args...>(S());
return format_to(out, compiled, args...);
#ifdef __cpp_if_constexpr
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return format_to(out,
static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return format_to(out, compiled, std::forward<Args>(args)...);
}
#else
return format_to(out, compiled, std::forward<Args>(args)...);
#endif
}
template <typename OutputIt, typename CompiledFormat, typename... Args>
@ -827,11 +853,26 @@ auto format_to_n(OutputIt out, size_t n, const CompiledFormat& cf,
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&,
const Args&... args) {
Args&&... args) {
constexpr auto compiled = detail::compile<Args...>(S());
#ifdef __cpp_if_constexpr
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
auto it =
format_to(detail::truncating_iterator<OutputIt>(out, n),
static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
return {it.base(), it.count()};
} else {
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled,
std::forward<Args>(args)...);
return {it.base(), it.count()};
}
#else
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled,
args...);
std::forward<Args>(args)...);
return {it.base(), it.count()};
#endif
}
template <typename CompiledFormat, typename... Args>

View File

@ -229,6 +229,25 @@ TEST(CompileTest, TextAndArg) {
EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42));
}
# if FMT_ENABLE_FALLBACK_TO_RUNTIME_API
TEST(CompileTest, UnknownFormatFallback) {
EXPECT_EQ(" 42 ",
fmt::format(FMT_COMPILE("{name:^4}"), fmt::arg("name", 42)));
std::vector<char> v;
fmt::format_to(std::back_inserter(v), FMT_COMPILE("{name:^4}"),
fmt::arg("name", 42));
EXPECT_EQ(" 42 ", fmt::string_view(v.data(), v.size()));
char buffer[4];
auto result = fmt::format_to_n(buffer, 4, FMT_COMPILE("{name:^4}"),
fmt::arg("name", 42));
EXPECT_EQ(4u, result.size);
EXPECT_EQ(buffer + 4, result.out);
EXPECT_EQ(" 42 ", fmt::string_view(buffer, 4));
}
# endif
TEST(CompileTest, Empty) { EXPECT_EQ("", fmt::format(FMT_COMPILE(""))); }
#endif