Skip to content

Commit 1f0ff5d

Browse files
committed
[FirstOrDefault] add extension
1 parent 6bc119d commit 1f0ff5d

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System.Linq;
2+
using FluentAssertions;
3+
using Xunit;
4+
5+
namespace StructLinq.Tests
6+
{
7+
public class FirstOrDefaultTests
8+
{
9+
[Fact]
10+
public void ShouldReturnFirstElement()
11+
{
12+
var array = Enumerable.Range(0, 10)
13+
.ToArray()
14+
.ToStructEnumerable()
15+
.FirstOrDefault()
16+
.Should()
17+
.Be(0);
18+
}
19+
20+
[Fact]
21+
public void ShouldReturnFirstElementZeroAlloc()
22+
{
23+
var array = Enumerable.Range(0, 10)
24+
.ToArray()
25+
.ToStructEnumerable()
26+
.FirstOrDefault(x=>x)
27+
.Should()
28+
.Be(0);
29+
}
30+
31+
[Fact]
32+
public void ShouldReturnDefault()
33+
{
34+
StructEnumerable.Empty<int>().FirstOrDefault().Should().Be(default);
35+
}
36+
37+
[Fact]
38+
public void ShouldReturnDefaultZeroAlloc()
39+
{
40+
StructEnumerable.Empty<int>().FirstOrDefault(x=>x).Should().Be(default);
41+
}
42+
43+
44+
[Fact]
45+
public void ShouldReturnFirstElementWithFunc()
46+
{
47+
var array = Enumerable.Range(0, 10)
48+
.ToArray()
49+
.ToStructEnumerable()
50+
.FirstOrDefault(x=> x > 5)
51+
.Should()
52+
.Be(6);
53+
}
54+
55+
[Fact]
56+
public void ShouldReturnFirstElementWithFuncZeroAlloc()
57+
{
58+
var array = Enumerable.Range(0, 10)
59+
.ToArray()
60+
.ToStructEnumerable()
61+
.FirstOrDefault(x=> x > 5, x=> x)
62+
.Should()
63+
.Be(6);
64+
}
65+
}
66+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// ReSharper disable once CheckNamespace
2+
3+
using System;
4+
using System.Runtime.CompilerServices;
5+
6+
// ReSharper disable once CheckNamespace
7+
namespace StructLinq
8+
{
9+
public static partial class StructEnumerable
10+
{
11+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
12+
private static T InnerFirstOrDefault<T, TEnumerator>(ref TEnumerator enumerator)
13+
where TEnumerator : struct, IStructEnumerator<T>
14+
{
15+
if (enumerator.MoveNext())
16+
{
17+
var current = enumerator.Current;
18+
enumerator.Dispose();
19+
return current;
20+
}
21+
enumerator.Dispose();
22+
return default;
23+
}
24+
25+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
26+
private static T InnerFirstOrDefault<T, TEnumerator>(ref TEnumerator enumerator, Func<T, bool> predicate)
27+
where TEnumerator : struct, IStructEnumerator<T>
28+
{
29+
while (enumerator.MoveNext())
30+
{
31+
var current = enumerator.Current;
32+
if (predicate(current))
33+
{
34+
enumerator.Dispose();
35+
return current;
36+
}
37+
}
38+
enumerator.Dispose();
39+
return default;
40+
}
41+
42+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
43+
private static T InnerFirstOrDefault<T, TEnumerator, TFunc>(ref TEnumerator enumerator, ref TFunc predicate)
44+
where TEnumerator : struct, IStructEnumerator<T>
45+
where TFunc : struct, IFunction<T, bool>
46+
{
47+
while (enumerator.MoveNext())
48+
{
49+
var current = enumerator.Current;
50+
if (predicate.Eval(current))
51+
{
52+
enumerator.Dispose();
53+
return current;
54+
}
55+
}
56+
enumerator.Dispose();
57+
return default;
58+
}
59+
60+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
61+
public static T FirstOrDefault<T, TEnumerable, TEnumerator>(this TEnumerable enumerable, Func<TEnumerable, IStructEnumerable<T, TEnumerator>> _)
62+
where TEnumerator : struct, IStructEnumerator<T>
63+
where TEnumerable : IStructEnumerable<T, TEnumerator>
64+
{
65+
var enumerator = enumerable.GetEnumerator();
66+
return InnerFirstOrDefault<T, TEnumerator>(ref enumerator);
67+
}
68+
69+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
70+
public static T FirstOrDefault<T, TEnumerator>(this IStructEnumerable<T, TEnumerator> enumerable)
71+
where TEnumerator : struct, IStructEnumerator<T>
72+
{
73+
var enumerator = enumerable.GetEnumerator();
74+
return InnerFirstOrDefault<T, TEnumerator>(ref enumerator);
75+
}
76+
77+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
78+
public static T FirstOrDefault<T, TEnumerable, TEnumerator>(this TEnumerable enumerable, Func<T, bool> predicate, Func<TEnumerable, IStructEnumerable<T, TEnumerator>> _)
79+
where TEnumerator : struct, IStructEnumerator<T>
80+
where TEnumerable : IStructEnumerable<T, TEnumerator>
81+
{
82+
var enumerator = enumerable.GetEnumerator();
83+
return InnerFirstOrDefault(ref enumerator, predicate);
84+
}
85+
86+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
87+
public static T FirstOrDefault<T, TEnumerator>(this IStructEnumerable<T, TEnumerator> enumerable, Func<T, bool> predicate)
88+
where TEnumerator : struct, IStructEnumerator<T>
89+
{
90+
var enumerator = enumerable.GetEnumerator();
91+
return InnerFirstOrDefault(ref enumerator, predicate);
92+
}
93+
94+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
95+
public static T FirstOrDefault<T, TEnumerable, TEnumerator, TFunc>(this TEnumerable enumerable, ref TFunc predicate, Func<TEnumerable, IStructEnumerable<T, TEnumerator>> _)
96+
where TEnumerator : struct, IStructEnumerator<T>
97+
where TEnumerable : IStructEnumerable<T, TEnumerator>
98+
where TFunc : struct, IFunction<T, bool>
99+
{
100+
var enumerator = enumerable.GetEnumerator();
101+
return InnerFirstOrDefault<T, TEnumerator, TFunc>(ref enumerator, ref predicate);
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)