| 396 | } |
| 397 | |
| 398 | uint32_t decode_utf8(std::string_view text, size_t& index) { |
| 399 | if (index >= text.size()) { |
| 400 | return 0; |
| 401 | } |
| 402 | |
| 403 | const unsigned char lead = static_cast<unsigned char>(text[index]); |
| 404 | if (lead < 0x80) { |
| 405 | ++index; |
| 406 | return lead; |
| 407 | } |
| 408 | |
| 409 | auto continuation = [&](size_t offset) -> unsigned char { |
| 410 | if (index + offset >= text.size()) { |
| 411 | return 0; |
| 412 | } |
| 413 | return static_cast<unsigned char>(text[index + offset]); |
| 414 | }; |
| 415 | |
| 416 | if ((lead & 0xE0) == 0xC0) { |
| 417 | const unsigned char b1 = continuation(1); |
| 418 | if ((b1 & 0xC0) == 0x80) { |
| 419 | index += 2; |
| 420 | return ((lead & 0x1F) << 6) | (b1 & 0x3F); |
| 421 | } |
| 422 | } else if ((lead & 0xF0) == 0xE0) { |
| 423 | const unsigned char b1 = continuation(1); |
| 424 | const unsigned char b2 = continuation(2); |
| 425 | if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80) { |
| 426 | index += 3; |
| 427 | return ((lead & 0x0F) << 12) | ((b1 & 0x3F) << 6) | (b2 & 0x3F); |
| 428 | } |
| 429 | } else if ((lead & 0xF8) == 0xF0) { |
| 430 | const unsigned char b1 = continuation(1); |
| 431 | const unsigned char b2 = continuation(2); |
| 432 | const unsigned char b3 = continuation(3); |
| 433 | if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80 && (b3 & 0xC0) == 0x80) { |
| 434 | index += 4; |
| 435 | return ((lead & 0x07) << 18) | ((b1 & 0x3F) << 12) | |
| 436 | ((b2 & 0x3F) << 6) | (b3 & 0x3F); |
| 437 | } |
| 438 | } |
| 439 | |
| 440 | ++index; |
| 441 | return lead; |
| 442 | } |
| 443 | |
| 444 | int utf16_units_between(std::string_view text, const size_t start, const size_t end) { |
| 445 | int units = 0; |
no test coverage detected