Skip to content

Commit cad2af2

Browse files
adamsitnikjkotas
andauthored
Vectorize {Last}IndexOf{Any}{Except} without code duplication (#73768) (#74086)
Co-authored-by: Jan Kotas <[email protected]> Co-authored-by: Jan Kotas <[email protected]>
1 parent 02789c3 commit cad2af2

File tree

14 files changed

+2126
-2879
lines changed

14 files changed

+2126
-2879
lines changed

src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ internal static unsafe void ConvertFixedToNative(int flags, string strManaged, I
176176

177177
internal static unsafe string ConvertFixedToManaged(IntPtr cstr, int length)
178178
{
179-
int end = SpanHelpers.IndexOf(ref *(byte*)cstr, 0, length);
179+
int end = new ReadOnlySpan<byte>((byte*)cstr, length).IndexOf((byte)0);
180180
if (end >= 0)
181181
{
182182
length = end;
@@ -450,7 +450,7 @@ internal static unsafe void ConvertToNative(string? strManaged, IntPtr nativeHom
450450

451451
internal static unsafe string ConvertToManaged(IntPtr nativeHome, int length)
452452
{
453-
int end = SpanHelpers.IndexOf(ref *(char*)nativeHome, '\0', length);
453+
int end = new ReadOnlySpan<char>((char*)nativeHome, length).IndexOf('\0');
454454
if (end >= 0)
455455
{
456456
length = end;

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ internal static unsafe void StringToByValAnsiString(string str, byte* pNative, i
5555

5656
public static unsafe string ByValAnsiStringToString(byte* buffer, int length)
5757
{
58-
int end = SpanHelpers.IndexOf(ref *(byte*)buffer, 0, length);
59-
if (end != -1)
58+
int end = new ReadOnlySpan<byte>(buffer, length).IndexOf((byte)0);
59+
if (end >= 0)
6060
{
6161
length = end;
6262
}
@@ -77,8 +77,8 @@ internal static unsafe void StringToUnicodeFixedArray(string str, ushort* buffer
7777

7878
internal static unsafe string UnicodeToStringFixedArray(ushort* buffer, int length)
7979
{
80-
int end = SpanHelpers.IndexOf(ref *(char*)buffer, '\0', length);
81-
if (end != -1)
80+
int end = new ReadOnlySpan<char>(buffer, length).IndexOf('\0');
81+
if (end >= 0)
8282
{
8383
length = end;
8484
}

src/libraries/System.Memory/tests/Span/IndexOf.T.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,5 +192,60 @@ public static void IndexOfNull_String(string[] spanInput, int expected)
192192
Span<string> theStrings = spanInput;
193193
Assert.Equal(expected, theStrings.IndexOf((string)null));
194194
}
195+
196+
[Fact]
197+
public static void NotBitwiseEquatableUsesCustomIEquatableImplementationForActualComparison()
198+
{
199+
const byte Ten = 10, NotTen = 11;
200+
for (int length = 1; length < 100; length++)
201+
{
202+
TwoBytes[] array = new TwoBytes[length];
203+
for (int i = 0; i < length; i++)
204+
{
205+
array[i] = new TwoBytes(Ten, (byte)i);
206+
}
207+
208+
Span<TwoBytes> span = new Span<TwoBytes>(array);
209+
ReadOnlySpan<TwoBytes> ros = new ReadOnlySpan<TwoBytes>(array);
210+
211+
ReadOnlySpan<TwoBytes> noMatch2 = new TwoBytes[2] { new TwoBytes(10, NotTen), new TwoBytes(10, NotTen) };
212+
Assert.Equal(-1, span.IndexOfAny(noMatch2));
213+
Assert.Equal(-1, ros.IndexOfAny(noMatch2));
214+
Assert.Equal(-1, span.LastIndexOfAny(noMatch2));
215+
Assert.Equal(-1, ros.LastIndexOfAny(noMatch2));
216+
217+
ReadOnlySpan<TwoBytes> noMatch3 = new TwoBytes[3] { new TwoBytes(10, NotTen), new TwoBytes(10, NotTen), new TwoBytes(10, NotTen) };
218+
Assert.Equal(-1, span.IndexOfAny(noMatch3));
219+
Assert.Equal(-1, ros.IndexOfAny(noMatch3));
220+
Assert.Equal(-1, span.LastIndexOfAny(noMatch3));
221+
Assert.Equal(-1, ros.LastIndexOfAny(noMatch3));
222+
223+
ReadOnlySpan<TwoBytes> match2 = new TwoBytes[2] { new TwoBytes(0, Ten), new TwoBytes(0, Ten) };
224+
Assert.Equal(0, span.IndexOfAny(match2));
225+
Assert.Equal(0, ros.IndexOfAny(match2));
226+
Assert.Equal(0, span.LastIndexOfAny(match2));
227+
Assert.Equal(0, ros.LastIndexOfAny(match2));
228+
229+
ReadOnlySpan<TwoBytes> match3 = new TwoBytes[3] { new TwoBytes(0, Ten), new TwoBytes(0, Ten), new TwoBytes(0, Ten) };
230+
Assert.Equal(0, span.IndexOfAny(match3));
231+
Assert.Equal(0, ros.IndexOfAny(match3));
232+
Assert.Equal(0, span.LastIndexOfAny(match3));
233+
Assert.Equal(0, ros.LastIndexOfAny(match3));
234+
}
235+
}
236+
237+
private readonly struct TwoBytes : IEquatable<TwoBytes>
238+
{
239+
private readonly byte _first, _second;
240+
241+
public TwoBytes(byte first, byte second)
242+
{
243+
_first = first;
244+
_second = second;
245+
}
246+
247+
// it compares different fields on purpose
248+
public bool Equals(TwoBytes other) => _first == other._second && _second == other._first;
249+
}
195250
}
196251
}

src/libraries/System.Private.CoreLib/src/System/Array.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,17 +1328,17 @@ public static int IndexOf<T>(T[] array, T value, int startIndex, int count)
13281328
{
13291329
if (Unsafe.SizeOf<T>() == sizeof(byte))
13301330
{
1331-
int result = SpanHelpers.IndexOf(
1331+
int result = SpanHelpers.IndexOfValueType(
13321332
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As<byte[]>(array)), startIndex),
13331333
Unsafe.As<T, byte>(ref value),
13341334
count);
13351335
return (result >= 0 ? startIndex : 0) + result;
13361336
}
1337-
else if (Unsafe.SizeOf<T>() == sizeof(char))
1337+
else if (Unsafe.SizeOf<T>() == sizeof(short))
13381338
{
1339-
int result = SpanHelpers.IndexOf(
1340-
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As<char[]>(array)), startIndex),
1341-
Unsafe.As<T, char>(ref value),
1339+
int result = SpanHelpers.IndexOfValueType(
1340+
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As<short[]>(array)), startIndex),
1341+
Unsafe.As<T, short>(ref value),
13421342
count);
13431343
return (result >= 0 ? startIndex : 0) + result;
13441344
}
@@ -1586,27 +1586,27 @@ public static int LastIndexOf<T>(T[] array, T value, int startIndex, int count)
15861586
if (Unsafe.SizeOf<T>() == sizeof(byte))
15871587
{
15881588
int endIndex = startIndex - count + 1;
1589-
int result = SpanHelpers.LastIndexOf(
1589+
int result = SpanHelpers.LastIndexOfValueType(
15901590
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As<byte[]>(array)), endIndex),
15911591
Unsafe.As<T, byte>(ref value),
15921592
count);
15931593

15941594
return (result >= 0 ? endIndex : 0) + result;
15951595
}
1596-
else if (Unsafe.SizeOf<T>() == sizeof(char))
1596+
else if (Unsafe.SizeOf<T>() == sizeof(short))
15971597
{
15981598
int endIndex = startIndex - count + 1;
1599-
int result = SpanHelpers.LastIndexOf(
1600-
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As<char[]>(array)), endIndex),
1601-
Unsafe.As<T, char>(ref value),
1599+
int result = SpanHelpers.LastIndexOfValueType(
1600+
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As<short[]>(array)), endIndex),
1601+
Unsafe.As<T, short>(ref value),
16021602
count);
16031603

16041604
return (result >= 0 ? endIndex : 0) + result;
16051605
}
16061606
else if (Unsafe.SizeOf<T>() == sizeof(int))
16071607
{
16081608
int endIndex = startIndex - count + 1;
1609-
int result = SpanHelpers.LastIndexOf(
1609+
int result = SpanHelpers.LastIndexOfValueType(
16101610
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As<int[]>(array)), endIndex),
16111611
Unsafe.As<T, int>(ref value),
16121612
count);
@@ -1616,7 +1616,7 @@ ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As<int[]>(array)),
16161616
else if (Unsafe.SizeOf<T>() == sizeof(long))
16171617
{
16181618
int endIndex = startIndex - count + 1;
1619-
int result = SpanHelpers.LastIndexOf(
1619+
int result = SpanHelpers.LastIndexOfValueType(
16201620
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As<long[]>(array)), endIndex),
16211621
Unsafe.As<T, long>(ref value),
16221622
count);

