Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move range #584

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
50 changes: 49 additions & 1 deletion Source/SuperLinq/Move.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,52 @@ static IEnumerable<T> Core(IEnumerable<T> source, int bufferStartIndex, int buff
yield return e.Current;
}
}
}

/// <summary>
viceroypenguin marked this conversation as resolved.
Show resolved Hide resolved
/// Returns a sequence with a range of elements in the source sequence moved to a new offset.
/// </summary>
/// <typeparam name="T">
/// Type of the source sequence.
/// </typeparam>
/// <param name="source">
/// The source sequence.
/// </param>
/// <param name="range">
/// The range of values to move.
/// </param>
/// <param name="toIndex">
/// The index where the specified range will be moved.</param>
/// <returns>
/// A sequence with the specified range moved to the new position.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="source"/> is <see langword="null"/>.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="range"/>'s start is less than <c>0</c> or <paramref name="range"/>'s end is before start in the sequence.
/// </exception>
/// <remarks>
/// This operator uses deferred executing and streams its results.
/// </remarks>
public static IEnumerable<T> Move<T>(this IEnumerable<T> source, Range range, Index toIndex)
{
int? length = 0;
if (range.Start.IsFromEnd || range.End.IsFromEnd || toIndex.IsFromEnd)
{
length = source.TryGetCollectionCount();
if (!length.HasValue)
{
length = source.GetCollectionCount();
Copy link
Owner

Choose a reason for hiding this comment

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

if TryGetCollectionCount() fails to return a value, then GetCollectionCount() will throw an exception. try calling Enumerable.Range(1, 10).Select(Identity).GetCollectionCount().

}
}
var fromIndex = range.Start.IsFromEnd ? range.Start.GetOffset(length.Value) : range.Start.Value;
Copy link
Owner

Choose a reason for hiding this comment

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

var count = (range.End.IsFromEnd ? range.End.GetOffset(length.Value) : range.End.Value) - fromIndex;
var to = toIndex.IsFromEnd ? toIndex.GetOffset(length.Value) : toIndex.Value;
return source.Move
(
fromIndex,
count,
to
);
}
}
1 change: 1 addition & 0 deletions Source/SuperLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Move<T>(this System.Collections.Generic.IEnumerable<T>! source, System.Range range, System.Index toIndex) -> System.Collections.Generic.IEnumerable<T>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
1 change: 1 addition & 0 deletions Source/SuperLinq/PublicAPI/net7.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Move<T>(this System.Collections.Generic.IEnumerable<T>! source, System.Range range, System.Index toIndex) -> System.Collections.Generic.IEnumerable<T>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
1 change: 1 addition & 0 deletions Source/SuperLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Move<T>(this System.Collections.Generic.IEnumerable<T>! source, System.Range range, System.Index toIndex) -> System.Collections.Generic.IEnumerable<T>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Batch<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, System.Func<System.ArraySegment<TSource>, TResult>! resultSelector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Move<T>(this System.Collections.Generic.IEnumerable<T>! source, System.Range range, System.Index toIndex) -> System.Collections.Generic.IEnumerable<T>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, int size, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, int size, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.Window<TSource, TResult>(this System.Collections.Generic.IEnumerable<TSource>! source, TSource[]! array, System.Func<System.ArraySegment<TSource>, TResult>! selector) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
95 changes: 94 additions & 1 deletion Tests/SuperLinq.Test/MoveTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,40 @@ public void MoveWithNegativeFromIndex()
new[] { 1 }.Move(-1, 0, 0));
}

[Fact]
public void MoveRangeWithNegativeStartIndex()
{
_ = Assert.Throws<ArgumentOutOfRangeException>(() => new[] { 1 }.Move(-1..-1, 0));
}

[Fact]
public void MoveWithNegativeCount()
{
_ = Assert.Throws<ArgumentOutOfRangeException>(() =>
new[] { 1 }.Move(0, -1, 0));
}

[Fact]
public void MoveRangeWithDecendingRange()
{
_ = Assert.Throws<ArgumentOutOfRangeException>(() =>
new[] { 1 }.Move(0..-1, 0));
}

[Fact]
public void MoveWithNegativeToIndex()
{
_ = Assert.Throws<ArgumentOutOfRangeException>(() =>
new[] { 1 }.Move(0, 0, -1));
}

