}
if (default(T) == null && array.GetType() != typeof(T[]))
ThrowHelper.ThrowArrayTypeMismatchException();
+#if BIT64
+ // 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
_object = array;
_index = start;
// Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not.
int capturedLength = _length;
int actualLength = capturedLength & RemoveFlagsBitMask;
+#if BIT64
+ // See comment in Span<T>.Slice for how this works.
+ if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)actualLength)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+#else
if ((uint)start > (uint)actualLength || (uint)length > (uint)(actualLength - start))
- {
ThrowHelper.ThrowArgumentOutOfRangeException();
- }
+#endif
// Set the high-bit to match the this._length high bit (1 for pre-pinned, 0 for unpinned).
return new Memory<T>(_object, _index + start, length | (capturedLength & ~RemoveFlagsBitMask));
return default;
}
+#if BIT64
+ // 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
return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), length);
}
return default;
}
+#if BIT64
+ // 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
return new ReadOnlyMemory<char>(text, start, length);
}
this = default;
return; // returns default
}
+#if BIT64
+ // 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
_object = array;
_index = start;
// Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not.
int capturedLength = _length;
int actualLength = _length & RemoveFlagsBitMask;
+#if BIT64
+ // See comment in Span<T>.Slice for how this works.
+ if ((ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)actualLength)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+#else
if ((uint)start > (uint)actualLength || (uint)length > (uint)(actualLength - start))
- {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
- }
+#endif
// Set the high-bit to match the this._length high bit (1 for pre-pinned, 0 for unpinned).
return new ReadOnlyMemory<T>(_object, _index + start, length | (capturedLength & ~RemoveFlagsBitMask));
this = default;
return; // returns default
}
+#if BIT64
+ // 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
_pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
_length = length;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<T> Slice(int start, int length)
{
+#if BIT64
+ // 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
return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
}
}
if (default(T) == null && array.GetType() != typeof(T[]))
ThrowHelper.ThrowArrayTypeMismatchException();
+#if BIT64
+ // 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
_pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
_length = length;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> Slice(int start, int length)
{
+#if BIT64
+ // 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
return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
}