Skip to content
159 changes: 151 additions & 8 deletions Source/SuperLinq/Move.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,30 @@ public static partial class SuperEnumerable
/// <remarks>
/// This operator uses deferred execution and streams its results.
/// </remarks>
public static IEnumerable<T> Move<T>(this IEnumerable<T> source, int fromIndex, int count, int toIndex)
public static IEnumerable<T> Move<T>(
this IEnumerable<T> 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<T> Core(IEnumerable<T> source, int bufferStartIndex, int bufferSize, int bufferYieldIndex)
static IEnumerable<T> Core(
IEnumerable<T> source,
int bufferStartIndex,
int bufferSize,
int bufferYieldIndex
)
{
var hasMore = true;
bool MoveNext(IEnumerator<T> e) => hasMore && (hasMore = e.MoveNext());
Expand All @@ -72,4 +81,138 @@ static IEnumerable<T> Core(IEnumerable<T> source, int bufferStartIndex, int buff
yield return e.Current;
}
}

/// <summary>
/// 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="to">
/// 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 to)
{
if (range.Start.IsFromEnd || range.End.IsFromEnd || to.IsFromEnd)
{
int startIndex;
int endIndex;
int toIndex;

if (source.TryGetCollectionCount() is int count)
{
startIndex = range.Start.GetOffset(count);
endIndex = range.End.GetOffset(count);
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<T>(bufferCap);
var move = new Queue<T>(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();
}
}
}
while (move.TryDequeue(out var element))
{
yield return element;
}
while (buffer.TryDequeue(out var element))
{
yield return element;
}
}
yield break;
case (false, true, false):
// [4, 5, 2, 4, 1, §, 5] Move(1..^4, 2)
break;
case (false, true, true):
// [4, 5, 2, 4, 1, §, 5] Move(1..^4, ^2)
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)
{
yield break;
}
// [4, 5, 2, 4, 1, §, 5] Move(^5..^2, 4)
// Cannot yield any elements until count is known.
// Once count is known, can proceed to yield elements
break;
case (true, true, true):
// [4, 5, 2, 4, 1, §, 5] Move(^5..^3, ^2)
break;
}
}
}
else
{
foreach (
var e in Move(
source,
range.Start.Value,
range.End.Value - range.Start.Value,
to.Value
)
)
{
yield return e;
}
}
}
}
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 @@ -109,6 +109,7 @@ static SuperLinq.SuperEnumerable.LeftOuterLoopJoin<TLeft, TRight, TKey, TResult>
static SuperLinq.SuperEnumerable.LeftOuterLoopJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TLeft, TResult>! leftResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.Move<T>(this System.Collections.Generic.IEnumerable<T>! source, System.Range range, System.Index to) -> System.Collections.Generic.IEnumerable<T>!
static SuperLinq.SuperEnumerable.RightOuterHashJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TRight, TResult>! rightResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.RightOuterHashJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft? Left, TRight Right)>!
static SuperLinq.SuperEnumerable.RightOuterMergeJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TRight, TResult>! rightResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> 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 @@ -109,6 +109,7 @@ static SuperLinq.SuperEnumerable.LeftOuterLoopJoin<TLeft, TRight, TKey, TResult>
static SuperLinq.SuperEnumerable.LeftOuterLoopJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TLeft, TResult>! leftResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.Move<T>(this System.Collections.Generic.IEnumerable<T>! source, System.Range range, System.Index to) -> System.Collections.Generic.IEnumerable<T>!
static SuperLinq.SuperEnumerable.RightOuterHashJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TRight, TResult>! rightResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.RightOuterHashJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft? Left, TRight Right)>!
static SuperLinq.SuperEnumerable.RightOuterMergeJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TRight, TResult>! rightResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> 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 @@ -109,6 +109,7 @@ static SuperLinq.SuperEnumerable.LeftOuterLoopJoin<TLeft, TRight, TKey, TResult>
static SuperLinq.SuperEnumerable.LeftOuterLoopJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TLeft, TResult>! leftResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.Move<T>(this System.Collections.Generic.IEnumerable<T>! source, System.Range range, System.Index to) -> System.Collections.Generic.IEnumerable<T>!
static SuperLinq.SuperEnumerable.RightOuterHashJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TRight, TResult>! rightResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.RightOuterHashJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft? Left, TRight Right)>!
static SuperLinq.SuperEnumerable.RightOuterMergeJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TRight, TResult>! rightResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ static SuperLinq.SuperEnumerable.LeftOuterLoopJoin<TLeft, TRight, TKey, TResult>
static SuperLinq.SuperEnumerable.LeftOuterLoopJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TLeft, TResult>! leftResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.LeftOuterMergeJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft Left, TRight? Right)>!
static SuperLinq.SuperEnumerable.Move<T>(this System.Collections.Generic.IEnumerable<T>! source, System.Range range, System.Index to) -> System.Collections.Generic.IEnumerable<T>!
static SuperLinq.SuperEnumerable.RightOuterHashJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TRight, TResult>! rightResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
static SuperLinq.SuperEnumerable.RightOuterHashJoin<TLeft, TRight, TKey>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<(TLeft? Left, TRight Right)>!
static SuperLinq.SuperEnumerable.RightOuterMergeJoin<TLeft, TRight, TKey, TResult>(this System.Collections.Generic.IEnumerable<TLeft>! left, System.Collections.Generic.IEnumerable<TRight>! right, System.Func<TLeft, TKey>! leftKeySelector, System.Func<TRight, TKey>! rightKeySelector, System.Func<TRight, TResult>! rightResultSelector, System.Func<TLeft, TRight, TResult>! bothResultSelector, System.Collections.Generic.IComparer<TKey>? comparer = null) -> System.Collections.Generic.IEnumerable<TResult>!
Expand Down
Loading