Skip to content

Commit

Permalink
Index and Range updates (dotnet/coreclr#22331)
Browse files Browse the repository at this point in the history
* Index and Range updates

* Address @mikedn  feedback

* Address Feedback

* more feedback

* Use Deconstruct in Range.GetOffsetAndLength

* Rename GetArrayRange to GetSubArray

* Temporary disable the old Corefx Range tests

* Return back the TimeSpan test disabling

* Fix Range jit test

* Exclude the jit test

* revert the changes in the jit Range test

* Address Suggested Feedback

Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
  • Loading branch information
tarekgh authored and dotnet-bot committed Feb 7, 2019
1 parent 21c65aa commit 42ba574
Show file tree
Hide file tree
Showing 11 changed files with 793 additions and 166 deletions.
124 changes: 113 additions & 11 deletions netcore/System.Private.CoreLib/shared/System/Index.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,138 @@
// See the LICENSE file in the project root for more information.

using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace System
{
/// <summary>Represent a type can be used to index a collection either from the start or the end.</summary>
/// <remarks>
/// Index is used by the C# compiler to support the new index syntax
/// <code>
/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ;
/// int lastElement = someArray[^1]; // lastElement = 5
/// </code>
/// </remarks>
public readonly struct Index : IEquatable<Index>
{
private readonly int _value;

public Index(int value, bool fromEnd)
/// <summary>Construct an Index using a value and indicating if the index is from the start or from the end.</summary>
/// <param name="value">The index value. it has to be zero or positive number.</param>
/// <param name="fromEnd">Indicating if the index is from the start or from the end.</param>
/// <remarks>
/// 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.
/// </remarks>
[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;
}

/// <summary>Create an Index pointing at first element.</summary>
public static Index Start => new Index(0);

/// <summary>Create an Index pointing at beyond last element.</summary>
public static Index End => new Index(~0);

/// <summary>Create an Index from the start at the position indicated by the value.</summary>
/// <param name="value">The index value from the start.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Index FromStart(int value)
{
if (value < 0)
{
ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException();
}

return new Index(value);
}

/// <summary>Create an Index from the end at the position indicated by the value.</summary>
/// <param name="value">The index value from the end.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Index FromEnd(int value)
{
if (value < 0)
{
ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException();
}

return new Index(~value);
}

/// <summary>Returns the index value.</summary>
public int Value
{
get
{
if (_value < 0)
return ~_value;
else
return _value;
}
}

/// <summary>Indicates whether the index is from the start or the end.</summary>
public bool IsFromEnd => _value < 0;

/// <summary>Calculate the offset from the start using the giving collection length.</summary>
/// <param name="length">The length of the collection that the Index will be used with. length has to be a positive value</param>
/// <remarks>
/// 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.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetOffset(int length)
{
int offset;

if (IsFromEnd)
offset = length - (~_value);
else
offset = _value;

return offset;
}

/// <summary>Indicates whether the current Index object is equal to another object of the same type.</summary>
/// <param name="value">An object to compare with this object</param>
public override bool Equals(object value) => value is Index && _value == ((Index)value)._value;

/// <summary>Indicates whether the current Index object is equal to another Index object.</summary>
/// <param name="other">An object to compare with this object</param>
public bool Equals (Index other) => _value == other._value;

public override int GetHashCode()
/// <summary>Returns the hash code for this instance.</summary>
public override int GetHashCode() => _value;

/// <summary>Converts integer number to an Index.</summary>
public static implicit operator Index(int value) => FromStart(value);

/// <summary>Converts the value of the current Index object to its equivalent string representation.</summary>
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()
{
Expand All @@ -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);
}
}
}
35 changes: 32 additions & 3 deletions netcore/System.Private.CoreLib/shared/System/Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public readonly struct Memory<T>
private readonly object _object;
private readonly int _index;
private readonly int _length;

/// <summary>
/// Creates a new memory over the entirety of the target array.
/// </summary>
Expand Down Expand Up @@ -258,6 +258,35 @@ public Memory<T> Slice(int start, int length)
return new Memory<T>(_object, _index + start, length);
}

/// <summary>
/// Forms a slice out of the given memory, beginning at 'startIndex'
/// </summary>
/// <param name="startIndex">The index at which to begin this slice.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Memory<T> Slice(Index startIndex)
{
int actualIndex = startIndex.GetOffset(_length);
return Slice(actualIndex);
}

/// <summary>
/// Forms a slice out of the given memory using the range start and end indexes.
/// </summary>
/// <param name="range">The range used to slice the memory using its start and end indexes.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Memory<T> 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<T>(_object, _index + start, length);
}

/// <summary>
/// Forms a slice out of the given memory using the range start and end indexes.
/// </summary>
/// <param name="range">The range used to slice the memory using its start and end indexes.</param>
public Memory<T> this[Range range] => Slice(range);

/// <summary>
/// Returns a span from the memory.
/// </summary>
Expand Down Expand Up @@ -336,7 +365,7 @@ public unsafe Span<T> Span
ThrowHelper.ThrowArgumentOutOfRangeException();
}
#endif

refToReturn = ref Unsafe.Add(ref refToReturn, desiredStartIndex);
lengthOfUnderlyingSpan = desiredLength;
}
Expand Down Expand Up @@ -477,4 +506,4 @@ public override int GetHashCode()
return (_object != null) ? HashCode.Combine(RuntimeHelpers.GetHashCode(_object), _index, _length) : 0;
}
}
}
}
Loading

0 comments on commit 42ba574

Please sign in to comment.