| 707 | } |
| 708 | |
| 709 | SZ_PUBLIC sz_size_t sz_utf8_count_ice(sz_cptr_t text, sz_size_t length) { |
| 710 | // UTF-8 character counting strategy: |
| 711 | // Count every byte that is NOT a continuation byte (i.e., character start bytes). |
| 712 | // |
| 713 | // UTF-8 byte patterns: |
| 714 | // ASCII: 0xxxxxxx (0x00-0x7F) - single byte character |
| 715 | // Start 2-byte: 110xxxxx (0xC0-0xDF) - first byte of 2-byte sequence |
| 716 | // Start 3-byte: 1110xxxx (0xE0-0xEF) - first byte of 3-byte sequence |
| 717 | // Start 4-byte: 11110xxx (0xF0-0xF7) - first byte of 4-byte sequence |
| 718 | // Continuation: 10xxxxxx (0x80-0xBF) - continuation byte (NOT a character start) |
| 719 | // |
| 720 | // To detect continuation bytes: (byte & 0xC0) == 0x80 |
| 721 | // 0xC0 = 11000000 - masks the top 2 bits |
| 722 | // 0x80 = 10000000 - pattern for continuation bytes after masking |
| 723 | |
| 724 | sz_u512_vec_t continuation_mask_vec, continuation_pattern_vec; |
| 725 | continuation_mask_vec.zmm = _mm512_set1_epi8((char)0xC0); // 0xC0 = 0b11000000 - mask top 2 bits |
| 726 | continuation_pattern_vec.zmm = _mm512_set1_epi8((char)0x80); // 0x80 = 0b10000000 - continuation pattern |
| 727 | |
| 728 | sz_u8_t const *text_u8 = (sz_u8_t const *)text; |
| 729 | sz_size_t char_count = 0; |
| 730 | |
| 731 | // Process 64 bytes at a time |
| 732 | sz_u512_vec_t text_vec, headers_vec; |
| 733 | while (length >= 64) { |
| 734 | text_vec.zmm = _mm512_loadu_epi8(text_u8); |
| 735 | |
| 736 | // Apply mask (byte & 0xC0) to extract top 2 bits of each byte |
| 737 | headers_vec.zmm = _mm512_and_si512(text_vec.zmm, continuation_mask_vec.zmm); |
| 738 | |
| 739 | // Compare with 0x80 (0b10000000) to find continuation bytes |
| 740 | sz_u64_t start_byte_mask = |
| 741 | _cvtmask64_u64(_mm512_cmpneq_epi8_mask(headers_vec.zmm, continuation_pattern_vec.zmm)); |
| 742 | |
| 743 | // Count non-continuation bytes (i.e., character starts) |
| 744 | char_count += _mm_popcnt_u64(start_byte_mask); |
| 745 | text_u8 += 64; |
| 746 | length -= 64; |
| 747 | } |
| 748 | |
| 749 | // Process remaining bytes with a masked variant |
| 750 | if (length) { |
| 751 | __mmask64 load_mask = sz_u64_mask_until_(length); |
| 752 | text_vec.zmm = _mm512_maskz_loadu_epi8(load_mask, text_u8); |
| 753 | headers_vec.zmm = _mm512_and_si512(text_vec.zmm, continuation_mask_vec.zmm); |
| 754 | __mmask64 start_byte_mask = |
| 755 | _mm512_mask_cmpneq_epi8_mask(load_mask, headers_vec.zmm, continuation_pattern_vec.zmm); |
| 756 | char_count += _mm_popcnt_u64(_cvtmask64_u64(start_byte_mask)); |
| 757 | } |
| 758 | return char_count; |
| 759 | } |
| 760 | |
| 761 | SZ_PUBLIC sz_cptr_t sz_utf8_find_nth_ice(sz_cptr_t text, sz_size_t length, sz_size_t n) { |
| 762 |
no test coverage detected
searching dependent graphs…