@@ -16,6 +16,7 @@ The wrapper template function below automatically converts all arguments (includ | |||
__attribute__((format(printf, 1, 2))) | |||
std::string f(const char* format, ...); | |||
std::string fV(const char* format, va_list args); | |||
// Converts std::string arguments of f() to `const char*` | |||
template<typename T> | |||
T convertFArg(const T& t) {return t;} | |||
@@ -101,14 +102,30 @@ std::string UTF32toUTF8(const std::u32string& s32); | |||
Skips invalid, overlong, and surrogate pair UTF-8 sequences. | |||
*/ | |||
std::u32string UTF8toUTF32(const std::string& s8); | |||
/** Finds the byte index of the next codepoint in a valid UTF-8 string. | |||
i must be the start of a codepoint. | |||
/** Finds the byte position of the next codepoint in a valid UTF-8 string. | |||
pos is the byte position of the start of a codepoint. | |||
Returns s8.size() if given codepoint is the last. | |||
*/ | |||
size_t UTF8NextCodepoint(const std::string& s8, size_t pos); | |||
/** Finds the byte position of the previous codepoint in a valid UTF-8 string. | |||
pos is the byte position of the start of a codepoint. | |||
Returns 0 if given codepoint is the first. | |||
*/ | |||
size_t UTF8PrevCodepoint(const std::string& s8, size_t pos); | |||
/** Returns the number of codepoints in a valid UTF-8 string. | |||
O(len) time | |||
*/ | |||
size_t UTF8Length(const std::string& s8); | |||
/** Returns a codepoint's index in a valid UTF-8 string. | |||
pos is the byte position of the start of a codepoint. | |||
O(pos) time | |||
*/ | |||
size_t UTF8NextCodepoint(const std::string& s8, size_t i); | |||
/** Finds the byte index of the previous codepoint in a valid UTF-8 string. | |||
i must be the start of a codepoint. | |||
size_t UTF8CodepointIndex(const std::string& s8, size_t pos); | |||
/** Returns a codepoint's byte position in a valid UTF-8 string. | |||
Returns s8.size() if index is beyond the last codepoint. | |||
O(index) time | |||
*/ | |||
size_t UTF8PrevCodepoint(const std::string& s8, size_t i); | |||
size_t UTF8CodepointPos(const std::string& s8, size_t index); | |||
#if defined ARCH_WIN | |||
/** Performs a Unicode string conversion from UTF-16 to UTF-8. | |||
@@ -421,38 +421,74 @@ static size_t UTF8CodepointSize(char c) { | |||
} | |||
size_t UTF8NextCodepoint(const std::string& s8, size_t i) { | |||
size_t UTF8NextCodepoint(const std::string& s8, size_t pos) { | |||
// Check out of bounds | |||
if (i >= s8.size()) | |||
if (pos >= s8.size()) | |||
return s8.size(); | |||
size_t size = UTF8CodepointSize(s8[i]); | |||
size_t size = UTF8CodepointSize(s8[pos]); | |||
// Check for continuation byte 0b10xxxxxx | |||
// if ((s8[1] & 0xc0) != 0x80) return 0; | |||
// if ((s8[2] & 0xc0) != 0x80) return 0; | |||
// if ((s8[3] & 0xc0) != 0x80) return 0; | |||
return std::min(i + size, s8.size()); | |||
return std::min(pos + size, s8.size()); | |||
} | |||
/** Finds the byte index of the front of a codepoint by reversing until a non-continuation byte is found. */ | |||
static size_t UTF8StartCodepoint(const std::string& s8, size_t i) { | |||
static size_t UTF8StartCodepoint(const std::string& s8, size_t pos) { | |||
// Check out of bounds | |||
if (i >= s8.size()) | |||
if (pos >= s8.size()) | |||
return s8.size(); | |||
while (i > 0) { | |||
while (pos > 0) { | |||
// Check for continuation byte 0b10xxxxxx | |||
if ((s8[i] & 0xc0) != 0x80) | |||
if ((s8[pos] & 0xc0) != 0x80) | |||
break; | |||
i--; | |||
pos--; | |||
} | |||
return i; | |||
return pos; | |||
} | |||
size_t UTF8PrevCodepoint(const std::string& s8, size_t i) { | |||
if (i == 0) | |||
size_t UTF8PrevCodepoint(const std::string& s8, size_t pos) { | |||
if (pos == 0) | |||
return 0; | |||
return UTF8StartCodepoint(s8, i - 1); | |||
return UTF8StartCodepoint(s8, pos - 1); | |||
} | |||
size_t UTF8Length(const std::string& s8) { | |||
return UTF8CodepointIndex(s8, s8.size()); | |||
} | |||
size_t UTF8CodepointIndex(const std::string& s8, size_t endPos) { | |||
size_t pos = 0; | |||
size_t index = 0; | |||
endPos = std::min(endPos, s8.size()); | |||
while (pos < endPos) { | |||
size_t newPos = UTF8NextCodepoint(s8, pos); | |||
// Check if codepoint is invalid | |||
if (pos == newPos) | |||
return index; | |||
pos = newPos; | |||
index++; | |||
} | |||
return index; | |||
} | |||
size_t UTF8CodepointPos(const std::string& s8, size_t endIndex) { | |||
size_t pos = 0; | |||
size_t index = 0; | |||
while (index < endIndex && pos < s8.size()) { | |||
size_t newPos = UTF8NextCodepoint(s8, pos); | |||
// Check if codepoint is invalid | |||
if (pos == newPos) | |||
return pos; | |||
pos = newPos; | |||
index++; | |||
} | |||
return pos; | |||
} | |||