using System.Runtime.InteropServices;
using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
-#if !FEATURE_PORTABLE_SPAN
+
using Internal.Runtime.CompilerServices;
-#endif // FEATURE_PORTABLE_SPAN
namespace System
{
// and then cast to a Memory<T>. Such a cast can only be done with unsafe or marshaling code,
// in which case that's the dangerous operation performed by the dev, and we're just following
// suit here to make it work as best as possible.
-#if FEATURE_PORTABLE_SPAN
- return new Span<T>(Unsafe.As<Pinnable<T>>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length);
-#else
return new Span<T>(ref Unsafe.As<char, T>(ref s.GetRawStringData()), s.Length).Slice(_index, _length);
-#endif // FEATURE_PORTABLE_SPAN
}
else if (_object != null)
{
// a readable ReadOnlyMemory<char> or a writable Memory<char> can still be pinned and
// used for interop purposes.
GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
-#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
return new MemoryHandle(pointer, handle);
}
else if (_object is T[] array)
// Array is already pre-pinned
if (_length < 0)
{
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref MemoryMarshal.GetReference<T>(array)), _index);
-#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
return new MemoryHandle(pointer);
}
else
{
GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
-#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
return new MemoryHandle(pointer, handle);
}
}
using System.Runtime.InteropServices;
using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
-#if !FEATURE_PORTABLE_SPAN
+
using Internal.Runtime.CompilerServices;
-#endif // FEATURE_PORTABLE_SPAN
namespace System
{
else if (typeof(T) == typeof(char) && _object is string s)
{
Debug.Assert(_length >= 0);
-#if FEATURE_PORTABLE_SPAN
- return new ReadOnlySpan<T>(Unsafe.As<Pinnable<T>>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length);
-#else
return new ReadOnlySpan<T>(ref Unsafe.As<char, T>(ref s.GetRawStringData()), s.Length).Slice(_index, _length);
-#endif // FEATURE_PORTABLE_SPAN
}
else if (_object != null)
{
else if (typeof(T) == typeof(char) && _object is string s)
{
GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
-#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
return new MemoryHandle(pointer, handle);
}
else if (_object is T[] array)
// Array is already pre-pinned
if (_length < 0)
{
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref MemoryMarshal.GetReference<T>(array)), _index);
-#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
return new MemoryHandle(pointer);
}
else
{
GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned);
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
-#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
return new MemoryHandle(pointer, handle);
}
}
using System.Collections.Generic;
using System.Diagnostics;
-#if !netstandard
using Internal.Runtime.CompilerServices;
-#endif
namespace System.Runtime.InteropServices
{
if ((length & ReadOnlyMemory<T>.RemoveFlagsBitMask) == 0)
{
-#if FEATURE_PORTABLE_SPAN
- segment = new ArraySegment<T>(SpanHelpers.PerTypeValues<T>.EmptyArray);
-#else
segment = ArraySegment<T>.Empty;
-#endif // FEATURE_PORTABLE_SPAN
return true;
}
public static T Read<T>(ReadOnlySpan<byte> source)
where T : struct
{
-#if netstandard
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#else
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
}
-#endif
if (Unsafe.SizeOf<T>() > source.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
public static bool TryRead<T>(ReadOnlySpan<byte> source, out T value)
where T : struct
{
-#if netstandard
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#else
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
}
-#endif
if (Unsafe.SizeOf<T>() > (uint)source.Length)
{
value = default;
public static void Write<T>(Span<byte> destination, ref T value)
where T : struct
{
-#if netstandard
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#else
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
}
-#endif
if ((uint)Unsafe.SizeOf<T>() > (uint)destination.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
public static bool TryWrite<T>(Span<byte> destination, ref T value)
where T : struct
{
-#if netstandard
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#else
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
}
-#endif
if (Unsafe.SizeOf<T>() > (uint)destination.Length)
{
return false;
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using System.Numerics;
-#if !netstandard
using Internal.Runtime.CompilerServices;
-#endif
-
-#if !netstandard11
-using System.Numerics;
-#endif
-#if netstandard
-using nuint = System.NUInt;
-#else
#if BIT64
using nuint = System.UInt64;
#else
using nuint = System.UInt32;
#endif // BIT64
-#endif // netstandard
namespace System
{
uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions
IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
IntPtr nLength = (IntPtr)length;
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
nLength = (IntPtr)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
-#endif
while ((byte*)nLength >= (byte*)8)
{
nLength -= 8;
index += 1;
}
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length))
{
nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<byte>.Count - 1));
// Get comparison Vector
- Vector<byte> vComparison = GetVector(value);
+ Vector<byte> vComparison = new Vector<byte>(value);
while ((byte*)nLength > (byte*)index)
{
goto SequentialScan;
}
}
-#endif
return -1;
Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
return (int)(byte*)index;
uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions
IntPtr index = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
IntPtr nLength = (IntPtr)length;
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
nLength = (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
-#endif
while ((byte*)nLength >= (byte*)8)
{
nLength -= 8;
if (uValue == Unsafe.AddByteOffset(ref searchSpace, index))
goto Found;
}
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && ((byte*)index > (byte*)0))
{
nLength = (IntPtr)((int)(byte*)index & ~(Vector<byte>.Count - 1));
// Get comparison Vector
- Vector<byte> vComparison = GetVector(value);
+ Vector<byte> vComparison = new Vector<byte>(value);
while ((byte*)nLength > (byte*)(Vector<byte>.Count - 1))
{
goto SequentialScan;
}
}
-#endif
return -1;
Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
return (int)(byte*)index;
uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions
IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
IntPtr nLength = (IntPtr)length;
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
nLength = (IntPtr)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
-#endif
uint lookUp;
while ((byte*)nLength >= (byte*)8)
{
index += 1;
}
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length))
{
nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<byte>.Count - 1));
// Get comparison Vector
- Vector<byte> values0 = GetVector(value0);
- Vector<byte> values1 = GetVector(value1);
+ Vector<byte> values0 = new Vector<byte>(value0);
+ Vector<byte> values1 = new Vector<byte>(value1);
while ((byte*)nLength > (byte*)index)
{
goto SequentialScan;
}
}
-#endif
return -1;
Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
return (int)(byte*)index;
uint uValue2 = value2; // Use uint for comparisons to avoid unnecessary 8->32 extensions
IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
IntPtr nLength = (IntPtr)length;
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
nLength = (IntPtr)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
-#endif
uint lookUp;
while ((byte*)nLength >= (byte*)8)
{
index += 1;
}
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length))
{
nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<byte>.Count - 1));
// Get comparison Vector
- Vector<byte> values0 = GetVector(value0);
- Vector<byte> values1 = GetVector(value1);
- Vector<byte> values2 = GetVector(value2);
+ Vector<byte> values0 = new Vector<byte>(value0);
+ Vector<byte> values1 = new Vector<byte>(value1);
+ Vector<byte> values2 = new Vector<byte>(value2);
while ((byte*)nLength > (byte*)index)
{
goto SequentialScan;
}
}
-#endif
return -1;
Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
return (int)(byte*)index;
uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions
IntPtr index = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
IntPtr nLength = (IntPtr)length;
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
nLength = (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
-#endif
uint lookUp;
while ((byte*)nLength >= (byte*)8)
{
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found;
}
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && ((byte*)index > (byte*)0))
{
nLength = (IntPtr)((int)(byte*)index & ~(Vector<byte>.Count - 1));
// Get comparison Vector
- Vector<byte> values0 = GetVector(value0);
- Vector<byte> values1 = GetVector(value1);
+ Vector<byte> values0 = new Vector<byte>(value0);
+ Vector<byte> values1 = new Vector<byte>(value1);
while ((byte*)nLength > (byte*)(Vector<byte>.Count - 1))
{
goto SequentialScan;
}
}
-#endif
return -1;
Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
return (int)(byte*)index;
uint uValue2 = value2; // Use uint for comparisons to avoid unnecessary 8->32 extensions
IntPtr index = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
IntPtr nLength = (IntPtr)length;
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
nLength = (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
-#endif
uint lookUp;
while ((byte*)nLength >= (byte*)8)
{
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found;
}
-#if !netstandard11
+
if (Vector.IsHardwareAccelerated && ((byte*)index > (byte*)0))
{
nLength = (IntPtr)((int)(byte*)index & ~(Vector<byte>.Count - 1));
// Get comparison Vector
- Vector<byte> values0 = GetVector(value0);
- Vector<byte> values1 = GetVector(value1);
- Vector<byte> values2 = GetVector(value2);
+ Vector<byte> values0 = new Vector<byte>(value0);
+ Vector<byte> values1 = new Vector<byte>(value1);
+ Vector<byte> values2 = new Vector<byte>(value2);
while ((byte*)nLength > (byte*)(Vector<byte>.Count - 1))
{
goto SequentialScan;
}
}
-#endif
return -1;
Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
return (int)(byte*)index;
IntPtr i = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
IntPtr n = (IntPtr)(void*)length;
-#if !netstandard11
if (Vector.IsHardwareAccelerated && (byte*)n >= (byte*)Vector<byte>.Count)
{
n -= Vector<byte>.Count;
return Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref first, n)) ==
Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref second, n));
}
-#endif
if ((byte*)n >= (byte*)sizeof(UIntPtr))
{
return false;
}
-#if !netstandard11
// Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LocateFirstFoundByte(Vector<byte> match)
// Single LEA instruction with jitted const (using function result)
return i * 8 + LocateFirstFoundByte(candidate);
}
-#endif
public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref byte second, int secondLength)
{
IntPtr i = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
IntPtr n = (IntPtr)(void*)minLength;
-#if !netstandard11
if (Vector.IsHardwareAccelerated && (byte*)n > (byte*)Vector<byte>.Count)
{
n -= Vector<byte>.Count;
}
goto NotEqual;
}
-#endif
if ((byte*)n > (byte*)sizeof(UIntPtr))
{
return firstLength - secondLength;
}
-#if !netstandard11
// Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LocateLastFoundByte(Vector<byte> match)
// Single LEA instruction with jitted const (using function result)
return i * 8 + LocateLastFoundByte(candidate);
}
-#endif
-#if !netstandard11
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LocateFirstFoundByte(ulong match)
{
// Shift all powers of two into the high byte and extract
return (int)((powerOfTwoFlag * XorPowerOfTwoToHighByte) >> 57);
}
-#endif
-#if !netstandard11
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LocateLastFoundByte(ulong match)
{
}
return index;
}
-#endif
-
-#if !netstandard11
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static Vector<byte> GetVector(byte vectorByte)
- {
-#if !netcoreapp
- // Vector<byte> .ctor doesn't become an intrinsic due to detection issue
- // However this does cause it to become an intrinsic (with additional multiply and reg->reg copy)
- // https://github.com/dotnet/coreclr/issues/7459#issuecomment-253965670
- return Vector.AsVectorByte(new Vector<uint>(vectorByte * 0x01010101u));
-#else
- return new Vector<byte>(vectorByte);
-#endif
- }
-#endif
-#if !netstandard11
private const ulong XorPowerOfTwoToHighByte = (0x07ul |
0x06ul << 8 |
0x05ul << 16 |
0x03ul << 32 |
0x02ul << 40 |
0x01ul << 48) + 1;
-#endif
}
}