| 14 | namespace { |
| 15 | |
| 16 | uint32_t next_utf8_codepoint(std::string_view text, size_t & offset) { |
| 17 | if (offset >= text.size()) { |
| 18 | throw std::runtime_error("VoxCPM2 tokenizer UTF-8 offset is out of range"); |
| 19 | } |
| 20 | const unsigned char first = static_cast<unsigned char>(text[offset]); |
| 21 | uint32_t codepoint = 0; |
| 22 | size_t len = 1; |
| 23 | if ((first & 0x80U) == 0) { |
| 24 | codepoint = first; |
| 25 | } else if ((first & 0xE0U) == 0xC0U) { |
| 26 | len = 2; |
| 27 | codepoint = first & 0x1FU; |
| 28 | } else if ((first & 0xF0U) == 0xE0U) { |
| 29 | len = 3; |
| 30 | codepoint = first & 0x0FU; |
| 31 | } else if ((first & 0xF8U) == 0xF0U) { |
| 32 | len = 4; |
| 33 | codepoint = first & 0x07U; |
| 34 | } else { |
| 35 | throw std::runtime_error("VoxCPM2 tokenizer encountered invalid UTF-8"); |
| 36 | } |
| 37 | if (offset + len > text.size()) { |
| 38 | throw std::runtime_error("VoxCPM2 tokenizer encountered truncated UTF-8"); |
| 39 | } |
| 40 | for (size_t i = 1; i < len; ++i) { |
| 41 | const unsigned char ch = static_cast<unsigned char>(text[offset + i]); |
| 42 | if ((ch & 0xC0U) != 0x80U) { |
| 43 | throw std::runtime_error("VoxCPM2 tokenizer encountered invalid UTF-8 continuation"); |
| 44 | } |
| 45 | codepoint = (codepoint << 6U) | (ch & 0x3FU); |
| 46 | } |
| 47 | offset += len; |
| 48 | return codepoint; |
| 49 | } |
| 50 | |
| 51 | std::vector<std::string> utf8_codepoints(std::string_view text) { |
| 52 | std::vector<std::string> out; |
no test coverage detected