Skip to content

Commit 9c63165

Browse files
committed
Optimized rune methods for length edge cases and ascii-only strings
1 parent f256061 commit 9c63165

File tree

1 file changed

+29
-16
lines changed

1 file changed

+29
-16
lines changed

src/FirebirdSql.Data.FirebirdClient/Common/Extensions.cs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,18 @@ public static Encoding GetANSIEncoding()
105105

106106
public static int CountRunes(this ReadOnlySpan<char> text)
107107
{
108-
var count = 0;
109-
var i = 0;
110-
while(i < text.Length)
108+
var length = text.Length;
109+
if(length == 0)
110+
return 0;
111+
112+
var i = text.IndexOfAnyInRange('\uD800', '\uDBFF');
113+
if(i < 0)
114+
return length;
115+
116+
var count = i;
117+
while(i < length)
111118
{
112-
if(char.IsHighSurrogate(text[i]) && i + 1 < text.Length && char.IsLowSurrogate(text[i + 1]))
119+
if(char.IsHighSurrogate(text[i]) && i + 1 < length && char.IsLowSurrogate(text[i + 1]))
113120
{
114121
i += 2;
115122
}
@@ -124,24 +131,30 @@ public static int CountRunes(this ReadOnlySpan<char> text)
124131

125132
public static ReadOnlySpan<char> TruncateStringToRuneCount(this ReadOnlySpan<char> text, int maxRuneCount)
126133
{
127-
var count = 0;
128-
var i = 0;
129-
while(i < text.Length && count < maxRuneCount)
134+
if(maxRuneCount <= 0 || text.IsEmpty)
135+
return ReadOnlySpan<char>.Empty;
136+
137+
var length = text.Length;
138+
if(maxRuneCount >= length)
139+
return text;
140+
141+
var prefix = text[..maxRuneCount];
142+
var i = prefix.IndexOfAnyInRange('\uD800', '\uDBFF');
143+
if(i < 0)
144+
return prefix;
145+
146+
var remaining = maxRuneCount - i;
147+
while(i < length && remaining > 0)
130148
{
131-
var nextI = i;
132-
if(char.IsHighSurrogate(text[i]) && i + 1 < text.Length && char.IsLowSurrogate(text[i + 1]))
149+
if(char.IsHighSurrogate(text[i]) && i + 1 < length && char.IsLowSurrogate(text[i + 1]))
133150
{
134-
nextI += 2;
151+
i += 2;
135152
}
136153
else
137154
{
138-
nextI++;
139-
}
140-
count++;
141-
if(count <= maxRuneCount)
142-
{
143-
i = nextI;
155+
i++;
144156
}
157+
remaining--;
145158
}
146159
return text[..i];
147160
}

0 commit comments

Comments
 (0)