20 std::size_t byte_index)
noexcept {
21 const std::size_t limit = std::min(byte_index,
text.size());
23 std::size_t last_good = 0;
25 auto cont = [](
unsigned char b)
noexcept {
return (b & 0xC0) == 0x80; };
27 const auto b0 =
static_cast<unsigned char>(
text[i]);
31 }
else if (b0 >= 0xC2 && b0 <= 0xDF) {
33 }
else if (b0 >= 0xE0 && b0 <= 0xEF) {
35 }
else if (b0 >= 0xF0 && b0 <= 0xF4) {
41 if (i + len > limit)
break;
42 if (len >= 2 && !cont(
static_cast<unsigned char>(
text[i + 1])))
break;
43 if (len >= 3 && !cont(
static_cast<unsigned char>(
text[i + 2])))
break;
44 if (len >= 4 && !cont(
static_cast<unsigned char>(
text[i + 3])))
break;
46 const auto b1 =
static_cast<unsigned char>(
text[i + 1]);
47 if ((b0 == 0xE0 && b1 < 0xA0) || (b0 == 0xED && b1 >= 0xA0))
break;
48 }
else if (len == 4) {
49 const auto b1 =
static_cast<unsigned char>(
text[i + 1]);
50 if ((b0 == 0xF0 && b1 < 0x90) || (b0 == 0xF4 && b1 >= 0x90))
break;
69 std::size_t i)
noexcept {
70 if (i >=
text.size())
return {};
71 const auto b0 =
static_cast<unsigned char>(
text[i]);
72 if (b0 < 0x80u)
return {b0, 1};
74 if (b0 >= 0xC2u && b0 <= 0xDFu && i + 1 <
text.size()) {
75 const auto b1 =
static_cast<unsigned char>(
text[i + 1]);
77 return {
static_cast<std::uint32_t
>(((b0 & 0x1Fu) << 6) | (b1 & 0x3Fu)), 2};
80 if (b0 >= 0xE0u && b0 <= 0xEFu && i + 2 <
text.size()) {
81 const auto b1 =
static_cast<unsigned char>(
text[i + 1]);
82 const auto b2 =
static_cast<unsigned char>(
text[i + 2]);
83 const bool valid_prefix = (b0 != 0xE0u || b1 >= 0xA0u) && (b0 != 0xEDu || b1 < 0xA0u);
85 return {
static_cast<std::uint32_t
>(((b0 & 0x0Fu) << 12)
86 | ((b1 & 0x3Fu) << 6) | (b2 & 0x3Fu)), 3};
90 if (b0 >= 0xF0u && b0 <= 0xF4u && i + 3 <
text.size()) {
91 const auto b1 =
static_cast<unsigned char>(
text[i + 1]);
92 const auto b2 =
static_cast<unsigned char>(
text[i + 2]);
93 const auto b3 =
static_cast<unsigned char>(
text[i + 3]);
94 const bool valid_prefix = (b0 != 0xF0u || b1 >= 0x90u) && (b0 != 0xF4u || b1 < 0x90u);
96 return {
static_cast<std::uint32_t
>(((b0 & 0x07u) << 18)
97 | ((b1 & 0x3Fu) << 12) | ((b2 & 0x3Fu) << 6) | (b3 & 0x3Fu)), 4};
105 return cp >= 0x10000u ? 2u : 1u;
114 std::size_t utf16_offset)
noexcept {
115 std::size_t utf16_cursor = 0;
116 std::size_t byte_cursor = 0;
117 while (byte_cursor <
text.size()) {
118 if (utf16_cursor >= utf16_offset)
return byte_cursor;
121 if (utf16_offset < next_utf16)
return byte_cursor;
122 byte_cursor += std::max<std::size_t>(1, scalar.bytes);
123 utf16_cursor = next_utf16;
124 if (utf16_cursor == utf16_offset)
return byte_cursor;
132 std::size_t byte_offset)
noexcept {
134 std::size_t utf16_cursor = 0;
135 std::size_t byte_cursor = 0;
136 while (byte_cursor < byte_offset && byte_cursor <
text.size()) {
138 byte_cursor += std::max<std::size_t>(1, scalar.bytes);
147 std::size_t utf16_offset)
noexcept {
159 std::int64_t minimum_start = 0) noexcept {
160 if (start < minimum_start || start < 0 || length <= 0)
return false;
162 const auto unsigned_start =
static_cast<std::uint64_t
>(start);
163 const auto unsigned_length =
static_cast<std::uint64_t
>(length);
164 if (unsigned_length > units || unsigned_start > units - unsigned_length)
168 text,
static_cast<std::size_t
>(start + length));
std::size_t utf16_units_for_codepoint(std::uint32_t cp) noexcept
Definition text_utf8.hpp:104
Utf8ScalarForOffsets decode_utf8_scalar_for_offsets(const std::string &text, std::size_t i) noexcept
Definition text_utf8.hpp:68
bool utf8_continuation(unsigned char b) noexcept
Definition text_utf8.hpp:66
Definition affine_transform.hpp:24
std::size_t utf8_offset_for_utf16_offset(const std::string &text, std::size_t utf16_offset) noexcept
Convert a UTF-16 code-unit offset into the nearest safe UTF-8 byte offset.
Definition text_utf8.hpp:113
std::size_t safe_utf8_prefix_size(const std::string &text, std::size_t byte_index) noexcept
Return the largest prefix length <= byte_index that ends on a valid UTF-8 scalar boundary.
Definition text_utf8.hpp:19
bool is_valid_utf16_scalar_range(const std::string &text, std::int64_t start, std::int64_t length, std::int64_t minimum_start=0) noexcept
Validate one positive, non-overlapping UTF-16 range against UTF-8 text.
Definition text_utf8.hpp:156
bool is_utf16_scalar_boundary(const std::string &text, std::size_t utf16_offset) noexcept
True when a UTF-16 code-unit offset falls between Unicode scalars rather than between the two code un...
Definition text_utf8.hpp:146
std::size_t utf16_offset_for_utf8_offset(const std::string &text, std::size_t byte_offset) noexcept
Convert a UTF-8 byte offset into a UTF-16 code-unit offset.
Definition text_utf8.hpp:131
std::size_t cluster_step(const std::string &text, std::size_t byte_offset, bool forward=true)
Grapheme-aware cursor step for TextEditor.
@ text
Definition scene_node.hpp:96
Definition text_utf8.hpp:61
std::uint32_t codepoint
Definition text_utf8.hpp:62
std::size_t bytes
Definition text_utf8.hpp:63