Add compile-time format string check
This commit is contained in:
parent
8ca6e76dbc
commit
780b44bf82
@ -3548,7 +3548,7 @@ struct id_adapter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Iterator, typename Handler>
|
template <typename Iterator, typename Handler>
|
||||||
constexpr void parse_format_string(Iterator it, Handler &handler) {
|
constexpr void parse_format_string(Iterator it, Handler &&handler) {
|
||||||
using char_type = typename std::iterator_traits<Iterator>::value_type;
|
using char_type = typename std::iterator_traits<Iterator>::value_type;
|
||||||
auto start = it;
|
auto start = it;
|
||||||
while (*it) {
|
while (*it) {
|
||||||
@ -3781,8 +3781,9 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
|
|||||||
basic_buffer<Char> &buffer;
|
basic_buffer<Char> &buffer;
|
||||||
basic_context<Char> context;
|
basic_context<Char> context;
|
||||||
basic_arg<Context> arg;
|
basic_arg<Context> arg;
|
||||||
} handler(buffer, format_str, args);
|
};
|
||||||
parse_format_string(iterator(format_str.begin(), format_str.end()), handler);
|
parse_format_string(iterator(format_str.begin(), format_str.end()),
|
||||||
|
handler(buffer, format_str, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Casts ``p`` to ``const void*`` for pointer formatting.
|
// Casts ``p`` to ``const void*`` for pointer formatting.
|
||||||
@ -3796,8 +3797,44 @@ inline const void *ptr(const T *p) { return p; }
|
|||||||
namespace fmt {
|
namespace fmt {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
# if FMT_UDL_TEMPLATE
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
struct udl_format {
|
struct udl_format_handler {
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
|
constexpr void on_text(const Char *, const Char *) {}
|
||||||
|
|
||||||
|
constexpr void on_arg_id() {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr void on_arg_id(T) {}
|
||||||
|
|
||||||
|
constexpr void on_replacement_field(const Char *) {}
|
||||||
|
|
||||||
|
constexpr const Char *on_format_specs(const Char *s) { return s; }
|
||||||
|
|
||||||
|
constexpr void on_error(const char *) { error = true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, Char... CHARS>
|
||||||
|
struct udl_formatter {
|
||||||
|
template <typename... Args>
|
||||||
|
static constexpr bool check_format(const Char *s) {
|
||||||
|
udl_format_handler<Char> handler;
|
||||||
|
internal::parse_format_string(s, handler);
|
||||||
|
return !handler.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::basic_string<Char> operator()(const Args &... args) const {
|
||||||
|
constexpr Char s[] = {CHARS..., '\0'};
|
||||||
|
static_assert(check_format<Args...>(s), "invalid format string");
|
||||||
|
return format(s, args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
# else
|
||||||
|
template <typename Char>
|
||||||
|
struct udl_formatter {
|
||||||
const Char *str;
|
const Char *str;
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
@ -3806,6 +3843,7 @@ struct udl_format {
|
|||||||
return format(str, std::forward<Args>(args)...);
|
return format(str, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
# endif // FMT_UDL_TEMPLATE
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
struct UdlArg {
|
struct UdlArg {
|
||||||
@ -3821,6 +3859,12 @@ struct UdlArg {
|
|||||||
|
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
|
|
||||||
|
# if FMT_UDL_TEMPLATE
|
||||||
|
template <typename Char, Char... CHARS>
|
||||||
|
constexpr internal::udl_formatter<Char, CHARS...> operator""_format() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
# else
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
C++11 literal equivalent of :func:`fmt::format`.
|
C++11 literal equivalent of :func:`fmt::format`.
|
||||||
@ -3831,10 +3875,11 @@ inline namespace literals {
|
|||||||
std::string message = "The answer is {}"_format(42);
|
std::string message = "The answer is {}"_format(42);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
inline internal::udl_format<char>
|
inline internal::udl_formatter<char>
|
||||||
operator"" _format(const char *s, std::size_t) { return {s}; }
|
operator"" _format(const char *s, std::size_t) { return {s}; }
|
||||||
inline internal::udl_format<wchar_t>
|
inline internal::udl_formatter<wchar_t>
|
||||||
operator"" _format(const wchar_t *s, std::size_t) { return {s}; }
|
operator"" _format(const wchar_t *s, std::size_t) { return {s}; }
|
||||||
|
# endif // FMT_UDL_TEMPLATE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -3850,23 +3895,6 @@ inline internal::UdlArg<char>
|
|||||||
operator"" _a(const char *s, std::size_t) { return {s}; }
|
operator"" _a(const char *s, std::size_t) { return {s}; }
|
||||||
inline internal::UdlArg<wchar_t>
|
inline internal::UdlArg<wchar_t>
|
||||||
operator"" _a(const wchar_t *s, std::size_t) { return {s}; }
|
operator"" _a(const wchar_t *s, std::size_t) { return {s}; }
|
||||||
|
|
||||||
# if FMT_UDL_TEMPLATE
|
|
||||||
template <typename Char, Char... CHARS>
|
|
||||||
struct udl_formatter {
|
|
||||||
template <typename... Args>
|
|
||||||
std::string operator()(const Args &... args) const {
|
|
||||||
const Char s[] = {CHARS...};
|
|
||||||
// TODO
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, Char... CHARS>
|
|
||||||
constexpr auto operator""_format() {
|
|
||||||
return udl_formatter<Char, CHARS...>();
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
} // inline namespace literals
|
} // inline namespace literals
|
||||||
} // namespace fmt
|
} // namespace fmt
|
||||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||||
|
Loading…
Reference in New Issue
Block a user