mirror of https://github.com/dotnet/runtime
Merge 45608b09e2
into 123627ba0f
This commit is contained in:
commit
4679ff76fd
|
@ -48,10 +48,8 @@ namespace Microsoft.Extensions.Primitives
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public StringSegment(string buffer, int offset, int length)
|
||||
{
|
||||
// Validate arguments, check is minimal instructions with reduced branching for inlinable fast-path
|
||||
// Negative values discovered though conversion to high values when converted to unsigned
|
||||
// Failure should be rare and location determination and message is delegated to failure functions
|
||||
if (buffer == null || (uint)offset > (uint)buffer.Length || (uint)length > (uint)(buffer.Length - offset))
|
||||
if (buffer == null || !SliceArgumentsAreValid(buffer.Length, offset, length))
|
||||
{
|
||||
ThrowInvalidArguments(buffer, offset, length);
|
||||
}
|
||||
|
@ -128,12 +126,17 @@ namespace Microsoft.Extensions.Primitives
|
|||
/// </exception>
|
||||
public ReadOnlySpan<char> AsSpan(int start)
|
||||
{
|
||||
if (!HasValue || start < 0)
|
||||
string? buffer = Buffer;
|
||||
int offset = Offset + start;
|
||||
int length = Length - start;
|
||||
|
||||
// Using the same validation as AsSpan(int, int) so that the compiler can delete the redundant validation.
|
||||
if (buffer is null || start < 0 || !SliceArgumentsAreValid(buffer.Length, offset, length))
|
||||
{
|
||||
ThrowInvalidArguments(start, Length - start, ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
}
|
||||
|
||||
return Buffer.AsSpan(Offset + start, Length - start);
|
||||
return buffer.AsSpan(offset, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -150,7 +153,7 @@ namespace Microsoft.Extensions.Primitives
|
|||
/// </exception>
|
||||
public ReadOnlySpan<char> AsSpan(int start, int length)
|
||||
{
|
||||
if (!HasValue || start < 0 || length < 0 || (uint)(start + length) > (uint)Length)
|
||||
if (!HasValue || !SliceArgumentsAreValid(Length, start, length))
|
||||
{
|
||||
ThrowInvalidArguments(start, length, ExceptionArgument.start);
|
||||
}
|
||||
|
@ -397,7 +400,7 @@ namespace Microsoft.Extensions.Primitives
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public string Substring(int offset, int length)
|
||||
{
|
||||
if (!HasValue || offset < 0 || length < 0 || (uint)(offset + length) > (uint)Length)
|
||||
if (!HasValue || !SliceArgumentsAreValid(Length, offset, length))
|
||||
{
|
||||
ThrowInvalidArguments(offset, length, ExceptionArgument.offset);
|
||||
}
|
||||
|
@ -430,7 +433,7 @@ namespace Microsoft.Extensions.Primitives
|
|||
/// </exception>
|
||||
public StringSegment Subsegment(int offset, int length)
|
||||
{
|
||||
if (!HasValue || offset < 0 || length < 0 || (uint)(offset + length) > (uint)Length)
|
||||
if (!HasValue || !SliceArgumentsAreValid(Length, offset, length))
|
||||
{
|
||||
ThrowInvalidArguments(offset, length, ExceptionArgument.offset);
|
||||
}
|
||||
|
@ -671,6 +674,20 @@ namespace Microsoft.Extensions.Primitives
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool SliceArgumentsAreValid(int sourceLength, int start, int length)
|
||||
{
|
||||
// Copy of the internal MemoryExtensions.SliceArgumentsAreValid helper.
|
||||
if (IntPtr.Size == 8)
|
||||
{
|
||||
return (ulong)(uint)start + (ulong)(uint)length <= (ulong)(uint)sourceLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (uint)start <= (uint)sourceLength && (uint)length <= (uint)(sourceLength - start);
|
||||
}
|
||||
}
|
||||
|
||||
// Methods that do no return (i.e. throw) are not inlined
|
||||
// https://github.com/dotnet/coreclr/pull/6103
|
||||
[DoesNotReturn]
|
||||
|
|
|
@ -146,14 +146,14 @@ namespace System.MemoryTests
|
|||
[MemberData(nameof(TestHelpers.StringSlice2ArgTestOutOfRangeData), MemberType = typeof(TestHelpers))]
|
||||
public static unsafe void AsMemory_2Arg_OutOfRange(string text, int start)
|
||||
{
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsMemory(start));
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => text.AsMemory(start));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestHelpers.StringSlice3ArgTestOutOfRangeData), MemberType = typeof(TestHelpers))]
|
||||
public static unsafe void AsMemory_3Arg_OutOfRange(string text, int start, int length)
|
||||
{
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsMemory(start, length));
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => text.AsMemory(start, length));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -103,10 +103,10 @@ namespace System.SpanTests
|
|||
[MemberData(nameof(TestHelpers.StringSlice2ArgTestOutOfRangeData), MemberType = typeof(TestHelpers))]
|
||||
public static unsafe void AsSpan_2Arg_OutOfRange(string text, int start)
|
||||
{
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsSpan(start).DontBox());
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => text.AsSpan(start).DontBox());
|
||||
if (start >= 0)
|
||||
{
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>("startIndex", () => text.AsSpan(new Index(start)).DontBox());
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => text.AsSpan(new Index(start)).DontBox());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,10 +114,10 @@ namespace System.SpanTests
|
|||
[MemberData(nameof(TestHelpers.StringSlice3ArgTestOutOfRangeData), MemberType = typeof(TestHelpers))]
|
||||
public static unsafe void AsSpan_3Arg_OutOfRange(string text, int start, int length)
|
||||
{
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsSpan(start, length).DontBox());
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => text.AsSpan(start, length).DontBox());
|
||||
if (start >= 0 && length >= 0 && start + length >= 0)
|
||||
{
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>("length", () => text.AsSpan(start..(start + length)).DontBox());
|
||||
AssertExtensions.Throws<ArgumentOutOfRangeException>(null, () => text.AsSpan(start..(start + length)).DontBox());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,10 +53,8 @@ namespace System
|
|||
|
||||
public ArraySegment(T[] array, int offset, int count)
|
||||
{
|
||||
// Validate arguments, check is minimal instructions with reduced branching for inlinable fast-path
|
||||
// Negative values discovered though conversion to high values when converted to unsigned
|
||||
// Failure should be rare and location determination and message is delegated to failure functions
|
||||
if (array == null || (uint)offset > (uint)array.Length || (uint)count > (uint)(array.Length - offset))
|
||||
if (array == null || !MemoryExtensions.SliceArgumentsAreValid(array.Length, offset, count))
|
||||
ThrowHelper.ThrowArraySegmentCtorValidationFailedExceptions(array, offset, count);
|
||||
|
||||
_array = array;
|
||||
|
@ -144,7 +142,7 @@ namespace System
|
|||
{
|
||||
ThrowInvalidOperationIfDefault();
|
||||
|
||||
if ((uint)index > (uint)_count || (uint)count > (uint)(_count - index))
|
||||
if (!MemoryExtensions.SliceArgumentsAreValid(_count, index, count))
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRange_IndexMustBeLessOrEqualException();
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace System
|
|||
this = default;
|
||||
return; // returns default
|
||||
}
|
||||
|
||||
if (!typeof(T).IsValueType && array.GetType() != typeof(T[]))
|
||||
ThrowHelper.ThrowArrayTypeMismatchException();
|
||||
|
||||
|
@ -59,6 +60,7 @@ namespace System
|
|||
this = default;
|
||||
return; // returns default
|
||||
}
|
||||
|
||||
if (!typeof(T).IsValueType && array.GetType() != typeof(T[]))
|
||||
ThrowHelper.ThrowArrayTypeMismatchException();
|
||||
if ((uint)start > (uint)array.Length)
|
||||
|
@ -91,16 +93,11 @@ namespace System
|
|||
this = default;
|
||||
return; // returns default
|
||||
}
|
||||
|
||||
if (!typeof(T).IsValueType && array.GetType() != typeof(T[]))
|
||||
ThrowHelper.ThrowArrayTypeMismatchException();
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#else
|
||||
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#endif
|
||||
|
||||
MemoryExtensions.ValidateSliceArguments(array.Length, start, length);
|
||||
|
||||
_object = array;
|
||||
_index = start;
|
||||
|
@ -226,7 +223,7 @@ namespace System
|
|||
{
|
||||
if ((uint)start > (uint)_length)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
// It is expected for _index + start to be negative if the memory is already pre-pinned.
|
||||
|
@ -244,14 +241,7 @@ namespace System
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Memory<T> Slice(int start, int length)
|
||||
{
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#else
|
||||
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#endif
|
||||
MemoryExtensions.ValidateSliceArguments(_length, start, length);
|
||||
|
||||
// It is expected for _index + start to be negative if the memory is already pre-pinned.
|
||||
return new Memory<T>(_object, _index + start, length);
|
||||
|
@ -324,25 +314,12 @@ namespace System
|
|||
// least to be in-bounds when compared with the original Memory<T> instance, so using the span won't
|
||||
// AV the process.
|
||||
|
||||
// We use 'nuint' because it gives us a free early zero-extension to 64 bits when running on a 64-bit platform.
|
||||
nuint desiredStartIndex = (uint)_index & (uint)ReadOnlyMemory<T>.RemoveFlagsBitMask;
|
||||
|
||||
int desiredStartIndex = _index & ReadOnlyMemory<T>.RemoveFlagsBitMask;
|
||||
int desiredLength = _length;
|
||||
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)desiredStartIndex + (ulong)(uint)desiredLength > (ulong)(uint)lengthOfUnderlyingSpan)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
}
|
||||
#else
|
||||
if ((uint)desiredStartIndex > (uint)lengthOfUnderlyingSpan || (uint)desiredLength > (uint)lengthOfUnderlyingSpan - (uint)desiredStartIndex)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
}
|
||||
#endif
|
||||
MemoryExtensions.ValidateSliceArguments(lengthOfUnderlyingSpan, desiredStartIndex, desiredLength);
|
||||
|
||||
refToReturn = ref Unsafe.Add(ref refToReturn, desiredStartIndex);
|
||||
refToReturn = ref Unsafe.Add(ref refToReturn, (uint)desiredStartIndex);
|
||||
lengthOfUnderlyingSpan = desiredLength;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,31 @@ namespace System
|
|||
/// </summary>
|
||||
public static partial class MemoryExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static bool SliceArgumentsAreValid(int sourceLength, int start, int length)
|
||||
{
|
||||
#if TARGET_64BIT
|
||||
// Since start and length are both 32-bit, their sum can be computed across a 64-bit domain
|
||||
// without loss of fidelity. The cast to uint before the cast to ulong ensures that the
|
||||
// extension from 32- to 64-bit is zero-extending rather than sign-extending. The end result
|
||||
// of this is that if either input is negative or if the input sum overflows past Int32.MaxValue,
|
||||
// that information is captured correctly in the comparison against the source length.
|
||||
// We don't use this same mechanism in a 32-bit process due to the overhead of 64-bit arithmetic.
|
||||
return (ulong)(uint)start + (ulong)(uint)length <= (ulong)(uint)sourceLength;
|
||||
#else
|
||||
return (uint)start <= (uint)sourceLength && (uint)length <= (uint)(sourceLength - start);
|
||||
#endif
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void ValidateSliceArguments(int sourceLength, int start, int length)
|
||||
{
|
||||
if (!SliceArgumentsAreValid(sourceLength, start, length))
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new span over the portion of the target array.
|
||||
/// </summary>
|
||||
|
@ -116,12 +141,12 @@ namespace System
|
|||
if (text == null)
|
||||
{
|
||||
if (start != 0)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
return default;
|
||||
}
|
||||
|
||||
if ((uint)start > (uint)text.Length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
|
||||
return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), (nint)(uint)start /* force zero-extension */), text.Length - start);
|
||||
}
|
||||
|
@ -137,7 +162,7 @@ namespace System
|
|||
{
|
||||
if (!startIndex.Equals(Index.Start))
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
return default;
|
||||
|
@ -146,7 +171,7 @@ namespace System
|
|||
int actualIndex = startIndex.GetOffset(text.Length);
|
||||
if ((uint)actualIndex > (uint)text.Length)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), (nint)(uint)actualIndex /* force zero-extension */), text.Length - actualIndex);
|
||||
|
@ -194,18 +219,11 @@ namespace System
|
|||
if (text == null)
|
||||
{
|
||||
if (start != 0 || length != 0)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
return default;
|
||||
}
|
||||
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)text.Length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
#else
|
||||
if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
#endif
|
||||
ValidateSliceArguments(text.Length, start, length);
|
||||
|
||||
return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), (nint)(uint)start /* force zero-extension */), length);
|
||||
}
|
||||
|
@ -233,12 +251,12 @@ namespace System
|
|||
if (text == null)
|
||||
{
|
||||
if (start != 0)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
return default;
|
||||
}
|
||||
|
||||
if ((uint)start > (uint)text.Length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
|
||||
return new ReadOnlyMemory<char>(text, start, text.Length - start);
|
||||
}
|
||||
|
@ -276,18 +294,11 @@ namespace System
|
|||
if (text == null)
|
||||
{
|
||||
if (start != 0 || length != 0)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
return default;
|
||||
}
|
||||
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)text.Length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
#else
|
||||
if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
#endif
|
||||
ValidateSliceArguments(text.Length, start, length);
|
||||
|
||||
return new ReadOnlyMemory<char>(text, start, length);
|
||||
}
|
||||
|
@ -3739,7 +3750,7 @@ namespace System
|
|||
public static Span<T> AsSpan<T>(this ArraySegment<T> segment, int start)
|
||||
{
|
||||
if (((uint)start) > (uint)segment.Count)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
|
||||
return new Span<T>(segment.Array, segment.Offset + start, segment.Count - start);
|
||||
}
|
||||
|
@ -3772,10 +3783,7 @@ namespace System
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Span<T> AsSpan<T>(this ArraySegment<T> segment, int start, int length)
|
||||
{
|
||||
if (((uint)start) > (uint)segment.Count)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
if (((uint)length) > (uint)(segment.Count - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
|
||||
ValidateSliceArguments(segment.Count, start, length);
|
||||
|
||||
return new Span<T>(segment.Array, segment.Offset + start, length);
|
||||
}
|
||||
|
@ -3881,7 +3889,7 @@ namespace System
|
|||
public static Memory<T> AsMemory<T>(this ArraySegment<T> segment, int start)
|
||||
{
|
||||
if (((uint)start) > (uint)segment.Count)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
|
||||
return new Memory<T>(segment.Array, segment.Offset + start, segment.Count - start);
|
||||
}
|
||||
|
@ -3900,10 +3908,7 @@ namespace System
|
|||
/// </exception>
|
||||
public static Memory<T> AsMemory<T>(this ArraySegment<T> segment, int start, int length)
|
||||
{
|
||||
if (((uint)start) > (uint)segment.Count)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
if (((uint)length) > (uint)(segment.Count - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
|
||||
ValidateSliceArguments(segment.Count, start, length);
|
||||
|
||||
return new Memory<T>(segment.Array, segment.Offset + start, length);
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ namespace System
|
|||
|
||||
private static void ThrowArgumentOutOfRangeException()
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("length");
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,14 +71,8 @@ namespace System
|
|||
this = default;
|
||||
return; // returns default
|
||||
}
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#else
|
||||
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#endif
|
||||
|
||||
MemoryExtensions.ValidateSliceArguments(array.Length, start, length);
|
||||
|
||||
_object = array;
|
||||
_index = start;
|
||||
|
@ -155,7 +149,7 @@ namespace System
|
|||
{
|
||||
if ((uint)start > (uint)_length)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
// It is expected for _index + start to be negative if the memory is already pre-pinned.
|
||||
|
@ -173,14 +167,7 @@ namespace System
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ReadOnlyMemory<T> Slice(int start, int length)
|
||||
{
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
#else
|
||||
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
|
||||
#endif
|
||||
MemoryExtensions.ValidateSliceArguments(_length, start, length);
|
||||
|
||||
// It is expected for _index + start to be negative if the memory is already pre-pinned.
|
||||
return new ReadOnlyMemory<T>(_object, _index + start, length);
|
||||
|
@ -246,25 +233,12 @@ namespace System
|
|||
// least to be in-bounds when compared with the original Memory<T> instance, so using the span won't
|
||||
// AV the process.
|
||||
|
||||
// We use 'nuint' because it gives us a free early zero-extension to 64 bits when running on a 64-bit platform.
|
||||
nuint desiredStartIndex = (uint)_index & (uint)RemoveFlagsBitMask;
|
||||
|
||||
int desiredStartIndex = _index & RemoveFlagsBitMask;
|
||||
int desiredLength = _length;
|
||||
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)desiredStartIndex + (ulong)(uint)desiredLength > (ulong)(uint)lengthOfUnderlyingSpan)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
}
|
||||
#else
|
||||
if ((uint)desiredStartIndex > (uint)lengthOfUnderlyingSpan || (uint)desiredLength > (uint)lengthOfUnderlyingSpan - (uint)desiredStartIndex)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
}
|
||||
#endif
|
||||
MemoryExtensions.ValidateSliceArguments(lengthOfUnderlyingSpan, desiredStartIndex, desiredLength);
|
||||
|
||||
refToReturn = ref Unsafe.Add(ref refToReturn, desiredStartIndex);
|
||||
refToReturn = ref Unsafe.Add(ref refToReturn, (uint)desiredStartIndex);
|
||||
lengthOfUnderlyingSpan = desiredLength;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,14 +71,8 @@ namespace System
|
|||
this = default;
|
||||
return; // returns default
|
||||
}
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#else
|
||||
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#endif
|
||||
|
||||
MemoryExtensions.ValidateSliceArguments(array.Length, start, length);
|
||||
|
||||
_reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */);
|
||||
_length = length;
|
||||
|
@ -387,14 +381,7 @@ namespace System
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ReadOnlySpan<T> Slice(int start, int length)
|
||||
{
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#else
|
||||
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#endif
|
||||
MemoryExtensions.ValidateSliceArguments(_length, start, length);
|
||||
|
||||
return new ReadOnlySpan<T>(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), length);
|
||||
}
|
||||
|
|
|
@ -606,10 +606,11 @@ namespace System.Runtime.InteropServices
|
|||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
return default;
|
||||
}
|
||||
|
||||
if (!typeof(T).IsValueType && array.GetType() != typeof(T[]))
|
||||
ThrowHelper.ThrowArrayTypeMismatchException();
|
||||
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
|
||||
MemoryExtensions.ValidateSliceArguments(array.Length, start, length);
|
||||
|
||||
// Before using _index, check if _index < 0, then 'and' it with RemoveFlagsBitMask
|
||||
return new Memory<T>((object)array, start | (1 << 31), length);
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace System
|
|||
this = default;
|
||||
return; // returns default
|
||||
}
|
||||
|
||||
if (!typeof(T).IsValueType && array.GetType() != typeof(T[]))
|
||||
ThrowHelper.ThrowArrayTypeMismatchException();
|
||||
|
||||
|
@ -74,16 +75,11 @@ namespace System
|
|||
this = default;
|
||||
return; // returns default
|
||||
}
|
||||
|
||||
if (!typeof(T).IsValueType && array.GetType() != typeof(T[]))
|
||||
ThrowHelper.ThrowArrayTypeMismatchException();
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)array.Length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#else
|
||||
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#endif
|
||||
|
||||
MemoryExtensions.ValidateSliceArguments(array.Length, start, length);
|
||||
|
||||
_reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */);
|
||||
_length = length;
|
||||
|
@ -411,19 +407,7 @@ namespace System
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Span<T> Slice(int start, int length)
|
||||
{
|
||||
#if TARGET_64BIT
|
||||
// Since start and length are both 32-bit, their sum can be computed across a 64-bit domain
|
||||
// without loss of fidelity. The cast to uint before the cast to ulong ensures that the
|
||||
// extension from 32- to 64-bit is zero-extending rather than sign-extending. The end result
|
||||
// of this is that if either input is negative or if the input sum overflows past Int32.MaxValue,
|
||||
// that information is captured correctly in the comparison against the backing _length field.
|
||||
// We don't use this same mechanism in a 32-bit process due to the overhead of 64-bit arithmetic.
|
||||
if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)_length)
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#else
|
||||
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||
#endif
|
||||
MemoryExtensions.ValidateSliceArguments(_length, start, length);
|
||||
|
||||
return new Span<T>(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), length);
|
||||
}
|
||||
|
|
|
@ -2237,12 +2237,7 @@ namespace System
|
|||
|
||||
public string Substring(int startIndex, int length)
|
||||
{
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)startIndex + (ulong)(uint)length > (ulong)(uint)Length)
|
||||
#else
|
||||
if ((uint)startIndex > (uint)Length || (uint)length > (uint)(Length - startIndex))
|
||||
#endif
|
||||
if (!MemoryExtensions.SliceArgumentsAreValid(Length, startIndex, length))
|
||||
{
|
||||
ThrowSubstringArgumentOutOfRange(startIndex, length);
|
||||
}
|
||||
|
|
|
@ -368,20 +368,11 @@ namespace System
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal bool TryGetSpan(int startIndex, int count, out ReadOnlySpan<char> slice)
|
||||
{
|
||||
#if TARGET_64BIT
|
||||
// See comment in Span<T>.Slice for how this works.
|
||||
if ((ulong)(uint)startIndex + (ulong)(uint)count > (ulong)(uint)Length)
|
||||
if (!MemoryExtensions.SliceArgumentsAreValid(Length, startIndex, count))
|
||||
{
|
||||
slice = default;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if ((uint)startIndex > (uint)Length || (uint)count > (uint)(Length - startIndex))
|
||||
{
|
||||
slice = default;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
slice = new ReadOnlySpan<char>(ref Unsafe.Add(ref _firstChar, (nint)(uint)startIndex /* force zero-extension */), count);
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue