mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-08 12:20:06 +00:00
Simplify parse_format_string
This commit is contained in:
parent
985c3399d1
commit
b310a0d48b
@ -2387,23 +2387,6 @@ FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
|
|||||||
return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 3) + 1;
|
return static_cast<int>((0x3a55000000000000ull >> (2 * (c >> 3))) & 3) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the result via the out param to workaround gcc bug 77539.
|
|
||||||
template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
|
|
||||||
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool {
|
|
||||||
for (out = first; out != last; ++out) {
|
|
||||||
if (*out == value) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline auto find<false, char>(const char* first, const char* last, char value,
|
|
||||||
const char*& out) -> bool {
|
|
||||||
out =
|
|
||||||
static_cast<const char*>(memchr(first, value, to_unsigned(last - first)));
|
|
||||||
return out != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses the range [begin, end) as an unsigned integer. This function assumes
|
// Parses the range [begin, end) as an unsigned integer. This function assumes
|
||||||
// that the range is non-empty and the first character is a digit.
|
// that the range is non-empty and the first character is a digit.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -2775,54 +2758,24 @@ FMT_CONSTEXPR FMT_INLINE auto parse_replacement_field(const Char* begin,
|
|||||||
return begin + 1;
|
return begin + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool IS_CONSTEXPR = true, typename Char, typename Handler>
|
template <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> fmt,
|
||||||
Handler&& handler) {
|
Handler&& handler) {
|
||||||
auto begin = format_str.data();
|
auto begin = fmt.data(), end = begin + fmt.size();
|
||||||
auto end = begin + format_str.size();
|
auto p = begin;
|
||||||
if (FMT_OPTIMIZE_SIZE || end - begin < 32) {
|
while (p != end) {
|
||||||
// Use a simple loop instead of memchr for small strings.
|
auto c = *p++;
|
||||||
const Char* p = begin;
|
if (c == '{') {
|
||||||
while (p != end) {
|
handler.on_text(begin, p - 1);
|
||||||
auto c = *p++;
|
begin = p = parse_replacement_field(p - 1, end, handler);
|
||||||
if (c == '{') {
|
} else if (c == '}') {
|
||||||
handler.on_text(begin, p - 1);
|
if (p == end || *p != '}')
|
||||||
begin = p = parse_replacement_field(p - 1, end, handler);
|
return handler.on_error("unmatched '}' in format string");
|
||||||
} else if (c == '}') {
|
handler.on_text(begin, p);
|
||||||
if (p == end || *p != '}')
|
begin = ++p;
|
||||||
return handler.on_error("unmatched '}' in format string");
|
|
||||||
handler.on_text(begin, p);
|
|
||||||
begin = ++p;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
handler.on_text(begin, end);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
struct writer {
|
|
||||||
FMT_CONSTEXPR void operator()(const Char* from, const Char* to) {
|
|
||||||
if (from == to) return;
|
|
||||||
for (;;) {
|
|
||||||
const Char* p = nullptr;
|
|
||||||
if (!find<IS_CONSTEXPR>(from, to, Char('}'), p))
|
|
||||||
return handler_.on_text(from, to);
|
|
||||||
++p;
|
|
||||||
if (p == to || *p != '}')
|
|
||||||
return handler_.on_error("unmatched '}' in format string");
|
|
||||||
handler_.on_text(from, p);
|
|
||||||
from = p + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Handler& handler_;
|
|
||||||
} write = {handler};
|
|
||||||
while (begin != end) {
|
|
||||||
// Doing two passes with memchr (one for '{' and another for '}') is up to
|
|
||||||
// 2.5x faster than the naive one-pass implementation on big format strings.
|
|
||||||
const Char* p = begin;
|
|
||||||
if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, Char('{'), p))
|
|
||||||
return write(begin, end);
|
|
||||||
write(begin, p);
|
|
||||||
begin = parse_replacement_field(p, end, handler);
|
|
||||||
}
|
}
|
||||||
|
handler.on_text(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks char specs and returns true iff the presentation type is char-like.
|
// Checks char specs and returns true iff the presentation type is char-like.
|
||||||
@ -2841,8 +2794,7 @@ FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool {
|
|||||||
|
|
||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769).
|
FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769).
|
||||||
FMT_CONSTEXPR auto parse_format_specs(parse_context<Char>& ctx)
|
FMT_CONSTEXPR auto invoke_parse(parse_context<Char>& ctx) -> const Char* {
|
||||||
-> decltype(ctx.begin()) {
|
|
||||||
using mapper = arg_mapper<buffered_context<Char>>;
|
using mapper = arg_mapper<buffered_context<Char>>;
|
||||||
using mapped_type = remove_cvref_t<decltype(mapper::map(std::declval<T&>()))>;
|
using mapped_type = remove_cvref_t<decltype(mapper::map(std::declval<T&>()))>;
|
||||||
#if defined(__cpp_if_constexpr)
|
#if defined(__cpp_if_constexpr)
|
||||||
@ -2863,7 +2815,7 @@ class format_string_checker {
|
|||||||
named_arg_info<Char> named_args_[NUM_NAMED_ARGS > 0 ? NUM_NAMED_ARGS : 1];
|
named_arg_info<Char> named_args_[NUM_NAMED_ARGS > 0 ? NUM_NAMED_ARGS : 1];
|
||||||
compile_parse_context<Char> context_;
|
compile_parse_context<Char> context_;
|
||||||
|
|
||||||
using parse_func = const Char* (*)(parse_context<Char>&);
|
using parse_func = auto (*)(parse_context<Char>&) -> const Char*;
|
||||||
parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1];
|
parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -2873,7 +2825,7 @@ class format_string_checker {
|
|||||||
: types_{mapped_type_constant<T, buffered_context<Char>>::value...},
|
: types_{mapped_type_constant<T, buffered_context<Char>>::value...},
|
||||||
named_args_{},
|
named_args_{},
|
||||||
context_(fmt, NUM_ARGS, types_),
|
context_(fmt, NUM_ARGS, types_),
|
||||||
parse_funcs_{&parse_format_specs<T, Char>...} {
|
parse_funcs_{&invoke_parse<T, Char>...} {
|
||||||
using ignore = int[];
|
using ignore = int[];
|
||||||
int arg_index = 0, named_arg_index = 0;
|
int arg_index = 0, named_arg_index = 0;
|
||||||
(void)ignore{0, (init_statically_named_arg<T>(named_args_, arg_index,
|
(void)ignore{0, (init_statically_named_arg<T>(named_args_, arg_index,
|
||||||
@ -3011,8 +2963,7 @@ template <typename Char, typename... Args> class basic_format_string {
|
|||||||
detail::count<(std::is_base_of<view, remove_reference_t<Args>>::value &&
|
detail::count<(std::is_base_of<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");
|
||||||
if (FMT_USE_CONSTEVAL)
|
if (FMT_USE_CONSTEVAL) parse_format_string<Char>(s, checker(s, arg_pack()));
|
||||||
parse_format_string<true, Char>(s, checker(s, arg_pack()));
|
|
||||||
#ifdef FMT_ENFORCE_COMPILE_STRING
|
#ifdef FMT_ENFORCE_COMPILE_STRING
|
||||||
static_assert(
|
static_assert(
|
||||||
FMT_USE_CONSTEVAL && sizeof(S) != 0,
|
FMT_USE_CONSTEVAL && sizeof(S) != 0,
|
||||||
|
@ -4229,7 +4229,7 @@ void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
|
|||||||
auto out = basic_appender<Char>(buf);
|
auto out = basic_appender<Char>(buf);
|
||||||
if (fmt.size() == 2 && equal2(fmt.data(), "{}"))
|
if (fmt.size() == 2 && equal2(fmt.data(), "{}"))
|
||||||
return args.get(0).visit(default_arg_formatter<Char>{out});
|
return args.get(0).visit(default_arg_formatter<Char>{out});
|
||||||
parse_format_string<false>(
|
parse_format_string(
|
||||||
fmt, format_handler<Char>{parse_context<Char>(fmt), {out, args, loc}});
|
fmt, format_handler<Char>{parse_context<Char>(fmt), {out, args, loc}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,23 @@ template <typename Char> class basic_printf_context {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
// Return the result via the out param to workaround gcc bug 77539.
|
||||||
|
template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
|
||||||
|
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool {
|
||||||
|
for (out = first; out != last; ++out) {
|
||||||
|
if (*out == value) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline auto find<false, char>(const char* first, const char* last, char value,
|
||||||
|
const char*& out) -> bool {
|
||||||
|
out =
|
||||||
|
static_cast<const char*>(memchr(first, value, to_unsigned(last - first)));
|
||||||
|
return out != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||||
// signed and unsigned integers.
|
// signed and unsigned integers.
|
||||||
template <bool IsSigned> struct int_checker {
|
template <bool IsSigned> struct int_checker {
|
||||||
|
@ -561,7 +561,7 @@ struct test_format_string_handler {
|
|||||||
|
|
||||||
template <size_t N> constexpr bool parse_string(const char (&s)[N]) {
|
template <size_t N> constexpr bool parse_string(const char (&s)[N]) {
|
||||||
auto h = test_format_string_handler();
|
auto h = test_format_string_handler();
|
||||||
fmt::detail::parse_format_string<true>(fmt::string_view(s, N - 1), h);
|
fmt::detail::parse_format_string(fmt::string_view(s, N - 1), h);
|
||||||
return !h.error;
|
return !h.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ struct scan_handler {
|
|||||||
|
|
||||||
void vscan(detail::scan_buffer& buf, string_view fmt, scan_args args) {
|
void vscan(detail::scan_buffer& buf, string_view fmt, scan_args args) {
|
||||||
auto h = detail::scan_handler(fmt, buf, args);
|
auto h = detail::scan_handler(fmt, buf, args);
|
||||||
detail::parse_format_string<false>(fmt, h);
|
detail::parse_format_string(fmt, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t I, typename... T, FMT_ENABLE_IF(I == sizeof...(T))>
|
template <size_t I, typename... T, FMT_ENABLE_IF(I == sizeof...(T))>
|
||||||
|
Loading…
Reference in New Issue
Block a user