Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Index and Ranges Changes #35003

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/System.Memory/ref/System.Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,29 @@ public static partial class MemoryExtensions
public static System.ReadOnlyMemory<char> AsMemory(this string text) { throw null; }
public static System.ReadOnlyMemory<char> AsMemory(this string text, int start) { throw null; }
public static System.ReadOnlyMemory<char> AsMemory(this string text, int start, int length) { throw null; }
public static System.ReadOnlyMemory<char> AsMemory(this string text, Index startIndex) { throw null; }
public static System.ReadOnlyMemory<char> AsMemory(this string text, Range range) { throw null; }
public static System.Memory<T> AsMemory<T>(this System.ArraySegment<T> segment) { throw null; }
public static System.Memory<T> AsMemory<T>(this System.ArraySegment<T> segment, int start) { throw null; }
public static System.Memory<T> AsMemory<T>(this System.ArraySegment<T> segment, int start, int length) { throw null; }
public static System.Memory<T> AsMemory<T>(this T[] array) { throw null; }
public static System.Memory<T> AsMemory<T>(this T[] array, int start) { throw null; }
public static System.Memory<T> AsMemory<T>(this T[] array, int start, int length) { throw null; }
public static System.Memory<T> AsMemory<T>(this T[] array, Index startIndex) { throw null; }
public static System.Memory<T> AsMemory<T>(this T[] array, Range range) { throw null; }
public static System.ReadOnlySpan<char> AsSpan(this string text) { throw null; }
public static System.ReadOnlySpan<char> AsSpan(this string text, int start) { throw null; }
public static System.ReadOnlySpan<char> AsSpan(this string text, int start, int length) { throw null; }
public static System.Span<T> AsSpan<T>(this System.ArraySegment<T> segment) { throw null; }
public static System.Span<T> AsSpan<T>(this System.ArraySegment<T> segment, int start) { throw null; }
public static System.Span<T> AsSpan<T>(this System.ArraySegment<T> segment, int start, int length) { throw null; }
public static Span<T> AsSpan<T>(this System.ArraySegment<T> segment, Index startIndex) { throw null; }
public static Span<T> AsSpan<T>(this System.ArraySegment<T> segment, Range range) { throw null; }
public static System.Span<T> AsSpan<T>(this T[] array) { throw null; }
public static System.Span<T> AsSpan<T>(this T[] array, int start) { throw null; }
public static System.Span<T> AsSpan<T>(this T[] array, int start, int length) { throw null; }
public static Span<T> AsSpan<T>(this T[] array, Index startIndex) { throw null; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are adding Index/Range overloads to AsSpan for array/segment, why not add it for string as well?

public static System.ReadOnlySpan<char> AsSpan(this string text, int start, int length) { throw null; }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good question, I don't think this was discussed and I don't see a strong reason why we shouldn't have it. but in general it is easy to achieve the same with the current APIs String.AsSpan().Slice(Index/Range)

@terrajobst what you think about this one?

public static Span<T> AsSpan<T>(this T[] array, Range range) { throw null; }
public static int BinarySearch<T>(this System.ReadOnlySpan<T> span, System.IComparable<T> comparable) { throw null; }
public static int BinarySearch<T>(this System.Span<T> span, System.IComparable<T> comparable) { throw null; }
public static int BinarySearch<T, TComparer>(this System.ReadOnlySpan<T> span, T value, TComparer comparer) where TComparer : System.Collections.Generic.IComparer<T> { throw null; }
Expand Down
100 changes: 100 additions & 0 deletions src/System.Memory/tests/Memory/IndexAndRange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Xunit;

namespace System.MemoryTests
{
public static partial class MemoryTests
{
[Fact]
public static void SlicingUsingIndexAndRangeTest()
{
Range range;
int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Memory<int> memory = a;
ReadOnlyMemory<int> roMemory = a;

for (int i = 0; i < a.Length; i++)
{
range = new Range(Index.FromStart(i), Index.FromEnd(0));
Assert.Equal(memory.Slice(i, a.Length - i), memory[range]);
Assert.Equal(roMemory.Slice(i, a.Length - i), roMemory[range]);

Assert.Equal(memory.Slice(i), memory.Slice(Index.FromStart(i)));
Assert.Equal(roMemory.Slice(i), roMemory.Slice(Index.FromStart(i)));

Assert.Equal(memory.Slice(i, a.Length - i), memory.Slice(range));
Assert.Equal(roMemory.Slice(i, a.Length - i), roMemory.Slice(range));
}

range = new Range(Index.FromStart(0), Index.FromStart(a.Length + 1));
Assert.Throws<ArgumentOutOfRangeException>(() => { Memory<int> m = memory[range]; });
Assert.Throws<ArgumentOutOfRangeException>(() => { ReadOnlyMemory<int> m = roMemory[range]; });
}

[Fact]
public static void MemoryExtensionsTest()
{
Range range;
int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Memory<int> memory = a;
ReadOnlyMemory<int> roMemory = a;

for (int i = 0; i < a.Length; i++)
{
Assert.Equal(memory.Slice(i), a.AsMemory(Index.FromStart(i)));

range = new Range(Index.FromStart(i), Index.FromEnd(0));
Assert.Equal(memory.Slice(i, a.Length - i), a.AsMemory(range));
}

range = new Range(Index.FromStart(0), Index.FromStart(a.Length + 1));
Assert.Throws<ArgumentOutOfRangeException>(() => { Memory<int> m = a.AsMemory(Index.FromStart(a.Length + 1)); });
Assert.Throws<ArgumentOutOfRangeException>(() => { Memory<int> m = a.AsMemory(range); });

string s = "0123456789ABCDEF";
ReadOnlyMemory<char> roStringMemory = s.AsMemory();

for (int i = 0; i < s.Length; i++)
{
Assert.Equal(roStringMemory.Slice(i), s.AsMemory(Index.FromStart(i)));

range = new Range(Index.FromStart(i), Index.FromEnd(0));
Assert.Equal(roStringMemory.Slice(i, s.Length - i), s.AsMemory(range));
}

range = new Range(Index.FromStart(0), Index.FromStart(s.Length + 1));
Assert.Throws<ArgumentOutOfRangeException>(() => { ReadOnlyMemory<char> m = s.AsMemory(Index.FromStart(s.Length + 1)); });
Assert.Throws<ArgumentOutOfRangeException>(() => { ReadOnlyMemory<char> m = s.AsMemory(range); });

Span<int> span = a.AsSpan();

for (int i = 0; i < a.Length; i++)
{
Assert.True(span.Slice(i) == a.AsSpan(Index.FromStart(i)));

range = new Range(Index.FromStart(i), Index.FromEnd(0));
Assert.True(span.Slice(i, span.Length - i) == a.AsSpan(range));
}

range = new Range(Index.FromStart(0), Index.FromStart(a.Length + 1));
Assert.Throws<ArgumentOutOfRangeException>(() => { Span<int> sp = a.AsSpan(Index.FromStart(a.Length + 1)); });
Assert.Throws<ArgumentOutOfRangeException>(() => { Span<int> sp = a.AsSpan(range); });

ArraySegment<int> segment = new ArraySegment<int>(a);
for (int i = 0; i < a.Length; i++)
{
Assert.True(span.Slice(i) == segment.AsSpan(Index.FromStart(i)));

range = new Range(Index.FromStart(i), Index.FromEnd(0));
Assert.True(span.Slice(i, span.Length - i) == segment.AsSpan(range));
}

range = new Range(Index.FromStart(0), Index.FromStart(a.Length + 1));
Assert.Throws<ArgumentOutOfRangeException>(() => { Span<int> sp = segment.AsSpan(Index.FromStart(a.Length + 1)); });
Assert.Throws<ArgumentOutOfRangeException>(() => { Span<int> sp = segment.AsSpan(range); });
}
}
}
34 changes: 30 additions & 4 deletions src/System.Memory/tests/Span/Indexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,44 @@ public static void IndexerWithIndexTest()
public static void IndexerWithRangeTest()
{
ReadOnlySpan<char> span = "Hello".AsSpan();
ReadOnlySpan<char> sliced = span[Range.Create(new Index(1, fromEnd: false), new Index(1, fromEnd: true))];
ReadOnlySpan<char> sliced = span[new Range(new Index(1, fromEnd: false), new Index(1, fromEnd: true))];
Assert.True(span.Slice(1, 3) == sliced);

Assert.Throws<ArgumentOutOfRangeException>(() =>
{ ReadOnlySpan<char> s = "Hello".AsSpan()[Range.Create(new Index(1, fromEnd: true), new Index(1, fromEnd: false))]; });
{ ReadOnlySpan<char> s = "Hello".AsSpan()[new Range(new Index(1, fromEnd: true), new Index(1, fromEnd: false))]; });

Span<char> span1 = new Span<char>(new char [] { 'H', 'e', 'l', 'l', 'o'});
Span<char> sliced1 = span1[Range.Create(new Index(2, fromEnd: false), new Index(1, fromEnd: true))];
Span<char> sliced1 = span1[new Range(new Index(2, fromEnd: false), new Index(1, fromEnd: true))];
Assert.True(span1.Slice(2, 2) == sliced1);

Assert.Throws<ArgumentOutOfRangeException>(() =>
{ Span<char> s = new Span<char>(new char [] { 'H', 'i' })[Range.Create(new Index(0, fromEnd: true), new Index(1, fromEnd: false))]; });
{ Span<char> s = new Span<char>(new char [] { 'H', 'i' })[new Range(new Index(0, fromEnd: true), new Index(1, fromEnd: false))]; });
}

