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

Optimise FallbackIfEmpty #464

36 changes: 33 additions & 3 deletions Source/SuperLinq/FallbackIfEmpty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,22 @@ public static IEnumerable<T> FallbackIfEmpty<T>(this IEnumerable<T> source, IEnu
Guard.IsNotNull(source);
Guard.IsNotNull(fallback);

return Core(source, fallback);
return source.TryGetCollectionCount() is not null
julienasp marked this conversation as resolved.
Show resolved Hide resolved
&& fallback.TryGetCollectionCount() is not null
? new FallbackIfEmptyCollectionIterator<T>(source, fallback)
: Core(source, fallback);

static IEnumerable<T> Core(IEnumerable<T> source, IEnumerable<T> fallback)
{
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
do { yield return e.Current; }
while (e.MoveNext());
do
{
yield return e.Current;
} while (e.MoveNext());

yield break;
}
}
Expand All @@ -58,4 +64,28 @@ static IEnumerable<T> Core(IEnumerable<T> source, IEnumerable<T> fallback)
yield return item;
}
}

private sealed class FallbackIfEmptyCollectionIterator<T> : CollectionIterator<T>
{
private readonly IEnumerable<T> _source;
private readonly IEnumerable<T> _fallback;

public FallbackIfEmptyCollectionIterator(IEnumerable<T> source, IEnumerable<T> fallback)
{
_source = source;
_fallback = fallback;
}

public override int Count =>
_source.GetCollectionCount() == 0
? _fallback.Count()
: _source.GetCollectionCount();

protected override IEnumerable<T> GetEnumerable()
{
return _source.GetCollectionCount() == 0
? _fallback
: _source;
}
}
}
54 changes: 49 additions & 5 deletions Tests/SuperLinq.Test/FallbackIfEmptyTest.cs
julienasp marked this conversation as resolved.
Show resolved Hide resolved
julienasp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,60 @@ public class FallbackIfEmptyTest
[Fact]
public void FallbackIfEmptyWithEmptySequence()
{
using var source = Enumerable.Empty<int>().AsTestingSequence(maxEnumerations: 2);
using var source = Seq<int>().AsTestingSequence();
source.FallbackIfEmpty(12).AssertSequenceEqual(12);
}

[Fact]
public void FallbackIfEmptyWithCollectionSequence()
{
using var source = Seq<int>().AsTestingCollection();
source.FallbackIfEmpty(12).AssertSequenceEqual(12);
source.FallbackIfEmpty(12, 23).AssertSequenceEqual(12, 23);
}

[Fact]
public void FallbackIfEmptyWithNotEmptySequence()
{
using var source = Seq(1).AsTestingSequence(maxEnumerations: 2);
source.FallbackIfEmpty(12).AssertSequenceEqual(1);
source.FallbackIfEmpty(12, 23).AssertSequenceEqual(1);
using var source = Seq(1).AsTestingSequence();
source.FallbackIfEmpty(new BreakingSequence<int>()).AssertSequenceEqual(1);
}

[Fact]
public void FallbackIfEmptyWithNotEmptyCollectionSequence()
{
using var source = Seq(1).AsTestingCollection();
source.FallbackIfEmpty(new BreakingSequence<int>()).AssertSequenceEqual(1);
}

[Fact]
public void AssertFallbackIfEmptyCollectionBehaviorOnEmptyCollection()
{
using var source = Seq<int>().AsBreakingCollection();
using var fallback = Enumerable.Range(0, 10_000).AsBreakingCollection();

var result = source.FallbackIfEmpty(fallback);
result.AssertCollectionErrorChecking(10_000);
}

[Fact]
public void AssertFallbackIfEmptyCollectionBehaviorOnNonEmptyCollection()
{
using var source = Enumerable.Range(0, 10_000).AsBreakingCollection();
using var fallback = new BreakingCollection<int>();

var result = source.FallbackIfEmpty(fallback);
result.AssertCollectionErrorChecking(10_000);
}

[Fact]
public void FallbackIfEmptyUsesCollectionCountAtIterationTime()
{
var stack = new Stack<int>();

var result = stack.FallbackIfEmpty(4);
result.AssertSequenceEqual(4);

stack.Push(1);
result.AssertSequenceEqual(1);
}
}