Source: https://github.com/skeeto/branchless-utf8 Should switch this to a SIMD implementation later, possibly: https://dirtyhandscoding.github.io/posts/utf8lut-vectorized-utf-8-converter-decoding-utf-8.html
| 10 | // Should switch this to a SIMD implementation later, possibly: |
| 11 | // https://dirtyhandscoding.github.io/posts/utf8lut-vectorized-utf-8-converter-decoding-utf-8.html |
| 12 | char32_t utf8_decode_fast(const char *utf8_str, const char **out_next_char) { |
| 13 | static const uint32_t lengths[] = { |
| 14 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 15 | 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 |
| 16 | }; |
| 17 | static const int32_t masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; |
| 18 | static const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; |
| 19 | static const int32_t shiftc[] = {0, 18, 12, 6, 0}; |
| 20 | static const int32_t shifte[] = {0, 6, 4, 2, 0}; |
| 21 | |
| 22 | const unsigned char *s = (unsigned char *)utf8_str; |
| 23 | int32_t len = lengths[s[0] >> 3]; |
| 24 | |
| 25 | // Compute the pointer to the next character early so that the next |
| 26 | // iteration can start working on the next character. Neither Clang |
| 27 | // nor GCC figure out this reordering on their own. |
| 28 | const unsigned char *next = s + len + !len; |
| 29 | |
| 30 | // Assume a four-byte character and load four bytes. Unused bits are |
| 31 | // shifted out. |
| 32 | char32_t result = (char32_t)(s[0] & masks[len]) << 18; |
| 33 | result |= (char32_t)(s[1] & 0x3f) << 12; |
| 34 | result |= (char32_t)(s[2] & 0x3f) << 6; |
| 35 | result |= (char32_t)(s[3] & 0x3f) << 0; |
| 36 | result >>= shiftc[len]; |
| 37 | |
| 38 | *out_next_char = (const char *)next; |
| 39 | return result; |
| 40 | } |
| 41 | |
| 42 | /////////////////////////////////////////// |
| 43 |
no outgoing calls
no test coverage detected