@@ -43,64 +43,22 @@ private void InitSort(CultureInfo culture)
4343            } 
4444        } 
4545
46-         internal  static unsafe  int  IndexOfOrdinalCore ( string  source ,  string  value ,  int  startIndex ,  int  count ,  bool  ignoreCase ) 
47-         { 
48-             Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
49- 
50-             Debug . Assert ( source  !=  null ) ; 
51-             Debug . Assert ( value  !=  null ) ; 
52- 
53-             if  ( value . Length  ==  0 ) 
54-             { 
55-                 return  startIndex ; 
56-             } 
57- 
58-             if  ( count  <  value . Length ) 
59-             { 
60-                 return  - 1 ; 
61-             } 
62- 
63-             if  ( ignoreCase ) 
64-             { 
65-                 fixed ( char *  pSource  =  source ) 
66-                 { 
67-                     int  index  =  Interop . Globalization . IndexOfOrdinalIgnoreCase ( value ,  value . Length ,  pSource  +  startIndex ,  count ,  findLast :  false ) ; 
68-                     return  index  !=  - 1  ? 
69-                         startIndex  +  index  : 
70-                         - 1 ; 
71-                 } 
72-             } 
73- 
74-             int  endIndex  =  startIndex  +  ( count  -  value . Length ) ; 
75-             for  ( int  i  =  startIndex ;  i  <=  endIndex ;  i ++ ) 
76-             { 
77-                 int  valueIndex ,  sourceIndex ; 
78- 
79-                 for  ( valueIndex  =  0 ,  sourceIndex  =  i ; 
80-                      valueIndex  <  value . Length  &&  source [ sourceIndex ]  ==  value [ valueIndex ] ; 
81-                      valueIndex ++ ,  sourceIndex ++ )  ; 
82- 
83-                 if  ( valueIndex  ==  value . Length ) 
84-                 { 
85-                     return  i ; 
86-                 } 
87-             } 
88- 
89-             return  - 1 ; 
90-         } 
91- 
9246        internal  static unsafe  int  IndexOfOrdinalCore ( ReadOnlySpan < char >  source ,  ReadOnlySpan < char >  value ,  bool  ignoreCase ,  bool  fromBeginning ) 
9347        { 
9448            Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
49+             Debug . Assert ( ! value . IsEmpty ) ; 
9550
96-             Debug . Assert ( source . Length  !=  0 ) ; 
97-             Debug . Assert ( value . Length  !=  0 ) ; 
51+             // Ordinal (non-linguistic) comparisons require the length of the target string to be no greater 
52+             // than the length of the search space. Since our caller already checked for empty target strings, 
53+             // the below check also handles the case of empty search space strings. 
9854
9955            if  ( source . Length  <  value . Length ) 
10056            { 
10157                return  - 1 ; 
10258            } 
10359
60+             Debug . Assert ( ! source . IsEmpty ) ; 
61+ 
10462            if  ( ignoreCase ) 
10563            { 
10664                fixed ( char *  pSource  =  & MemoryMarshal . GetReference ( source ) ) 
@@ -199,9 +157,14 @@ private static unsafe int CompareStringOrdinalIgnoreCase(ref char string1, int c
199157        { 
200158            Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
201159
160+             Debug . Assert ( count1  >  0 ) ; 
161+             Debug . Assert ( count2  >  0 ) ; 
162+ 
202163            fixed ( char *  char1  =  & string1 ) 
203164            fixed ( char *  char2  =  & string2 ) 
204165            { 
166+                 Debug . Assert ( char1  !=  null ) ; 
167+                 Debug . Assert ( char2  !=  null ) ; 
205168                return  Interop . Globalization . CompareStringOrdinalIgnoreCase ( char1 ,  count1 ,  char2 ,  count2 ) ; 
206169            } 
207170        } 
@@ -215,6 +178,9 @@ private unsafe int CompareString(ReadOnlySpan<char> string1, string string2, Com
215178            Debug . Assert ( string2  !=  null ) ; 
216179            Debug . Assert ( ( options  &  ( CompareOptions . Ordinal  |  CompareOptions . OrdinalIgnoreCase ) )  ==  0 ) ; 
217180
181+             // Unlike NLS, ICU (ucol_getSortKey) allows passing nullptr for either of the source arguments 
182+             // as long as the corresponding length parameter is 0. 
183+ 
218184            fixed ( char *  pString1  =  & MemoryMarshal . GetReference ( string1 ) ) 
219185            fixed ( char *  pString2  =  & string2 . GetRawStringData ( ) ) 
220186            { 
@@ -227,6 +193,9 @@ private unsafe int CompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char>
227193            Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
228194            Debug . Assert ( ( options  &  ( CompareOptions . Ordinal  |  CompareOptions . OrdinalIgnoreCase ) )  ==  0 ) ; 
229195
196+             // Unlike NLS, ICU (ucol_getSortKey) allows passing nullptr for either of the source arguments 
197+             // as long as the corresponding length parameter is 0. 
198+ 
230199            fixed ( char *  pString1  =  & MemoryMarshal . GetReference ( string1 ) ) 
231200            fixed ( char *  pString2  =  & MemoryMarshal . GetReference ( string2 ) ) 
232201            { 
@@ -540,7 +509,6 @@ private unsafe bool StartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> pre
540509        { 
541510            Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
542511
543-             Debug . Assert ( ! source . IsEmpty ) ; 
544512            Debug . Assert ( ! prefix . IsEmpty ) ; 
545513            Debug . Assert ( ( options  &  ( CompareOptions . Ordinal  |  CompareOptions . OrdinalIgnoreCase ) )  ==  0 ) ; 
546514
@@ -553,7 +521,7 @@ private unsafe bool StartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> pre
553521            } 
554522            else 
555523            { 
556-                 fixed ( char *  pSource  =  & MemoryMarshal . GetReference ( source ) ) 
524+                 fixed ( char *  pSource  =  & MemoryMarshal . GetReference ( source ) )   // could be null (or otherwise unable to be dereferenced) 
557525                fixed ( char *  pPrefix  =  & MemoryMarshal . GetReference ( prefix ) ) 
558526                { 
559527                    return  Interop . Globalization . StartsWith ( _sortHandle ,  pPrefix ,  prefix . Length ,  pSource ,  source . Length ,  options ) ; 
@@ -565,13 +533,12 @@ private unsafe bool StartsWithOrdinalIgnoreCaseHelper(ReadOnlySpan<char> source,
565533        { 
566534            Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
567535
568-             Debug . Assert ( ! source . IsEmpty ) ; 
569536            Debug . Assert ( ! prefix . IsEmpty ) ; 
570537            Debug . Assert ( _isAsciiEqualityOrdinal ) ; 
571538
572539            int  length  =  Math . Min ( source . Length ,  prefix . Length ) ; 
573540
574-             fixed ( char *  ap  =  & MemoryMarshal . GetReference ( source ) ) 
541+             fixed ( char *  ap  =  & MemoryMarshal . GetReference ( source ) )   // could be null (or otherwise unable to be dereferenced) 
575542            fixed ( char *  bp  =  & MemoryMarshal . GetReference ( prefix ) ) 
576543            { 
577544                char *  a  =  ap ; 
@@ -636,13 +603,12 @@ private unsafe bool StartsWithOrdinalHelper(ReadOnlySpan<char> source, ReadOnlyS
636603        { 
637604            Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
638605
639-             Debug . Assert ( ! source . IsEmpty ) ; 
640606            Debug . Assert ( ! prefix . IsEmpty ) ; 
641607            Debug . Assert ( _isAsciiEqualityOrdinal ) ; 
642608
643609            int  length  =  Math . Min ( source . Length ,  prefix . Length ) ; 
644610
645-             fixed ( char *  ap  =  & MemoryMarshal . GetReference ( source ) ) 
611+             fixed ( char *  ap  =  & MemoryMarshal . GetReference ( source ) )   // could be null (or otherwise unable to be dereferenced) 
646612            fixed ( char *  bp  =  & MemoryMarshal . GetReference ( prefix ) ) 
647613            { 
648614                char *  a  =  ap ; 
@@ -696,7 +662,6 @@ private unsafe bool EndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffi
696662        { 
697663            Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
698664
699-             Debug . Assert ( ! source . IsEmpty ) ; 
700665            Debug . Assert ( ! suffix . IsEmpty ) ; 
701666            Debug . Assert ( ( options  &  ( CompareOptions . Ordinal  |  CompareOptions . OrdinalIgnoreCase ) )  ==  0 ) ; 
702667
@@ -709,7 +674,7 @@ private unsafe bool EndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffi
709674            } 
710675            else 
711676            { 
712-                 fixed ( char *  pSource  =  & MemoryMarshal . GetReference ( source ) ) 
677+                 fixed ( char *  pSource  =  & MemoryMarshal . GetReference ( source ) )   // could be null (or otherwise unable to be dereferenced) 
713678                fixed ( char *  pSuffix  =  & MemoryMarshal . GetReference ( suffix ) ) 
714679                { 
715680                    return  Interop . Globalization . EndsWith ( _sortHandle ,  pSuffix ,  suffix . Length ,  pSource ,  source . Length ,  options ) ; 
@@ -721,13 +686,12 @@ private unsafe bool EndsWithOrdinalIgnoreCaseHelper(ReadOnlySpan<char> source, R
721686        { 
722687            Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
723688
724-             Debug . Assert ( ! source . IsEmpty ) ; 
725689            Debug . Assert ( ! suffix . IsEmpty ) ; 
726690            Debug . Assert ( _isAsciiEqualityOrdinal ) ; 
727691
728692            int  length  =  Math . Min ( source . Length ,  suffix . Length ) ; 
729693
730-             fixed ( char *  ap  =  & MemoryMarshal . GetReference ( source ) ) 
694+             fixed ( char *  ap  =  & MemoryMarshal . GetReference ( source ) )   // could be null (or otherwise unable to be dereferenced) 
731695            fixed ( char *  bp  =  & MemoryMarshal . GetReference ( suffix ) ) 
732696            { 
733697                char *  a  =  ap  +  source . Length  -  1 ; 
@@ -773,13 +737,12 @@ private unsafe bool EndsWithOrdinalHelper(ReadOnlySpan<char> source, ReadOnlySpa
773737        { 
774738            Debug . Assert ( ! GlobalizationMode . Invariant ) ; 
775739
776-             Debug . Assert ( ! source . IsEmpty ) ; 
777740            Debug . Assert ( ! suffix . IsEmpty ) ; 
778741            Debug . Assert ( _isAsciiEqualityOrdinal ) ; 
779742
780743            int  length  =  Math . Min ( source . Length ,  suffix . Length ) ; 
781744
782-             fixed ( char *  ap  =  & MemoryMarshal . GetReference ( source ) ) 
745+             fixed ( char *  ap  =  & MemoryMarshal . GetReference ( source ) )   // could be null (or otherwise unable to be dereferenced) 
783746            fixed ( char *  bp  =  & MemoryMarshal . GetReference ( suffix ) ) 
784747            { 
785748                char *  a  =  ap  +  source . Length  -  1 ; 
@@ -836,7 +799,7 @@ private unsafe SortKey CreateSortKey(string source, CompareOptions options)
836799                } 
837800            } 
838801
839-             return  new  SortKey ( Name ,  source ,  options ,  keyData ) ; 
802+             return  new  SortKey ( this ,  source ,  options ,  keyData ) ; 
840803        } 
841804
842805        private  static unsafe  bool  IsSortable ( char  * text ,  int  length ) 
0 commit comments