| 2573 | |
| 2574 | template <bool IS_CONSTEXPR, typename Char, typename Handler> |
| 2575 | FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str, |
| 2576 | Handler&& handler) { |
| 2577 | struct pfs_writer { |
| 2578 | FMT_CONSTEXPR void operator()(const Char* begin, const Char* end) { |
| 2579 | if (begin == end) return; |
| 2580 | for (;;) { |
| 2581 | const Char* p = nullptr; |
| 2582 | if (!find<IS_CONSTEXPR>(begin, end, '}', p)) |
| 2583 | return handler_.on_text(begin, end); |
| 2584 | ++p; |
| 2585 | if (p == end || *p != '}') |
| 2586 | return handler_.on_error("unmatched '}' in format string"); |
| 2587 | handler_.on_text(begin, p); |
| 2588 | begin = p + 1; |
| 2589 | } |
| 2590 | } |
| 2591 | Handler& handler_; |
| 2592 | } write{handler}; |
| 2593 | auto begin = format_str.data(); |
| 2594 | auto end = begin + format_str.size(); |
| 2595 | while (begin != end) { |
| 2596 | // Doing two passes with memchr (one for '{' and another for '}') is up to |
| 2597 | // 2.5x faster than the naive one-pass implementation on big format strings. |
| 2598 | const Char* p = begin; |
| 2599 | if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p)) |
| 2600 | return write(begin, end); |
| 2601 | write(begin, p); |
| 2602 | ++p; |
| 2603 | if (p == end) return handler.on_error("invalid format string"); |
| 2604 | if (static_cast<char>(*p) == '}') { |
| 2605 | handler.on_arg_id(); |
| 2606 | handler.on_replacement_field(p); |
| 2607 | } else if (*p == '{') { |
| 2608 | handler.on_text(p, p + 1); |
| 2609 | } else { |
| 2610 | p = parse_arg_id(p, end, id_adapter<Handler, Char>{handler}); |
| 2611 | Char c = p != end ? *p : Char(); |
| 2612 | if (c == '}') { |
| 2613 | handler.on_replacement_field(p); |
| 2614 | } else if (c == ':') { |
| 2615 | p = handler.on_format_specs(p + 1, end); |
| 2616 | if (p == end || *p != '}') |
| 2617 | return handler.on_error("unknown format specifier"); |
| 2618 | } else { |
| 2619 | return handler.on_error("missing '}' in format string"); |
| 2620 | } |
| 2621 | } |
| 2622 | begin = p + 1; |
| 2623 | } |
| 2624 | } |
| 2625 | |
| 2626 | template <typename T, typename ParseContext> |
| 2627 | FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs( |
nothing calls this directly
no test coverage detected