| 2521 | |
| 2522 | template <bool IS_CONSTEXPR, typename Char, typename Handler> |
| 2523 | FMT_CONSTEXPR FMT_INLINE void parse_format_string( |
| 2524 | basic_string_view<Char> format_str, Handler&& handler) { |
| 2525 | auto begin = format_str.data(); |
| 2526 | auto end = begin + format_str.size(); |
| 2527 | if (end - begin < 32) { |
| 2528 | // Use a simple loop instead of memchr for small strings. |
| 2529 | const Char* p = begin; |
| 2530 | while (p != end) { |
| 2531 | auto c = *p++; |
| 2532 | if (c == '{') { |
| 2533 | handler.on_text(begin, p - 1); |
| 2534 | begin = p = parse_replacement_field(p - 1, end, handler); |
| 2535 | } else if (c == '}') { |
| 2536 | if (p == end || *p != '}') |
| 2537 | return handler.on_error("unmatched '}' in format string"); |
| 2538 | handler.on_text(begin, p); |
| 2539 | begin = ++p; |
| 2540 | } |
| 2541 | } |
| 2542 | handler.on_text(begin, end); |
| 2543 | return; |
| 2544 | } |
| 2545 | struct writer { |
| 2546 | FMT_CONSTEXPR void operator()(const Char* from, const Char* to) { |
| 2547 | if (from == to) return; |
| 2548 | for (;;) { |
| 2549 | const Char* p = nullptr; |
| 2550 | if (!find<IS_CONSTEXPR>(from, to, Char('}'), p)) |
| 2551 | return handler_.on_text(from, to); |
| 2552 | ++p; |
| 2553 | if (p == to || *p != '}') |
| 2554 | return handler_.on_error("unmatched '}' in format string"); |
| 2555 | handler_.on_text(from, p); |
| 2556 | from = p + 1; |
| 2557 | } |
| 2558 | } |
| 2559 | Handler& handler_; |
| 2560 | } write = {handler}; |
| 2561 | while (begin != end) { |
| 2562 | // Doing two passes with memchr (one for '{' and another for '}') is up to |
| 2563 | // 2.5x faster than the naive one-pass implementation on big format strings. |
| 2564 | const Char* p = begin; |
| 2565 | if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, Char('{'), p)) |
| 2566 | return write(begin, end); |
| 2567 | write(begin, p); |
| 2568 | begin = parse_replacement_field(p, end, handler); |
| 2569 | } |
| 2570 | } |
| 2571 | |
| 2572 | template <typename T, bool = is_named_arg<T>::value> struct strip_named_arg { |
| 2573 | using type = T; |