Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions src/ReactiveList.Benchmarks/ListBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,80 @@ public int SourceList_Filter()
list.Edit(l => l.AddRange(_data));
return list.Items.Where(x => x % 2 == 0).Count();
}

[Benchmark]
public int ReactiveList_Connect()
{
using var list = new ReactiveList<int>();
var total = 0;
using var sub = list.Connect().Subscribe(changes => total += changes.Count);
list.AddRange(_data);
return total;
}

[Benchmark]
public int SourceList_Connect()
{
using var list = new SourceList<int>();
var total = 0;
using var sub = list.Connect().Subscribe(changes => total += changes.Count);
list.AddRange(_data);
return total;
}

[Benchmark]
public int ReactiveList_ReplaceAll()
{
using var list = new ReactiveList<int>(_data);
var newData = Enumerable.Range(Count, Count).ToArray();
list.ReplaceAll(newData);
return list.Count;
}

[Benchmark]
public int SourceList_ReplaceAll()
{
using var list = new SourceList<int>();
list.Edit(l => l.AddRange(_data));
var newData = Enumerable.Range(Count, Count).ToArray();
list.Edit(innerList =>
{
innerList.Clear();
innerList.AddRange(newData);
});
return list.Count;
}

[Benchmark]
public int ReactiveList_Move()
{
using var list = new ReactiveList<int>(_data);
list.Move(0, Count / 2);
return list.Count;
}

[Benchmark]
public int SourceList_Move()
{
using var list = new SourceList<int>();
list.Edit(l => l.AddRange(_data));
list.Move(0, Count / 2);
return list.Count;
}

[Benchmark]
public int ReactiveList_RemoveMany()
{
using var list = new ReactiveList<int>(_data);
return list.RemoveMany(x => x % 2 == 0);
}

[Benchmark]
public int SourceList_RemoveMany()
{
using var list = new SourceList<int>();
list.Edit(l => l.AddRange(_data));
list.RemoveMany(list.Items.Where(x => x % 2 == 0));
return list.Count;
}
}
110 changes: 110 additions & 0 deletions src/ReactiveList.Benchmarks/QuaternaryDictionaryBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using BenchmarkDotNet.Attributes;
using CP.Reactive;
using CP.Reactive.Quaternary;
using DynamicData;

namespace ReactiveList.Benchmarks;
Expand Down Expand Up @@ -212,5 +214,113 @@ public int QuaternaryDictionary_RemoveMany()
return dict.RemoveMany(kvp => kvp.Key % 2 == 0);
}

[Benchmark]
public long QuaternaryDictionary_VersionTracking()
{
using var dict = new QuaternaryDictionary<int, int>();
var initialVersion = dict.Version;
dict.AddRange(_kvps);
dict.RemoveMany(kvp => kvp.Key % 2 == 0);
dict.Clear();
return dict.Version - initialVersion;
}

[Benchmark]
public int QuaternaryDictionary_ValueIndex()
{
using var dict = new QuaternaryDictionary<int, int>();
dict.AddValueIndex("Mod2", v => v % 2);
dict.AddRange(_kvps);
return dict.GetValuesBySecondaryIndex("Mod2", 0).Count();
}

[Benchmark]
public int QuaternaryDictionary_ParallelAdd()
{
using var dict = new QuaternaryDictionary<int, int>();

// Large dataset to trigger parallel processing (threshold is 256)
var largeKvps = Enumerable.Range(0, Math.Max(Count, 500))
.Select(i => new KeyValuePair<int, int>(i, i))
.ToArray();
dict.AddRange(largeKvps);
return dict.Count;
}

[Benchmark]
public int QuaternaryDictionary_IterateAll()
{
using var dict = new QuaternaryDictionary<int, int>();
dict.AddRange(_kvps);
var sum = 0;
foreach (var kvp in dict)
{
sum += kvp.Value;
}

return sum;
}

[Benchmark]
public int Dictionary_IterateAll()
{
var dict = _kvps.ToDictionary(k => k.Key, k => k.Value);
var sum = 0;
foreach (var kvp in dict)
{
sum += kvp.Value;
}

return sum;
}

[Benchmark]
public int QuaternaryDictionary_AddOrUpdate()
{
using var dict = new QuaternaryDictionary<int, int>();
for (var i = 0; i < Count; i++)
{
dict.AddOrUpdate(i, i);
}

// Update existing
for (var i = 0; i < Count / 2; i++)
{
dict.AddOrUpdate(i, i * 2);
}

return dict.Count;
}

[Benchmark]
public int QuaternaryDictionary_Keys()
{
using var dict = new QuaternaryDictionary<int, int>();
dict.AddRange(_kvps);
return dict.Keys.Count;
}

[Benchmark]
public int QuaternaryDictionary_Values()
{
using var dict = new QuaternaryDictionary<int, int>();
dict.AddRange(_kvps);
return dict.Values.Count;
}

[Benchmark]
public int QuaternaryDictionary_Enumerate()
{
using var dict = new QuaternaryDictionary<int, int>();
dict.AddRange(_kvps);
var count = 0;
foreach (var kvp in dict)
{
count += kvp.Key >= 0 ? 1 : 0;
}

return count;
}

