Skip to content

Commit db9df6e

Browse files
committed
[Union] use visitor to improve performance.
1 parent 7647116 commit db9df6e

File tree

5 files changed

+61
-37
lines changed

5 files changed

+61
-37
lines changed

Documents/BenchmarksResults/Union.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical core
1616
```
1717
| Method | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
1818
|---------------------------------- |---------:|--------:|--------:|------:|--------:|--------:|--------:|----------:|
19-
| Linq | 424.0 μs | 8.27 μs | 7.74 μs | 1.00 | 90.8203 | 90.8203 | 90.8203 | 524824 B |
20-
| StructLinq | 184.9 μs | 2.72 μs | 2.42 μs | 0.44 | - | - | - | 64 B |
21-
| StructLinqZeroAlloc | 184.4 μs | 1.89 μs | 1.58 μs | 0.43 | - | - | - | - |
22-
| StructLinqZeroAllocAndComparer | 149.1 μs | 0.82 μs | 0.69 μs | 0.35 | - | - | - | - |
23-
| StructLinqZeroAllocAndComparerSum | 132.7 μs | 0.41 μs | 0.37 μs | 0.31 | - | - | - | - |
19+
| Linq | 430.9 μs | 3.74 μs | 3.12 μs | 1.00 | 90.8203 | 90.8203 | 90.8203 | 524824 B |
20+
| StructLinq | 182.4 μs | 3.57 μs | 3.34 μs | 0.42 | - | - | - | 64 B |
21+
| StructLinqZeroAlloc | 187.4 μs | 3.61 μs | 3.71 μs | 0.43 | - | - | - | - |
22+
| StructLinqZeroAllocAndComparer | 152.3 μs | 2.96 μs | 3.40 μs | 0.36 | - | - | - | - |
23+
| StructLinqZeroAllocAndComparerSum | 109.8 μs | 2.19 μs | 3.48 μs | 0.25 | - | - | - | - |

src/StructLinq.Tests/UnionTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,17 @@ public void SameAsSystem()
3030
var value = array1.ToStructEnumerable().Union(array2.ToStructEnumerable()).ToArray();
3131
Assert.Equal(expected, value);
3232
}
33+
34+
[Fact]
35+
public void SameAsSystemEnumerable()
36+
{
37+
var array1 = new int[] { 1, 1, 2, 3, 4, 4, 5 };
38+
var array2 = new int[] { 4, 5, 6, 6, 7, 8, 9 };
39+
40+
var expected = array1.Union(array2);
41+
var value = array1.ToStructEnumerable().Union(array2.ToStructEnumerable()).ToEnumerable();
42+
Assert.Equal(expected, value);
43+
}
44+
3345
}
3446
}

src/StructLinq/Distinct/DistinctEnumerable.cs

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Buffers;
22
using System.Collections.Generic;
33
using System.Runtime.CompilerServices;
4+
using StructLinq.Utils;
45
using StructLinq.Utils.Collections;
56

67
namespace StructLinq.Distinct
@@ -38,36 +39,11 @@ public DistinctEnumerator<T, TEnumerator, TComparer> GetEnumerator()
3839
public VisitStatus Visit<TVisitor>(ref TVisitor visitor)
3940
where TVisitor : IVisitor<T>
4041
{
41-
var distinctVisitor = new DistinctVisitor<TVisitor>(capacity, bucketPool, slotPool, comparer, ref visitor);
42+
var distinctVisitor = new DistinctVisitor<T, TComparer, TVisitor>(capacity, bucketPool, slotPool, comparer, ref visitor);
4243
var visitStatus = enumerable.Visit(ref distinctVisitor);
43-
visitor = distinctVisitor.visitor;
44+
visitor = distinctVisitor.Visitor;
4445
distinctVisitor.Dispose();
4546
return visitStatus;
4647
}
47-
48-
private struct DistinctVisitor<TVisitor> : IVisitor<T>
49-
where TVisitor : IVisitor<T>
50-
{
51-
public TVisitor visitor;
52-
private PooledSet<T, TComparer> set;
53-
54-
public DistinctVisitor(int capacity, ArrayPool<int> bucketPool, ArrayPool<Slot<T>> slotPool, TComparer comparer, ref TVisitor visitor)
55-
{
56-
this.visitor = visitor;
57-
set = new PooledSet<T, TComparer>(capacity, bucketPool, slotPool, comparer);
58-
}
59-
60-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
61-
public bool Visit(T input)
62-
{
63-
return !set.AddIfNotPresent(input) || visitor.Visit(input);
64-
}
65-
66-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
67-
public void Dispose()
68-
{
69-
set.Dispose();
70-
}
71-
}
7248
}
7349
}

src/StructLinq/Union/UnionEnumerable.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Buffers;
22
using System.Collections.Generic;
33
using System.Runtime.CompilerServices;
4+
using StructLinq.Utils;
45
using StructLinq.Utils.Collections;
56

67
namespace StructLinq.Union
@@ -44,13 +45,15 @@ public UnionEnumerator<T, TEnumerator1, TEnumerator2, TComparer> GetEnumerator()
4445
public VisitStatus Visit<TVisitor>(ref TVisitor visitor)
4546
where TVisitor : IVisitor<T>
4647
{
47-
foreach (var input in this)
48+
var distinctVisitor = new DistinctVisitor<T, TComparer, TVisitor>(capacity, bucketPool, slotPool, comparer, ref visitor);
49+
var visitStatus = enumerable1.Visit(ref distinctVisitor);
50+
if (visitStatus != VisitStatus.VisitorFinished)
4851
{
49-
if (!visitor.Visit(input))
50-
return VisitStatus.VisitorFinished;
52+
visitStatus = enumerable2.Visit(ref distinctVisitor);
5153
}
52-
53-
return VisitStatus.EnumeratorFinished;
54+
visitor = distinctVisitor.Visitor;
55+
distinctVisitor.Dispose();
56+
return visitStatus;
5457
}
5558
}
5659
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Buffers;
2+
using System.Collections.Generic;
3+
using System.Runtime.CompilerServices;
4+
using StructLinq.Utils.Collections;
5+
6+
namespace StructLinq.Utils
7+
{
8+
internal struct DistinctVisitor<T, TComparer, TVisitor> : IVisitor<T>
9+
where TComparer : IEqualityComparer<T>
10+
where TVisitor : IVisitor<T>
11+
{
12+
public TVisitor Visitor;
13+
private PooledSet<T, TComparer> set;
14+
15+
public DistinctVisitor(int capacity, ArrayPool<int> bucketPool, ArrayPool<Slot<T>> slotPool, TComparer comparer, ref TVisitor visitor)
16+
{
17+
this.Visitor = visitor;
18+
set = new PooledSet<T, TComparer>(capacity, bucketPool, slotPool, comparer);
19+
}
20+
21+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
22+
public bool Visit(T input)
23+
{
24+
return !set.AddIfNotPresent(input) || Visitor.Visit(input);
25+
}
26+
27+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
28+
public void Dispose()
29+
{
30+
set.Dispose();
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)