@@ -13,12 +13,15 @@ public partial class CompareInfo
13
13
[ SecurityCritical ]
14
14
private readonly Interop . GlobalizationInterop . SafeSortHandle m_sortHandle ;
15
15
16
+ private readonly bool m_isAsciiEqualityOrdinal ;
17
+
16
18
[ SecuritySafeCritical ]
17
19
internal CompareInfo ( CultureInfo culture )
18
20
{
19
21
m_name = culture . m_name ;
20
22
m_sortName = culture . SortName ;
21
23
m_sortHandle = Interop . GlobalizationInterop . GetSortHandle ( System . Text . Encoding . UTF8 . GetBytes ( m_sortName ) ) ;
24
+ m_isAsciiEqualityOrdinal = ( m_sortName == "en-US" || m_sortName == "" ) ;
22
25
}
23
26
24
27
[ SecurityCritical ]
@@ -161,6 +164,11 @@ private unsafe int IndexOfCore(string source, string target, int startIndex, int
161
164
return IndexOfOrdinal ( source , target , startIndex , count , ignoreCase : false ) ;
162
165
}
163
166
167
+ if ( m_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions ( options ) && source . IsAscii ( ) && target . IsAscii ( ) )
168
+ {
169
+ return IndexOf ( source , target , startIndex , count , GetOrdinalCompareOptions ( options ) ) ;
170
+ }
171
+
164
172
fixed ( char * pSource = source )
165
173
{
166
174
int index = Interop . GlobalizationInterop . IndexOf ( m_sortHandle , target , target . Length , pSource + startIndex , count , options ) ;
@@ -180,12 +188,17 @@ private unsafe int LastIndexOfCore(string source, string target, int startIndex,
180
188
{
181
189
return startIndex ;
182
190
}
183
-
191
+
184
192
if ( options == CompareOptions . Ordinal )
185
193
{
186
194
return LastIndexOfOrdinal ( source , target , startIndex , count , ignoreCase : false ) ;
187
195
}
188
196
197
+ if ( m_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions ( options ) && source . IsAscii ( ) && target . IsAscii ( ) )
198
+ {
199
+ return LastIndexOf ( source , target , startIndex , count , GetOrdinalCompareOptions ( options ) ) ;
200
+ }
201
+
189
202
// startIndex is the index into source where we start search backwards from. leftStartIndex is the index into source
190
203
// of the start of the string that is count characters away from startIndex.
191
204
int leftStartIndex = ( startIndex - count + 1 ) ;
@@ -205,6 +218,11 @@ private bool StartsWith(string source, string prefix, CompareOptions options)
205
218
Contract . Assert ( ! string . IsNullOrEmpty ( prefix ) ) ;
206
219
Contract . Assert ( ( options & ( CompareOptions . Ordinal | CompareOptions . OrdinalIgnoreCase ) ) == 0 ) ;
207
220
221
+ if ( m_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions ( options ) && source . IsAscii ( ) && prefix . IsAscii ( ) )
222
+ {
223
+ return IsPrefix ( source , prefix , GetOrdinalCompareOptions ( options ) ) ;
224
+ }
225
+
208
226
return Interop . GlobalizationInterop . StartsWith ( m_sortHandle , prefix , prefix . Length , source , source . Length , options ) ;
209
227
}
210
228
@@ -215,6 +233,11 @@ private bool EndsWith(string source, string suffix, CompareOptions options)
215
233
Contract . Assert ( ! string . IsNullOrEmpty ( suffix ) ) ;
216
234
Contract . Assert ( ( options & ( CompareOptions . Ordinal | CompareOptions . OrdinalIgnoreCase ) ) == 0 ) ;
217
235
236
+ if ( m_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions ( options ) && source . IsAscii ( ) && suffix . IsAscii ( ) )
237
+ {
238
+ return IsSuffix ( source , suffix , GetOrdinalCompareOptions ( options ) ) ;
239
+ }
240
+
218
241
return Interop . GlobalizationInterop . EndsWith ( m_sortHandle , suffix , suffix . Length , source , source . Length , options ) ;
219
242
}
220
243
@@ -251,5 +274,23 @@ internal unsafe int GetHashCodeOfStringCore(string source, CompareOptions option
251
274
[ DllImport ( JitHelpers . QCall ) ]
252
275
[ SuppressUnmanagedCodeSecurity ]
253
276
private static unsafe extern int InternalHashSortKey ( byte * sortKey , int sortKeyLength , [ MarshalAs ( UnmanagedType . Bool ) ] bool forceRandomizedHashing , long additionalEntropy ) ;
277
+
278
+ private static CompareOptions GetOrdinalCompareOptions ( CompareOptions options )
279
+ {
280
+ if ( ( options & CompareOptions . IgnoreCase ) == CompareOptions . IgnoreCase )
281
+ {
282
+ return CompareOptions . OrdinalIgnoreCase ;
283
+ }
284
+ else
285
+ {
286
+ return CompareOptions . Ordinal ;
287
+ }
288
+ }
289
+
290
+ private static bool CanUseAsciiOrdinalForOptions ( CompareOptions options )
291
+ {
292
+ // Unlike the other Ignore options, IgnoreSymbols impacts ASCII characters (e.g. ').
293
+ return ( options & CompareOptions . IgnoreSymbols ) == 0 ;
294
+ }
254
295
}
255
296
}
0 commit comments