| 94 | for (size_t i = 1; i < width; ++i) { |
| 95 | if (!is_utf8_continuation(static_cast<unsigned char>(text[pos + i]))) { |
| 96 | throw std::runtime_error(std::string(label) + " contains invalid UTF-8 continuation byte"); |
| 97 | } |
| 98 | } |
| 99 | spans.push_back({pos, pos + width, text.substr(pos, width)}); |
| 100 | pos += width; |
| 101 | } |
| 102 | return spans; |
| 103 | } |
| 104 | |
| 105 | std::vector<WordRange> split_word_ranges(const std::vector<Utf8Span> & spans) { |
| 106 | std::vector<WordRange> words; |
| 107 | size_t span_pos = 0; |
| 108 | while (span_pos < spans.size()) { |
| 109 | while (span_pos < spans.size() && is_ascii_space(spans[span_pos].text)) { |
| 110 | ++span_pos; |
| 111 | } |
| 112 | if (span_pos >= spans.size()) { |
| 113 | break; |
| 114 | } |
| 115 | const size_t word_start = span_pos; |
| 116 | size_t word_end = span_pos + 1; |
| 117 | while (word_end < spans.size() && !is_ascii_space(spans[word_end].text)) { |
| 118 | ++word_end; |
| 119 | } |
| 120 | const auto last = spans[word_end - 1].text; |
| 121 | words.push_back({ |
| 122 | word_start, |
| 123 | word_end, |
| 124 | spans[word_start].start, |
| 125 | spans[word_end - 1].end, |
| 126 | is_sentence_break(last), |
no test coverage detected