mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-27 03:21:34 +00:00
Cleanup compile-time checks
This commit is contained in:
parent
db496b47c1
commit
6797f0c39a
@ -122,7 +122,7 @@ hide:
|
||||
</p>
|
||||
<p>
|
||||
The library is highly portable and requires only a minimal <b>subset of
|
||||
C++11</b> features which are available in GCC 4.8, Clang 3.4, MSVC 19.0
|
||||
C++11</b> features which are available in GCC 4.9, Clang 3.4, MSVC 19.0
|
||||
(2015) and later. Newer compiler and standard library features are used
|
||||
if available, and enable additional functionality.
|
||||
</p>
|
||||
|
@ -2765,7 +2765,7 @@ FMT_CONSTEXPR FMT_INLINE auto parse_replacement_field(const Char* begin,
|
||||
return begin + 1;
|
||||
}
|
||||
|
||||
template <bool IS_CONSTEXPR, typename Char, typename Handler>
|
||||
template <bool IS_CONSTEXPR = true, typename Char, typename Handler>
|
||||
FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
|
||||
Handler&& handler) {
|
||||
auto begin = format_str.data();
|
||||
@ -2938,21 +2938,6 @@ template <typename Char, typename... Args> class format_string_checker {
|
||||
// A base class for compile-time strings.
|
||||
struct compile_string {};
|
||||
|
||||
template <typename S>
|
||||
using is_compile_string = std::is_base_of<compile_string, S>;
|
||||
|
||||
// Reports a compile-time error if S is not a valid format string for T.
|
||||
template <typename... T, typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
|
||||
void check_format_string(S fmt) {
|
||||
using char_type = typename S::char_type;
|
||||
FMT_CONSTEXPR auto s = basic_string_view<char_type>(fmt);
|
||||
using checker = format_string_checker<char_type, remove_cvref_t<T>...>;
|
||||
FMT_CONSTEXPR bool error = (parse_format_string<true>(s, checker(s)), true);
|
||||
ignore_unused(error);
|
||||
}
|
||||
template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
|
||||
FMT_ALWAYS_INLINE void check_format_string(S) {}
|
||||
|
||||
// Use vformat_args and avoid type_identity to keep symbols short.
|
||||
template <typename Char = char> struct vformat_args {
|
||||
using type = basic_format_args<buffered_context<Char>>;
|
||||
@ -3027,36 +3012,49 @@ template <typename Char, typename... Args> class basic_format_string {
|
||||
private:
|
||||
basic_string_view<Char> str_;
|
||||
|
||||
public:
|
||||
template <
|
||||
typename S,
|
||||
FMT_ENABLE_IF(
|
||||
std::is_convertible<const S&, basic_string_view<Char>>::value ||
|
||||
(detail::is_compile_string<S>::value &&
|
||||
std::is_constructible<basic_string_view<Char>, const S&>::value))>
|
||||
FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_format_string(const S& s) : str_(s) {
|
||||
using checker = detail::format_string_checker<Char, remove_cvref_t<Args>...>;
|
||||
|
||||
template <typename S>
|
||||
FMT_CONSTEXPR FMT_ALWAYS_INLINE void check(const S& s) {
|
||||
static_assert(
|
||||
detail::count<
|
||||
(std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
|
||||
std::is_reference<Args>::value)...>() == 0,
|
||||
std::is_reference<Args>::value)...>() == 0,
|
||||
"passing views as lvalues is disallowed");
|
||||
detail::ignore_unused(s);
|
||||
#if FMT_USE_CONSTEVAL
|
||||
if constexpr (detail::count_named_args<Args...>() ==
|
||||
detail::count_statically_named_args<Args...>()) {
|
||||
using checker =
|
||||
detail::format_string_checker<Char, remove_cvref_t<Args>...>;
|
||||
detail::parse_format_string<true>(str_, checker(s));
|
||||
detail::parse_format_string(str_, checker(str_));
|
||||
}
|
||||
#else
|
||||
# ifdef FMT_ENFORCE_COMPILE_STRING
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
// Reports a compile-time error if S is not a valid format string for Args.
|
||||
template <typename S,
|
||||
FMT_ENABLE_IF(
|
||||
std::is_convertible<const S&, basic_string_view<Char>>::value)>
|
||||
FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_format_string(const S& s) : str_(s) {
|
||||
check(s);
|
||||
#ifdef FMT_ENFORCE_COMPILE_STRING
|
||||
static_assert(
|
||||
detail::is_compile_string<S>::value,
|
||||
FMT_USE_CONSTEVAL && sizeof(S) != 0,
|
||||
"FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
|
||||
"FMT_STRING.");
|
||||
# endif
|
||||
detail::check_format_string<Args...>(s);
|
||||
#endif
|
||||
}
|
||||
template <typename S,
|
||||
FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&&
|
||||
std::is_constructible<basic_string_view<Char>,
|
||||
const S&>::value)>
|
||||
FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_format_string(const S& s) : str_(s) {
|
||||
check(s);
|
||||
if (FMT_USE_CONSTEVAL) return;
|
||||
FMT_CONSTEXPR auto v = basic_string_view<Char>(S());
|
||||
FMT_CONSTEXPR int ignore = (detail::parse_format_string(v, checker(v)), 0);
|
||||
detail::ignore_unused(ignore);
|
||||
}
|
||||
basic_format_string(runtime_format_string<Char> fmt) : str_(fmt.str) {}
|
||||
|
||||
FMT_ALWAYS_INLINE operator basic_string_view<Char>() const { return str_; }
|
||||
|
@ -36,7 +36,7 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
||||
* std::string s = fmt::format(FMT_COMPILE("{}"), 42);
|
||||
*/
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string, explicit)
|
||||
# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string)
|
||||
#else
|
||||
# define FMT_COMPILE(s) FMT_STRING(s)
|
||||
#endif
|
||||
|
@ -1869,7 +1869,7 @@ inline auto find_escape(const char* begin, const char* end)
|
||||
return result;
|
||||
}
|
||||
|
||||
#define FMT_STRING_IMPL(s, base, explicit) \
|
||||
#define FMT_STRING_IMPL(s, base) \
|
||||
[] { \
|
||||
/* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \
|
||||
/* Use a macro-like name to avoid shadowing warnings. */ \
|
||||
@ -1880,6 +1880,8 @@ inline auto find_escape(const char* begin, const char* end)
|
||||
return fmt::detail_exported::compile_string_to_view<char_type>(s); \
|
||||
} \
|
||||
}; \
|
||||
typename FMT_COMPILE_STRING::char_type FMT_CHAR = {}; \
|
||||
(void)FMT_CHAR; \
|
||||
return FMT_COMPILE_STRING(); \
|
||||
}()
|
||||
|
||||
@ -1891,7 +1893,7 @@ inline auto find_escape(const char* begin, const char* end)
|
||||
* // A compile-time error because 'd' is an invalid specifier for strings.
|
||||
* std::string s = fmt::format(FMT_STRING("{:d}"), "foo");
|
||||
*/
|
||||
#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, )
|
||||
#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string)
|
||||
|
||||
template <size_t width, typename Char, typename OutputIt>
|
||||
auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt {
|
||||
|
@ -34,7 +34,8 @@ struct format_string_char<
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
struct format_string_char<S, enable_if_t<is_compile_string<S>::value>> {
|
||||
struct format_string_char<
|
||||
S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> {
|
||||
using type = typename S::char_type;
|
||||
};
|
||||
|
||||
|
@ -2203,7 +2203,7 @@ TEST(format_test, vformat_to) {
|
||||
fmt::vformat_to(std::back_inserter(s), "{}", args);
|
||||
EXPECT_EQ(s, "42");
|
||||
s.clear();
|
||||
fmt::vformat_to(std::back_inserter(s), FMT_STRING("{}"), args);
|
||||
fmt::vformat_to(std::back_inserter(s), "{}", args);
|
||||
EXPECT_EQ(s, "42");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user