private record Item(int Id, int Value);
}
99 changes: 98 additions & 1 deletion src/ReactiveList.Benchmarks/QuaternaryListBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using BenchmarkDotNet.Attributes;
using CP.Reactive;
using CP.Reactive.Quaternary;
using DynamicData;

namespace ReactiveList.Benchmarks;
Expand Down Expand Up @@ -185,4 +186,100 @@ public int SourceList_RemoveMany()
list.RemoveMany(list.Items.Where(x => x % 2 == 0));
return list.Count;
}

[Benchmark]
public long QuaternaryList_VersionTracking()
{
using var list = new QuaternaryList<int>();
var initialVersion = list.Version;
list.AddRange(_data);
list.RemoveMany(x => x % 2 == 0);
list.Clear();
return list.Version - initialVersion;
}

[Benchmark]
public int QuaternaryList_MultipleIndices()
{
using var list = new QuaternaryList<int>();
list.AddIndex("Mod2", x => x % 2);
list.AddIndex("Mod3", x => x % 3);
list.AddIndex("Mod5", x => x % 5);
list.AddRange(_data);
return list.GetItemsBySecondaryIndex("Mod2", 0).Count() +
list.GetItemsBySecondaryIndex("Mod3", 0).Count() +
list.GetItemsBySecondaryIndex("Mod5", 0).Count();
}

[Benchmark]
public int QuaternaryList_ParallelAdd()
{
using var list = new QuaternaryList<int>();

// Large dataset to trigger parallel processing (threshold is 256)
var largeData = Enumerable.Range(0, Math.Max(Count, 500)).ToArray();
list.AddRange(largeData);
return list.Count;
}

[Benchmark]
public int QuaternaryList_IterateAll()
{
using var list = new QuaternaryList<int>();
list.AddRange(_data);
var sum = 0;
foreach (var item in list)
{
sum += item;
}

return sum;
}

[Benchmark]
public int List_IterateAll()
{
var list = new List<int>(_data);
var sum = 0;
foreach (var item in list)
{
sum += item;
}

return sum;
}

[Benchmark]
public int QuaternaryList_CopyTo()
{
using var list = new QuaternaryList<int>();
list.AddRange(_data);
var buffer = new int[Count];
list.CopyTo(buffer, 0);
return buffer.Length;
}

[Benchmark]
public int QuaternaryList_ReplaceAll()
{
using var list = new QuaternaryList<int>();
list.AddRange(_data);
var newData = Enumerable.Range(Count, Count).ToArray();
list.ReplaceAll(newData);
return list.Count;
}

[Benchmark]
public int SourceList_ReplaceAll()
{
using var list = new SourceList<int>();
list.AddRange(_data);
var newData = Enumerable.Range(Count, Count).ToArray();
list.Edit(innerList =>
{
innerList.Clear();
innerList.AddRange(newData);
});
return list.Count;
}
}
16 changes: 10 additions & 6 deletions src/ReactiveList.Test/CacheActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#if NET6_0_OR_GREATER
using System;
using CP.Reactive;
using CP.Reactive.Quaternary;
using FluentAssertions;
using Xunit;

Expand All @@ -23,10 +23,12 @@ public void CacheAction_ShouldHaveCorrectValues()
((int)CacheAction.Added).Should().Be(0);
((int)CacheAction.Removed).Should().Be(1);
((int)CacheAction.Updated).Should().Be(2);
((int)CacheAction.Cleared).Should().Be(3);
((int)CacheAction.BatchOperation).Should().Be(4);
((int)CacheAction.BatchAdded).Should().Be(5);
((int)CacheAction.BatchRemoved).Should().Be(6);
((int)CacheAction.Moved).Should().Be(3);
((int)CacheAction.Refreshed).Should().Be(4);
((int)CacheAction.Cleared).Should().Be(5);
((int)CacheAction.BatchOperation).Should().Be(6);
((int)CacheAction.BatchAdded).Should().Be(7);
((int)CacheAction.BatchRemoved).Should().Be(8);
}

/// <summary>
Expand All @@ -37,10 +39,12 @@ public void CacheAction_AllValuesShouldBeDefined()
{
var values = Enum.GetValues<CacheAction>();

values.Should().HaveCount(7);
values.Should().HaveCount(9);
values.Should().Contain(CacheAction.Added);
values.Should().Contain(CacheAction.Removed);
values.Should().Contain(CacheAction.Updated);
values.Should().Contain(CacheAction.Moved);
values.Should().Contain(CacheAction.Refreshed);
values.Should().Contain(CacheAction.Cleared);
values.Should().Contain(CacheAction.BatchOperation);
values.Should().Contain(CacheAction.BatchAdded);
Expand Down
2 changes: 1 addition & 1 deletion src/ReactiveList.Test/CacheNotifyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#if NET6_0_OR_GREATER
using System;
using System.Buffers;
using CP.Reactive;
using CP.Reactive.Quaternary;
using FluentAssertions;
using Xunit;

Expand Down
2 changes: 1 addition & 1 deletion src/ReactiveList.Test/DynamicSearchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using CP.Reactive;
using CP.Reactive.Quaternary;
using FluentAssertions;
using Xunit;

Expand Down
Loading
Loading