MCPcopy Create free account
hub / github.com/fmtlib/fmt / utf8_decode

Function utf8_decode

include/fmt/format.h:579–614  ·  view source on GitHub ↗

A public domain branchless UTF-8 decoder by Christopher Wellons: https://github.com/skeeto/branchless-utf8 Decode the next character, c, from s, reporting errors in e. * * Since this is a branchless decoder, four bytes will be read from the * buffer regardless of the actual length of the next character. This * means the buffer _must_ have at least three bytes of zero padding * following the e

Source from the content-addressed store, hash-verified

577 * error, but it will always advance at least one byte.
578 */
579FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e)
580 -> const char* {
581 constexpr int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
582 constexpr uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
583 constexpr int shiftc[] = {0, 18, 12, 6, 0};
584 constexpr int shifte[] = {0, 6, 4, 2, 0};
585
586 int len = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4"
587 [static_cast<unsigned char>(*s) >> 3];
588 // Compute the pointer to the next character early so that the next
589 // iteration can start working on the next character. Neither Clang
590 // nor GCC figure out this reordering on their own.
591 const char* next = s + len + !len;
592
593 using uchar = unsigned char;
594
595 // Assume a four-byte character and load four bytes. Unused bits are
596 // shifted out.
597 *c = uint32_t(uchar(s[0]) & masks[len]) << 18;
598 *c |= uint32_t(uchar(s[1]) & 0x3f) << 12;
599 *c |= uint32_t(uchar(s[2]) & 0x3f) << 6;
600 *c |= uint32_t(uchar(s[3]) & 0x3f) << 0;
601 *c >>= shiftc[len];
602
603 // Accumulate the various error conditions.
604 *e = (*c < mins[len]) << 6; // non-canonical encoding
605 *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half?
606 *e |= (*c > 0x10FFFF) << 8; // out of range?
607 *e |= (uchar(s[1]) & 0xc0) >> 2;
608 *e |= (uchar(s[2]) & 0xc0) >> 4;
609 *e |= uchar(s[3]) >> 6;
610 *e ^= 0x2a; // top two bits of each tail byte correct?
611 *e >>= shifte[len];
612
613 return next;
614}
615
616constexpr FMT_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t();
617

Callers 2

TESTFunction · 0.85
for_each_codepointFunction · 0.85

Calls

no outgoing calls

Tested by 1

TESTFunction · 0.68