src/libraries/System.Private.CoreLib/src/System/Enum.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ private static int FindDefinedIndex(ulong[] ulValues, ulong ulValue)
436436
int ulValuesLength = ulValues.Length;
437437
ref ulong start = ref MemoryMarshal.GetArrayDataReference(ulValues);
438438
return ulValuesLength <= NumberOfValuesThreshold ?
439-
SpanHelpers.IndexOf(ref start, ulValue, ulValuesLength) :
439+
SpanHelpers.IndexOfValueType(ref Unsafe.As<ulong, long>(ref start), (long)ulValue, ulValuesLength) :
440440
SpanHelpers.BinarySearch(ref start, ulValuesLength, ulValue);
441441
}
442442

src/libraries/System.Private.CoreLib/src/System/Globalization/Ordinal.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ internal static int IndexOfOrdinalIgnoreCase(ReadOnlySpan<char> source, ReadOnly
264264
{
265265
// Do a quick search for the first element of "value".
266266
int relativeIndex = isLetter ?
267-
SpanHelpers.IndexOfAny(ref Unsafe.Add(ref searchSpace, offset), valueCharU, valueCharL, searchSpaceLength) :
268-
SpanHelpers.IndexOf(ref Unsafe.Add(ref searchSpace, offset), valueChar, searchSpaceLength);
267+
SpanHelpers.IndexOfAnyChar(ref Unsafe.Add(ref searchSpace, offset), valueCharU, valueCharL, searchSpaceLength) :
268+
SpanHelpers.IndexOfChar(ref Unsafe.Add(ref searchSpace, offset), valueChar, searchSpaceLength);
269269
if (relativeIndex < 0)
270270
{
271271
break;

0 commit comments

Comments
 (0)