From 2142e403aa9ec19c27954fc35e2d796ab4a20066 Mon Sep 17 00:00:00 2001 From: Orace Date: Thu, 12 Dec 2019 11:30:14 +0100 Subject: [PATCH 1/3] Renamed TestInterleaveDisposesOnError to TestInterleaveDisposesOnErrorAtGetEnumerator. Add TestInterleaveDisposesOnErrorAtMoveNext. --- MoreLinq.Test/InterleaveTest.cs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/MoreLinq.Test/InterleaveTest.cs b/MoreLinq.Test/InterleaveTest.cs index 35c3bd863..f27ce34b9 100644 --- a/MoreLinq.Test/InterleaveTest.cs +++ b/MoreLinq.Test/InterleaveTest.cs @@ -52,13 +52,27 @@ public void TestInterleaveDoNoCallMoveNextEagerly() /// to open successfully /// [Test] - public void TestInterleaveDisposesOnError() + public void TestInterleaveDisposesOnErrorAtGetEnumerator() { - using (var sequenceA = TestingSequence.Of()) - { - Assert.Throws(() => // Expected and thrown by BreakingSequence - sequenceA.Interleave(new BreakingSequence()).Consume()); - } + using var sequenceA = TestingSequence.Of(); + var sequenceB = new BreakingSequence(); + + // Expected and thrown by BreakingSequence + Assert.Throws(() => sequenceA.Interleave(sequenceB).Consume()); + } + + /// + /// Verify that interleaving disposes those enumerators that it managed + /// to open successfully + /// + [Test] + public void TestInterleaveDisposesOnErrorAtMoveNext() + { + using var sequenceA = TestingSequence.Of(); + using var sequenceB = MoreEnumerable.From(() => throw new TestException()).AsTestingSequence(); + + // Expected and thrown by sequenceB + Assert.Throws(() => sequenceA.Interleave(sequenceB).Consume()); } /// From 673b42ca15881fe31199b278f3d487ef5a19a513 Mon Sep 17 00:00:00 2001 From: Orace Date: Thu, 12 Dec 2019 11:39:13 +0100 Subject: [PATCH 2/3] Avoid eagerly calls to GetEnumerator in Interleave --- MoreLinq/Interleave.cs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/MoreLinq/Interleave.cs b/MoreLinq/Interleave.cs index 164fec136..3ffcb26c0 100644 --- a/MoreLinq/Interleave.cs +++ b/MoreLinq/Interleave.cs @@ -53,17 +53,29 @@ public static IEnumerable Interleave(this IEnumerable sequence, params return _(); IEnumerable _() { var sequences = new[] { sequence }.Concat(otherSequences); - - // produce an enumerators collection for all IEnumerable instances passed to us - var enumerators = sequences.Select(e => e.GetEnumerator()).Acquire(); + var enumerators = new List>(); try { + foreach (var enumerator in sequences.Select(s => s.GetEnumerator())) + { + enumerators.Add(enumerator); + if (enumerator.MoveNext()) + { + yield return enumerator.Current; + } + else + { + enumerators.Remove(enumerator); + enumerator.Dispose(); + } + } + var hasNext = true; while (hasNext) { hasNext = false; - for (var i = 0; i < enumerators.Length; i++) + for (var i = 0; i < enumerators.Count; i++) { var enumerator = enumerators[i]; if (enumerator == null) From 03161436113dba3e62054e0c9e4e01aea12298a9 Mon Sep 17 00:00:00 2001 From: Orace Date: Thu, 12 Dec 2019 11:57:05 +0100 Subject: [PATCH 3/3] Add TestInterleaveDoNotCallGetEnumeratorEagerly --- MoreLinq.Test/InterleaveTest.cs | 36 ++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/MoreLinq.Test/InterleaveTest.cs b/MoreLinq.Test/InterleaveTest.cs index f27ce34b9..6c1498262 100644 --- a/MoreLinq.Test/InterleaveTest.cs +++ b/MoreLinq.Test/InterleaveTest.cs @@ -35,18 +35,6 @@ public void TestInterleaveIsLazy() new BreakingSequence().Interleave(new BreakingSequence()); } - /// - /// Verify that interleaving do not call enumerators MoveNext method eagerly - /// - [Test] - public void TestInterleaveDoNoCallMoveNextEagerly() - { - var sequenceA = Enumerable.Range(1, 1); - var sequenceB = MoreEnumerable.From(() => throw new TestException()); - - sequenceA.Interleave(sequenceB).Take(1).Consume(); - } - /// /// Verify that interleaving disposes those enumerators that it managed /// to open successfully @@ -75,6 +63,30 @@ public void TestInterleaveDisposesOnErrorAtMoveNext() Assert.Throws(() => sequenceA.Interleave(sequenceB).Consume()); } + /// + /// Verify that interleaving do not call enumerable GetEnumerator method eagerly + /// + [Test] + public void TestInterleaveDoNotCallGetEnumeratorEagerly() + { + var sequenceA = TestingSequence.Of(1); + var sequenceB = new BreakingSequence(); + + sequenceA.Interleave(sequenceB).Take(1).Consume(); + } + + /// + /// Verify that interleaving do not call enumerators MoveNext method eagerly + /// + [Test] + public void TestInterleaveDoNoCallMoveNextEagerly() + { + var sequenceA = Enumerable.Range(1, 1); + var sequenceB = MoreEnumerable.From(() => throw new TestException()); + + sequenceA.Interleave(sequenceB).Take(1).Consume(); + } + /// /// Verify that two balanced sequences will interleave all of their elements ///