Skip to content

Commit fd10ce0

Browse files
authored
Decompose "TagFirstLast" implementation for speed (#643)
1 parent 728bca9 commit fd10ce0

File tree

2 files changed

+38
-18
lines changed

2 files changed

+38
-18
lines changed

MoreLinq.Test/TagFirstLastTest.cs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ public class TagFirstLastTest
2525
[Test]
2626
public void TagFirstLastDoesOneLookAhead()
2727
{
28-
var source = MoreEnumerable.From(() => 123, () => 456, BreakingFunc.Of<int>());
29-
source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast })
30-
.Take(1)
31-
.Consume();
28+
using var source = MoreEnumerable.From(() => 123, () => 456, BreakingFunc.Of<int>()).AsTestingSequence();
29+
var result = source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast });
30+
31+
result.Take(1).Consume();
3232
}
3333

3434
[Test]
@@ -40,34 +40,38 @@ public void TagFirstLastIsLazy()
4040
[Test]
4141
public void TagFirstLastWithSourceSequenceOfZero()
4242
{
43-
var source = Enumerable.Empty<int>();
44-
var sut = source.TagFirstLast(BreakingFunc.Of<int, bool, bool, int>());
45-
Assert.That(sut, Is.Empty);
43+
using var source = Enumerable.Empty<int>().AsTestingSequence();
44+
var result = source.TagFirstLast(BreakingFunc.Of<int, bool, bool, int>());
45+
46+
Assert.That(result, Is.Empty);
4647
}
4748

4849
[Test]
4950
public void TagFirstLastWithSourceSequenceOfOne()
5051
{
51-
var source = new[] { 123 };
52-
source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast })
53-
.AssertSequenceEqual(new { Item = 123, IsFirst = true, IsLast = true });
52+
using var source = new[] { 123 }.AsTestingSequence();
53+
var result = source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast });
54+
55+
result.AssertSequenceEqual(new { Item = 123, IsFirst = true, IsLast = true });
5456
}
5557

5658
[Test]
5759
public void TagFirstLastWithSourceSequenceOfTwo()
5860
{
59-
var source = new[] { 123, 456 };
60-
source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast })
61-
.AssertSequenceEqual(new { Item = 123, IsFirst = true, IsLast = false },
61+
using var source = new[] { 123, 456 }.AsTestingSequence();
62+
var result = source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast });
63+
64+
result.AssertSequenceEqual(new { Item = 123, IsFirst = true, IsLast = false },
6265
new { Item = 456, IsFirst = false, IsLast = true });
6366
}
6467

6568
[Test]
6669
public void TagFirstLastWithSourceSequenceOfThree()
6770
{
68-
var source = new[] { 123, 456, 789 };
69-
source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast })
70-
.AssertSequenceEqual(new { Item = 123, IsFirst = true, IsLast = false },
71+
using var source = new[] { 123, 456, 789 }.AsTestingSequence();
72+
var result = source.TagFirstLast((item, isFirst, isLast) => new { Item = item, IsFirst = isFirst, IsLast = isLast });
73+
74+
result.AssertSequenceEqual(new { Item = 123, IsFirst = true, IsLast = false },
7175
new { Item = 456, IsFirst = false, IsLast = false },
7276
new { Item = 789, IsFirst = false, IsLast = true });
7377
}

MoreLinq/TagFirstLast.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,24 @@ public static IEnumerable<TResult> TagFirstLast<TSource, TResult>(this IEnumerab
5959
if (source == null) throw new ArgumentNullException(nameof(source));
6060
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
6161

62-
return source.Index() // count-up
63-
.CountDown(1, (e, cd) => resultSelector(e.Value, e.Key == 0, cd == 0));
62+
return _(); IEnumerable<TResult> _()
63+
{
64+
using var enumerator = source.GetEnumerator();
65+
66+
if (!enumerator.MoveNext())
67+
yield break;
68+
69+
var current = enumerator.Current;
70+
var hasNext = enumerator.MoveNext();
71+
yield return resultSelector(current, true, !hasNext);
72+
73+
while (hasNext)
74+
{
75+
current = enumerator.Current;
76+
hasNext = enumerator.MoveNext();
77+
yield return resultSelector(current, false, !hasNext);
78+
}
79+
}
6480
}
6581
}
6682
}

0 commit comments

Comments
 (0)