[Fact]
public void MoveRangeWithNegativeToIndex()
{
_ = Assert.Throws<ArgumentOutOfRangeException>(() =>
new[] { 1 }.Move(0..0, -1));
}

[Fact]
public void MoveIsLazy()
{
Expand All @@ -44,6 +64,21 @@ public void Move(int length, int fromIndex, int count, int toIndex)
result.AssertSequenceEqual(expectations);
}

[Theory, MemberData(nameof(MoveRangeSource))]
public void MoveRange(int length, Range range, int toIndex)
{
var source = Enumerable.Range(0, length);

using var test = source.AsTestingSequence();

var result = test.Move(range, toIndex);

var slice = source.Take(range);
var exclude = source.Exclude(range.Start.Value, range.End.Value - range.Start.Value);
var expectations = exclude.Take(toIndex).Concat(slice).Concat(exclude.Skip(toIndex));
result.AssertSequenceEqual(expectations);
}

public static IEnumerable<object[]> MoveSource()
{
const int Length = 10;
Expand All @@ -58,6 +93,20 @@ from count in Enumerable.Range(0, Length + 1)
select tcd;
}

public static IEnumerable<object[]> MoveRangeSource()
{
const int Length = 10;
return
from index in Enumerable.Range(0, Length)
from count in Enumerable.Range(0, Length + 1)
from tcd in new object[][]
{
[Length, index..(index + count), Math.Max(0, index - 1),],
[Length, index..(index + count), index + 1,],
}
select tcd;
}

[Theory, MemberData(nameof(MoveWithSequenceShorterThanToIndexSource))]
public void MoveWithSequenceShorterThanToIndex(int length, int fromIndex, int count, int toIndex)
{
Expand All @@ -71,10 +120,27 @@ public void MoveWithSequenceShorterThanToIndex(int length, int fromIndex, int co
Assert.Equal(expectations, result);
}

[Theory, MemberData(nameof(MoveRangeWithSequenceShorterThanToIndexSource))]
public void MoveRangeWithSequenceShorterThanToIndex(int length, Range range, int toIndex)
{
var source = Enumerable.Range(0, length);

using var test = source.AsTestingSequence();

var result = test.Move(range, toIndex);

var expectations = source.Exclude(range.Start.Value, range.End.Value - range.Start.Value).Concat(source.Take(range));
Assert.Equal(expectations, result);
}

public static IEnumerable<object[]> MoveWithSequenceShorterThanToIndexSource() =>
Enumerable.Range(10, 10 + 5)
.Select(toIndex => new object[] { 10, 5, 2, toIndex, });

public static IEnumerable<object[]> MoveRangeWithSequenceShorterThanToIndexSource() =>
Enumerable.Range(10, 10 + 5)
.Select(toIndex => new object[] { 10, 5..7, toIndex, });

[Fact]
public void MoveIsRepeatable()
{
Expand All @@ -84,6 +150,15 @@ public void MoveIsRepeatable()
Assert.Equal(result, result.ToArray());
}

[Fact]
public void MoveRangeIsRepeatable()
{
using var source = Enumerable.Range(0, 10).AsTestingSequence(maxEnumerations: 2);

var result = source.Move(0..5, 10);
Assert.Equal(result, result.ToArray());
}

[Fact]
public void MoveWithFromIndexEqualsToIndex()
{
Expand All @@ -93,6 +168,15 @@ public void MoveWithFromIndexEqualsToIndex()
result.AssertSequenceEqual(Enumerable.Range(0, 10));
}

[Fact]
public void MoveRangeWithFomrIndexEqualsToIndex()
{
using var source = Enumerable.Range(0, 10).AsTestingSequence();

var result = source.Move(5..1004, 5);
result.AssertSequenceEqual(Enumerable.Range(0, 10));
}

[Fact]
public void MoveWithCountEqualsZero()
{
Expand All @@ -101,4 +185,13 @@ public void MoveWithCountEqualsZero()
var result = source.Move(5, 0, 999);
result.AssertSequenceEqual(Enumerable.Range(0, 10));
}
}

[Fact]
public void MoveRngeWithCountEqualsZero()
{
using var source = Enumerable.Range(0, 10).AsTestingSequence();

var result = source.Move(5..5, 999);
result.AssertSequenceEqual(Enumerable.Range(0, 10));
}
}