diff --git a/netcore/System.Private.CoreLib/shared/System/Index.cs b/netcore/System.Private.CoreLib/shared/System/Index.cs
index 887506ec629a..94d7be198916 100644
--- a/netcore/System.Private.CoreLib/shared/System/Index.cs
+++ b/netcore/System.Private.CoreLib/shared/System/Index.cs
@@ -3,34 +3,138 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Runtime.CompilerServices;
namespace System
{
+ /// Represent a type can be used to index a collection either from the start or the end.
+ ///
+ /// Index is used by the C# compiler to support the new index syntax
+ ///
+ /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ;
+ /// int lastElement = someArray[^1]; // lastElement = 5
+ ///
+ ///
public readonly struct Index : IEquatable
{
private readonly int _value;
- public Index(int value, bool fromEnd)
+ /// Construct an Index using a value and indicating if the index is from the start or from the end.
+ /// The index value. it has to be zero or positive number.
+ /// Indicating if the index is from the start or from the end.
+ ///
+ /// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Index(int value, bool fromEnd = false)
{
if (value < 0)
{
ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException();
}
- _value = fromEnd ? ~value : value;
+ if (fromEnd)
+ _value = ~value;
+ else
+ _value = value;
}
- public int Value => _value < 0 ? ~_value : _value;
- public bool FromEnd => _value < 0;
+ // The following private constructors mainly created for perf reason to avoid the checks
+ private Index(int value)
+ {
+ _value = value;
+ }
+
+ /// Create an Index pointing at first element.
+ public static Index Start => new Index(0);
+
+ /// Create an Index pointing at beyond last element.
+ public static Index End => new Index(~0);
+
+ /// Create an Index from the start at the position indicated by the value.
+ /// The index value from the start.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Index FromStart(int value)
+ {
+ if (value < 0)
+ {
+ ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException();
+ }
+
+ return new Index(value);
+ }
+
+ /// Create an Index from the end at the position indicated by the value.
+ /// The index value from the end.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Index FromEnd(int value)
+ {
+ if (value < 0)
+ {
+ ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException();
+ }
+
+ return new Index(~value);
+ }
+
+ /// Returns the index value.
+ public int Value
+ {
+ get
+ {
+ if (_value < 0)
+ return ~_value;
+ else
+ return _value;
+ }
+ }
+
+ /// Indicates whether the index is from the start or the end.
+ public bool IsFromEnd => _value < 0;
+
+ /// Calculate the offset from the start using the giving collection length.
+ /// The length of the collection that the Index will be used with. length has to be a positive value
+ ///
+ /// For performance reason, we don't validate the input length parameter and the returned offset value against negative values.
+ /// we don't validate either the returned offset is greater than the input length.
+ /// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and
+ /// then used to index a collection will get out of range exception which will be same affect as the validation.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public int GetOffset(int length)
+ {
+ int offset;
+
+ if (IsFromEnd)
+ offset = length - (~_value);
+ else
+ offset = _value;
+
+ return offset;
+ }
+
+ /// Indicates whether the current Index object is equal to another object of the same type.
+ /// An object to compare with this object
public override bool Equals(object value) => value is Index && _value == ((Index)value)._value;
+
+ /// Indicates whether the current Index object is equal to another Index object.
+ /// An object to compare with this object
public bool Equals (Index other) => _value == other._value;
- public override int GetHashCode()
+ /// Returns the hash code for this instance.
+ public override int GetHashCode() => _value;
+
+ /// Converts integer number to an Index.
+ public static implicit operator Index(int value) => FromStart(value);
+
+ /// Converts the value of the current Index object to its equivalent string representation.
+ public override string ToString()
{
- return _value;
- }
+ if (IsFromEnd)
+ return ToStringFromEnd();
- public override string ToString() => FromEnd ? ToStringFromEnd() : ((uint)Value).ToString();
+ return ((uint)Value).ToString();
+ }
private string ToStringFromEnd()
{
@@ -41,7 +145,5 @@ private string ToStringFromEnd()
return new string(span.Slice(0, charsWritten + 1));
}
- public static implicit operator Index(int value)
- => new Index(value, fromEnd: false);
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/Memory.cs b/netcore/System.Private.CoreLib/shared/System/Memory.cs
index 033b806c20d5..2f5d75ec894e 100644
--- a/netcore/System.Private.CoreLib/shared/System/Memory.cs
+++ b/netcore/System.Private.CoreLib/shared/System/Memory.cs
@@ -30,7 +30,7 @@ public readonly struct Memory
private readonly object _object;
private readonly int _index;
private readonly int _length;
-
+
///
/// Creates a new memory over the entirety of the target array.
///
@@ -258,6 +258,35 @@ public Memory Slice(int start, int length)
return new Memory(_object, _index + start, length);
}
+ ///
+ /// Forms a slice out of the given memory, beginning at 'startIndex'
+ ///
+ /// The index at which to begin this slice.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Memory Slice(Index startIndex)
+ {
+ int actualIndex = startIndex.GetOffset(_length);
+ return Slice(actualIndex);
+ }
+
+ ///
+ /// Forms a slice out of the given memory using the range start and end indexes.
+ ///
+ /// The range used to slice the memory using its start and end indexes.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Memory Slice(Range range)
+ {
+ (int start, int length) = range.GetOffsetAndLength(_length);
+ // It is expected for _index + start to be negative if the memory is already pre-pinned.
+ return new Memory(_object, _index + start, length);
+ }
+
+ ///
+ /// Forms a slice out of the given memory using the range start and end indexes.
+ ///
+ /// The range used to slice the memory using its start and end indexes.
+ public Memory this[Range range] => Slice(range);
+
///
/// Returns a span from the memory.
///
@@ -336,7 +365,7 @@ public unsafe Span Span
ThrowHelper.ThrowArgumentOutOfRangeException();
}
#endif
-
+
refToReturn = ref Unsafe.Add(ref refToReturn, desiredStartIndex);
lengthOfUnderlyingSpan = desiredLength;
}
@@ -477,4 +506,4 @@ public override int GetHashCode()
return (_object != null) ? HashCode.Combine(RuntimeHelpers.GetHashCode(_object), _index, _length) : 0;
}
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/MemoryExtensions.cs b/netcore/System.Private.CoreLib/shared/System/MemoryExtensions.cs
index 34b49d41234e..99cbef8a35c7 100644
--- a/netcore/System.Private.CoreLib/shared/System/MemoryExtensions.cs
+++ b/netcore/System.Private.CoreLib/shared/System/MemoryExtensions.cs
@@ -125,7 +125,7 @@ public static ReadOnlySpan TrimEnd(this ReadOnlySpan span, char trim
}
///
- /// Removes all leading and trailing occurrences of a set of characters specified
+ /// Removes all leading and trailing occurrences of a set of characters specified
/// in a readonly span from the span.
///
/// The source span from which the characters are removed.
@@ -137,7 +137,7 @@ public static ReadOnlySpan Trim(this ReadOnlySpan span, ReadOnlySpan
}
///
- /// Removes all leading occurrences of a set of characters specified
+ /// Removes all leading occurrences of a set of characters specified
/// in a readonly span from the span.
///
/// The source span from which the characters are removed.
@@ -166,7 +166,7 @@ public static ReadOnlySpan TrimStart(this ReadOnlySpan span, ReadOnl
}
///
- /// Removes all trailing occurrences of a set of characters specified
+ /// Removes all trailing occurrences of a set of characters specified
/// in a readonly span from the span.
///
/// The source span from which the characters are removed.
@@ -258,7 +258,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
+ /// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The value to search for.
@@ -282,7 +282,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
+ /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The sequence to search for.
@@ -307,7 +307,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
}
///
- /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
+ /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The value to search for.
@@ -331,7 +331,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
+ /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The sequence to search for.
@@ -350,7 +350,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
}
///
- /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T).
+ /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T).
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool SequenceEqual(this Span span, ReadOnlySpan other)
@@ -369,7 +369,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(other)),
}
///
- /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T).
+ /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T).
///
public static int SequenceCompareTo(this Span span, ReadOnlySpan other)
where T : IComparable
@@ -392,7 +392,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(other)),
}
///
- /// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
+ /// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The value to search for.
@@ -416,7 +416,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
+ /// Searches for the specified sequence and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The sequence to search for.
@@ -441,7 +441,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
}
///
- /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
+ /// Searches for the specified value and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The value to search for.
@@ -465,7 +465,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
+ /// Searches for the specified sequence and returns the index of its last occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
///
/// The span to search.
/// The sequence to search for.
@@ -539,7 +539,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
+ /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// The set of values to search for.
@@ -661,7 +661,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
+ /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// One of the values to search for.
@@ -690,7 +690,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
+ /// Searches for the first index of any of the specified values similar to calling IndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// The set of values to search for.
@@ -829,7 +829,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
+ /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// The set of values to search for.
@@ -868,7 +868,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
+ /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// One of the values to search for.
@@ -890,7 +890,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
}
///
- /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
+ /// Searches for the last index of any of the specified values similar to calling LastIndexOf several times with the logical OR operator. If not found, returns -1.
///
/// The span to search.
/// The set of values to search for.
@@ -909,7 +909,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(values)),
}
///
- /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T).
+ /// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T).
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool SequenceEqual(this ReadOnlySpan span, ReadOnlySpan other)
@@ -927,7 +927,7 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(other)),
}
///
- /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T).
+ /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T).
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int SequenceCompareTo(this ReadOnlySpan span, ReadOnlySpan other)
@@ -1132,6 +1132,19 @@ public static Span AsSpan(this ArraySegment segment, int start)
return new Span(segment.Array, segment.Offset + start, segment.Count - start);
}
+ ///
+ /// Creates a new Span over the portion of the target array beginning
+ /// at 'startIndex' and ending at the end of the segment.
+ ///
+ /// The target array.
+ /// The index at which to begin the Span.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span AsSpan(this ArraySegment segment, Index startIndex)
+ {
+ int actualIndex = startIndex.GetOffset(segment.Count);
+ return AsSpan(segment, actualIndex);
+ }
+
///
/// Creates a new Span over the portion of the target array beginning
/// at 'start' index and ending at 'end' index (exclusive).
@@ -1155,6 +1168,18 @@ public static Span AsSpan(this ArraySegment segment, int start, int len
return new Span(segment.Array, segment.Offset + start, length);
}
+ ///
+ /// Creates a new Span over the portion of the target array using the range start and end indexes
+ ///
+ /// The target array.
+ /// The range which has start and end indexes to use for slicing the array.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span AsSpan(this ArraySegment segment, Range range)
+ {
+ (int start, int length) = range.GetOffsetAndLength(segment.Count);
+ return new Span(segment.Array, segment.Offset + start, length);
+ }
+
///
/// Creates a new memory over the target array.
///
@@ -1173,6 +1198,24 @@ public static Span AsSpan(this ArraySegment segment, int start, int len
///
public static Memory AsMemory(this T[] array, int start) => new Memory(array, start);
+ ///
+ /// Creates a new memory over the portion of the target array starting from
+ /// 'startIndex' to the end of the array.
+ ///
+ public static Memory AsMemory(this T[] array, Index startIndex)
+ {
+ if (array == null)
+ {
+ if (!startIndex.Equals(Index.Start))
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+
+ return default;
+ }
+
+ int actualIndex = startIndex.GetOffset(array.Length);
+ return new Memory(array, actualIndex);
+ }
+
///
/// Creates a new memory over the portion of the target array beginning
/// at 'start' index and ending at 'end' index (exclusive).
@@ -1187,6 +1230,26 @@ public static Span AsSpan(this ArraySegment segment, int start, int len
///
public static Memory AsMemory(this T[] array, int start, int length) => new Memory(array, start, length);
+ ///
+ /// Creates a new memory over the portion of the target array beginning at inclusive start index of the range
+ /// and ending at the exclusive end index of the range.
+ ///
+ public static Memory AsMemory(this T[] array, Range range)
+ {
+ if (array == null)
+ {
+ Index startIndex = range.Start;
+ Index endIndex = range.End;
+ if (!startIndex.Equals(Index.Start) || !endIndex.Equals(Index.Start))
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+
+ return default;
+ }
+
+ (int start, int length) = range.GetOffsetAndLength(array.Length);
+ return new Memory(array, start, length);
+ }
+
///
/// Creates a new memory over the portion of the target array.
///
@@ -1237,7 +1300,7 @@ public static Memory AsMemory(this ArraySegment segment, int start, int
/// Copies the contents of the array into the span. If the source
/// and destinations overlap, this method behaves as if the original values in
/// a temporary location before the destination is overwritten.
- ///
+ ///
///The array to copy items from.
/// The span to copy items into.
///
@@ -1254,7 +1317,7 @@ public static void CopyTo(this T[] source, Span destination)
/// Copies the contents of the array into the memory. If the source
/// and destinations overlap, this method behaves as if the original values are in
/// a temporary location before the destination is overwritten.
- ///
+ ///
///The array to copy items from.
/// The memory to copy items into.
///
@@ -1353,16 +1416,16 @@ public static void CopyTo(this T[] source, Memory destination)
// nuint x2 = xLength
// nuint y1 = (nuint)Unsafe.ByteOffset(xRef, yRef)
// nuint y2 = y1 + yLength
- //
+ //
// xRef relative to xRef is 0.
- //
+ //
// x2 is simply x1 + xLength. This cannot overflow.
- //
+ //
// yRef relative to xRef is (yRef - xRef). If (yRef - xRef) is
// negative, casting it to an unsigned 32-bit integer turns it into
// (yRef - xRef + 2³²). So, in the example above, y1 moves to the right
// of x2.
- //
+ //
// y2 is simply y1 + yLength. Note that this can overflow, as in the
// example above, which must be avoided.
//
@@ -1389,11 +1452,11 @@ public static void CopyTo(this T[] source, Memory destination)
// integers:
//
// == (y1 < xLength) || (y1 > -yLength)
- //
+ //
// Due to modulo arithmetic, this gives exactly same result *except* if
// yLength is zero, since 2³² - 0 is 0 and not 2³². So the case
// y.IsEmpty must be handled separately first.
- //
+ //
///
/// Determines whether two sequences overlap in memory.
@@ -1674,4 +1737,4 @@ private static bool IsTypeComparableAsBytes(out nuint size)
return false;
}
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/Range.cs b/netcore/System.Private.CoreLib/shared/System/Range.cs
index b858da2fb438..db3523c1e453 100644
--- a/netcore/System.Private.CoreLib/shared/System/Range.cs
+++ b/netcore/System.Private.CoreLib/shared/System/Range.cs
@@ -3,20 +3,38 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Runtime.CompilerServices;
namespace System
{
+ /// Represent a range has start and end indexes.
+ ///
+ /// Range is used by the C# compiler to support the range syntax.
+ ///
+ /// int[] someArray = new int[5] { 1, 2, 3, 4, 5 };
+ /// int[] subArray1 = someArray[0..2]; // { 1, 2 }
+ /// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 }
+ ///
+ ///
public readonly struct Range : IEquatable
{
+ /// Represent the inclusive start index of the Range.
public Index Start { get; }
+
+ /// Represent the exclusive end index of the Range.
public Index End { get; }
- private Range(Index start, Index end)
+ /// Construct a Range object using the start and end indexes.
+ /// Represent the inclusive start index of the range.
+ /// Represent the exclusive end index of the range.
+ public Range(Index start, Index end)
{
Start = start;
End = end;
}
+ /// Indicates whether the current Range object is equal to another object of the same type.
+ /// An object to compare with this object
public override bool Equals(object value)
{
if (value is Range)
@@ -28,20 +46,24 @@ public override bool Equals(object value)
return false;
}
+ /// Indicates whether the current Range object is equal to another Range object.
+ /// An object to compare with this object
public bool Equals (Range other) => other.Start.Equals(Start) && other.End.Equals(End);
+ /// Returns the hash code for this instance.
public override int GetHashCode()
{
return HashCode.Combine(Start.GetHashCode(), End.GetHashCode());
}
+ /// Converts the value of the current Range object to its equivalent string representation.
public override string ToString()
{
Span span = stackalloc char[2 + (2 * 11)]; // 2 for "..", then for each index 1 for '^' and 10 for longest possible uint
int charsWritten;
int pos = 0;
- if (Start.FromEnd)
+ if (Start.IsFromEnd)
{
span[0] = '^';
pos = 1;
@@ -53,7 +75,7 @@ public override string ToString()
span[pos++] = '.';
span[pos++] = '.';
- if (End.FromEnd)
+ if (End.IsFromEnd)
{
span[pos++] = '^';
}
@@ -64,9 +86,63 @@ public override string ToString()
return new string(span.Slice(0, pos));
}
- public static Range Create(Index start, Index end) => new Range(start, end);
- public static Range FromStart(Index start) => new Range(start, new Index(0, fromEnd: true));
- public static Range ToEnd(Index end) => new Range(new Index(0, fromEnd: false), end);
- public static Range All() => new Range(new Index(0, fromEnd: false), new Index(0, fromEnd: true));
+ /// Create a Range object starting from start index to the end of the collection.
+ public static Range StartAt(Index start) => new Range(start, Index.End);
+
+ /// Create a Range object starting from first element in the collection to the end Index.
+ public static Range EndAt(Index end) => new Range(Index.Start, end);
+
+ /// Create a Range object starting from first element to the end.
+ public static Range All => new Range(Index.Start, Index.End);
+
+ /// Destruct the range object according to a collection length and return the start offset from the beginning and the length of this range.
+ /// The length of the collection that the range will be used with. length has to be a positive value
+ ///
+ /// For performance reason, we don't validate the input length parameter against negative values.
+ /// It is expected Range will be used with collections which always have non negative length/count.
+ /// We validate the range is inside the length scope though.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public OffsetAndLength GetOffsetAndLength(int length)
+ {
+ int start;
+ Index startIndex = Start;
+ if (startIndex.IsFromEnd)
+ start = length - startIndex.Value;
+ else
+ start = startIndex.Value;
+
+ int end;
+ Index endIndex = End;
+ if (endIndex.IsFromEnd)
+ end = length - endIndex.Value;
+ else
+ end = endIndex.Value;
+
+ if ((uint)end > (uint)length || (uint)start > (uint)end)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
+ }
+
+ return new OffsetAndLength(start, end - start);
+ }
+
+ public readonly struct OffsetAndLength
+ {
+ public int Offset { get; }
+ public int Length { get; }
+
+ public OffsetAndLength(int offset, int length)
+ {
+ Offset = offset;
+ Length = length;
+ }
+
+ public void Deconstruct(out int offset, out int length)
+ {
+ offset = Offset;
+ length = Length;
+ }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/ReadOnlyMemory.cs b/netcore/System.Private.CoreLib/shared/System/ReadOnlyMemory.cs
index 8fd659aeaa0c..5cb2da0ebc7c 100644
--- a/netcore/System.Private.CoreLib/shared/System/ReadOnlyMemory.cs
+++ b/netcore/System.Private.CoreLib/shared/System/ReadOnlyMemory.cs
@@ -187,6 +187,35 @@ public ReadOnlyMemory Slice(int start, int length)
return new ReadOnlyMemory(_object, _index + start, length);
}
+ ///
+ /// Forms a slice out of the given memory, beginning at 'startIndex'
+ ///
+ /// The index at which to begin this slice.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlyMemory Slice(Index startIndex)
+ {
+ int actualIndex = startIndex.GetOffset(_length);
+ return Slice(actualIndex);
+ }
+
+ ///
+ /// Forms a slice out of the given memory using the range start and end indexes.
+ ///
+ /// The range used to slice the memory using its start and end indexes.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlyMemory Slice(Range range)
+ {
+ (int start, int length) = range.GetOffsetAndLength(_length);
+ // It is expected for _index + start to be negative if the memory is already pre-pinned.
+ return new ReadOnlyMemory(_object, _index + start, length);
+ }
+
+ ///
+ /// Forms a slice out of the given memory using the range start and end indexes.
+ ///
+ /// The range used to slice the memory using its start and end indexes.
+ public ReadOnlyMemory this[Range range] => Slice(range);
+
///
/// Returns a span from the memory.
///
@@ -386,7 +415,7 @@ public override int GetHashCode()
// code is based on object identity and referential equality, not deep equality (as common with string).
return (_object != null) ? HashCode.Combine(RuntimeHelpers.GetHashCode(_object), _index, _length) : 0;
}
-
+
/// Gets the state of the memory as individual fields.
/// The offset.
/// The count.
@@ -399,4 +428,4 @@ internal object GetObjectStartLength(out int start, out int length)
return _object;
}
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/ReadOnlySpan.Fast.cs b/netcore/System.Private.CoreLib/shared/System/ReadOnlySpan.Fast.cs
index b2ce53be2cd0..9426ce820104 100644
--- a/netcore/System.Private.CoreLib/shared/System/ReadOnlySpan.Fast.cs
+++ b/netcore/System.Private.CoreLib/shared/System/ReadOnlySpan.Fast.cs
@@ -157,20 +157,12 @@ public ref readonly T this[Index index]
get
{
// Evaluate the actual index first because it helps performance
- int actualIndex = index.FromEnd ? _length - index.Value : index.Value;
+ int actualIndex = index.GetOffset(_length);
return ref this [actualIndex];
}
}
- public ReadOnlySpan this[Range range]
- {
- get
- {
- int start = range.Start.FromEnd ? _length - range.Start.Value : range.Start.Value;
- int end = range.End.FromEnd ? _length - range.End.Value : range.End.Value;
- return Slice(start, end - start);
- }
- }
+ public ReadOnlySpan this[Range range] => Slice(range);
///
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns null reference.
@@ -296,6 +288,33 @@ public ReadOnlySpan Slice(int start, int length)
return new ReadOnlySpan(ref Unsafe.Add(ref _pointer.Value, start), length);
}
+ ///
+ /// Forms a slice out of the given read-only span, beginning at 'startIndex'
+ ///
+ /// The index at which to begin this slice.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan Slice(Index startIndex)
+ {
+ int actualIndex;
+ if (startIndex.IsFromEnd)
+ actualIndex = _length - startIndex.Value;
+ else
+ actualIndex = startIndex.Value;
+
+ return Slice(actualIndex);
+ }
+
+ ///
+ /// Forms a slice out of the given read-only span, beginning at range start index to the range end
+ ///
+ /// The range which has the start and end indexes used to slice the span.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan Slice(Range range)
+ {
+ (int start, int length) = range.GetOffsetAndLength(_length);
+ return new ReadOnlySpan(ref Unsafe.Add(ref _pointer.Value, start), length);
+ }
+
///
/// Copies the contents of this read-only span into a new array. This heap
/// allocates, so should generally be avoided, however it is sometimes
@@ -311,4 +330,4 @@ public T[] ToArray()
return destination;
}
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/ReadOnlySpan.cs b/netcore/System.Private.CoreLib/shared/System/ReadOnlySpan.cs
index 17b7134e27c0..bd22bb9c3f8f 100644
--- a/netcore/System.Private.CoreLib/shared/System/ReadOnlySpan.cs
+++ b/netcore/System.Private.CoreLib/shared/System/ReadOnlySpan.cs
@@ -134,4 +134,4 @@ public ref readonly T Current
}
}
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/Span.Fast.cs b/netcore/System.Private.CoreLib/shared/System/Span.Fast.cs
index 490767dc53c8..01148369ef94 100644
--- a/netcore/System.Private.CoreLib/shared/System/Span.Fast.cs
+++ b/netcore/System.Private.CoreLib/shared/System/Span.Fast.cs
@@ -163,20 +163,12 @@ public ref T this[Index index]
get
{
// Evaluate the actual index first because it helps performance
- int actualIndex = index.FromEnd ? _length - index.Value : index.Value;
+ int actualIndex = index.GetOffset(_length);
return ref this [actualIndex];
}
}
- public Span this[Range range]
- {
- get
- {
- int start = range.Start.FromEnd ? _length - range.Start.Value : range.Start.Value;
- int end = range.End.FromEnd ? _length - range.End.Value : range.End.Value;
- return Slice(start, end - start);
- }
- }
+ public Span this[Range range] => Slice(range);
///
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns null reference.
@@ -380,6 +372,28 @@ public Span Slice(int start, int length)
return new Span(ref Unsafe.Add(ref _pointer.Value, start), length);
}
+ ///
+ /// Forms a slice out of the given span, beginning at 'startIndex'
+ ///
+ /// The index at which to begin this slice.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span Slice(Index startIndex)
+ {
+ int actualIndex = startIndex.GetOffset(_length);
+ return Slice(actualIndex);
+ }
+
+ ///
+ /// Forms a slice out of the given span, beginning at range start index to the range end
+ ///
+ /// The range which has the start and end indexes used to slice the span.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span Slice(Range range)
+ {
+ (int start, int length) = range.GetOffsetAndLength(_length);
+ return new Span(ref Unsafe.Add(ref _pointer.Value, start), length);
+ }
+
///
/// Copies the contents of this span into a new array. This heap
/// allocates, so should generally be avoided, however it is sometimes
@@ -396,4 +410,4 @@ public T[] ToArray()
return destination;
}
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/String.Manipulation.cs b/netcore/System.Private.CoreLib/shared/System/String.Manipulation.cs
index f183ed6a59dc..125529b2b1e8 100644
--- a/netcore/System.Private.CoreLib/shared/System/String.Manipulation.cs
+++ b/netcore/System.Private.CoreLib/shared/System/String.Manipulation.cs
@@ -1686,6 +1686,20 @@ public string Substring(int startIndex, int length)
return InternalSubString(startIndex, length);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public string Substring(Index startIndex)
+ {
+ int actualIndex = startIndex.GetOffset(Length);
+ return Substring(actualIndex);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public string Substring(Range range)
+ {
+ (int start, int length) = range.GetOffsetAndLength(Length);
+ return Substring(start, length);
+ }
+
private unsafe string InternalSubString(int startIndex, int length)
{
Debug.Assert(startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!");
@@ -1909,4 +1923,4 @@ private enum TrimType
Both = 2
}
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/String.cs b/netcore/System.Private.CoreLib/shared/System/String.cs
index 0958e865db7f..8d8ab93123c3 100644
--- a/netcore/System.Private.CoreLib/shared/System/String.cs
+++ b/netcore/System.Private.CoreLib/shared/System/String.cs
@@ -444,6 +444,19 @@ public static bool IsNullOrEmpty(string value)
return (value == null || 0u >= (uint)value.Length) ? true : false;
}
+ [System.Runtime.CompilerServices.IndexerName("Chars")]
+ public char this[Index index]
+ {
+ get
+ {
+ int actualIndex = index.GetOffset(Length);
+ return this[actualIndex];
+ }
+ }
+
+ [System.Runtime.CompilerServices.IndexerName("Chars")]
+ public string this[Range range] => Substring(range);
+
public static bool IsNullOrWhiteSpace(string value)
{
if (value == null) return true;
@@ -672,7 +685,7 @@ private static void ThrowMustBeNullTerminatedString()
//
// IConvertible implementation
- //
+ //
public TypeCode GetTypeCode()
{
@@ -798,4 +811,4 @@ public string Normalize(NormalizationForm normalizationForm)
return Normalization.Normalize(this, normalizationForm);
}
}
-}
+}
\ No newline at end of file
diff --git a/netcore/System.Private.CoreLib/shared/System/ThrowHelper.cs b/netcore/System.Private.CoreLib/shared/System/ThrowHelper.cs
index 0c80cd3cd8e0..6cc1236253de 100644
--- a/netcore/System.Private.CoreLib/shared/System/ThrowHelper.cs
+++ b/netcore/System.Private.CoreLib/shared/System/ThrowHelper.cs
@@ -4,8 +4,8 @@
// This file defines an internal class used to throw exceptions in BCL code.
-// The main purpose is to reduce code size.
-//
+// The main purpose is to reduce code size.
+//
// The old way to throw an exception generates quite a lot IL code and assembly code.
// Following is an example:
// C# source
@@ -17,10 +17,10 @@
// IL_0012: newobj instance void System.ArgumentNullException::.ctor(string,string)
// IL_0017: throw
// which is 21bytes in IL.
-//
+//
// So we want to get rid of the ldstr and call to Environment.GetResource in IL.
// In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the
-// argument name and resource name in a small integer. The source code will be changed to
+// argument name and resource name in a small integer. The source code will be changed to
// ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key);
//
// The IL code will be 7 bytes.
@@ -29,11 +29,11 @@
// IL_000a: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
// IL_000f: ldarg.0
//
-// This will also reduce the Jitted code size a lot.
+// This will also reduce the Jitted code size a lot.
+//
+// It is very important we do this for generic classes because we can easily generate the same code
+// multiple times for different instantiation.
//
-// It is very important we do this for generic classes because we can easily generate the same code
-// multiple times for different instantiation.
-//
using System.Buffers;
using System.Collections.Generic;
@@ -66,34 +66,11 @@ internal static void ThrowArgumentOutOfRangeException()
throw new ArgumentOutOfRangeException();
}
- internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument)
- {
- throw new ArgumentOutOfRangeException(GetArgumentName(argument));
- }
-
- private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
- {
- return new ArgumentOutOfRangeException(GetArgumentName(argument), GetResourceString(resource));
- }
- internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
- {
- throw GetArgumentOutOfRangeException(argument, resource);
- }
- internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index()
- {
- throw GetArgumentOutOfRangeException(ExceptionArgument.startIndex,
- ExceptionResource.ArgumentOutOfRange_Index);
- }
- internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count()
- {
- throw GetArgumentOutOfRangeException(ExceptionArgument.count,
- ExceptionResource.ArgumentOutOfRange_Count);
- }
-
internal static void ThrowArgumentException_DestinationTooShort()
{
throw new ArgumentException(SR.Argument_DestinationTooShort);
}
+
internal static void ThrowArgumentException_OverlapAlignmentMismatch()
{
throw new ArgumentException(SR.Argument_OverlapAlignmentMismatch);
@@ -109,85 +86,120 @@ internal static void ThrowArgumentOutOfRange_IndexException()
throw GetArgumentOutOfRangeException(ExceptionArgument.index,
ExceptionResource.ArgumentOutOfRange_Index);
}
+
internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException()
{
throw GetArgumentOutOfRangeException(ExceptionArgument.index,
ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
+
internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException()
{
throw GetArgumentOutOfRangeException(ExceptionArgument.value,
ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
- private static ArgumentException GetWrongKeyTypeArgumentException(object key, Type targetType)
+ internal static void ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum()
{
- return new ArgumentException(SR.Format(SR.Arg_WrongType, key, targetType), nameof(key));
+ throw GetArgumentOutOfRangeException(ExceptionArgument.length,
+ ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
- internal static void ThrowWrongKeyTypeArgumentException(object key, Type targetType)
+
+ internal static void ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index()
{
- throw GetWrongKeyTypeArgumentException(key, targetType);
+ throw GetArgumentOutOfRangeException(ExceptionArgument.startIndex,
+ ExceptionResource.ArgumentOutOfRange_Index);
}
- private static ArgumentException GetWrongValueTypeArgumentException(object value, Type targetType)
+ internal static void ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count()
{
- return new ArgumentException(SR.Format(SR.Arg_WrongType, value, targetType), nameof(value));
+ throw GetArgumentOutOfRangeException(ExceptionArgument.count,
+ ExceptionResource.ArgumentOutOfRange_Count);
}
- internal static void ThrowWrongValueTypeArgumentException(object value, Type targetType)
+
+ internal static void ThrowArgumentOutOfRangeException_ArgumentOutOfRange_Enum()
{
- throw GetWrongValueTypeArgumentException(value, targetType);
+ throw GetArgumentOutOfRangeException(ExceptionArgument.type,
+ ExceptionResource.ArgumentOutOfRange_Enum);
}
- private static ArgumentException GetAddingDuplicateWithKeyArgumentException(object key)
+ internal static void ThrowWrongKeyTypeArgumentException(T key, Type targetType)
{
- return new ArgumentException(SR.Format(SR.Argument_AddingDuplicate, key));
+ // Generic key to move the boxing to the right hand side of throw
+ throw GetWrongKeyTypeArgumentException((object)key, targetType);
}
- internal static void ThrowAddingDuplicateWithKeyArgumentException(object key)
+
+ internal static void ThrowWrongValueTypeArgumentException(T value, Type targetType)
{
- throw GetAddingDuplicateWithKeyArgumentException(key);
+ // Generic key to move the boxing to the right hand side of throw
+ throw GetWrongValueTypeArgumentException((object)value, targetType);
}
- private static KeyNotFoundException GetKeyNotFoundException(object key)
+ private static ArgumentException GetAddingDuplicateWithKeyArgumentException(object key)
{
- throw new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString()));
+ return new ArgumentException(SR.Format(SR.Argument_AddingDuplicateWithKey, key));
}
- internal static void ThrowKeyNotFoundException(object key)
+
+ internal static void ThrowAddingDuplicateWithKeyArgumentException(T key)
{
- throw GetKeyNotFoundException(key);
+ // Generic key to move the boxing to the right hand side of throw
+ throw GetAddingDuplicateWithKeyArgumentException((object)key);
}
- internal static void ThrowArgumentException(ExceptionResource resource)
+ internal static void ThrowKeyNotFoundException(T key)
{
- throw new ArgumentException(GetResourceString(resource));
+ // Generic key to move the boxing to the right hand side of throw
+ throw GetKeyNotFoundException((object)key);
}
- private static ArgumentException GetArgumentException(ExceptionResource resource, ExceptionArgument argument)
+ internal static void ThrowArgumentException(ExceptionResource resource)
{
- return new ArgumentException(GetResourceString(resource), GetArgumentName(argument));
+ throw GetArgumentException(resource);
}
+
internal static void ThrowArgumentException(ExceptionResource resource, ExceptionArgument argument)
{
throw GetArgumentException(resource, argument);
}
- internal static void ThrowAggregateException(List exceptions)
+ private static ArgumentNullException GetArgumentNullException(ExceptionArgument argument)
{
- throw new AggregateException(exceptions);
+ return new ArgumentNullException(GetArgumentName(argument));
}
- internal static void ThrowArgumentException_Argument_InvalidArrayType()
+ internal static void ThrowArgumentNullException(ExceptionArgument argument)
{
- throw new ArgumentException(SR.Argument_InvalidArrayType);
+ throw GetArgumentNullException(argument);
}
- internal static void ThrowArgumentNullException(ExceptionArgument argument)
+ internal static void ThrowArgumentNullException(ExceptionResource resource)
+ {
+ throw new ArgumentNullException(GetResourceString(resource));
+ }
+
+ internal static void ThrowArgumentNullException(ExceptionArgument argument, ExceptionResource resource)
+ {
+ throw new ArgumentNullException(GetArgumentName(argument), GetResourceString(resource));
+ }
+
+ internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument)
{
- throw new ArgumentNullException(GetArgumentName(argument));
+ throw new ArgumentOutOfRangeException(GetArgumentName(argument));
+ }
+
+ internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
+ {
+ throw GetArgumentOutOfRangeException(argument, resource);
+ }
+
+ internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, int paramNumber, ExceptionResource resource)
+ {
+ throw GetArgumentOutOfRangeException(argument, paramNumber, resource);
}
internal static void ThrowInvalidOperationException(ExceptionResource resource)
{
- throw new InvalidOperationException(GetResourceString(resource));
+ throw GetInvalidOperationException(resource);
}
internal static void ThrowInvalidOperationException_OutstandingReferences()
@@ -195,14 +207,64 @@ internal static void ThrowInvalidOperationException_OutstandingReferences()
throw new InvalidOperationException(SR.Memory_OutstandingReferences);
}
- internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion()
+ internal static void ThrowInvalidOperationException(ExceptionResource resource, Exception e)
{
- throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
+ throw new InvalidOperationException(GetResourceString(resource), e);
}
- internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen()
+ internal static void ThrowSerializationException(ExceptionResource resource)
{
- throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
+ throw new SerializationException(GetResourceString(resource));
+ }
+
+ internal static void ThrowSecurityException(ExceptionResource resource)
+ {
+ throw new System.Security.SecurityException(GetResourceString(resource));
+ }
+
+ internal static void ThrowRankException(ExceptionResource resource)
+ {
+ throw new RankException(GetResourceString(resource));
+ }
+
+ internal static void ThrowNotSupportedException(ExceptionResource resource)
+ {
+ throw new NotSupportedException(GetResourceString(resource));
+ }
+
+ internal static void ThrowUnauthorizedAccessException(ExceptionResource resource)
+ {
+ throw new UnauthorizedAccessException(GetResourceString(resource));
+ }
+
+ internal static void ThrowObjectDisposedException(string objectName, ExceptionResource resource)
+ {
+ throw new ObjectDisposedException(objectName, GetResourceString(resource));
+ }
+
+ internal static void ThrowObjectDisposedException(ExceptionResource resource)
+ {
+ throw new ObjectDisposedException(null, GetResourceString(resource));
+ }
+
+ internal static void ThrowNotSupportedException()
+ {
+ throw new NotSupportedException();
+ }
+
+ internal static void ThrowAggregateException(List exceptions)
+ {
+ throw new AggregateException(exceptions);
+ }
+
+ internal static void ThrowOutOfMemoryException()
+ {
+ throw new OutOfMemoryException();
+ }
+
+ internal static void ThrowArgumentException_Argument_InvalidArrayType()
+ {
+ throw new ArgumentException(SR.Argument_InvalidArrayType);
}
internal static void ThrowInvalidOperationException_InvalidOperation_EnumNotStarted()
@@ -215,6 +277,21 @@ internal static void ThrowInvalidOperationException_InvalidOperation_EnumEnded()
throw new InvalidOperationException(SR.InvalidOperation_EnumEnded);
}
+ internal static void ThrowInvalidOperationException_EnumCurrent(int index)
+ {
+ throw GetInvalidOperationException_EnumCurrent(index);
+ }
+
+ internal static void ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion()
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion);
+ }
+
+ internal static void ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen()
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_EnumOpCantHappen);
+ }
+
internal static void ThrowInvalidOperationException_InvalidOperation_NoValue()
{
throw new InvalidOperationException(SR.InvalidOperation_NoValue);
@@ -225,24 +302,29 @@ internal static void ThrowInvalidOperationException_ConcurrentOperationsNotSuppo
throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
}
- internal static void ThrowSerializationException(ExceptionResource resource)
+ internal static void ThrowInvalidOperationException_HandleIsNotInitialized()
{
- throw new SerializationException(GetResourceString(resource));
+ throw new InvalidOperationException(SR.InvalidOperation_HandleIsNotInitialized);
}
- internal static void ThrowObjectDisposedException(ExceptionResource resource)
+ internal static void ThrowArraySegmentCtorValidationFailedExceptions(Array array, int offset, int count)
{
- throw new ObjectDisposedException(null, GetResourceString(resource));
+ throw GetArraySegmentCtorValidationFailedException(array, offset, count);
}
- internal static void ThrowNotSupportedException()
+ internal static void ThrowFormatException_BadFormatSpecifier()
{
- throw new NotSupportedException();
+ throw new FormatException(SR.Argument_BadFormatSpecifier);
}
- internal static void ThrowNotSupportedException(ExceptionResource resource)
+ internal static void ThrowArgumentOutOfRangeException_PrecisionTooLarge()
{
- throw new NotSupportedException(GetResourceString(resource));
+ throw new ArgumentOutOfRangeException("precision", SR.Format(SR.Argument_PrecisionTooLarge, StandardFormat.MaxPrecision));
+ }
+
+ internal static void ThrowArgumentOutOfRangeException_SymbolDoesNotFit()
+ {
+ throw new ArgumentOutOfRangeException("symbol", SR.Argument_BadFormatSpecifier);
}
private static Exception GetArraySegmentCtorValidationFailedException(Array array, int offset, int count)
@@ -257,24 +339,53 @@ private static Exception GetArraySegmentCtorValidationFailedException(Array arra
Debug.Assert(array.Length - offset < count);
return new ArgumentException(SR.Argument_InvalidOffLen);
}
- internal static void ThrowArraySegmentCtorValidationFailedExceptions(Array array, int offset, int count)
+
+ private static ArgumentException GetArgumentException(ExceptionResource resource)
{
- throw GetArraySegmentCtorValidationFailedException(array, offset, count);
+ return new ArgumentException(GetResourceString(resource));
}
- internal static void ThrowFormatException_BadFormatSpecifier()
+ private static InvalidOperationException GetInvalidOperationException(ExceptionResource resource)
{
- throw new FormatException(SR.Argument_BadFormatSpecifier);
+ return new InvalidOperationException(GetResourceString(resource));
}
- internal static void ThrowArgumentOutOfRangeException_PrecisionTooLarge()
+ private static ArgumentException GetWrongKeyTypeArgumentException(object key, Type targetType)
{
- throw new ArgumentOutOfRangeException("precision", SR.Format(SR.Argument_PrecisionTooLarge, StandardFormat.MaxPrecision));
+ return new ArgumentException(SR.Format(SR.Arg_WrongType, key, targetType), nameof(key));
}
- internal static void ThrowArgumentOutOfRangeException_SymbolDoesNotFit()
+ private static ArgumentException GetWrongValueTypeArgumentException(object value, Type targetType)
{
- throw new ArgumentOutOfRangeException("symbol", SR.Argument_BadFormatSpecifier);
+ return new ArgumentException(SR.Format(SR.Arg_WrongType, value, targetType), nameof(value));
+ }
+
+ private static KeyNotFoundException GetKeyNotFoundException(object key)
+ {
+ return new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString()));
+ }
+
+ private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
+ {
+ return new ArgumentOutOfRangeException(GetArgumentName(argument), GetResourceString(resource));
+ }
+
+ private static ArgumentException GetArgumentException(ExceptionResource resource, ExceptionArgument argument)
+ {
+ return new ArgumentException(GetResourceString(resource), GetArgumentName(argument));
+ }
+
+ private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument, int paramNumber, ExceptionResource resource)
+ {
+ return new ArgumentOutOfRangeException(GetArgumentName(argument) + "[" + paramNumber.ToString() + "]", GetResourceString(resource));
+ }
+
+ private static InvalidOperationException GetInvalidOperationException_EnumCurrent(int index)
+ {
+ return new InvalidOperationException(
+ index < 0 ?
+ SR.InvalidOperation_EnumNotStarted :
+ SR.InvalidOperation_EnumEnded);
}
// Allow nulls for reference types and Nullable, but not for value types.
@@ -283,11 +394,36 @@ internal static void ThrowArgumentOutOfRangeException_SymbolDoesNotFit()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void IfNullAndNullsAreIllegalThenThrow(object value, ExceptionArgument argName)
{
- // Note that default(T) is not equal to null for value types except when T is Nullable.
+ // Note that default(T) is not equal to null for value types except when T is Nullable.
if (!(default(T) == null) && value == null)
ThrowHelper.ThrowArgumentNullException(argName);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void ThrowForUnsupportedVectorBaseType() where T : struct
+ {
+ if (typeof(T) != typeof(byte) && typeof(T) != typeof(sbyte) &&
+ typeof(T) != typeof(short) && typeof(T) != typeof(ushort) &&
+ typeof(T) != typeof(int) && typeof(T) != typeof(uint) &&
+ typeof(T) != typeof(long) && typeof(T) != typeof(ulong) &&
+ typeof(T) != typeof(float) && typeof(T) != typeof(double))
+ {
+ ThrowNotSupportedException(ExceptionResource.Arg_TypeNotSupported);
+ }
+ }
+
+#if false // Reflection-based implementation does not work for CoreRT/ProjectN
+ // This function will convert an ExceptionArgument enum value to the argument name string.
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static string GetArgumentName(ExceptionArgument argument)
+ {
+ Debug.Assert(Enum.IsDefined(typeof(ExceptionArgument), argument),
+ "The enum value is not defined, please check the ExceptionArgument Enum.");
+
+ return argument.ToString();
+ }
+#endif
+
private static string GetArgumentName(ExceptionArgument argument)
{
switch (argument)
@@ -404,18 +540,72 @@ private static string GetArgumentName(ExceptionArgument argument)
return "stateMachine";
case ExceptionArgument.timeout:
return "timeout";
+ case ExceptionArgument.type:
+ return "type";
+ case ExceptionArgument.sourceIndex:
+ return "sourceIndex";
+ case ExceptionArgument.sourceArray:
+ return "sourceArray";
+ case ExceptionArgument.destinationIndex:
+ return "destinationIndex";
+ case ExceptionArgument.destinationArray:
+ return "destinationArray";
+ case ExceptionArgument.pHandle:
+ return "pHandle";
+ case ExceptionArgument.other:
+ return "other";
+ case ExceptionArgument.newSize:
+ return "newSize";
+ case ExceptionArgument.lowerBounds:
+ return "lowerBounds";
+ case ExceptionArgument.lengths:
+ return "lengths";
+ case ExceptionArgument.len:
+ return "len";
+ case ExceptionArgument.keys:
+ return "keys";
+ case ExceptionArgument.indices:
+ return "indices";
+ case ExceptionArgument.index1:
+ return "index1";
+ case ExceptionArgument.index2:
+ return "index2";
+ case ExceptionArgument.index3:
+ return "index3";
+ case ExceptionArgument.length1:
+ return "length1";
+ case ExceptionArgument.length2:
+ return "length2";
+ case ExceptionArgument.length3:
+ return "length3";
+ case ExceptionArgument.endIndex:
+ return "endIndex";
+ case ExceptionArgument.elementType:
+ return "elementType";
+ case ExceptionArgument.arrayIndex:
+ return "arrayIndex";
default:
Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum.");
return "";
}
}
+#if false // Reflection-based implementation does not work for CoreRT/ProjectN
+ // This function will convert an ExceptionResource enum value to the resource string.
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static string GetResourceString(ExceptionResource resource)
+ {
+ Debug.Assert(Enum.IsDefined(typeof(ExceptionResource), resource),
+ "The enum value is not defined, please check the ExceptionResource Enum.");
+
+ return SR.GetResourceString(resource.ToString());
+ }
+#endif
+
private static string GetResourceString(ExceptionResource resource)
{
switch (resource)
{
- case ExceptionResource.Argument_InvalidArgumentForComparison:
- return SR.Argument_InvalidArgumentForComparison;
case ExceptionResource.ArgumentOutOfRange_Index:
return SR.ArgumentOutOfRange_Index;
case ExceptionResource.ArgumentOutOfRange_Count:
@@ -498,6 +688,44 @@ private static string GetResourceString(ExceptionResource resource)
return SR.Task_ThrowIfDisposed;
case ExceptionResource.Task_WaitMulti_NullTask:
return SR.Task_WaitMulti_NullTask;
+ case ExceptionResource.ArgumentException_OtherNotArrayOfCorrectLength:
+ return SR.ArgumentException_OtherNotArrayOfCorrectLength;
+ case ExceptionResource.ArgumentNull_SafeHandle:
+ return SR.ArgumentNull_SafeHandle;
+ case ExceptionResource.ArgumentOutOfRange_EndIndexStartIndex:
+ return SR.ArgumentOutOfRange_EndIndexStartIndex;
+ case ExceptionResource.ArgumentOutOfRange_Enum:
+ return SR.ArgumentOutOfRange_Enum;
+ case ExceptionResource.ArgumentOutOfRange_HugeArrayNotSupported:
+ return SR.ArgumentOutOfRange_HugeArrayNotSupported;
+ case ExceptionResource.Argument_AddingDuplicate:
+ return SR.Argument_AddingDuplicate;
+ case ExceptionResource.Argument_InvalidArgumentForComparison:
+ return SR.Argument_InvalidArgumentForComparison;
+ case ExceptionResource.Arg_LowerBoundsMustMatch:
+ return SR.Arg_LowerBoundsMustMatch;
+ case ExceptionResource.Arg_MustBeType:
+ return SR.Arg_MustBeType;
+ case ExceptionResource.Arg_Need1DArray:
+ return SR.Arg_Need1DArray;
+ case ExceptionResource.Arg_Need2DArray:
+ return SR.Arg_Need2DArray;
+ case ExceptionResource.Arg_Need3DArray:
+ return SR.Arg_Need3DArray;
+ case ExceptionResource.Arg_NeedAtLeast1Rank:
+ return SR.Arg_NeedAtLeast1Rank;
+ case ExceptionResource.Arg_RankIndices:
+ return SR.Arg_RankIndices;
+ case ExceptionResource.Arg_RanksAndBounds:
+ return SR.Arg_RanksAndBounds;
+ case ExceptionResource.InvalidOperation_IComparerFailed:
+ return SR.InvalidOperation_IComparerFailed;
+ case ExceptionResource.NotSupported_FixedSizeCollection:
+ return SR.NotSupported_FixedSizeCollection;
+ case ExceptionResource.Rank_MultiDimNotSupported:
+ return SR.Rank_MultiDimNotSupported;
+ case ExceptionResource.Arg_TypeNotSupported:
+ return SR.Arg_TypeNotSupported;
default:
Debug.Assert(false,
"The enum value is not defined, please check the ExceptionResource Enum.");
@@ -508,7 +736,7 @@ private static string GetResourceString(ExceptionResource resource)
//
// The convention for this enum is using the argument name as the enum name
- //
+ //
internal enum ExceptionArgument
{
obj,
@@ -567,14 +795,35 @@ internal enum ExceptionArgument
millisecondsTimeout,
stateMachine,
timeout,
+ type,
+ sourceIndex,
+ sourceArray,
+ destinationIndex,
+ destinationArray,
+ pHandle,
+ other,
+ newSize,
+ lowerBounds,
+ lengths,
+ len,
+ keys,
+ indices,
+ index1,
+ index2,
+ index3,
+ length1,
+ length2,
+ length3,
+ endIndex,
+ elementType,
+ arrayIndex,
}
//
// The convention for this enum is using the resource name as the enum name
- //
+ //
internal enum ExceptionResource
{
- Argument_InvalidArgumentForComparison,
ArgumentOutOfRange_Index,
ArgumentOutOfRange_Count,
Arg_ArrayPlusOffTooSmall,
@@ -616,5 +865,24 @@ internal enum ExceptionResource
Task_Dispose_NotCompleted,
Task_ThrowIfDisposed,
Task_WaitMulti_NullTask,
+ ArgumentException_OtherNotArrayOfCorrectLength,
+ ArgumentNull_SafeHandle,
+ ArgumentOutOfRange_EndIndexStartIndex,
+ ArgumentOutOfRange_Enum,
+ ArgumentOutOfRange_HugeArrayNotSupported,
+ Argument_AddingDuplicate,
+ Argument_InvalidArgumentForComparison,
+ Arg_LowerBoundsMustMatch,
+ Arg_MustBeType,
+ Arg_Need1DArray,
+ Arg_Need2DArray,
+ Arg_Need3DArray,
+ Arg_NeedAtLeast1Rank,
+ Arg_RankIndices,
+ Arg_RanksAndBounds,
+ InvalidOperation_IComparerFailed,
+ NotSupported_FixedSizeCollection,
+ Rank_MultiDimNotSupported,
+ Arg_TypeNotSupported,
}
-}
+}
\ No newline at end of file