Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d6d748e

Browse files
authored
Feature/stateless filtering and transforming (reactivemarbles#823)
* Fixed a build defect, present only for Debug builds, within Cache/TransformManyAsyncFixture * Adjusted .editorconfig to allow for multi-line expressions to be passed as method parameters. * Adjusted .editorconfig to re-allow omission of brackets for single-line code blocks. * Consolidated language settings across all projects, and added polyfills to .Benchmarks, to match the other two. * Added new operators `.FilterImmutable()` and `.TransformImmutable()` to provide better performance for static/deterministic scenarios.
1 parent 38c6a38 commit d6d748e

19 files changed

+1400
-11
lines changed

.editorconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ dotnet_diagnostic.SA1114.severity = error
349349
dotnet_diagnostic.SA1115.severity = error
350350
dotnet_diagnostic.SA1116.severity = error
351351
dotnet_diagnostic.SA1117.severity = error
352-
dotnet_diagnostic.SA1118.severity = error
352+
dotnet_diagnostic.SA1118.severity = none
353353
dotnet_diagnostic.SA1119.severity = error
354354
dotnet_diagnostic.SA1120.severity = error
355355
dotnet_diagnostic.SA1121.severity = error
@@ -415,7 +415,7 @@ dotnet_diagnostic.SA1413.severity = none
415415
dotnet_diagnostic.SA1500.severity = error
416416
dotnet_diagnostic.SA1501.severity = error
417417
dotnet_diagnostic.SA1502.severity = error
418-
dotnet_diagnostic.SA1503.severity = error
418+
dotnet_diagnostic.SA1503.severity = none
419419
dotnet_diagnostic.SA1504.severity = error
420420
dotnet_diagnostic.SA1505.severity = error
421421
dotnet_diagnostic.SA1506.severity = error

src/Directory.Build.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
<GenerateDocumentationFile>true</GenerateDocumentationFile>
66
<NoWarn>$(NoWarn);1591;1701;1702;1705;VSX1000</NoWarn>
77
<Platform>AnyCPU</Platform>
8+
<Nullable>enable</Nullable>
9+
<LangVersion>latest</LangVersion>
810
<IsTestProject>$(MSBuildProjectName.Contains('Tests'))</IsTestProject>
911
<IsBenchmarkProject>$(MSBuildProjectName.Contains('Benchmarks'))</IsBenchmarkProject>
1012
<DebugType>embedded</DebugType>
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reactive.Subjects;
4+
5+
using BenchmarkDotNet.Attributes;
6+
7+
namespace DynamicData.Benchmarks.Cache;
8+
9+
[MemoryDiagnoser]
10+
[MarkdownExporterAttribute.GitHub]
11+
public class FilterImmutable
12+
{
13+
private readonly IReadOnlyList<IChangeSet<Item, int>> _addChangeSets;
14+
private readonly IReadOnlyList<IChangeSet<Item, int>> _replaceChangeSets;
15+
private readonly IReadOnlyList<IChangeSet<Item, int>> _removeChangeSets;
16+
17+
public FilterImmutable()
18+
{
19+
var source = new ChangeAwareCache<Item, int>(capacity: 1_000);
20+
21+
var addChangeSets = new List<IChangeSet<Item, int>>(capacity: 1_000);
22+
for (var id = 1; id <= 1_000; ++id)
23+
{
24+
source.Add(
25+
item: new Item()
26+
{
27+
Id = id,
28+
IsIncluded = (id % 2) == 0
29+
},
30+
key: id);
31+
addChangeSets.Add(source.CaptureChanges());
32+
}
33+
_addChangeSets = addChangeSets;
34+
35+
var replaceChangeSets = new List<IChangeSet<Item, int>>(capacity: 500);
36+
for (var id = 2; id <= 1_000; id += 2)
37+
{
38+
source.AddOrUpdate(
39+
item: new Item()
40+
{
41+
Id = id,
42+
IsIncluded = (id % 4) != 0
43+
},
44+
key: id);
45+
replaceChangeSets.Add(source.CaptureChanges());
46+
}
47+
_replaceChangeSets = replaceChangeSets;
48+
49+
var removeChangeSets = new List<IChangeSet<Item, int>>(capacity: 1_000);
50+
for (var id = 1; id <= 1_000; ++id)
51+
{
52+
source.Remove(id);
53+
removeChangeSets.Add(source.CaptureChanges());
54+
}
55+
_removeChangeSets = removeChangeSets;
56+
}
57+
58+
[Benchmark]
59+
public void Adds()
60+
{
61+
using var source = new Subject<IChangeSet<Item, int>>();
62+
63+
using var subscription = source
64+
.FilterImmutable(static item => item.IsIncluded)
65+
.Subscribe();
66+
67+
foreach (var changeSet in _addChangeSets)
68+
source.OnNext(changeSet);
69+
70+
source.OnCompleted();
71+
}
72+
73+
[Benchmark]
74+
public void AddsAndReplacements()
75+
{
76+
using var source = new Subject<IChangeSet<Item, int>>();
77+
78+
using var subscription = source
79+
.FilterImmutable(static item => item.IsIncluded)
80+
.Subscribe();
81+
82+
foreach (var changeSet in _addChangeSets)
83+
source.OnNext(changeSet);
84+
85+
foreach (var changeSet in _replaceChangeSets)
86+
source.OnNext(changeSet);
87+
88+
source.OnCompleted();
89+
}
90+
91+
[Benchmark]
92+
public void AddsAndRemoves()
93+
{
94+
using var source = new Subject<IChangeSet<Item, int>>();
95+
96+
using var subscription = source
97+
.FilterImmutable(static item => item.IsIncluded)
98+
.Subscribe();
99+
100+
foreach (var changeSet in _addChangeSets)
101+
source.OnNext(changeSet);
102+
103+
foreach (var changeSet in _removeChangeSets)
104+
source.OnNext(changeSet);
105+
106+
source.OnCompleted();
107+
}
108+
109+
[Benchmark]
110+
public void AddsReplacementsAndRemoves()
111+
{
112+
using var source = new Subject<IChangeSet<Item, int>>();
113+
114+
using var subscription = source
115+
.FilterImmutable(static item => item.IsIncluded)
116+
.Subscribe();
117+
118+
foreach (var changeSet in _addChangeSets)
119+
source.OnNext(changeSet);
120+
121+
foreach (var changeSet in _replaceChangeSets)
122+
source.OnNext(changeSet);
123+
124+
foreach (var changeSet in _removeChangeSets)
125+
source.OnNext(changeSet);
126+
127+
source.OnCompleted();
128+
}
129+
130+
private sealed class Item
131+
{
132+
public required int Id { get; init; }
133+
134+
public required bool IsIncluded { get; init; }
135+
}
136+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reactive.Subjects;
4+
5+
using BenchmarkDotNet.Attributes;
6+
7+
namespace DynamicData.Benchmarks.Cache;
8+
9+
[MemoryDiagnoser]
10+
[MarkdownExporterAttribute.GitHub]
11+
public class StatelessFiltering
12+
{
13+
private readonly IReadOnlyList<IChangeSet<Item, int>> _changeSets;
14+
15+
public StatelessFiltering()
16+
{
17+
var source = new ChangeAwareCache<Item, int>(capacity: 1_000);
18+
var changeSets = new List<IChangeSet<Item, int>>(capacity: 2_500);
19+
20+
for (var id = 1; id <= 1_000; ++id)
21+
{
22+
source.Add(
23+
item: new Item()
24+
{
25+
Id = id,
26+
IsIncluded = (id % 2) == 0
27+
},
28+
key: id);
29+
changeSets.Add(source.CaptureChanges());
30+
}
31+
32+
for (var id = 2; id <= 1_000; id += 2)
33+
{
34+
source.AddOrUpdate(
35+
item: new Item()
36+
{
37+
Id = id,
38+
IsIncluded = (id % 4) != 0
39+
},
40+
key: id);
41+
changeSets.Add(source.CaptureChanges());
42+
}
43+
44+
for (var id = 1; id <= 1_000; ++id)
45+
{
46+
source.Remove(id);
47+
changeSets.Add(source.CaptureChanges());
48+
}
49+
50+
_changeSets = changeSets;
51+
}
52+
53+
[Benchmark(Baseline = true)]
54+
public void Filter()
55+
{
56+
using var source = new Subject<IChangeSet<Item, int>>();
57+
58+
using var subscription = source
59+
.Filter(static item => item.IsIncluded)
60+
.Subscribe();
61+
62+
foreach (var changeSet in _changeSets)
63+
source.OnNext(changeSet);
64+
source.OnCompleted();
65+
}
66+
67+
[Benchmark]
68+
public void FilterImmutable()
69+
{
70+
using var source = new Subject<IChangeSet<Item, int>>();
71+
72+
using var subscription = source
73+
.FilterImmutable(static item => item.IsIncluded)
74+
.Subscribe();
75+
76+
foreach (var changeSet in _changeSets)
77+
source.OnNext(changeSet);
78+
source.OnCompleted();
79+
}
80+
81+
private sealed class Item
82+
{
83+
public required int Id { get; init; }
84+
85+
public required bool IsIncluded { get; init; }
86+
}
87+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reactive.Subjects;
5+
6+
using BenchmarkDotNet.Attributes;
7+
8+
namespace DynamicData.Benchmarks.Cache;
9+
10+
[MemoryDiagnoser]
11+
[MarkdownExporterAttribute.GitHub]
12+
public class StatelessTransforming
13+
{
14+
private readonly IReadOnlyList<IChangeSet<Item, int>> _changeSets;
15+
16+
public StatelessTransforming()
17+
{
18+
var source = new ChangeAwareCache<Item, int>(capacity: 1_000);
19+
var changeSets = new List<IChangeSet<Item, int>>(capacity: 2_500);
20+
21+
for (var id = 1; id <= 1_000; ++id)
22+
{
23+
source.Add(
24+
item: new Item()
25+
{
26+
Id = id,
27+
Name = $"Item #{id}"
28+
},
29+
key: id);
30+
changeSets.Add(source.CaptureChanges());
31+
}
32+
33+
for (var id = 2; id <= 1_000; id += 2)
34+
{
35+
source.AddOrUpdate(
36+
item: new Item()
37+
{
38+
Id = id,
39+
Name = $"Replacement Item #{id}"
40+
},
41+
key: id);
42+
changeSets.Add(source.CaptureChanges());
43+
}
44+
45+
for (var id = 1; id <= 1_000; ++id)
46+
{
47+
source.Remove(id);
48+
changeSets.Add(source.CaptureChanges());
49+
}
50+
51+
_changeSets = changeSets;
52+
}
53+
54+
[Benchmark(Baseline = true)]
55+
public void Transform()
56+
{
57+
using var source = new Subject<IChangeSet<Item, int>>();
58+
59+
using var subscription = source
60+
.Transform(static item => item.Name)
61+
.Subscribe();
62+
63+
foreach (var changeSet in _changeSets)
64+
source.OnNext(changeSet);
65+
source.OnCompleted();
66+
}
67+
68+
[Benchmark]
69+
public void TransformImmutable()
70+
{
71+
using var source = new Subject<IChangeSet<Item, int>>();
72+
73+
using var subscription = source
74+
.TransformImmutable(static item => item.Name)
75+
.Subscribe();
76+
77+
foreach (var changeSet in _changeSets)
78+
source.OnNext(changeSet);
79+
source.OnCompleted();
80+
}
81+
82+
private sealed class Item
83+
{
84+
public required int Id { get; init; }
85+
86+
public required string Name { get; init; }
87+
}
88+
}

0 commit comments

Comments
 (0)