// A test string containing one, two, three and four byte UTF-8 sequences. staticconst uint8_t kAllSequences[] = { 0x24, 0xc2, 0xa2, 0xe2, 0x82, 0xac, 0xf0, 0x9f, 0x8f, 0xa0, 0x00
};
// A test string that contains a UTF-8 encoding of a surrogate pair // (code point = U+10400). staticconst uint8_t kSurrogateEncoding[] = { 0xed, 0xa0, 0x81, 0xed, 0xb0, 0x80, 0x00
};
// Old versions of functions, here to compare answers with optimized versions.
size_t CountModifiedUtf8Chars_reference(constchar* utf8) {
size_t len = 0; int ic; while ((ic = *utf8++) != '\0') {
len++; if ((ic & 0x80) == 0) { // one-byte encoding continue;
} // two- or three-byte encoding
utf8++; if ((ic & 0x20) == 0) { // two-byte encoding continue;
}
utf8++; if ((ic & 0x10) == 0) { // three-byte encoding continue;
}
// four-byte encoding: needs to be converted into a surrogate // pair.
utf8++;
len++;
} return len;
}
static size_t CountModifiedUtf8BytesInUtf16_reference(const uint16_t* chars, size_t char_count) {
size_t result = 0; while (char_count--) { const uint16_t ch = *chars++; if (ch > 0 && ch <= 0x7f) {
++result;
} elseif (ch >= 0xd800 && ch <= 0xdbff) { if (char_count > 0) { const uint16_t ch2 = *chars; // If we find a properly paired surrogate, we emit it as a 4 byte // UTF sequence. If we find an unpaired leading or trailing surrogate, // we emit it as a 3 byte sequence like would have done earlier. if (ch2 >= 0xdc00 && ch2 <= 0xdfff) {
chars++;
char_count--;
result += 4;
} else {
result += 3;
}
} else { // This implies we found an unpaired trailing surrogate at the end // of a string.
result += 3;
}
} elseif (ch > 0x7ff) {
result += 3;
} else {
result += 2;
}
} return result;
}
staticvoid ConvertUtf16ToModifiedUtf8_reference(char* utf8_out, const uint16_t* utf16_in,
size_t char_count) { while (char_count--) { const uint16_t ch = *utf16_in++; if (ch > 0 && ch <= 0x7f) {
*utf8_out++ = ch;
} else { // Char_count == 0 here implies we've encountered an unpaired // surrogate and we have no choice but to encode it as 3-byte UTF // sequence. Note that unpaired surrogates can occur as a part of // "normal" operation. if ((ch >= 0xd800 && ch <= 0xdbff) && (char_count > 0)) { const uint16_t ch2 = *utf16_in;
// Check if the other half of the pair is within the expected // range. If it isn't, we will have to emit both "halves" as // separate 3 byte sequences. if (ch2 >= 0xdc00 && ch2 <= 0xdfff) {
utf16_in++;
char_count--; const uint32_t code_point = (ch << 10) + ch2 - 0x035fdc00;
*utf8_out++ = (code_point >> 18) | 0xf0;
*utf8_out++ = ((code_point >> 12) & 0x3f) | 0x80;
*utf8_out++ = ((code_point >> 6) & 0x3f) | 0x80;
*utf8_out++ = (code_point & 0x3f) | 0x80; continue;
}
}
// Calculate the number of utf-8 bytes for the utf-16 chars.
byte_count_reference = CountModifiedUtf8BytesInUtf16_reference(buf, char_count);
byte_count_test = CountModifiedUtf8BytesInUtf16(buf, char_count);
EXPECT_EQ(byte_count_reference, byte_count_test);
// Convert the utf-16 string to utf-8 bytes.
ConvertUtf16ToModifiedUtf8_reference(bytes_reference, buf, char_count);
ConvertUtf16ToModifiedUtf8(bytes_test, byte_count_test, buf, char_count); for (int i = 0; i < byte_count_test; ++i) {
EXPECT_EQ(bytes_reference[i], bytes_test[i]);
}
// Calculate the number of utf-16 chars from the utf-8 bytes.
bytes_reference[byte_count_reference] = 0; // Reference function needs null termination.
char_count_reference = CountModifiedUtf8Chars_reference(bytes_reference);
char_count_test = CountModifiedUtf8Chars(bytes_test, byte_count_test);
EXPECT_EQ(char_count, char_count_reference);
EXPECT_EQ(char_count, char_count_test);
// Convert the utf-8 bytes back to utf-16 chars. // Does not need copied _reference version of the function because the original // function with the old API is retained for debug/testing code.
ConvertModifiedUtf8ToUtf16(out_buf_reference, bytes_reference);
ConvertModifiedUtf8ToUtf16(out_buf_test, char_count_test, bytes_test, byte_count_test); for (int i = 0; i < char_count_test; ++i) {
EXPECT_EQ(buf[i], out_buf_reference[i]);
EXPECT_EQ(buf[i], out_buf_test[i]);
}
}
TEST_F(UtfTest, ExhaustiveBidirectionalCodePointCheck) { for (int codePoint = 0; codePoint <= 0x10ffff; ++codePoint) {
uint16_t buf[4] = { 0 }; if (codePoint <= 0xffff) { if (codePoint >= 0xd800 && codePoint <= 0xdfff) { // According to the Unicode standard, no character will ever // be assigned to these code points, and they cannot be encoded // into either utf-16 or utf-8. continue;
}
buf[0] = 'h';
buf[1] = codePoint;
buf[2] = 'e';
testConversions(buf, 2);
testConversions(buf, 3);
testConversions(buf + 1, 1);
testConversions(buf + 1, 2);
} else {
buf[0] = 'h';
codePointToSurrogatePair(codePoint, buf[1], buf[2]);
buf[3] = 'e';
testConversions(buf, 2);
testConversions(buf, 3);
testConversions(buf, 4);
testConversions(buf + 1, 1);
testConversions(buf + 1, 2);
testConversions(buf + 1, 3);
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.