[Fact]
public static void SlicingUsingIndexAndRangeTest()
{
Range range;
string s = "0123456789ABCDEF";
ReadOnlySpan<char> roSpan = s.AsSpan();
Span<char> span = new Span<char>(s.ToCharArray());

for (int i = 0; i < span.Length; i++)
{
Assert.True(span.Slice(i) == span.Slice(Index.FromStart(i)));
Assert.True(span.Slice(span.Length - i - 1) == span.Slice(Index.FromEnd(i + 1)));

Assert.True(roSpan.Slice(i) == roSpan.Slice(Index.FromStart(i)));
Assert.True(roSpan.Slice(roSpan.Length - i - 1) == roSpan.Slice(Index.FromEnd(i + 1)));

range = new Range(Index.FromStart(i), Index.FromEnd(0));
Assert.True(span.Slice(i, span.Length - i) == span.Slice(range));
Assert.True(roSpan.Slice(i, roSpan.Length - i) == roSpan.Slice(range));
}

range = new Range(Index.FromStart(0), Index.FromStart(span.Length + 1));
Assert.Throws<ArgumentOutOfRangeException>(() => new Span<char>(s.ToCharArray()).Slice(range));
Assert.Throws<ArgumentOutOfRangeException>(() => s.AsSpan().Slice(range));
}
}
}
1 change: 1 addition & 0 deletions src/System.Memory/tests/System.Memory.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@
<Compile Include="Memory\Equality.cs" />
<Compile Include="Memory\GetHashCode.cs" />
<Compile Include="Memory\ImplicitConversion.cs" />
<Compile Include="Memory\IndexAndRange.cs" />
<Compile Include="Memory\MemoryManager.cs" />
<Compile Include="Memory\Pin.cs" />
<Compile Include="Memory\Slice.cs" />
Expand Down
44 changes: 38 additions & 6 deletions src/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1458,9 +1458,14 @@ public partial interface IFormattable
public readonly partial struct Index : System.IEquatable<System.Index>
{
private readonly int _dummyPrimitive;
public Index(int value, bool fromEnd) { throw null; }
public bool FromEnd { get { throw null; } }
public Index(int value, bool fromEnd = false) { throw null; }
public bool IsFromEnd { get { throw null; } }
public int Value { get { throw null; } }
public static Index Start { get { throw null; } }
public static Index End { get { throw null; } }
public static Index FromStart(int value) { throw null; }
public static Index FromEnd(int value) { throw null; }
public int GetOffset(int length) { throw null; }
public bool Equals(System.Index other) { throw null; }
public override bool Equals(object value) { throw null; }
public override int GetHashCode() { throw null; }
Expand Down Expand Up @@ -1747,6 +1752,9 @@ public partial class MemberAccessException : System.SystemException
public System.Buffers.MemoryHandle Pin() { throw null; }
public System.Memory<T> Slice(int start) { throw null; }
public System.Memory<T> Slice(int start, int length) { throw null; }
public System.Memory<T> Slice(System.Index startIndex) { throw null; }
public System.Memory<T> Slice(System.Range range) { throw null; }
public System.Memory<T> this[System.Range range] { get { throw null; } }
public T[] ToArray() { throw null; }
public override string ToString() { throw null; }
public bool TryCopyTo(System.Memory<T> destination) { throw null; }
Expand Down Expand Up @@ -1973,14 +1981,24 @@ public partial class PlatformNotSupportedException : System.NotSupportedExceptio
private readonly int _dummyPrimitive;
public System.Index End { get { throw null; } }
public System.Index Start { get { throw null; } }
public static System.Range All() { throw null; }
public static System.Range Create(System.Index start, System.Index end) { throw null; }
public Range(System.Index start, System.Index end) { throw null; }
public OffsetAndLength GetOffsetAndLength(int length) { throw null; }
public override bool Equals(object value) { throw null; }
public bool Equals(System.Range other) { throw null; }
public static System.Range FromStart(System.Index start) { throw null; }
public override int GetHashCode() { throw null; }
public static System.Range ToEnd(System.Index end) { throw null; }
public override string ToString() { throw null; }
public static System.Range StartAt(System.Index start) { throw null; }
public static System.Range EndAt(System.Index end) { throw null; }
public static System.Range All { get { throw null; } }

public readonly struct OffsetAndLength
{
private readonly int _dummyPrimitive;
public int Offset { get { throw null; } }
public int Length { get { throw null; } }
public OffsetAndLength(int offset, int length) { throw null; }
public void Deconstruct(out int offset, out int length) { throw null; }
}
}
public partial class RankException : System.SystemException
{
Expand Down Expand Up @@ -2010,6 +2028,9 @@ public partial class RankException : System.SystemException
public System.Buffers.MemoryHandle Pin() { throw null; }
public System.ReadOnlyMemory<T> Slice(int start) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start, int length) { throw null; }
public System.ReadOnlyMemory<T> Slice(System.Index startIndex) { throw null; }
public System.ReadOnlyMemory<T> Slice(System.Range range) { throw null; }
public System.ReadOnlyMemory<T> this[System.Range range] { get { throw null; } }
public T[] ToArray() { throw null; }
public override string ToString() { throw null; }
public bool TryCopyTo(System.Memory<T> destination) { throw null; }
Expand Down Expand Up @@ -2044,6 +2065,8 @@ public partial class RankException : System.SystemException
public static bool operator !=(System.ReadOnlySpan<T> left, System.ReadOnlySpan<T> right) { throw null; }
public System.ReadOnlySpan<T> Slice(int start) { throw null; }
public System.ReadOnlySpan<T> Slice(int start, int length) { throw null; }
public System.ReadOnlySpan<T> Slice(System.Index startIndex) { throw null; }
public System.ReadOnlySpan<T> Slice(System.Range range) { throw null; }
public T[] ToArray() { throw null; }
public override string ToString() { throw null; }
public bool TryCopyTo(System.Span<T> destination) { throw null; }
Expand Down Expand Up @@ -2251,6 +2274,8 @@ public sealed partial class SerializableAttribute : System.Attribute
public static bool operator !=(System.Span<T> left, System.Span<T> right) { throw null; }
public System.Span<T> Slice(int start) { throw null; }
public System.Span<T> Slice(int start, int length) { throw null; }
public System.Span<T> Slice(System.Index startIndex) { throw null; }
public System.Span<T> Slice(System.Range range) { throw null; }
public T[] ToArray() { throw null; }
public override string ToString() { throw null; }
public bool TryCopyTo(System.Span<T> destination) { throw null; }
Expand Down Expand Up @@ -2292,6 +2317,10 @@ public sealed partial class String : System.Collections.Generic.IEnumerable<char
public unsafe String(sbyte* value, int startIndex, int length, System.Text.Encoding enc) { }
[System.Runtime.CompilerServices.IndexerName("Chars")]
public char this[int index] { get { throw null; } }
[System.Runtime.CompilerServices.IndexerName("Chars")]
public char this[System.Index index] { get { throw null; } }
[System.Runtime.CompilerServices.IndexerName("Chars")]
public System.String this[System.Range range] { get { throw null; } }
public int Length { get { throw null; } }
public object Clone() { throw null; }
public static int Compare(System.String strA, int indexA, System.String strB, int indexB, int length) { throw null; }
Expand Down Expand Up @@ -2424,6 +2453,8 @@ public sealed partial class String : System.Collections.Generic.IEnumerable<char
public bool StartsWith(System.String value, System.StringComparison comparisonType) { throw null; }
public System.String Substring(int startIndex) { throw null; }
public System.String Substring(int startIndex, int length) { throw null; }
public System.String Substring(System.Index startIndex) { throw null; }
public System.String Substring(System.Range range) { throw null; }
System.Collections.Generic.IEnumerator<char> System.Collections.Generic.IEnumerable<System.Char>.GetEnumerator() { throw null; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; }
Expand Down Expand Up @@ -6778,6 +6809,7 @@ public static partial class RuntimeHelpers
public static int GetHashCode(object o) { throw null; }
public static object GetObjectValue(object obj) { throw null; }
public static object GetUninitializedObject(System.Type type) { throw null; }
public static T[] GetArrayRange<T>(T[] array, System.Range range) { throw null; }
public static void InitializeArray(System.Array array, System.RuntimeFieldHandle fldHandle) { }
public static bool IsReferenceOrContainsReferences<T>() { throw null; }
public static void PrepareConstrainedRegions() { }
Expand Down