1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Diagnostics;
6 
7 namespace System.Globalization
8 {
9     public partial class CompareInfo
10     {
InitSort(CultureInfo culture)11         private void InitSort(CultureInfo culture)
12         {
13             _sortName = culture.SortName;
14         }
15 
IndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)16         internal static unsafe int IndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
17         {
18             fixed (char* pSource = source) fixed (char* pValue = value)
19             {
20                 char* pSrc = &pSource[startIndex];
21                 int index = FindStringOrdinal(pSrc, count, pValue, value.Length, FindStringOptions.Start, ignoreCase);
22                 if (index >= 0)
23                 {
24                     return index + startIndex;
25                 }
26                 return -1;
27             }
28         }
29 
LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)30         internal static unsafe int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
31         {
32             fixed (char* pSource = source) fixed (char* pValue = value)
33             {
34                 char* pSrc = &pSource[startIndex - count + 1];
35                 int index = FindStringOrdinal(pSrc, count, pValue, value.Length, FindStringOptions.End, ignoreCase);
36                 if (index >= 0)
37                 {
38                     return index + startIndex - (count - 1);
39                 }
40                 return -1;
41             }
42         }
43 
StartsWith(string source, string prefix, CompareOptions options)44         private unsafe bool StartsWith(string source, string prefix, CompareOptions options)
45         {
46             fixed (char* pSource = source) fixed (char* pValue = prefix)
47             {
48                 return FindStringOrdinal(pSource, source.Length, pValue, prefix.Length, FindStringOptions.StartsWith,
49                                          (options & CompareOptions.IgnoreCase) != 0) >= 0;
50             }
51         }
52 
EndsWith(string source, string suffix, CompareOptions options)53         private unsafe bool EndsWith(string source, string suffix, CompareOptions options)
54         {
55             fixed (char* pSource = source) fixed (char* pValue = suffix)
56             {
57                 return FindStringOrdinal(pSource, source.Length, pValue, suffix.Length, FindStringOptions.EndsWith,
58                                          (options & CompareOptions.IgnoreCase) != 0) >= 0;
59             }
60         }
61 
IndexOfCore(string source, string value, int startIndex, int count, CompareOptions options, int *matchLengthPtr)62         private unsafe int IndexOfCore(string source, string value, int startIndex, int count, CompareOptions options, int *matchLengthPtr)
63         {
64             int index = IndexOfOrdinal(source, value, startIndex, count, (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0);
65             if  ((index != -1) && (matchLengthPtr != null))
66                 *matchLengthPtr = value.Length;
67 
68             return index;
69         }
70 
LastIndexOfCore(string source, string value, int startIndex, int count, CompareOptions options)71         private unsafe int LastIndexOfCore(string source, string value, int startIndex, int count, CompareOptions options)
72         {
73             return LastIndexOfOrdinal(source, value, startIndex, count, (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0);
74         }
75 
GetHashCodeOfStringCore(string source, CompareOptions options)76         private unsafe int GetHashCodeOfStringCore(string source, CompareOptions options)
77         {
78             bool ignoreCase = (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0;
79 
80             if (ignoreCase)
81             {
82                 return source.ToUpper().GetHashCode();
83             }
84 
85             return source.GetHashCode();
86         }
87 
CompareString(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options)88         private unsafe int CompareString(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options)
89         {
90             fixed (char* pStr1 = string1) fixed (char* pStr2 = string2)
91             {
92                 char* pString1 = &pStr1[offset1];
93                 char* pString2 = &pStr2[offset2];
94 
95                 return CompareString(pString1, length1, pString2, length2, options);
96             }
97         }
98 
CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2)99         private static unsafe int CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2)
100         {
101             return CompareString(string1, count1, string2, count2, 0);
102         }
103 
CompareString(char* pString1, int length1, char* pString2, int length2, CompareOptions options)104         private static unsafe int CompareString(char* pString1, int length1, char* pString2, int length2, CompareOptions options)
105         {
106             bool ignoreCase = (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0;
107             int index = 0;
108 
109             if (ignoreCase)
110             {
111                 while (index < length1 &&
112                         index < length2 &&
113                         ToUpper(pString1[index]) == ToUpper(pString2[index]))
114                 {
115                     index++;
116                 }
117             }
118             else
119             {
120                 while (index < length1 &&
121                         index < length2 &&
122                         pString1[index] == pString2[index])
123                 {
124                     index++;
125                 }
126             }
127 
128             if (index >= length1)
129             {
130                 if (index >= length2)
131                 {
132                     return 0;
133                 }
134                 return -1;
135             }
136 
137             if (index >= length2)
138             {
139                 return 1;
140             }
141 
142             return ignoreCase ? ToUpper(pString1[index]) - ToUpper(pString2[index]) : pString1[index] - pString2[index];
143         }
144 
145 
FindStringOrdinal(char* source, int sourceCount, char* value, int valueCount, FindStringOptions option, bool ignoreCase)146         private static unsafe int FindStringOrdinal(char* source, int sourceCount, char* value, int valueCount, FindStringOptions option, bool ignoreCase)
147         {
148             int ctrSource = 0;  // index value into source
149             int ctrValue = 0;   // index value into value
150             char sourceChar;    // Character for case lookup in source
151             char valueChar;     // Character for case lookup in value
152             int lastSourceStart;
153 
154             Debug.Assert(source != null);
155             Debug.Assert(value != null);
156             Debug.Assert(sourceCount >= 0);
157             Debug.Assert(valueCount >= 0);
158 
159             if (valueCount == 0)
160             {
161                 switch (option)
162                 {
163                     case FindStringOptions.StartsWith:
164                     case FindStringOptions.Start:
165                         return (0);
166 
167                     case FindStringOptions.EndsWith:
168                     case FindStringOptions.End:
169                         return (sourceCount);
170 
171                     default:
172                         return -1;
173                 }
174             }
175 
176             if (sourceCount < valueCount)
177             {
178                 return -1;
179             }
180 
181             switch (option)
182             {
183                 case FindStringOptions.StartsWith:
184                     {
185                         if (ignoreCase)
186                         {
187                             for (ctrValue = 0; ctrValue < valueCount; ctrValue++)
188                             {
189                                 sourceChar = ToUpper(source[ctrValue]);
190                                 valueChar = ToUpper(value[ctrValue]);
191 
192                                 if (sourceChar != valueChar)
193                                 {
194                                     break;
195                                 }
196                             }
197                         }
198                         else
199                         {
200                             for (ctrValue = 0; ctrValue < valueCount; ctrValue++)
201                             {
202                                 sourceChar = source[ctrValue];
203                                 valueChar = value[ctrValue];
204 
205                                 if (sourceChar != valueChar)
206                                 {
207                                     break;
208                                 }
209                             }
210                         }
211 
212                         if (ctrValue == valueCount)
213                         {
214                             return 0;
215                         }
216                     }
217                     break;
218 
219                 case FindStringOptions.Start:
220                     {
221                         lastSourceStart = sourceCount - valueCount;
222                         if (ignoreCase)
223                         {
224                             char firstValueChar = ToUpper(value[0]);
225                             for (ctrSource = 0; ctrSource <= lastSourceStart; ctrSource++)
226                             {
227                                 sourceChar = ToUpper(source[ctrSource]);
228                                 if (sourceChar != firstValueChar)
229                                 {
230                                     continue;
231                                 }
232 
233                                 for (ctrValue = 1; ctrValue < valueCount; ctrValue++)
234                                 {
235                                     sourceChar = ToUpper(source[ctrSource + ctrValue]);
236                                     valueChar = ToUpper(value[ctrValue]);
237 
238                                     if (sourceChar != valueChar)
239                                     {
240                                         break;
241                                     }
242                                 }
243 
244                                 if (ctrValue == valueCount)
245                                 {
246                                     return ctrSource;
247                                 }
248                             }
249                         }
250                         else
251                         {
252                             char firstValueChar = value[0];
253                             for (ctrSource = 0; ctrSource <= lastSourceStart; ctrSource++)
254                             {
255                                 sourceChar = source[ctrSource];
256                                 if (sourceChar != firstValueChar)
257                                 {
258                                     continue;
259                                 }
260 
261                                 for (ctrValue = 1; ctrValue < valueCount; ctrValue++)
262                                 {
263                                     sourceChar = source[ctrSource + ctrValue];
264                                     valueChar = value[ctrValue];
265 
266                                     if (sourceChar != valueChar)
267                                     {
268                                         break;
269                                     }
270                                 }
271 
272                                 if (ctrValue == valueCount)
273                                 {
274                                     return ctrSource;
275                                 }
276                             }
277                         }
278                     }
279                     break;
280 
281                 case FindStringOptions.EndsWith:
282                     {
283                         lastSourceStart = sourceCount - valueCount;
284                         if (ignoreCase)
285                         {
286                             for (ctrSource = lastSourceStart, ctrValue = 0; ctrValue < valueCount; ctrSource++, ctrValue++)
287                             {
288                                 sourceChar = ToUpper(source[ctrSource]);
289                                 valueChar = ToUpper(value[ctrValue]);
290 
291                                 if (sourceChar != valueChar)
292                                 {
293                                     break;
294                                 }
295                             }
296                         }
297                         else
298                         {
299                             for (ctrSource = lastSourceStart, ctrValue = 0; ctrValue < valueCount; ctrSource++, ctrValue++)
300                             {
301                                 sourceChar = source[ctrSource];
302                                 valueChar = value[ctrValue];
303 
304                                 if (sourceChar != valueChar)
305                                 {
306                                     break;
307                                 }
308                             }
309                         }
310 
311                         if (ctrValue == valueCount)
312                         {
313                             return sourceCount - valueCount;
314                         }
315                     }
316                     break;
317 
318                 case FindStringOptions.End:
319                     {
320                         lastSourceStart = sourceCount - valueCount;
321                         if (ignoreCase)
322                         {
323                             char firstValueChar = ToUpper(value[0]);
324                             for (ctrSource = lastSourceStart; ctrSource >= 0; ctrSource--)
325                             {
326                                 sourceChar = ToUpper(source[ctrSource]);
327                                 if (sourceChar != firstValueChar)
328                                 {
329                                     continue;
330                                 }
331                                 for (ctrValue = 1; ctrValue < valueCount; ctrValue++)
332                                 {
333                                     sourceChar = ToUpper(source[ctrSource + ctrValue]);
334                                     valueChar = ToUpper(value[ctrValue]);
335 
336                                     if (sourceChar != valueChar)
337                                     {
338                                         break;
339                                     }
340                                 }
341 
342                                 if (ctrValue == valueCount)
343                                 {
344                                     return ctrSource;
345                                 }
346                             }
347                         }
348                         else
349                         {
350                             char firstValueChar = value[0];
351                             for (ctrSource = lastSourceStart; ctrSource >= 0; ctrSource--)
352                             {
353                                 sourceChar = source[ctrSource];
354                                 if (sourceChar != firstValueChar)
355                                 {
356                                     continue;
357                                 }
358 
359                                 for (ctrValue = 1; ctrValue < valueCount; ctrValue++)
360                                 {
361                                     sourceChar = source[ctrSource + ctrValue];
362                                     valueChar = value[ctrValue];
363 
364                                     if (sourceChar != valueChar)
365                                     {
366                                         break;
367                                     }
368                                 }
369 
370                                 if (ctrValue == valueCount)
371                                 {
372                                     return ctrSource;
373                                 }
374                             }
375                         }
376                     }
377                     break;
378 
379                 default:
380                     return -1;
381             }
382 
383             return -1;
384         }
385 
ToUpper(char c)386         private static char ToUpper(char c)
387         {
388             return ('a' <= c && c <= 'z') ? (char)(c - 0x20) : c;
389         }
390 
391         private enum FindStringOptions
392         {
393             Start,
394             StartsWith,
395             End,
396             EndsWith,
397         }
398 
CreateSortKey(String source, CompareOptions options)399         private unsafe SortKey CreateSortKey(String source, CompareOptions options)
400         {
401             if (source == null) { throw new ArgumentNullException(nameof(source)); }
402 
403             if ((options & ValidSortkeyCtorMaskOffFlags) != 0)
404             {
405                 throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
406             }
407 
408             throw new NotImplementedException();
409         }
410 
IsSortable(char* text, int length)411         private static unsafe bool IsSortable(char* text, int length)
412         {
413             // CompareInfo c = CultureInfo.InvariantCulture.CompareInfo;
414             // return (InternalIsSortable(c.m_dataHandle, c.m_handleOrigin, c.m_sortName, text, text.Length));
415             throw new NotImplementedException();
416         }
417 
GetSortVersion()418         private SortVersion GetSortVersion()
419         {
420             throw new NotImplementedException();
421         }
422     }
423 }
424