Skip to content

Commit c789e55

Browse files
committed
[Contains] add Contains extensions.
1 parent 0086f22 commit c789e55

File tree

11 files changed

+1079
-2
lines changed

11 files changed

+1079
-2
lines changed

src/StructLinq.Benchmark/ArrayOfBigStructSum.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Linq;
1+
using System;
2+
using System.Linq;
23
using BenchmarkDotNet.Attributes;
34

45
namespace StructLinq.Benchmark
@@ -98,9 +99,25 @@ public readonly int Eval(in StructContainer element)
9899
}
99100

100101

101-
internal struct StructContainer
102+
internal struct StructContainer : IEquatable<StructContainer>
102103
{
103104
public readonly int Element;
105+
106+
public bool Equals(StructContainer other)
107+
{
108+
return Element == other.Element;
109+
}
110+
111+
public override bool Equals(object obj)
112+
{
113+
return obj is StructContainer other && Equals(other);
114+
}
115+
116+
public override int GetHashCode()
117+
{
118+
return Element;
119+
}
120+
104121
public readonly int Element1;
105122
public readonly int Element2;
106123
public readonly int Element3;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using BenchmarkDotNet.Attributes;
4+
5+
namespace StructLinq.Benchmark
6+
{
7+
//``` ini
8+
9+
//BenchmarkDotNet=v0.12.0, OS=Windows 10.0.19041
10+
//Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
11+
//.NET Core SDK=3.1.402
12+
//[Host] : .NET Core 3.1.8 (CoreCLR 4.700.20.41105, CoreFX 4.700.20.41903), X64 RyuJIT
13+
//DefaultJob : .NET Core 3.1.8 (CoreCLR 4.700.20.41105, CoreFX 4.700.20.41903), X64 RyuJIT
14+
15+
16+
//```
17+
//| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
18+
//|-------------------- |---------:|----------:|----------:|---------:|------:|--------:|-------:|------:|------:|----------:|
19+
//| Linq | 1.409 us | 0.0343 us | 0.1001 us | 1.382 us | 1.00 | 0.00 | - | - | - | - |
20+
//| Array | 1.274 us | 0.0175 us | 0.0163 us | 1.272 us | 0.92 | 0.05 | - | - | - | - |
21+
//| StructLinq | 2.244 us | 0.0353 us | 0.0313 us | 2.240 us | 1.63 | 0.09 | 0.0076 | - | - | 40 B |
22+
//| StructLinqZeroAlloc | 2.924 us | 0.0203 us | 0.0190 us | 2.926 us | 2.11 | 0.12 | - | - | - | - |
23+
24+
[DisassemblyDiagnoser(recursiveDepth: 4),MemoryDiagnoser]
25+
public class Contains
26+
{
27+
private const int Count = 10_000;
28+
private readonly int[] array;
29+
private readonly IEnumerable<int> enumerable;
30+
31+
32+
public Contains()
33+
{
34+
array = Enumerable.Range(0, Count).ToArray();
35+
enumerable = Enumerable.Range(0, Count).ToArray();
36+
}
37+
38+
[Benchmark(Baseline = true)]
39+
public bool Linq()
40+
{
41+
return enumerable.Contains(5_000);
42+
}
43+
44+
[Benchmark]
45+
public bool Array()
46+
{
47+
return array.Contains(5_000);
48+
}
49+
50+
[Benchmark]
51+
public bool StructLinq()
52+
{
53+
return array.ToStructEnumerable().Contains(5_000);
54+
}
55+
56+
[Benchmark]
57+
public bool StructLinqZeroAlloc()
58+
{
59+
return array.ToStructEnumerable().Contains(5_000, x=> x);
60+
}
61+
}
62+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using BenchmarkDotNet.Attributes;
4+
5+
namespace StructLinq.Benchmark
6+
{
7+
8+
//``` ini
9+
10+
//BenchmarkDotNet=v0.12.0, OS=Windows 10.0.19041
11+
//Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
12+
//.NET Core SDK=3.1.402
13+
//[Host] : .NET Core 3.1.8 (CoreCLR 4.700.20.41105, CoreFX 4.700.20.41903), X64 RyuJIT
14+
//DefaultJob : .NET Core 3.1.8 (CoreCLR 4.700.20.41105, CoreFX 4.700.20.41903), X64 RyuJIT
15+
16+
17+
//```
18+
//| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
19+
//|----------------------------------------- |----------:|----------:|----------:|------:|--------:|------:|------:|------:|----------:|
20+
//| Linq | 5.819 us | 0.0537 us | 0.0448 us | 1.00 | 0.00 | - | - | - | - |
21+
//| Array | 5.933 us | 0.1170 us | 0.1955 us | 1.04 | 0.03 | - | - | - | - |
22+
//| StructLinq | 22.997 us | 0.5700 us | 0.4760 us | 3.95 | 0.09 | - | - | - | - |
23+
//| RefStructLinq | 33.126 us | 0.6585 us | 1.2687 us | 5.72 | 0.23 | - | - | - | - |
24+
//| StructLinqWithCustomComparer | 15.626 us | 0.0944 us | 0.0837 us | 2.69 | 0.03 | - | - | - | - |
25+
//| RefStructLinqZeroAllocwithCustomComparer | 3.775 us | 0.0654 us | 0.0580 us | 0.65 | 0.01 | - | - | - | - |
26+
27+
28+
[MemoryDiagnoser]
29+
public class ContainsOnBigStruct
30+
{
31+
private const int Count = 10_000;
32+
private readonly StructContainer[] array;
33+
private readonly IEnumerable<StructContainer> enumerable;
34+
35+
public ContainsOnBigStruct()
36+
{
37+
array = Enumerable.Range(0, Count).Select(StructContainer.Create).ToArray();
38+
enumerable = Enumerable.Range(0, Count).Select(StructContainer.Create).ToArray();
39+
}
40+
41+
[Benchmark(Baseline = true)]
42+
public bool Linq()
43+
{
44+
return enumerable.Contains(StructContainer.Create(5_000));
45+
}
46+
47+
[Benchmark]
48+
public bool Array()
49+
{
50+
return array.Contains(StructContainer.Create(5_000));
51+
}
52+
53+
[Benchmark]
54+
public bool StructLinq()
55+
{
56+
return array.ToStructEnumerable().Contains(StructContainer.Create(5_000), x=>x);
57+
58+
}
59+
60+
[Benchmark]
61+
public bool RefStructLinq()
62+
{
63+
return array.ToRefStructEnumerable().Contains(StructContainer.Create(5_000), x=> x);
64+
}
65+
66+
[Benchmark]
67+
public bool StructLinqWithCustomComparer()
68+
{
69+
var comparer = new DistinctOnBigStruct.StructEqualityComparer();
70+
return array.ToStructEnumerable().Contains(StructContainer.Create(5_000), comparer, x=>x);
71+
72+
}
73+
74+
[Benchmark]
75+
public bool RefStructLinqZeroAllocwithCustomComparer()
76+
{
77+
var comparer = new DistinctOnBigStruct.StructEqualityComparer();
78+
return array.ToRefStructEnumerable().Contains(StructContainer.Create(5_000), comparer, x=> x);
79+
}
80+
}
81+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using BenchmarkDotNet.Attributes;
4+
5+
namespace StructLinq.Benchmark
6+
{
7+
//``` ini
8+
9+
//BenchmarkDotNet=v0.12.0, OS=Windows 10.0.19041
10+
//Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
11+
//.NET Core SDK=3.1.402
12+
//[Host] : .NET Core 3.1.8 (CoreCLR 4.700.20.41105, CoreFX 4.700.20.41903), X64 RyuJIT
13+
//DefaultJob : .NET Core 3.1.8 (CoreCLR 4.700.20.41105, CoreFX 4.700.20.41903), X64 RyuJIT
14+
15+
16+
//```
17+
//| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
18+
//|-------------------- |---------:|---------:|---------:|------:|--------:|------:|------:|------:|----------:|
19+
//| Linq | 32.64 us | 0.638 us | 0.566 us | 1.00 | 0.00 | - | - | - | 48 B |
20+
//| Array | 32.22 us | 0.400 us | 0.355 us | 0.99 | 0.02 | - | - | - | 48 B |
21+
//| StructLinq | 18.95 us | 0.172 us | 0.152 us | 0.58 | 0.01 | - | - | - | 72 B |
22+
//| StructLinqZeroAlloc | 19.46 us | 0.607 us | 0.596 us | 0.60 | 0.02 | - | - | - | - |
23+
24+
25+
[DisassemblyDiagnoser(recursiveDepth: 4),MemoryDiagnoser]
26+
public class ContainsWhere
27+
{
28+
private const int Count = 10_000;
29+
private readonly int[] array;
30+
private readonly IEnumerable<int> enumerable;
31+
32+
33+
public ContainsWhere()
34+
{
35+
array = Enumerable.Range(0, Count).ToArray();
36+
enumerable = Enumerable.Range(0, Count).ToArray();
37+
}
38+
39+
[Benchmark(Baseline = true)]
40+
public bool Linq()
41+
{
42+
return enumerable.Where(x=> true).Contains(5_000);
43+
}
44+
45+
[Benchmark]
46+
public bool Array()
47+
{
48+
return array.Where(x=> true).Contains(5_000);
49+
}
50+
51+
[Benchmark]
52+
public bool StructLinq()
53+
{
54+
return array.ToStructEnumerable().Where(x=> true).Contains(5_000);
55+
}
56+
57+
[Benchmark]
58+
public bool StructLinqZeroAlloc()
59+
{
60+
return array.ToStructEnumerable().Where(x=> true, x=> x).Contains(5_000, x=> x);
61+
}
62+
}
63+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using BenchmarkDotNet.Attributes;
4+
5+
namespace StructLinq.Benchmark
6+
{
7+
//``` ini
8+
9+
//BenchmarkDotNet=v0.12.0, OS=Windows 10.0.19041
10+
//Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
11+
//.NET Core SDK=3.1.402
12+
//[Host] : .NET Core 3.1.8 (CoreCLR 4.700.20.41105, CoreFX 4.700.20.41903), X64 RyuJIT
13+
//DefaultJob : .NET Core 3.1.8 (CoreCLR 4.700.20.41105, CoreFX 4.700.20.41903), X64 RyuJIT
14+
15+
16+
//```
17+
//| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
18+
//|----------------------------------------- |----------:|---------:|---------:|------:|--------:|------:|------:|------:|----------:|
19+
//| Linq | 110.22 us | 2.488 us | 6.976 us | 1.00 | 0.00 | - | - | - | 80 B |
20+
//| Array | 104.70 us | 2.050 us | 3.481 us | 0.94 | 0.08 | - | - | - | 80 B |
21+
//| StructLinq | 43.85 us | 0.550 us | 0.459 us | 0.37 | 0.03 | - | - | - | - |
22+
//| RefStructLinq | 51.53 us | 1.077 us | 1.058 us | 0.44 | 0.03 | - | - | - | - |
23+
//| StructLinqWithCustomComparer | 35.22 us | 0.636 us | 0.563 us | 0.30 | 0.02 | - | - | - | - |
24+
//| RefStructLinqZeroAllocwithCustomComparer | 21.92 us | 0.160 us | 0.149 us | 0.19 | 0.01 | - | - | - | - |
25+
26+
27+
[MemoryDiagnoser]
28+
public class ContainsWhereOnBigStruct
29+
{
30+
private const int Count = 10_000;
31+
private readonly StructContainer[] array;
32+
private readonly IEnumerable<StructContainer> enumerable;
33+
34+
public ContainsWhereOnBigStruct()
35+
{
36+
array = Enumerable.Range(0, Count).Select(StructContainer.Create).ToArray();
37+
enumerable = Enumerable.Range(0, Count).Select(StructContainer.Create).ToArray();
38+
}
39+
40+
[Benchmark(Baseline = true)]
41+
public bool Linq()
42+
{
43+
return enumerable.Where(x=> true).Contains(StructContainer.Create(5_000));
44+
}
45+
46+
[Benchmark]
47+
public bool Array()
48+
{
49+
return array.Where(x=> true).Contains(StructContainer.Create(5_000));
50+
}
51+
52+
[Benchmark]
53+
public bool StructLinq()
54+
{
55+
return array.ToStructEnumerable().Where(x=> true, x=>x).Contains(StructContainer.Create(5_000), x=>x);
56+
57+
}
58+
59+
[Benchmark]
60+
public bool RefStructLinq()
61+
{
62+
return array.ToRefStructEnumerable().Where((in StructContainer x)=> true, x=>x).Contains(StructContainer.Create(5_000), x=> x);
63+
}
64+
65+
[Benchmark]
66+
public bool StructLinqWithCustomComparer()
67+
{
68+
var comparer = new DistinctOnBigStruct.StructEqualityComparer();
69+
return array.ToStructEnumerable().Where(x=> true, x=>x).Contains(StructContainer.Create(5_000), comparer, x=>x);
70+
71+
}
72+
73+
[Benchmark]
74+
public bool RefStructLinqZeroAllocwithCustomComparer()
75+
{
76+
var comparer = new DistinctOnBigStruct.StructEqualityComparer();
77+
return array.ToRefStructEnumerable().Where((in StructContainer x)=> true, x=>x).Contains(StructContainer.Create(5_000), comparer, x=> x);
78+
}
79+
}
80+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using FluentAssertions;
2+
using Xunit;
3+
4+
namespace StructLinq.Tests
5+
{
6+
public class ContainsTests
7+
{
8+
[Fact]
9+
public void ShouldReturnTrue()
10+
{
11+
var enumerable = StructEnumerable.Range(0, 100);
12+
for (int i = 0; i < 100; i++)
13+
{
14+
enumerable.Contains(i, x => x).Should().BeTrue();
15+
}
16+
}
17+
18+
[Fact]
19+
public void ShouldReturnFalse()
20+
{
21+
var enumerable = StructEnumerable.Range(0, 100);
22+
enumerable.Contains(-10, x => x).Should().BeFalse();
23+
}
24+
25+
[Fact]
26+
public void ShouldReturnFalseWithInterface()
27+
{
28+
var enumerable = StructEnumerable.Range(0, 100);
29+
enumerable.Contains(-10).Should().BeFalse();
30+
}
31+
32+
[Fact]
33+
public void ShouldReturnTrueWithInterface()
34+
{
35+
var enumerable = StructEnumerable.Range(0, 100);
36+
for (int i = 0; i < 100; i++)
37+
{
38+
enumerable.Contains(i).Should().BeTrue();
39+
}
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)