// Adapted from IndexOf(...)
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
- public static unsafe bool Contains(ref byte searchSpace, byte value, int length)
+ public static bool Contains(ref byte searchSpace, byte value, int length)
{
Debug.Assert(length >= 0);
uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr lengthToExamine = (IntPtr)length;
+ nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations
+ nuint lengthToExamine = (nuint)(uint)length;
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
}
SequentialScan:
- while ((byte*)lengthToExamine >= (byte*)8)
+ while (lengthToExamine >= 8)
{
lengthToExamine -= 8;
offset += 8;
}
- if ((byte*)lengthToExamine >= (byte*)4)
+ if (lengthToExamine >= 4)
{
lengthToExamine -= 4;
offset += 4;
}
- while ((byte*)lengthToExamine > (byte*)0)
+ while (lengthToExamine > 0)
{
lengthToExamine -= 1;
offset += 1;
}
- if (Vector.IsHardwareAccelerated && ((int)(byte*)offset < length))
+ if (Vector.IsHardwareAccelerated && (offset < (nuint)(uint)length))
{
- lengthToExamine = (IntPtr)((length - (int)(byte*)offset) & ~(Vector<byte>.Count - 1));
+ lengthToExamine = (((nuint)(uint)length - offset) & (nuint)~(Vector<byte>.Count - 1));
Vector<byte> values = new Vector<byte>(value);
- while ((byte*)lengthToExamine > (byte*)offset)
+ while (lengthToExamine > offset)
{
var matches = Vector.Equals(values, LoadVector(ref searchSpace, offset));
if (Vector<byte>.Zero.Equals(matches))
{
- offset += Vector<byte>.Count;
+ offset += (nuint)Vector<byte>.Count;
continue;
}
goto Found;
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
Debug.Assert(length >= 0);
uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr lengthToExamine = (IntPtr)length;
+ nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations
+ nuint lengthToExamine = (nuint)(uint)length;
if (Avx2.IsSupported || Sse2.IsSupported)
{
}
}
SequentialScan:
- while ((byte*)lengthToExamine >= (byte*)8)
+ while (lengthToExamine >= 8)
{
lengthToExamine -= 8;
offset += 8;
}
- if ((byte*)lengthToExamine >= (byte*)4)
+ if (lengthToExamine >= 4)
{
lengthToExamine -= 4;
offset += 4;
}
- while ((byte*)lengthToExamine > (byte*)0)
+ while (lengthToExamine > 0)
{
lengthToExamine -= 1;
// have hardware accelerated. After processing Vector lengths we return to SequentialScan to finish any remaining.
if (Avx2.IsSupported)
{
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- if ((((nuint)Unsafe.AsPointer(ref searchSpace) + (nuint)offset) & (nuint)(Vector256<byte>.Count - 1)) != 0)
+ if ((((nuint)(uint)Unsafe.AsPointer(ref searchSpace) + offset) & (nuint)(Vector256<byte>.Count - 1)) != 0)
{
// Not currently aligned to Vector256 (is aligned to Vector128); this can cause a problem for searches
// with no upper bound e.g. String.strlen.
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector128<byte>.Count;
+ offset += (nuint)Vector128<byte>.Count;
}
else
{
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
}
}
lengthToExamine = GetByteVector256SpanLength(offset, length);
- if ((byte*)lengthToExamine > (byte*)offset)
+ if (lengthToExamine > offset)
{
Vector256<byte> values = Vector256.Create(value);
do
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector256<byte>.Count;
+ offset += (nuint)Vector256<byte>.Count;
continue;
}
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
- } while ((byte*)lengthToExamine > (byte*)offset);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
+ } while (lengthToExamine > offset);
}
lengthToExamine = GetByteVector128SpanLength(offset, length);
- if ((byte*)lengthToExamine > (byte*)offset)
+ if (lengthToExamine > offset)
{
Vector128<byte> values = Vector128.Create(value);
Vector128<byte> search = LoadVector128(ref searchSpace, offset);
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector128<byte>.Count;
+ offset += (nuint)Vector128<byte>.Count;
}
else
{
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
}
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
}
else if (Sse2.IsSupported)
{
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
lengthToExamine = GetByteVector128SpanLength(offset, length);
Vector128<byte> values = Vector128.Create(value);
- while ((byte*)lengthToExamine > (byte*)offset)
+ while (lengthToExamine > offset)
{
Vector128<byte> search = LoadVector128(ref searchSpace, offset);
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector128<byte>.Count;
+ offset += (nuint)Vector128<byte>.Count;
continue;
}
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
}
else if (Vector.IsHardwareAccelerated)
{
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
lengthToExamine = GetByteVectorSpanLength(offset, length);
Vector<byte> values = new Vector<byte>(value);
- while ((byte*)lengthToExamine > (byte*)offset)
+ while (lengthToExamine > offset)
{
var matches = Vector.Equals(values, LoadVector(ref searchSpace, offset));
if (Vector<byte>.Zero.Equals(matches))
{
- offset += Vector<byte>.Count;
+ offset += (nuint)Vector<byte>.Count;
continue;
}
// Find offset of first match and add to current offset
- return (int)(byte*)offset + LocateFirstFoundByte(matches);
+ return (int)offset + LocateFirstFoundByte(matches);
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
}
return -1;
Found: // Workaround for https://github.com/dotnet/runtime/issues/8795
- return (int)(byte*)offset;
+ return (int)offset;
Found1:
- return (int)(byte*)(offset + 1);
+ return (int)(offset + 1);
Found2:
- return (int)(byte*)(offset + 2);
+ return (int)(offset + 2);
Found3:
- return (int)(byte*)(offset + 3);
+ return (int)(offset + 3);
Found4:
- return (int)(byte*)(offset + 4);
+ return (int)(offset + 4);
Found5:
- return (int)(byte*)(offset + 5);
+ return (int)(offset + 5);
Found6:
- return (int)(byte*)(offset + 6);
+ return (int)(offset + 6);
Found7:
- return (int)(byte*)(offset + 7);
+ return (int)(offset + 7);
}
public static int LastIndexOf(ref byte searchSpace, int searchSpaceLength, ref byte value, int valueLength)
break;
// Found the first element of "value". See if the tail matches.
- if (SequenceEqual(ref Unsafe.Add(ref searchSpace, relativeIndex + 1), ref valueTail, (nuint)valueTailLength)) // The (nunit)-cast is necessary to pick the correct overload
+ if (SequenceEqual(ref Unsafe.Add(ref searchSpace, relativeIndex + 1), ref valueTail, (nuint)(uint)valueTailLength)) // The (nunit)-cast is necessary to pick the correct overload
return relativeIndex; // The tail matched. Return a successful find.
offset += remainingSearchSpaceLength - relativeIndex;
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
- public static unsafe int LastIndexOf(ref byte searchSpace, byte value, int length)
+ public static int LastIndexOf(ref byte searchSpace, byte value, int length)
{
Debug.Assert(length >= 0);
uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr offset = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr lengthToExamine = (IntPtr)length;
+ nuint offset = (nuint)(uint)length; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations
+ nuint lengthToExamine = (nuint)(uint)length;
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
lengthToExamine = UnalignedCountVectorFromEnd(ref searchSpace, length);
}
SequentialScan:
- while ((byte*)lengthToExamine >= (byte*)8)
+ while (lengthToExamine >= 8)
{
lengthToExamine -= 8;
offset -= 8;
goto Found;
}
- if ((byte*)lengthToExamine >= (byte*)4)
+ if (lengthToExamine >= 4)
{
lengthToExamine -= 4;
offset -= 4;
goto Found;
}
- while ((byte*)lengthToExamine > (byte*)0)
+ while (lengthToExamine > 0)
{
lengthToExamine -= 1;
offset -= 1;
goto Found;
}
- if (Vector.IsHardwareAccelerated && ((byte*)offset > (byte*)0))
+ if (Vector.IsHardwareAccelerated && (offset > 0))
{
- lengthToExamine = (IntPtr)((int)(byte*)offset & ~(Vector<byte>.Count - 1));
+ lengthToExamine = (offset & (nuint)~(Vector<byte>.Count - 1));
Vector<byte> values = new Vector<byte>(value);
- while ((byte*)lengthToExamine > (byte*)(Vector<byte>.Count - 1))
+ while (lengthToExamine > (nuint)(Vector<byte>.Count - 1))
{
- var matches = Vector.Equals(values, LoadVector(ref searchSpace, offset - Vector<byte>.Count));
+ var matches = Vector.Equals(values, LoadVector(ref searchSpace, offset - (nuint)Vector<byte>.Count));
if (Vector<byte>.Zero.Equals(matches))
{
- offset -= Vector<byte>.Count;
- lengthToExamine -= Vector<byte>.Count;
+ offset -= (nuint)Vector<byte>.Count;
+ lengthToExamine -= (nuint)Vector<byte>.Count;
continue;
}
// Find offset of first match and add to current offset
return (int)(offset) - Vector<byte>.Count + LocateLastFoundByte(matches);
}
- if ((byte*)offset > (byte*)0)
+ if (offset > 0)
{
lengthToExamine = offset;
goto SequentialScan;
}
return -1;
Found: // Workaround for https://github.com/dotnet/runtime/issues/8795
- return (int)(byte*)offset;
+ return (int)offset;
Found1:
- return (int)(byte*)(offset + 1);
+ return (int)(offset + 1);
Found2:
- return (int)(byte*)(offset + 2);
+ return (int)(offset + 2);
Found3:
- return (int)(byte*)(offset + 3);
+ return (int)(offset + 3);
Found4:
- return (int)(byte*)(offset + 4);
+ return (int)(offset + 4);
Found5:
- return (int)(byte*)(offset + 5);
+ return (int)(offset + 5);
Found6:
- return (int)(byte*)(offset + 6);
+ return (int)(offset + 6);
Found7:
- return (int)(byte*)(offset + 7);
+ return (int)(offset + 7);
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
- public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int length)
+ public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int length)
{
Debug.Assert(length >= 0);
uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr lengthToExamine = (IntPtr)length;
+ nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations
+ nuint lengthToExamine = (nuint)(uint)length;
if (Avx2.IsSupported || Sse2.IsSupported)
{
}
SequentialScan:
uint lookUp;
- while ((byte*)lengthToExamine >= (byte*)8)
+ while (lengthToExamine >= 8)
{
lengthToExamine -= 8;
offset += 8;
}
- if ((byte*)lengthToExamine >= (byte*)4)
+ if (lengthToExamine >= 4)
{
lengthToExamine -= 4;
offset += 4;
}
- while ((byte*)lengthToExamine > (byte*)0)
+ while (lengthToExamine > 0)
{
lengthToExamine -= 1;
// the JIT to see that the code is unreachable and eliminate it when the platform does not have hardware accelerated.
if (Avx2.IsSupported)
{
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
lengthToExamine = GetByteVector256SpanLength(offset, length);
- if ((byte*)lengthToExamine > (byte*)offset)
+ if (lengthToExamine > offset)
{
Vector256<byte> values0 = Vector256.Create(value0);
Vector256<byte> values1 = Vector256.Create(value1);
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector256<byte>.Count;
+ offset += (nuint)Vector256<byte>.Count;
continue;
}
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
- } while ((byte*)lengthToExamine > (byte*)offset);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
+ } while (lengthToExamine > offset);
}
lengthToExamine = GetByteVector128SpanLength(offset, length);
- if ((byte*)lengthToExamine > (byte*)offset)
+ if (lengthToExamine > offset)
{
Vector128<byte> values0 = Vector128.Create(value0);
Vector128<byte> values1 = Vector128.Create(value1);
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector128<byte>.Count;
+ offset += (nuint)Vector128<byte>.Count;
}
else
{
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
}
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
}
else if (Sse2.IsSupported)
{
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
lengthToExamine = GetByteVector128SpanLength(offset, length);
Vector128<byte> values0 = Vector128.Create(value0);
Vector128<byte> values1 = Vector128.Create(value1);
- while ((byte*)lengthToExamine > (byte*)offset)
+ while (lengthToExamine > offset)
{
Vector128<byte> search = LoadVector128(ref searchSpace, offset);
// Same method as above
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector128<byte>.Count;
+ offset += (nuint)Vector128<byte>.Count;
continue;
}
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
}
else if (Vector.IsHardwareAccelerated)
{
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
lengthToExamine = GetByteVectorSpanLength(offset, length);
Vector<byte> values0 = new Vector<byte>(value0);
Vector<byte> values1 = new Vector<byte>(value1);
- while ((byte*)lengthToExamine > (byte*)offset)
+ while (lengthToExamine > offset)
{
Vector<byte> search = LoadVector(ref searchSpace, offset);
var matches = Vector.BitwiseOr(
Vector.Equals(search, values1));
if (Vector<byte>.Zero.Equals(matches))
{
- offset += Vector<byte>.Count;
+ offset += (nuint)Vector<byte>.Count;
continue;
}
// Find offset of first match and add to current offset
- return (int)(byte*)offset + LocateFirstFoundByte(matches);
+ return (int)offset + LocateFirstFoundByte(matches);
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
}
return -1;
Found: // Workaround for https://github.com/dotnet/runtime/issues/8795
- return (int)(byte*)offset;
+ return (int)offset;
Found1:
- return (int)(byte*)(offset + 1);
+ return (int)(offset + 1);
Found2:
- return (int)(byte*)(offset + 2);
+ return (int)(offset + 2);
Found3:
- return (int)(byte*)(offset + 3);
+ return (int)(offset + 3);
Found4:
- return (int)(byte*)(offset + 4);
+ return (int)(offset + 4);
Found5:
- return (int)(byte*)(offset + 5);
+ return (int)(offset + 5);
Found6:
- return (int)(byte*)(offset + 6);
+ return (int)(offset + 6);
Found7:
- return (int)(byte*)(offset + 7);
+ return (int)(offset + 7);
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
- public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length)
+ public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length)
{
Debug.Assert(length >= 0);
uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue1 = value1;
uint uValue2 = value2;
- IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr lengthToExamine = (IntPtr)length;
+ nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations
+ nuint lengthToExamine = (nuint)(uint)length;
if (Avx2.IsSupported || Sse2.IsSupported)
{
}
SequentialScan:
uint lookUp;
- while ((byte*)lengthToExamine >= (byte*)8)
+ while (lengthToExamine >= 8)
{
lengthToExamine -= 8;
offset += 8;
}
- if ((byte*)lengthToExamine >= (byte*)4)
+ if (lengthToExamine >= 4)
{
lengthToExamine -= 4;
offset += 4;
}
- while ((byte*)lengthToExamine > (byte*)0)
+ while (lengthToExamine > 0)
{
lengthToExamine -= 1;
if (Avx2.IsSupported)
{
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
lengthToExamine = GetByteVector256SpanLength(offset, length);
- if ((byte*)lengthToExamine > (byte*)offset)
+ if (lengthToExamine > offset)
{
Vector256<byte> values0 = Vector256.Create(value0);
Vector256<byte> values1 = Vector256.Create(value1);
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector256<byte>.Count;
+ offset += (nuint)Vector256<byte>.Count;
continue;
}
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
- } while ((byte*)lengthToExamine > (byte*)offset);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
+ } while (lengthToExamine > offset);
}
lengthToExamine = GetByteVector128SpanLength(offset, length);
- if ((byte*)lengthToExamine > (byte*)offset)
+ if (lengthToExamine > offset)
{
Vector128<byte> values0 = Vector128.Create(value0);
Vector128<byte> values1 = Vector128.Create(value1);
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector128<byte>.Count;
+ offset += (nuint)Vector128<byte>.Count;
}
else
{
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
}
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
}
else if (Sse2.IsSupported)
{
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
lengthToExamine = GetByteVector128SpanLength(offset, length);
Vector128<byte> values1 = Vector128.Create(value1);
Vector128<byte> values2 = Vector128.Create(value2);
- while ((byte*)lengthToExamine > (byte*)offset)
+ while (lengthToExamine > offset)
{
Vector128<byte> search = LoadVector128(ref searchSpace, offset);
if (matches == 0)
{
// Zero flags set so no matches
- offset += Vector128<byte>.Count;
+ offset += (nuint)Vector128<byte>.Count;
continue;
}
// Find bitflag offset of first match and add to current offset
- return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches);
+ return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches));
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
}
else if (Vector.IsHardwareAccelerated)
{
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
lengthToExamine = GetByteVectorSpanLength(offset, length);
Vector<byte> values1 = new Vector<byte>(value1);
Vector<byte> values2 = new Vector<byte>(value2);
- while ((byte*)lengthToExamine > (byte*)offset)
+ while (lengthToExamine > offset)
{
Vector<byte> search = LoadVector(ref searchSpace, offset);
if (Vector<byte>.Zero.Equals(matches))
{
- offset += Vector<byte>.Count;
+ offset += (nuint)Vector<byte>.Count;
continue;
}
// Find offset of first match and add to current offset
- return (int)(byte*)offset + LocateFirstFoundByte(matches);
+ return (int)offset + LocateFirstFoundByte(matches);
}
- if ((int)(byte*)offset < length)
+ if (offset < (nuint)(uint)length)
{
- lengthToExamine = (IntPtr)(length - (int)(byte*)offset);
+ lengthToExamine = ((nuint)(uint)length - offset);
goto SequentialScan;
}
}
}
return -1;
Found: // Workaround for https://github.com/dotnet/runtime/issues/8795
- return (int)(byte*)offset;
+ return (int)offset;
Found1:
- return (int)(byte*)(offset + 1);
+ return (int)(offset + 1);
Found2:
- return (int)(byte*)(offset + 2);
+ return (int)(offset + 2);
Found3:
- return (int)(byte*)(offset + 3);
+ return (int)(offset + 3);
Found4:
- return (int)(byte*)(offset + 4);
+ return (int)(offset + 4);
Found5:
- return (int)(byte*)(offset + 5);
+ return (int)(offset + 5);
Found6:
- return (int)(byte*)(offset + 6);
+ return (int)(offset + 6);
Found7:
- return (int)(byte*)(offset + 7);
+ return (int)(offset + 7);
}
- public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, int length)
+ public static int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, int length)
{
Debug.Assert(length >= 0);
uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue1 = value1;
- IntPtr offset = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr lengthToExamine = (IntPtr)length;
+ nuint offset = (nuint)(uint)length; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations
+ nuint lengthToExamine = (nuint)(uint)length;
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
}
SequentialScan:
uint lookUp;
- while ((byte*)lengthToExamine >= (byte*)8)
+ while (lengthToExamine >= 8)
{
lengthToExamine -= 8;
offset -= 8;
goto Found;
}
- if ((byte*)lengthToExamine >= (byte*)4)
+ if (lengthToExamine >= 4)
{
lengthToExamine -= 4;
offset -= 4;
goto Found;
}
- while ((byte*)lengthToExamine > (byte*)0)
+ while (lengthToExamine > 0)
{
lengthToExamine -= 1;
offset -= 1;
goto Found;
}
- if (Vector.IsHardwareAccelerated && ((byte*)offset > (byte*)0))
+ if (Vector.IsHardwareAccelerated && (offset > 0))
{
- lengthToExamine = (IntPtr)((int)(byte*)offset & ~(Vector<byte>.Count - 1));
+ lengthToExamine = (offset & (nuint)~(Vector<byte>.Count - 1));
Vector<byte> values0 = new Vector<byte>(value0);
Vector<byte> values1 = new Vector<byte>(value1);
- while ((byte*)lengthToExamine > (byte*)(Vector<byte>.Count - 1))
+ while (lengthToExamine > (nuint)(Vector<byte>.Count - 1))
{
- Vector<byte> search = LoadVector(ref searchSpace, offset - Vector<byte>.Count);
+ Vector<byte> search = LoadVector(ref searchSpace, offset - (nuint)Vector<byte>.Count);
var matches = Vector.BitwiseOr(
Vector.Equals(search, values0),
Vector.Equals(search, values1));
if (Vector<byte>.Zero.Equals(matches))
{
- offset -= Vector<byte>.Count;
- lengthToExamine -= Vector<byte>.Count;
+ offset -= (nuint)Vector<byte>.Count;
+ lengthToExamine -= (nuint)Vector<byte>.Count;
continue;
}
return (int)(offset) - Vector<byte>.Count + LocateLastFoundByte(matches);
}
- if ((byte*)offset > (byte*)0)
+ if (offset > 0)
{
lengthToExamine = offset;
goto SequentialScan;
}
return -1;
Found: // Workaround for https://github.com/dotnet/runtime/issues/8795
- return (int)(byte*)offset;
+ return (int)offset;
Found1:
- return (int)(byte*)(offset + 1);
+ return (int)(offset + 1);
Found2:
- return (int)(byte*)(offset + 2);
+ return (int)(offset + 2);
Found3:
- return (int)(byte*)(offset + 3);
+ return (int)(offset + 3);
Found4:
- return (int)(byte*)(offset + 4);
+ return (int)(offset + 4);
Found5:
- return (int)(byte*)(offset + 5);
+ return (int)(offset + 5);
Found6:
- return (int)(byte*)(offset + 6);
+ return (int)(offset + 6);
Found7:
- return (int)(byte*)(offset + 7);
+ return (int)(offset + 7);
}
- public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length)
+ public static int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length)
{
Debug.Assert(length >= 0);
uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue1 = value1;
uint uValue2 = value2;
- IntPtr offset = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr lengthToExamine = (IntPtr)length;
+ nuint offset = (nuint)(uint)length; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations
+ nuint lengthToExamine = (nuint)(uint)length;
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
}
SequentialScan:
uint lookUp;
- while ((byte*)lengthToExamine >= (byte*)8)
+ while (lengthToExamine >= 8)
{
lengthToExamine -= 8;
offset -= 8;
goto Found;
}
- if ((byte*)lengthToExamine >= (byte*)4)
+ if (lengthToExamine >= 4)
{
lengthToExamine -= 4;
offset -= 4;
goto Found;
}
- while ((byte*)lengthToExamine > (byte*)0)
+ while (lengthToExamine > 0)
{
lengthToExamine -= 1;
offset -= 1;
goto Found;
}
- if (Vector.IsHardwareAccelerated && ((byte*)offset > (byte*)0))
+ if (Vector.IsHardwareAccelerated && (offset > 0))
{
- lengthToExamine = (IntPtr)((int)(byte*)offset & ~(Vector<byte>.Count - 1));
+ lengthToExamine = (offset & (nuint)~(Vector<byte>.Count - 1));
Vector<byte> values0 = new Vector<byte>(value0);
Vector<byte> values1 = new Vector<byte>(value1);
Vector<byte> values2 = new Vector<byte>(value2);
- while ((byte*)lengthToExamine > (byte*)(Vector<byte>.Count - 1))
+ while (lengthToExamine > (nuint)(Vector<byte>.Count - 1))
{
- Vector<byte> search = LoadVector(ref searchSpace, offset - Vector<byte>.Count);
+ Vector<byte> search = LoadVector(ref searchSpace, offset - (nuint)Vector<byte>.Count);
var matches = Vector.BitwiseOr(
Vector.BitwiseOr(
if (Vector<byte>.Zero.Equals(matches))
{
- offset -= Vector<byte>.Count;
- lengthToExamine -= Vector<byte>.Count;
+ offset -= (nuint)Vector<byte>.Count;
+ lengthToExamine -= (nuint)Vector<byte>.Count;
continue;
}
return (int)(offset) - Vector<byte>.Count + LocateLastFoundByte(matches);
}
- if ((byte*)offset > (byte*)0)
+ if (offset > 0)
{
lengthToExamine = offset;
goto SequentialScan;
}
return -1;
Found: // Workaround for https://github.com/dotnet/runtime/issues/8795
- return (int)(byte*)offset;
+ return (int)offset;
Found1:
- return (int)(byte*)(offset + 1);
+ return (int)(offset + 1);
Found2:
- return (int)(byte*)(offset + 2);
+ return (int)(offset + 2);
Found3:
- return (int)(byte*)(offset + 3);
+ return (int)(offset + 3);
Found4:
- return (int)(byte*)(offset + 4);
+ return (int)(offset + 4);
Found5:
- return (int)(byte*)(offset + 5);
+ return (int)(offset + 5);
Found6:
- return (int)(byte*)(offset + 6);
+ return (int)(offset + 6);
Found7:
- return (int)(byte*)(offset + 7);
+ return (int)(offset + 7);
}
// Optimized byte-based SequenceEquals. The "length" parameter for this one is declared a nuint rather than int as we also use it for types other than byte
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
- public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref byte second, int secondLength)
+ public static int SequenceCompareTo(ref byte first, int firstLength, ref byte second, int secondLength)
{
Debug.Assert(firstLength >= 0);
Debug.Assert(secondLength >= 0);
if (Unsafe.AreSame(ref first, ref second))
goto Equal;
- IntPtr minLength = (IntPtr)((firstLength < secondLength) ? firstLength : secondLength);
+ nuint minLength = (nuint)(((uint)firstLength < (uint)secondLength) ? (uint)firstLength : (uint)secondLength);
- IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr lengthToExamine = (IntPtr)(void*)minLength;
+ nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations
+ nuint lengthToExamine = minLength;
if (Avx2.IsSupported)
{
- if ((byte*)lengthToExamine >= (byte*)Vector256<byte>.Count)
+ if (lengthToExamine >= (nuint)Vector256<byte>.Count)
{
- lengthToExamine -= Vector256<byte>.Count;
+ lengthToExamine -= (nuint)Vector256<byte>.Count;
uint matches;
- while ((byte*)lengthToExamine > (byte*)offset)
+ while (lengthToExamine > offset)
{
matches = (uint)Avx2.MoveMask(Avx2.CompareEqual(LoadVector256(ref first, offset), LoadVector256(ref second, offset)));
// Note that MoveMask has converted the equal vector elements into a set of bit flags,
if (matches == uint.MaxValue)
{
// All matched
- offset += Vector256<byte>.Count;
+ offset += (nuint)Vector256<byte>.Count;
continue;
}
// Invert matches to find differences
uint differences = ~matches;
// Find bitflag offset of first difference and add to current offset
- offset = (IntPtr)((int)(byte*)offset + BitOperations.TrailingZeroCount((int)differences));
+ offset += (uint)BitOperations.TrailingZeroCount(differences);
int result = Unsafe.AddByteOffset(ref first, offset).CompareTo(Unsafe.AddByteOffset(ref second, offset));
Debug.Assert(result != 0);
return result;
}
- if ((byte*)lengthToExamine >= (byte*)Vector128<byte>.Count)
+ if (lengthToExamine >= (nuint)Vector128<byte>.Count)
{
- lengthToExamine -= Vector128<byte>.Count;
+ lengthToExamine -= (nuint)Vector128<byte>.Count;
uint matches;
- if ((byte*)lengthToExamine > (byte*)offset)
+ if (lengthToExamine > offset)
{
matches = (uint)Sse2.MoveMask(Sse2.CompareEqual(LoadVector128(ref first, offset), LoadVector128(ref second, offset)));
// Note that MoveMask has converted the equal vector elements into a set of bit flags,
// Invert matches to find differences
uint differences = ~matches;
// Find bitflag offset of first difference and add to current offset
- offset = (IntPtr)((int)(byte*)offset + BitOperations.TrailingZeroCount((int)differences));
+ offset += (uint)BitOperations.TrailingZeroCount(differences);
int result = Unsafe.AddByteOffset(ref first, offset).CompareTo(Unsafe.AddByteOffset(ref second, offset));
Debug.Assert(result != 0);
}
else if (Sse2.IsSupported)
{
- if ((byte*)lengthToExamine >= (byte*)Vector128<byte>.Count)
+ if (lengthToExamine >= (nuint)Vector128<byte>.Count)
{
- lengthToExamine -= Vector128<byte>.Count;
+ lengthToExamine -= (nuint)Vector128<byte>.Count;
uint matches;
- while ((byte*)lengthToExamine > (byte*)offset)
+ while (lengthToExamine > offset)
{
matches = (uint)Sse2.MoveMask(Sse2.CompareEqual(LoadVector128(ref first, offset), LoadVector128(ref second, offset)));
// Note that MoveMask has converted the equal vector elements into a set of bit flags,
if (matches == ushort.MaxValue)
{
// All matched
- offset += Vector128<byte>.Count;
+ offset += (nuint)Vector128<byte>.Count;
continue;
}
// Invert matches to find differences
uint differences = ~matches;
// Find bitflag offset of first difference and add to current offset
- offset = (IntPtr)((int)(byte*)offset + BitOperations.TrailingZeroCount((int)differences));
+ offset += (uint)BitOperations.TrailingZeroCount(differences);
int result = Unsafe.AddByteOffset(ref first, offset).CompareTo(Unsafe.AddByteOffset(ref second, offset));
Debug.Assert(result != 0);
}
else if (Vector.IsHardwareAccelerated)
{
- if ((byte*)lengthToExamine > (byte*)Vector<byte>.Count)
+ if (lengthToExamine > (nuint)Vector<byte>.Count)
{
- lengthToExamine -= Vector<byte>.Count;
- while ((byte*)lengthToExamine > (byte*)offset)
+ lengthToExamine -= (nuint)Vector<byte>.Count;
+ while (lengthToExamine > offset)
{
if (LoadVector(ref first, offset) != LoadVector(ref second, offset))
{
goto BytewiseCheck;
}
- offset += Vector<byte>.Count;
+ offset += (nuint)Vector<byte>.Count;
}
goto BytewiseCheck;
}
}
- if ((byte*)lengthToExamine > (byte*)sizeof(UIntPtr))
+ if (lengthToExamine > sizeof(nuint))
{
- lengthToExamine -= sizeof(UIntPtr);
- while ((byte*)lengthToExamine > (byte*)offset)
+ lengthToExamine -= sizeof(nuint);
+ while (lengthToExamine > offset)
{
- if (LoadUIntPtr(ref first, offset) != LoadUIntPtr(ref second, offset))
+ if (LoadNUInt(ref first, offset) != LoadNUInt(ref second, offset))
{
goto BytewiseCheck;
}
- offset += sizeof(UIntPtr);
+ offset += sizeof(nuint);
}
}
BytewiseCheck: // Workaround for https://github.com/dotnet/runtime/issues/8795
- while ((byte*)minLength > (byte*)offset)
+ while (minLength > offset)
{
int result = Unsafe.AddByteOffset(ref first, offset).CompareTo(Unsafe.AddByteOffset(ref second, offset));
if (result != 0)
=> Unsafe.ReadUnaligned<ushort>(ref start);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static ushort LoadUShort(ref byte start, nuint offset)
- => Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref start, offset));
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint LoadUInt(ref byte start)
=> Unsafe.ReadUnaligned<uint>(ref start);
=> Unsafe.ReadUnaligned<nuint>(ref Unsafe.AddByteOffset(ref start, offset));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static UIntPtr LoadUIntPtr(ref byte start, IntPtr offset)
- => Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.AddByteOffset(ref start, offset));
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static Vector<byte> LoadVector(ref byte start, IntPtr offset)
- => Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref start, offset));
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<byte> LoadVector(ref byte start, nuint offset)
=> Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref start, offset));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static Vector128<byte> LoadVector128(ref byte start, IntPtr offset)
- => Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AddByteOffset(ref start, offset));
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<byte> LoadVector128(ref byte start, nuint offset)
=> Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AddByteOffset(ref start, offset));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static Vector256<byte> LoadVector256(ref byte start, IntPtr offset)
- => Unsafe.ReadUnaligned<Vector256<byte>>(ref Unsafe.AddByteOffset(ref start, offset));
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector256<byte> LoadVector256(ref byte start, nuint offset)
=> Unsafe.ReadUnaligned<Vector256<byte>>(ref Unsafe.AddByteOffset(ref start, offset));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static unsafe IntPtr GetByteVectorSpanLength(IntPtr offset, int length)
- => (IntPtr)((length - (int)(byte*)offset) & ~(Vector<byte>.Count - 1));
+ private static nuint GetByteVectorSpanLength(nuint offset, int length)
+ => (nuint)(uint)((length - (int)offset) & ~(Vector<byte>.Count - 1));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static unsafe IntPtr GetByteVector128SpanLength(IntPtr offset, int length)
- => (IntPtr)((length - (int)(byte*)offset) & ~(Vector128<byte>.Count - 1));
+ private static nuint GetByteVector128SpanLength(nuint offset, int length)
+ => (nuint)(uint)((length - (int)offset) & ~(Vector128<byte>.Count - 1));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static unsafe IntPtr GetByteVector256SpanLength(IntPtr offset, int length)
- => (IntPtr)((length - (int)(byte*)offset) & ~(Vector256<byte>.Count - 1));
+ private static nuint GetByteVector256SpanLength(nuint offset, int length)
+ => (nuint)(uint)((length - (int)offset) & ~(Vector256<byte>.Count - 1));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static unsafe IntPtr UnalignedCountVector(ref byte searchSpace)
+ private static unsafe nuint UnalignedCountVector(ref byte searchSpace)
{
- int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
- return (IntPtr)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
+ nint unaligned = (nint)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
+ return (nuint)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static unsafe IntPtr UnalignedCountVector128(ref byte searchSpace)
+ private static unsafe nuint UnalignedCountVector128(ref byte searchSpace)
{
- int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector128<byte>.Count - 1);
- return (IntPtr)((Vector128<byte>.Count - unaligned) & (Vector128<byte>.Count - 1));
+ nint unaligned = (nint)Unsafe.AsPointer(ref searchSpace) & (Vector128<byte>.Count - 1);
+ return (nuint)(uint)((Vector128<byte>.Count - unaligned) & (Vector128<byte>.Count - 1));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static unsafe IntPtr UnalignedCountVectorFromEnd(ref byte searchSpace, int length)
+ private static unsafe nuint UnalignedCountVectorFromEnd(ref byte searchSpace, int length)
{
- int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
- return (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
+ nint unaligned = (nint)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
+ return (nuint)(uint)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
}
}
}