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

Use LinkedList in Interleave to avoid many null checks #726

Merged
merged 24 commits into from
Jan 14, 2023
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c9aa710
Add TestInterleaveDoNoCallMoveNextEagerly.
Orace Nov 14, 2019
66d1228
Fix interleave implementation so it doen't call MoveNext eagerly.
Orace Nov 14, 2019
336423a
Update MoreLinq/Interleave.cs
Orace Nov 14, 2019
61e4921
Fix the test
atifaziz Nov 22, 2019
b790e53
Undo implementation to prove test isn't bokren
atifaziz Nov 22, 2019
c569479
Merge branch 'master' into issue694
atifaziz Nov 22, 2019
32f02e4
Add TestInterleaveDoNoCallMoveNextEagerly.
Orace Nov 14, 2019
6ff6d03
Fix interleave implementation so it doen't call MoveNext eagerly.
Orace Nov 14, 2019
8a972a9
Merge back originally proposed fix and test
atifaziz Nov 22, 2019
1a4270f
Interleave: add early test of null elements in otherSequences
Orace Nov 22, 2019
76e3516
Added TestInterleaveEarlyThrowOnNullElementInOtherSequences
Orace Nov 22, 2019
6f61760
Remove useless private extension method
Orace Nov 22, 2019
81479fb
Added TestInterleaveDisposesOnPartialEnumeration
Orace Nov 25, 2019
00ef366
Made TestInterleaveDisposesOnPartialEnumeration pass
Orace Nov 25, 2019
d70974b
Interleave: simple implementation using Acquire.
Orace Nov 25, 2019
9be11ad
remove trailing whitespaces
Orace Nov 25, 2019
08f7d20
Merge branch 'issue694' into ImproveInterleave
Orace Nov 25, 2019
7cc48f8
Merge remote-tracking branch 'upstream/master' into ImproveInterleave
atifaziz Jan 14, 2023
15d0da9
Dispose enumerator if first move fails
atifaziz Jan 14, 2023
3faa3bf
Improve comments
atifaziz Jan 14, 2023
31611f3
Use pattern matching on node
atifaziz Jan 14, 2023
6eb13c4
Remove redundant modifier
atifaziz Jan 14, 2023
f78c19d
Remove "Skip" suffix from iterator method name
atifaziz Jan 14, 2023
5314fb3
Convert core iterator into local function
atifaziz Jan 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 27 additions & 26 deletions MoreLinq/Interleave.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,54 +50,55 @@ public static IEnumerable<T> Interleave<T>(this IEnumerable<T> sequence, params
if (otherSequences.Any(s => s == null))
throw new ArgumentNullException(nameof(otherSequences), "One or more sequences passed to Interleave was null.");

return _(); IEnumerable<T> _()
return _(otherSequences.Prepend(sequence));

static IEnumerable<T> _(IEnumerable<IEnumerable<T>> sequences)
{
var sequences = new[] { sequence }.Concat(otherSequences);
var enumerators = new List<IEnumerator<T>?>();
var enumerators = new LinkedList<IEnumerator<T>>();

try
{
foreach (var enumerator in sequences.Select(s => s.GetEnumerator()))
// First, yield first element of each sequence.

foreach (var sequence in sequences)
{
enumerators.Add(enumerator);
var enumerator = sequence.GetEnumerator();

enumerators.AddLast(enumerator);
if (enumerator.MoveNext())
{
yield return enumerator.Current;
}
else
else // Dispose and remove empty sequence
{
enumerators.Remove(enumerator);
enumerator.Dispose();
enumerators.Remove(enumerator);
}
}

var hasNext = true;
while (hasNext)
// Then, yield remaining elements from each sequence.

var node = enumerators.First;
while (node is { Value: var enumerator, Next: var nextNode })
{
hasNext = false;
for (var i = 0; i < enumerators.Count; i++)
if (enumerator.MoveNext())
{
var enumerator = enumerators[i];
if (enumerator == null)
continue;

if (enumerator.MoveNext())
{
hasNext = true;
yield return enumerator.Current;
}
else
{
enumerators[i] = null;
enumerator.Dispose();
}
yield return enumerator.Current;
}
else
{
enumerator.Dispose();
enumerators.Remove(node);
}

// Work on next node or restart from first one.
node = nextNode ?? enumerators.First;
}
}
finally
{
foreach (var enumerator in enumerators)
enumerator?.Dispose();
enumerator.Dispose();
}
}
}
Expand Down