Encapuslate UTF-8 decoder state in a struct

This commit is contained in:
Rangi
2026-07-03 19:35:23 -04:00
parent e3c594c250
commit 0996a2f5ed
5 changed files with 36 additions and 34 deletions
+16 -19
View File
@@ -279,18 +279,17 @@ static void errorInvalidUTF8Byte(uint8_t byte, char const *functionName) {
size_t act_StringLen(std::string const &str, bool printErrors) {
size_t len = 0;
uint32_t state = UTF8_ACCEPT;
uint32_t codepoint = 0;
Utf8Decoder decoder;
for (char c : str) {
uint8_t byte = static_cast<uint8_t>(c);
switch (decode(&state, &codepoint, byte)) {
switch (decoder.update(byte)) {
case UTF8_REJECT:
if (printErrors) {
errorInvalidUTF8Byte(byte, "STRLEN");
}
state = UTF8_ACCEPT;
decoder.state = UTF8_ACCEPT;
// fallthrough
case UTF8_ACCEPT:
++len;
@@ -299,7 +298,7 @@ size_t act_StringLen(std::string const &str, bool printErrors) {
}
// Check for partial code point.
if (state != UTF8_ACCEPT) {
if (decoder.state != UTF8_ACCEPT) {
if (printErrors) {
error("STRLEN: Incomplete UTF-8 character");
}
@@ -317,16 +316,15 @@ std::string
size_t strLen = str.length();
size_t index = 0;
uint32_t state = UTF8_ACCEPT;
uint32_t codepoint = 0;
Utf8Decoder decoder;
uint32_t curIdx = 0;
// Advance to starting index in source string.
while (index < strLen && curIdx < start) {
switch (decode(&state, &codepoint, str[index])) {
switch (decoder.update(str[index])) {
case UTF8_REJECT:
errorInvalidUTF8Byte(str[index], "STRSLICE");
state = UTF8_ACCEPT;
decoder.state = UTF8_ACCEPT;
// fallthrough
case UTF8_ACCEPT:
++curIdx;
@@ -349,10 +347,10 @@ std::string
// Advance to ending index in source string.
while (index < strLen && curIdx < stop) {
switch (decode(&state, &codepoint, str[index])) {
switch (decoder.update(str[index])) {
case UTF8_REJECT:
errorInvalidUTF8Byte(str[index], "STRSLICE");
state = UTF8_ACCEPT;
decoder.state = UTF8_ACCEPT;
// fallthrough
case UTF8_ACCEPT:
++curIdx;
@@ -362,7 +360,7 @@ std::string
}
// Check for partial code point.
if (state != UTF8_ACCEPT) {
if (decoder.state != UTF8_ACCEPT) {
error("STRSLICE: Incomplete UTF-8 character");
++curIdx;
}
@@ -387,16 +385,15 @@ std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<
size_t strLen = str.length();
size_t index = 0;
uint32_t state = UTF8_ACCEPT;
uint32_t codepoint = 0;
Utf8Decoder decoder;
uint32_t curPos = 1;
// Advance to starting position in source string.
while (index < strLen && curPos < pos) {
switch (decode(&state, &codepoint, str[index])) {
switch (decoder.update(str[index])) {
case UTF8_REJECT:
errorInvalidUTF8Byte(str[index], "STRSUB");
state = UTF8_ACCEPT;
decoder.state = UTF8_ACCEPT;
// fallthrough
case UTF8_ACCEPT:
++curPos;
@@ -418,10 +415,10 @@ std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<
// Compute the result length in bytes.
while (index < strLen && curLen < len) {
switch (decode(&state, &codepoint, str[index])) {
switch (decoder.update(str[index])) {
case UTF8_REJECT:
errorInvalidUTF8Byte(str[index], "STRSUB");
state = UTF8_ACCEPT;
decoder.state = UTF8_ACCEPT;
// fallthrough
case UTF8_ACCEPT:
++curLen;
@@ -431,7 +428,7 @@ std::string act_StringSub(std::string const &str, int32_t negPos, std::optional<
}
// Check for partial code point.
if (state != UTF8_ACCEPT) {
if (decoder.state != UTF8_ACCEPT) {
error("STRSUB: Incomplete UTF-8 character");
++curLen;
}
+3 -4
View File
@@ -273,15 +273,14 @@ size_t charmap_ConvertNext(std::string_view &input, std::vector<int32_t> *output
} else if (inputIdx < input.length()) { // No match found, but there is some input left
size_t codepointLen = 0;
// This will write the codepoint's value to `output`, little-endian
for (uint32_t state = UTF8_ACCEPT, codepoint = 0;
inputIdx + codepointLen < input.length();) {
if (decode(&state, &codepoint, input[inputIdx + codepointLen]) == UTF8_REJECT) {
for (Utf8Decoder decoder; inputIdx + codepointLen < input.length();) {
if (decoder.update(input[inputIdx + codepointLen]) == UTF8_REJECT) {
error("Input string is not valid UTF-8");
codepointLen = 1;
break;
}
++codepointLen;
if (state == UTF8_ACCEPT) {
if (decoder.state == UTF8_ACCEPT) {
break;
}
}