diff --git a/Source/SuperLinq/Move.cs b/Source/SuperLinq/Move.cs
index b8623112..066dadc2 100644
--- a/Source/SuperLinq/Move.cs
+++ b/Source/SuperLinq/Move.cs
@@ -32,21 +32,30 @@ public static partial class SuperEnumerable
///
/// This operator uses deferred execution and streams its results.
///
- public static IEnumerable Move(this IEnumerable source, int fromIndex, int count, int toIndex)
+ public static IEnumerable Move(
+ this IEnumerable source,
+ int fromIndex,
+ int count,
+ int toIndex
+ )
{
ArgumentNullException.ThrowIfNull(source);
ArgumentOutOfRangeException.ThrowIfNegative(fromIndex);
ArgumentOutOfRangeException.ThrowIfNegative(count);
ArgumentOutOfRangeException.ThrowIfNegative(toIndex);
- return
- toIndex == fromIndex || count == 0
- ? source :
- toIndex < fromIndex
- ? Core(source, toIndex, fromIndex - toIndex, count)
- : Core(source, fromIndex, count, toIndex - fromIndex);
+ return toIndex == fromIndex || count == 0
+ ? source
+ : toIndex < fromIndex
+ ? Core(source, toIndex, fromIndex - toIndex, count)
+ : Core(source, fromIndex, count, toIndex - fromIndex);
- static IEnumerable Core(IEnumerable source, int bufferStartIndex, int bufferSize, int bufferYieldIndex)
+ static IEnumerable Core(
+ IEnumerable source,
+ int bufferStartIndex,
+ int bufferSize,
+ int bufferYieldIndex
+ )
{
var hasMore = true;
bool MoveNext(IEnumerator e) => hasMore && (hasMore = e.MoveNext());
@@ -72,4 +81,199 @@ static IEnumerable Core(IEnumerable source, int bufferStartIndex, int buff
yield return e.Current;
}
}
+
+ ///
+ /// Returns a sequence with a range of elements in the source sequence moved to a new offset.
+ ///
+ ///
+ /// Type of the source sequence.
+ ///
+ ///
+ /// The source sequence.
+ ///
+ ///
+ /// The range of values to move.
+ ///
+ ///
+ /// The index where the specified range will be moved.
+ ///
+ /// A sequence with the specified range moved to the new position.
+ ///
+ ///
+ /// is .
+ ///
+ ///
+ /// 's start is less than 0 or 's end is before start in the sequence.
+ ///
+ ///
+ /// This operator uses deferred executing and streams its results.
+ ///
+ public static IEnumerable Move(this IEnumerable source, Range range, Index to)
+ {
+ if (!range.Start.IsFromEnd && !range.End.IsFromEnd && !to.IsFromEnd)
+ {
+ foreach (
+ var e in Move(
+ source,
+ range.Start.Value,
+ range.End.Value - range.Start.Value,
+ to.Value
+ )
+ )
+ {
+ yield return e;
+ }
+ }
+ else
+ {
+ if (source.TryGetCollectionCount() is int count)
+ {
+ var startIndex = range.Start.GetOffset(count);
+ var endIndex = range.End.GetOffset(count);
+ var toIndex = to.GetOffset(count);
+ yield return (T)Move(source, startIndex, endIndex - startIndex, toIndex);
+ }
+ else
+ {
+ switch ((range.Start.IsFromEnd, range.End.IsFromEnd, to.IsFromEnd))
+ {
+ case (false, false, true):
+ using (var e = source.GetEnumerator())
+ {
+ if (!e.MoveNext())
+ {
+ yield break;
+ }
+
+ var bufferCap = to.Value;
+ var moveCap = range.End.Value - range.Start.Value;
+ var buffer = new Queue(bufferCap);
+ var move = new Queue(moveCap);
+
+ buffer.Enqueue(e.Current);
+ count = 1;
+
+ while (e.MoveNext())
+ {
+ buffer.Enqueue(e.Current);
+ checked
+ {
+ ++count;
+ }
+ if (count > to.Value)
+ {
+ var idx = count - bufferCap;
+ if (idx > range.Start.Value && idx <= range.End.Value)
+ {
+ move.Enqueue(buffer.Dequeue());
+ }
+ else
+ {
+ yield return buffer.Dequeue();
+ }
+ }
+ }
+
+ var preQSize = range.Start.Value - to.GetOffset(count);
+ var preQ = new Queue(Math.Abs(preQSize));
+ for (var i = 0; i < preQSize; i++)
+ preQ.Enqueue(buffer.Dequeue());
+
+ if (move.Count == 0)
+ {
+ for (var i = 0; i < moveCap && buffer.TryDequeue(out var el); i++)
+ yield return el;
+ }
+ else
+ {
+ while (move.TryDequeue(out var element))
+ yield return element;
+ }
+
+ while (preQ.TryDequeue(out var el))
+ yield return el;
+
+ while (buffer.TryDequeue(out var element))
+ yield return element;
+ }
+ yield break;
+ case (false, true, false):
+ using (var e = source.GetEnumerator())
+ {
+ if (!e.MoveNext())
+ {
+ yield break;
+ }
+
+ count = 1;
+ var toMove = new Queue();
+ var b = new Queue(range.End.Value);
+ var min = Math.Min(range.Start.Value, to.Value);
+ b.Enqueue(e.Current);
+
+ while (e.MoveNext())
+ {
+ if (count <= min)
+ {
+ yield return b.Dequeue();
+ }
+ else
+ {
+ if (count - min >= range.End.Value)
+ {
+ toMove.Enqueue(b.Dequeue());
+ }
+ }
+ b.Enqueue(e.Current);
+ checked
+ {
+ ++count;
+ }
+ }
+
+ var dir = range.Start.Value - to.Value;
+ for (; dir < 0; dir++)
+ yield return b.Dequeue();
+
+ var tmpQ = new Queue(Math.Abs(dir));
+ for (; dir > 0; dir--)
+ {
+ tmpQ.Enqueue(toMove.Dequeue());
+ }
+
+ while (toMove.TryDequeue(out var el))
+ yield return el;
+
+ while (tmpQ.TryDequeue(out var el))
+ yield return el;
+
+ while (b.TryDequeue(out var el))
+ yield return el;
+ }
+ break;
+ case (false, true, true):
+ // [4, 5, 2, 4, 1, §, 5] Move(1..^4, ^2)
+ // Optimisitc approach - yield elements until start.
+ break;
+ case (true, false, false):
+ // [4, 5, 2, 4, 1, §, 5] Move(^5..4, 2)
+
+ break;
+ case (true, false, true):
+ // [4, 5, 2, 4, 1, §, 5] Move(^5..4, ^2)
+ break;
+ case (true, true, false):
+ if (range.End.Value > range.Start.Value)
+ {
+ // Invalid range provided
+ yield break;
+ }
+ break;
+ case (true, true, true):
+ // [4, 5, 2, 4, 1, §, 5] Move(^5..^3, ^2)
+ break;
+ }
+ }
+ }
+ }
}
diff --git a/Source/SuperLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt b/Source/SuperLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt
index cf38aa4c..bd7a717e 100644
--- a/Source/SuperLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt
+++ b/Source/SuperLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt
@@ -109,6 +109,7 @@ static SuperLinq.SuperEnumerable.LeftOuterLoopJoin
static SuperLinq.SuperEnumerable.LeftOuterLoopJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! leftResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
+static SuperLinq.SuperEnumerable.Move(this System.Collections.Generic.IEnumerable! source, System.Range range, System.Index to) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.RightOuterHashJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! rightResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.RightOuterHashJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft? Left, TRight Right)>!
static SuperLinq.SuperEnumerable.RightOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! rightResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
diff --git a/Source/SuperLinq/PublicAPI/net7.0/PublicAPI.Unshipped.txt b/Source/SuperLinq/PublicAPI/net7.0/PublicAPI.Unshipped.txt
index cf38aa4c..bd7a717e 100644
--- a/Source/SuperLinq/PublicAPI/net7.0/PublicAPI.Unshipped.txt
+++ b/Source/SuperLinq/PublicAPI/net7.0/PublicAPI.Unshipped.txt
@@ -109,6 +109,7 @@ static SuperLinq.SuperEnumerable.LeftOuterLoopJoin
static SuperLinq.SuperEnumerable.LeftOuterLoopJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! leftResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
+static SuperLinq.SuperEnumerable.Move(this System.Collections.Generic.IEnumerable! source, System.Range range, System.Index to) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.RightOuterHashJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! rightResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.RightOuterHashJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft? Left, TRight Right)>!
static SuperLinq.SuperEnumerable.RightOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! rightResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
diff --git a/Source/SuperLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/Source/SuperLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt
index cf38aa4c..bd7a717e 100644
--- a/Source/SuperLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt
+++ b/Source/SuperLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt
@@ -109,6 +109,7 @@ static SuperLinq.SuperEnumerable.LeftOuterLoopJoin
static SuperLinq.SuperEnumerable.LeftOuterLoopJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! leftResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
+static SuperLinq.SuperEnumerable.Move(this System.Collections.Generic.IEnumerable! source, System.Range range, System.Index to) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.RightOuterHashJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! rightResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.RightOuterHashJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft? Left, TRight Right)>!
static SuperLinq.SuperEnumerable.RightOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! rightResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
diff --git a/Source/SuperLinq/PublicAPI/netcoreapp3.1/PublicAPI.Unshipped.txt b/Source/SuperLinq/PublicAPI/netcoreapp3.1/PublicAPI.Unshipped.txt
index cf38aa4c..bd7a717e 100644
--- a/Source/SuperLinq/PublicAPI/netcoreapp3.1/PublicAPI.Unshipped.txt
+++ b/Source/SuperLinq/PublicAPI/netcoreapp3.1/PublicAPI.Unshipped.txt
@@ -109,6 +109,7 @@ static SuperLinq.SuperEnumerable.LeftOuterLoopJoin
static SuperLinq.SuperEnumerable.LeftOuterLoopJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! leftResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
+static SuperLinq.SuperEnumerable.Move(this System.Collections.Generic.IEnumerable! source, System.Range range, System.Index to) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.RightOuterHashJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! rightResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
static SuperLinq.SuperEnumerable.RightOuterHashJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Collections.Generic.IEqualityComparer? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft? Left, TRight Right)>!
static SuperLinq.SuperEnumerable.RightOuterMergeJoin(this System.Collections.Generic.IEnumerable! left, System.Collections.Generic.IEnumerable! right, System.Func! leftKeySelector, System.Func! rightKeySelector, System.Func! rightResultSelector, System.Func! bothResultSelector, System.Collections.Generic.IComparer? comparer = null) -> System.Collections.Generic.IEnumerable!
diff --git a/Tests/SuperLinq.Test/MoveTest.cs b/Tests/SuperLinq.Test/MoveTest.cs
index 5bb076c1..1d8af375 100644
--- a/Tests/SuperLinq.Test/MoveTest.cs
+++ b/Tests/SuperLinq.Test/MoveTest.cs
@@ -5,22 +5,37 @@ public class MoveTest
[Fact]
public void MoveWithNegativeFromIndex()
{
- _ = Assert.Throws(() =>
- new[] { 1 }.Move(-1, 0, 0));
+ _ = Assert.Throws(() => new[] { 1 }.Move(-1, 0, 0));
+ }
+
+ [Fact]
+ public void MoveRangeWithNegativeStartIndex()
+ {
+ _ = Assert.Throws(() => new[] { 1 }.Move(-1..-1, 0));
}
[Fact]
public void MoveWithNegativeCount()
{
- _ = Assert.Throws(() =>
- new[] { 1 }.Move(0, -1, 0));
+ _ = Assert.Throws(() => new[] { 1 }.Move(0, -1, 0));
+ }
+
+ [Fact]
+ public void MoveRangeWithDecendingRange()
+ {
+ _ = Assert.Throws(() => new[] { 1 }.Move(0..-1, 0));
}
[Fact]
public void MoveWithNegativeToIndex()
{
- _ = Assert.Throws(() =>
- new[] { 1 }.Move(0, 0, -1));
+ _ = Assert.Throws(() => new[] { 1 }.Move(0, 0, -1));
+ }
+
+ [Fact]
+ public void MoveRangeWithNegativeToIndex()
+ {
+ _ = Assert.Throws(() => new[] { 1 }.Move(0..0, -1));
}
[Fact]
@@ -44,11 +59,25 @@ 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