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