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