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.
5 using System
.Diagnostics
;
7 using Internal
.Runtime
.CompilerServices
;
12 internal static partial class SpanHelpers
// .T
14 public static int IndexOf
<T
>(ref T searchSpace
, int searchSpaceLength
, ref T
value, int valueLength
)
15 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
16 where T
: IEquatable
<T
>
19 Debug
.Assert(searchSpaceLength
>= 0);
20 Debug
.Assert(valueLength
>= 0);
23 return 0; // A zero-length sequence is always treated as "found" at the start of the search space.
26 ref T valueTail
= ref Unsafe
.Add(ref value, 1);
27 int valueTailLength
= valueLength
- 1;
32 Debug
.Assert(0 <= index
&& index
<= searchSpaceLength
); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength".
33 int remainingSearchSpaceLength
= searchSpaceLength
- index
- valueTailLength
;
34 if (remainingSearchSpaceLength
<= 0)
35 break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there.
37 // Do a quick search for the first element of "value".
38 int relativeIndex
= IndexOf(ref Unsafe
.Add(ref searchSpace
, index
), valueHead
, remainingSearchSpaceLength
);
39 if (relativeIndex
== -1)
41 index
+= relativeIndex
;
43 // Found the first element of "value". See if the tail matches.
44 if (SequenceEqual(ref Unsafe
.Add(ref searchSpace
, index
+ 1), ref valueTail
, valueTailLength
))
45 return index
; // The tail matched. Return a successful find.
52 // Adapted from IndexOf(...)
53 public static unsafe bool Contains
<T
>(ref T searchSpace
, T
value, int length
)
54 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
55 where T
: IEquatable
<T
>
58 Debug
.Assert(length
>= 0);
60 IntPtr index
= (IntPtr
)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
62 if (default(T
)! != null || (object)value != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
68 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 0)) ||
69 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 1)) ||
70 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 2)) ||
71 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 3)) ||
72 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 4)) ||
73 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 5)) ||
74 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 6)) ||
75 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 7)))
87 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 0)) ||
88 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 1)) ||
89 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 2)) ||
90 value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 3)))
102 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
)))
110 byte* len
= (byte*)length
;
111 for (index
= (IntPtr
)0; index
.ToPointer() < len
; index
+= 1)
113 if ((object)Unsafe
.Add(ref searchSpace
, index
) is null)
126 public static unsafe int IndexOf
<T
>(ref T searchSpace
, T
value, int length
)
127 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
128 where T
: IEquatable
<T
>
131 Debug
.Assert(length
>= 0);
133 IntPtr index
= (IntPtr
)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
134 if (default(T
)! != null || (object)value != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
140 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
)))
142 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 1)))
144 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 2)))
146 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 3)))
148 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 4)))
150 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 5)))
152 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 6)))
154 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 7)))
164 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
)))
166 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 1)))
168 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 2)))
170 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
+ 3)))
178 if (value.Equals(Unsafe
.Add(ref searchSpace
, index
)))
187 byte* len
= (byte*)length
;
188 for (index
= (IntPtr
)0; index
.ToPointer() < len
; index
+= 1)
190 if ((object)Unsafe
.Add(ref searchSpace
, index
) is null)
198 Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
199 return (int)(byte*)index
;
201 return (int)(byte*)(index
+ 1);
203 return (int)(byte*)(index
+ 2);
205 return (int)(byte*)(index
+ 3);
207 return (int)(byte*)(index
+ 4);
209 return (int)(byte*)(index
+ 5);
211 return (int)(byte*)(index
+ 6);
213 return (int)(byte*)(index
+ 7);
216 public static int IndexOfAny
<T
>(ref T searchSpace
, T value0
, T value1
, int length
)
217 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
218 where T
: IEquatable
<T
>
221 Debug
.Assert(length
>= 0);
225 if (default(T
)! != null || ((object)value0
!= null && (object)value1
!= null)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
227 while ((length
- index
) >= 8)
229 lookUp
= Unsafe
.Add(ref searchSpace
, index
);
230 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
232 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 1);
233 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
235 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 2);
236 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
238 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 3);
239 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
241 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 4);
242 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
244 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 5);
245 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
247 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 6);
248 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
250 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 7);
251 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
257 if ((length
- index
) >= 4)
259 lookUp
= Unsafe
.Add(ref searchSpace
, index
);
260 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
262 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 1);
263 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
265 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 2);
266 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
268 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 3);
269 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
275 while (index
< length
)
277 lookUp
= Unsafe
.Add(ref searchSpace
, index
);
278 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
286 for (index
= 0; index
< length
; index
++)
288 lookUp
= Unsafe
.Add(ref searchSpace
, index
);
289 if ((object?)lookUp
is null)
291 if ((object?)value0
is null || (object?)value1
is null)
296 else if (lookUp
.Equals(value0
) || lookUp
.Equals(value1
))
305 Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
323 public static int IndexOfAny
<T
>(ref T searchSpace
, T value0
, T value1
, T value2
, int length
)
324 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
325 where T
: IEquatable
<T
>
328 Debug
.Assert(length
>= 0);
332 if (default(T
)! != null || ((object)value0
!= null && (object)value1
!= null && (object)value2
!= null)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
334 while ((length
- index
) >= 8)
336 lookUp
= Unsafe
.Add(ref searchSpace
, index
);
337 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
339 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 1);
340 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
342 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 2);
343 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
345 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 3);
346 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
348 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 4);
349 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
351 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 5);
352 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
354 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 6);
355 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
357 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 7);
358 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
364 if ((length
- index
) >= 4)
366 lookUp
= Unsafe
.Add(ref searchSpace
, index
);
367 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
369 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 1);
370 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
372 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 2);
373 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
375 lookUp
= Unsafe
.Add(ref searchSpace
, index
+ 3);
376 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
382 while (index
< length
)
384 lookUp
= Unsafe
.Add(ref searchSpace
, index
);
385 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
393 for (index
= 0; index
< length
; index
++)
395 lookUp
= Unsafe
.Add(ref searchSpace
, index
);
396 if ((object?)lookUp
is null)
398 if ((object?)value0
is null || (object?)value1
is null || (object?)value2
is null)
403 else if (lookUp
.Equals(value0
) || lookUp
.Equals(value1
) || lookUp
.Equals(value2
))
411 Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
429 public static int IndexOfAny
<T
>(ref T searchSpace
, int searchSpaceLength
, ref T
value, int valueLength
)
430 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
431 where T
: IEquatable
<T
>
434 Debug
.Assert(searchSpaceLength
>= 0);
435 Debug
.Assert(valueLength
>= 0);
437 if (valueLength
== 0)
438 return -1; // A zero-length set of values is always treated as "not found".
441 for (int i
= 0; i
< valueLength
; i
++)
443 int tempIndex
= IndexOf(ref searchSpace
, Unsafe
.Add(ref value, i
), searchSpaceLength
);
444 if ((uint)tempIndex
< (uint)index
)
447 // Reduce space for search, cause we don't care if we find the search value after the index of a previously found value
448 searchSpaceLength
= tempIndex
;
457 public static int LastIndexOf
<T
>(ref T searchSpace
, int searchSpaceLength
, ref T
value, int valueLength
)
458 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
459 where T
: IEquatable
<T
>
462 Debug
.Assert(searchSpaceLength
>= 0);
463 Debug
.Assert(valueLength
>= 0);
465 if (valueLength
== 0)
466 return 0; // A zero-length sequence is always treated as "found" at the start of the search space.
469 ref T valueTail
= ref Unsafe
.Add(ref value, 1);
470 int valueTailLength
= valueLength
- 1;
475 Debug
.Assert(0 <= index
&& index
<= searchSpaceLength
); // Ensures no deceptive underflows in the computation of "remainingSearchSpaceLength".
476 int remainingSearchSpaceLength
= searchSpaceLength
- index
- valueTailLength
;
477 if (remainingSearchSpaceLength
<= 0)
478 break; // The unsearched portion is now shorter than the sequence we're looking for. So it can't be there.
480 // Do a quick search for the first element of "value".
481 int relativeIndex
= LastIndexOf(ref searchSpace
, valueHead
, remainingSearchSpaceLength
);
482 if (relativeIndex
== -1)
485 // Found the first element of "value". See if the tail matches.
486 if (SequenceEqual(ref Unsafe
.Add(ref searchSpace
, relativeIndex
+ 1), ref valueTail
, valueTailLength
))
487 return relativeIndex
; // The tail matched. Return a successful find.
489 index
+= remainingSearchSpaceLength
- relativeIndex
;
494 public static int LastIndexOf
<T
>(ref T searchSpace
, T
value, int length
)
495 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
496 where T
: IEquatable
<T
>
499 Debug
.Assert(length
>= 0);
501 if (default(T
)! != null || (object)value != null) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
507 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 7)))
509 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 6)))
511 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 5)))
513 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 4)))
515 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 3)))
517 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 2)))
519 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 1)))
521 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
)))
529 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 3)))
531 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 2)))
533 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
+ 1)))
535 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
)))
543 if (value.Equals(Unsafe
.Add(ref searchSpace
, length
)))
549 for (length
--; length
>= 0; length
--)
551 if ((object)Unsafe
.Add(ref searchSpace
, length
) is null)
560 Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
578 public static int LastIndexOfAny
<T
>(ref T searchSpace
, T value0
, T value1
, int length
)
579 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
580 where T
: IEquatable
<T
>
583 Debug
.Assert(length
>= 0);
586 if (default(T
)! != null || ((object)value0
!= null && (object)value1
!= null)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
592 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 7);
593 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
595 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 6);
596 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
598 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 5);
599 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
601 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 4);
602 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
604 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 3);
605 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
607 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 2);
608 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
610 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 1);
611 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
613 lookUp
= Unsafe
.Add(ref searchSpace
, length
);
614 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
622 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 3);
623 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
625 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 2);
626 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
628 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 1);
629 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
631 lookUp
= Unsafe
.Add(ref searchSpace
, length
);
632 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
640 lookUp
= Unsafe
.Add(ref searchSpace
, length
);
641 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
))
647 for (length
--; length
>= 0; length
--)
649 lookUp
= Unsafe
.Add(ref searchSpace
, length
);
650 if ((object?)lookUp
is null)
652 if ((object?)value0
is null || (object?)value1
is null)
657 else if (lookUp
.Equals(value0
) || lookUp
.Equals(value1
))
666 Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
684 public static int LastIndexOfAny
<T
>(ref T searchSpace
, T value0
, T value1
, T value2
, int length
)
685 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
686 where T
: IEquatable
<T
>
689 Debug
.Assert(length
>= 0);
692 if (default(T
)! != null || ((object)value0
!= null && (object)value1
!= null)) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
698 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 7);
699 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
701 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 6);
702 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
704 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 5);
705 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
707 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 4);
708 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
710 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 3);
711 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
713 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 2);
714 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
716 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 1);
717 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
719 lookUp
= Unsafe
.Add(ref searchSpace
, length
);
720 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
728 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 3);
729 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
731 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 2);
732 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
734 lookUp
= Unsafe
.Add(ref searchSpace
, length
+ 1);
735 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
737 lookUp
= Unsafe
.Add(ref searchSpace
, length
);
738 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
746 lookUp
= Unsafe
.Add(ref searchSpace
, length
);
747 if (value0
.Equals(lookUp
) || value1
.Equals(lookUp
) || value2
.Equals(lookUp
))
753 for (length
--; length
>= 0; length
--)
755 lookUp
= Unsafe
.Add(ref searchSpace
, length
);
756 if ((object?)lookUp
is null)
758 if ((object?)value0
is null || (object?)value1
is null || (object?)value2
is null)
763 else if (lookUp
.Equals(value0
) || lookUp
.Equals(value1
) || lookUp
.Equals(value2
))
772 Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
790 public static int LastIndexOfAny
<T
>(ref T searchSpace
, int searchSpaceLength
, ref T
value, int valueLength
)
791 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
792 where T
: IEquatable
<T
>
795 Debug
.Assert(searchSpaceLength
>= 0);
796 Debug
.Assert(valueLength
>= 0);
798 if (valueLength
== 0)
799 return -1; // A zero-length set of values is always treated as "not found".
802 for (int i
= 0; i
< valueLength
; i
++)
804 int tempIndex
= LastIndexOf(ref searchSpace
, Unsafe
.Add(ref value, i
), searchSpaceLength
);
805 if (tempIndex
> index
)
811 public static bool SequenceEqual
<T
>(ref T first
, ref T second
, int length
)
812 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
813 where T
: IEquatable
<T
>
816 Debug
.Assert(length
>= 0);
818 if (Unsafe
.AreSame(ref first
, ref second
))
821 IntPtr index
= (IntPtr
)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
828 lookUp0
= Unsafe
.Add(ref first
, index
);
829 lookUp1
= Unsafe
.Add(ref second
, index
);
830 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
832 lookUp0
= Unsafe
.Add(ref first
, index
+ 1);
833 lookUp1
= Unsafe
.Add(ref second
, index
+ 1);
834 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
836 lookUp0
= Unsafe
.Add(ref first
, index
+ 2);
837 lookUp1
= Unsafe
.Add(ref second
, index
+ 2);
838 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
840 lookUp0
= Unsafe
.Add(ref first
, index
+ 3);
841 lookUp1
= Unsafe
.Add(ref second
, index
+ 3);
842 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
844 lookUp0
= Unsafe
.Add(ref first
, index
+ 4);
845 lookUp1
= Unsafe
.Add(ref second
, index
+ 4);
846 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
848 lookUp0
= Unsafe
.Add(ref first
, index
+ 5);
849 lookUp1
= Unsafe
.Add(ref second
, index
+ 5);
850 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
852 lookUp0
= Unsafe
.Add(ref first
, index
+ 6);
853 lookUp1
= Unsafe
.Add(ref second
, index
+ 6);
854 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
856 lookUp0
= Unsafe
.Add(ref first
, index
+ 7);
857 lookUp1
= Unsafe
.Add(ref second
, index
+ 7);
858 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
868 lookUp0
= Unsafe
.Add(ref first
, index
);
869 lookUp1
= Unsafe
.Add(ref second
, index
);
870 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
872 lookUp0
= Unsafe
.Add(ref first
, index
+ 1);
873 lookUp1
= Unsafe
.Add(ref second
, index
+ 1);
874 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
876 lookUp0
= Unsafe
.Add(ref first
, index
+ 2);
877 lookUp1
= Unsafe
.Add(ref second
, index
+ 2);
878 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
880 lookUp0
= Unsafe
.Add(ref first
, index
+ 3);
881 lookUp1
= Unsafe
.Add(ref second
, index
+ 3);
882 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
890 lookUp0
= Unsafe
.Add(ref first
, index
);
891 lookUp1
= Unsafe
.Add(ref second
, index
);
892 if (!(lookUp0
?.Equals(lookUp1
) ?? (object?)lookUp1
is null))
901 NotEqual: // Workaround for https://github.com/dotnet/coreclr/issues/13549
905 public static int SequenceCompareTo
<T
>(ref T first
, int firstLength
, ref T second
, int secondLength
)
906 where T
: IComparable
<T
>
908 Debug
.Assert(firstLength
>= 0);
909 Debug
.Assert(secondLength
>= 0);
911 int minLength
= firstLength
;
912 if (minLength
> secondLength
)
913 minLength
= secondLength
;
914 for (int i
= 0; i
< minLength
; i
++)
916 T lookUp
= Unsafe
.Add(ref second
, i
);
917 int result
= (Unsafe
.Add(ref first
, i
)?.CompareTo(lookUp
) ?? (((object?)lookUp
is null) ? 0 : -1));
921 return firstLength
.CompareTo(secondLength
);