added proper benchmarking against others

changed StandardStrategy tonuse binary search.

and ao on
This commit is contained in:
Linus Björnstam 2026-04-22 19:30:46 +02:00
parent 9242c1c751
commit c7c5c7b81b
9 changed files with 648 additions and 627 deletions

View file

@ -1,96 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using PersistentMap;
// Ensure your PersistentMap namespace is included here
// using MyProject.Collections;
[MemoryDiagnoser]
public class ImmutableBenchmark
{
[Params(10, 100)]
public int N { get; set; }
[Params(10000)]
public int CollectionSize { get; set; }
private ImmutableDictionary<string, string> _immutableDict;
private ImmutableSortedDictionary<string, string> _immutableSortedDict;
// 1. Add field for your map
private PersistentMap<string, string, UnicodeStrategy> _persistentMap;
private string[] _searchKeys;
[GlobalSetup]
public void Setup()
{
var random = new Random(42);
var data = new Dictionary<string, string>();
while (data.Count < CollectionSize)
{
string key = GenerateRandomString(random, N);
if (!data.ContainsKey(key))
{
data[key] = "value";
}
}
_immutableDict = data.ToImmutableDictionary();
_immutableSortedDict = data.ToImmutableSortedDictionary();
// 2. Initialize your map.
// ASSUMPTION: Standard immutable pattern (Add returns new instance).
// Adjust if you have a bulk loader like .ToPersistentMap() or a constructor.
_persistentMap = PersistentMap<string, string, UnicodeStrategy>.Empty(new UnicodeStrategy());
foreach (var kvp in data)
{
_persistentMap = _persistentMap.Set(kvp.Key, kvp.Value);
}
_searchKeys = data.Keys.ToArray();
}
[Benchmark(Baseline = true)]
public string ImmutableDict_Lookup()
{
var key = _searchKeys[CollectionSize / 2];
_immutableDict.TryGetValue(key, out var value);
return value;
}
[Benchmark]
public string ImmutableSortedDict_Lookup()
{
var key = _searchKeys[CollectionSize / 2];
_immutableSortedDict.TryGetValue(key, out var value);
return value;
}
// 3. Add the benchmark case
[Benchmark]
public string PersistentMap_Lookup()
{
var key = _searchKeys[CollectionSize / 2];
// Adjust API call if your map uses a different method (e.g. Find, Get, indexer)
_persistentMap.TryGetValue(key, out var value);
return value;
}
private string GenerateRandomString(Random rng, int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var buffer = new char[length];
for (int i = 0; i < length; i++)
{
buffer[i] = chars[rng.Next(chars.Length)];
}
return new string(buffer);
}
}

View file

@ -1,198 +0,0 @@
using System.Collections.Immutable;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using LanguageExt;
using PersistentMap;
namespace AgainstLanguageExt;
// Mocking your library types for the sake of the example to ensure compilation.
// Replace these with your actual namespace imports.
[MemoryDiagnoser]
[HideColumns("Ratio", "RatioSD", "Alloc Ratio")]
public class MapBenchmarks
{
[Params(10, 100, 1000)]
public int KeyLength { get; set; } // Key length
[Params(1000, 100000, 1000000)]
public int CollectionSize { get; set; }
// Data Source
private KeyValuePair<string, int>[] _data;
private string[] _searchKeys;
private int _index = 0;
private int _mask;
// Comparison Targets (for Lookup)
private ImmutableDictionary<string, int> _sysDict;
private ImmutableSortedDictionary<string, int> _sysSorted;
private LanguageExt.HashMap<string, int> _langExtHash;
private LanguageExt.Map<string, int> _langExtSorted; // Map<K,V> is Sorted in LangExt
private PersistentMap<string, int, UnicodeStrategy> _persistentMap;
[GlobalSetup]
public void Setup()
{
var random = new Random(42);
var dict = new Dictionary<string, int>();
// 1. Generate Data
while (dict.Count < CollectionSize)
{
string key = GenerateRandomString(random, KeyLength);
if (!dict.ContainsKey(key))
{
dict[key] = random.Next();
}
}
_data = dict.ToArray();
_searchKeys = dict.Keys.ToArray();
// 2. Pre-build maps for the Lookup benchmarks
_sysDict = dict.ToImmutableDictionary();
_sysSorted = dict.ToImmutableSortedDictionary();
_langExtHash = Prelude.toHashMap(dict);
_langExtSorted = Prelude.toMap(dict);
// Build PersistentMap for lookup test
var trans = PersistentMap<string, int, UnicodeStrategy>.Empty(new UnicodeStrategy()).ToTransient();
foreach (var kvp in _data)
{
trans.Set(kvp.Key, kvp.Value);
}
_persistentMap = trans.ToPersistent();
}
// ==========================================
// BUILD BENCHMARKS
// ==========================================
[Benchmark(Description = "Lookup: PersistentMap (Cyclic)")]
public int Lookup_Persistent_Cyclic()
{
// Fast wrap-around
var key = _searchKeys[_index++ & _mask];
_persistentMap.TryGetValue(key, out var value);
return value;
}
[Benchmark(Description = "Lookup: Sys.Sorted (Cyclic)")]
public int Lookup_SysSorted_Cyclic()
{
var key = _searchKeys[_index++ & _mask];
_sysSorted.TryGetValue(key, out var value);
return value;
}
[Benchmark(Description = "Build: Sys.ImmutableDict")]
public ImmutableDictionary<string, int> Build_SysImmutable()
{
// Using CreateRange/ToImmutable is usually the standard 'bulk' build
return _data.ToImmutableDictionary();
}
[Benchmark(Description = "Build: LangExt.HashMap")]
public LanguageExt.HashMap<string, int> Build_LangExtHash()
{
return Prelude.toHashMap(_data);
}
[Benchmark(Description = "Build: LangExt.SortedMap")]
public LanguageExt.Map<string, int> Build_LangExtSorted()
{
return Prelude.toMap(_data);
}
[Benchmark(Description = "Build: PersistentMap (Iterative)")]
public PersistentMap<string, int, UnicodeStrategy> Build_Persistent_Iterative()
{
// Simulating naive immutable building (O(n log n) or worse due to copying)
var map = PersistentMap<string, int, UnicodeStrategy>.Empty(new UnicodeStrategy());
foreach (var item in _data)
{
map = map.Set(item.Key, item.Value);
}
return map;
}
[Benchmark(Description = "Build: PersistentMap (Transient)")]
public PersistentMap<string, int, UnicodeStrategy> Build_Persistent_Transient()
{
// Simulating efficient mutable build -> freeze
var trans = PersistentMap<string, int, UnicodeStrategy>.Empty(new UnicodeStrategy()).ToTransient();
foreach (var item in _data)
{
trans.Set(item.Key, item.Value);
}
return trans.ToPersistent();
}
// ==========================================
// LOOKUP BENCHMARKS
// ==========================================
[Benchmark(Baseline = true, Description = "Lookup: Sys.ImmutableDict")]
public int Lookup_SysImmutable()
{
var key = _searchKeys[CollectionSize / 2];
_sysDict.TryGetValue(key, out var value);
return value;
}
[Benchmark(Description = "Lookup: Sys.SortedDict")]
public int Lookup_SysSorted()
{
var key = _searchKeys[CollectionSize / 2];
_sysSorted.TryGetValue(key, out var value);
return value;
}
[Benchmark(Description = "Lookup: LangExt.HashMap")]
public int Lookup_LangExtHash()
{
var key = _searchKeys[CollectionSize / 2];
// LanguageExt often uses Find which returns Option, or [] operator
// Assuming TryGetValue-like behavior or using match for fairness
return _langExtHash.Find(key).IfNone(0);
}
[Benchmark(Description = "Lookup: LangExt.SortedMap")]
public int Lookup_LangExtSorted()
{
var key = _searchKeys[CollectionSize / 2];
return _langExtSorted.Find(key).IfNone(0);
}
[Benchmark(Description = "Lookup: PersistentMap")]
public int Lookup_PersistentMap()
{
var key = _searchKeys[CollectionSize / 2];
_persistentMap.TryGetValue(key, out var value);
return value;
}
// Helper
private string GenerateRandomString(Random rng, int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var buffer = new char[length];
for (int i = 0; i < length; i++)
{
buffer[i] = chars[rng.Next(chars.Length)];
}
return new string(buffer);
}
}
public class Program
{
public static void Main(string[] args)
{
// This scans the assembly and lets the command line (args) decide what to run
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
}

View file

@ -1,112 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using LanguageExt;
using static LanguageExt.Prelude;
using PersistentMap;
[MemoryDiagnoser]
[HideColumns("Ratio", "RatioSD", "Alloc Ratio")]
public class CyclicMapBenchmarks
{
// Powers of 2 for fast bitwise masking
[Params(1024, 131072)]
public int CollectionSize { get; set; }
[Params(10, 100, 1000)]
public int N { get; set; }
// Collections
private PersistentMap<string, int, UnicodeStrategy> _persistentMap;
private ImmutableSortedDictionary<string, int> _sysSorted;
private LanguageExt.HashMap<string, int> _langExtHash;
private LanguageExt.Map<string, int> _langExtSorted;
// Lookup scaffolding
private string[] _searchKeys;
private int _index = 0;
private int _mask;
[GlobalSetup]
public void Setup()
{
_mask = CollectionSize - 1;
var random = new Random(42);
var data = new Dictionary<string, int>();
// 1. Generate Data
while (data.Count < CollectionSize)
{
string key = GenerateRandomString(random, N);
if (!data.ContainsKey(key))
{
data[key] = random.Next();
}
}
// 2. Build Collections
// PersistentMap
var builder = PersistentMap<string, int, UnicodeStrategy>.Empty(new UnicodeStrategy()).ToTransient();
foreach (var kvp in data) builder.Set(kvp.Key, kvp.Value);
_persistentMap = builder.ToPersistent();
// System
_sysSorted = data.ToImmutableSortedDictionary();
// LanguageExt
_langExtHash = toHashMap(data);
_langExtSorted = toMap(data);
// 3. Setup Cyclic Keys
_searchKeys = data.Keys.ToArray();
// Shuffle to defeat branch prediction / cache pre-fetching
Random.Shared.Shuffle(_searchKeys);
}
[Benchmark(Description = "Cyclic: PersistentMap")]
public int Lookup_Persistent()
{
var key = _searchKeys[_index++ & _mask];
_persistentMap.TryGetValue(key, out var value);
return value;
}
[Benchmark(Description = "Cyclic: Sys.Sorted")]
public int Lookup_SysSorted()
{
var key = _searchKeys[_index++ & _mask];
_sysSorted.TryGetValue(key, out var value);
return value;
}
[Benchmark(Description = "Cyclic: LangExt.HashMap")]
public int Lookup_LangExtHash()
{
var key = _searchKeys[_index++ & _mask];
// Option<T> struct return, overhead is minimal but present
return _langExtHash.Find(key).IfNone(0);
}
[Benchmark(Description = "Cyclic: LangExt.Sorted")]
public int Lookup_LangExtSorted()
{
var key = _searchKeys[_index++ & _mask];
// AVL Tree traversal
return _langExtSorted.Find(key).IfNone(0);
}
private string GenerateRandomString(Random rng, int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var buffer = new char[length];
for (int i = 0; i < length; i++)
{
buffer[i] = chars[rng.Next(chars.Length)];
}
return new string(buffer);
}
}

View file

@ -1,220 +0,0 @@
using System;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using LanguageExt; // Your Namespace
using LanguageExt;
using LanguageExt;
using PersistentMap; // NuGet: LanguageExt.Core
[MemoryDiagnoser]
public class ImmutableCollectionBenchmarks
{
[Params(100, 1000, 100_000)]
public int N;
private int[] _keys;
private int[] _values;
// --- 1. Your Collections ---
private PersistentMap<int, int, IntStrategy> _niceMap;
private IntStrategy _strategy;
// --- 2. Microsoft Collections ---
private System.Collections.Immutable.ImmutableSortedDictionary<int, int> _msSortedMap;
private System.Collections.Immutable.ImmutableDictionary<int, int> _msHashMap;
// --- 3. LanguageExt Collections ---
private LanguageExt.Map<int, int> _leMap; // AVL Tree (Sorted)
private LanguageExt.HashMap<int, int> _leHashMap; // Hash Array Mapped Trie (Unsorted)
[GlobalSetup]
public void Setup()
{
// Generate Data
var rand = new Random(42);
_keys = Enumerable.Range(0, N).Select(x => x * 2).ToArray();
rand.Shuffle(_keys);
_values = _keys.Select(k => k * 100).ToArray();
_strategy = new IntStrategy();
// 1. Setup NiceBTree
var transient = BaseOrderedMap<int, int, IntStrategy>.CreateTransient(_strategy);
for (int i = 0; i < N; i++) transient.Set(_keys[i], _values[i]);
_niceMap = transient.ToPersistent();
// 2. Setup MS Immutable
var msBuilder = System.Collections.Immutable.ImmutableSortedDictionary.CreateBuilder<int, int>();
for (int i = 0; i < N; i++) msBuilder.Add(_keys[i], _values[i]);
_msSortedMap = msBuilder.ToImmutable();
_msHashMap = System.Collections.Immutable.ImmutableDictionary.CreateRange(
_keys.Zip(_values, (k, v) => new System.Collections.Generic.KeyValuePair<int, int>(k, v)));
// 3. Setup LanguageExt
// Note: LanguageExt performs best when bulk-loaded from tuples
var tuples = _keys.Zip(_values, (k, v) => (k, v));
_leMap = new LanguageExt.Map<int,int>(tuples);
_leHashMap = new HashMap<int, int>(tuples);
}
// =========================================================
// 1. BUILD (Item by Item)
// Note: LanguageExt has no "Mutable Builder", so this tests
// the cost of pure immutable inserts vs your Transient/Builder.
// =========================================================
[Benchmark(Description = "Build: PersistentMap (Transient)")]
public int Build_NiceBTree()
{
var t = BaseOrderedMap<int, int, IntStrategy>.CreateTransient(_strategy);
for (int i = 0; i < N; i++) t.Set(_keys[i], _values[i]);
return t.Count;
}
[Benchmark(Description = "Build: PersistentMap (Persistent)")]
public int Build_PersistentBTree()
{
var t = PersistentMap<int, int, IntStrategy>.Empty(_strategy);
for (int i = 0; i < N; i++) t.Set(_keys[i], _values[i]);
return t.Count;
}
[Benchmark(Description = "Build: MS Sorted (Builder)")]
public int Build_MsSorted()
{
var b = System.Collections.Immutable.ImmutableSortedDictionary.CreateBuilder<int, int>();
for (int i = 0; i < N; i++) b.Add(_keys[i], _values[i]);
return b.Count;
}
[Benchmark(Description = "Build: LanguageExt Map (AVL)")]
public int Build_LanguageExt_Map()
{
var map = LanguageExt.Map<int, int>.Empty;
for (int i = 0; i < N; i++)
{
// Pure immutable add
map = map.Add(_keys[i], _values[i]);
}
return map.Count;
}
[Benchmark(Description = "Build: LanguageExt HashMap")]
public int Build_LanguageExt_HashMap()
{
var map = LanguageExt.HashMap<int, int>.Empty;
for (int i = 0; i < N; i++)
{
map = map.Add(_keys[i], _values[i]);
}
return map.Count;
}
// =========================================================
// 2. READ (Lookup)
// =========================================================
[Benchmark(Description = "Read: NiceBTree")]
public int Read_NiceBTree()
{
var found = 1;
if (_niceMap.TryGetValue(_keys[N/2], out _)) found++;
return found;
}
[Benchmark(Description = "Read: MS Sorted")]
public int Read_MsSorted()
{
int found = 0;
if (_msSortedMap.ContainsKey(_keys[N/2])) found++;
return found;
}
[Benchmark(Description = "Read: LanguageExt Map")]
public int Read_LanguageExt_Map()
{
int found = 0;
// Find returns Option<V>, IsSome checks if it exists
if (_leMap.Find(_keys[N/2]).IsSome) found++;
return found;
}
[Benchmark(Description = "Read: LanguageExt HashMap")]
public int Read_LanguageExt_HashMap()
{
int found = 0;
if (_leHashMap.Find(_keys[N/2]).IsSome) found++;
return found;
}
// =========================================================
// 3. ITERATE (Foreach)
// =========================================================
[Benchmark(Description = "Iterate: NiceBTree")]
public int Iterate_NiceBTree()
{
int sum = 0;
foreach (var kvp in _niceMap) sum += kvp.Key;
return sum;
}
[Benchmark(Description = "Iterate: MS Sorted")]
public int Iterate_MsSorted()
{
int sum = 0;
foreach (var kvp in _msSortedMap) sum += kvp.Key;
return sum;
}
[Benchmark(Description = "Iterate: LanguageExt Map")]
public int Iterate_LanguageExt_Map()
{
int sum = 0;
// LanguageExt Map is IEnumerable<(Key, Value)>
foreach (var item in _leMap) sum += item.Key;
return sum;
}
[Benchmark(Description = "Iterate: LanguageExt HashMap")]
public int Iterate_LanguageExt_HashMap()
{
int sum = 0;
foreach (var item in _leHashMap) sum += item.Key;
return sum;
}
// =========================================================
// 4. SET (Persistent / Immutable Update)
// =========================================================
[Benchmark(Description = "Set: NiceBTree")]
public PersistentMap<int, int, IntStrategy> Set_NiceBTree()
{
return _niceMap.Set(_keys[N / 2], -1);
}
[Benchmark(Description = "Set: MS Sorted")]
public System.Collections.Immutable.ImmutableSortedDictionary<int, int> Set_MsSorted()
{
return _msSortedMap.SetItem(_keys[N / 2], -1);
}
[Benchmark(Description = "Set: LanguageExt Map")]
public LanguageExt.Map<int, int> Set_LanguageExt_Map()
{
return _leMap.SetItem(_keys[N / 2], -1);
}
[Benchmark(Description = "Set: LanguageExt HashMap")]
public LanguageExt.HashMap<int, int> Set_LanguageExt_HashMap()
{
return _leHashMap.SetItem(_keys[N / 2], -1);
}
}

View file

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
<PackageReference Include="LanguageExt.Core" Version="4.4.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\PersistentMap\PersistentMap.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,368 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using LanguageExt;
using PersistentMap;
namespace MapBenchmarks;
[MemoryDiagnoser]
public class IntMapBenchmarks
{
[Params(100, 1000, 10000, 100000)]
public int N { get; set; }
private int[] _allKeys;
private int[] _retrieveKeys;
private int[] _updateKeys;
private int[] _removeKeys;
private int[] _mixedKeys; // Half existing, half new
// Pre-built collections for read/update/remove tests
private ImmutableDictionary<int, int> _immDict;
private ImmutableSortedDictionary<int, int> _immSortedDict;
private LanguageExt.Map<int, int> _extMap;
private LanguageExt.HashMap<int, int> _extHashMap;
private PersistentMap<int, int, IntStrategy> _persistentMap;
private readonly IntStrategy _intStrategy = new IntStrategy();
[GlobalSetup]
public void Setup()
{
var rnd = new Random(42);
// Build integer keys (inserted sorted)
_allKeys = Enumerable.Range(0, N).ToArray();
int subsetSize = Math.Max(1, N / 10);
// Subsets for different operations
var shuffled = _allKeys.OrderBy(x => rnd.Next()).ToArray();
_retrieveKeys = shuffled.Take(subsetSize).ToArray();
_updateKeys = shuffled.Skip(subsetSize).Take(subsetSize).ToArray();
_removeKeys = shuffled.Skip(subsetSize * 2).Take(subsetSize).ToArray();
// Mixed keys: half existing, half completely new (N + 1 to N + subsetSize/2)
var existingHalf = shuffled.Skip(subsetSize * 3).Take(subsetSize / 2).ToArray();
var newHalf = Enumerable.Range(N + 1, subsetSize - (subsetSize / 2)).ToArray();
_mixedKeys = existingHalf.Concat(newHalf).OrderBy(x => rnd.Next()).ToArray();
// Pre-build collections
_immDict = ImmutableDictionary.CreateRange(_allKeys.Select(k => new KeyValuePair<int, int>(k, k)));
_immSortedDict = ImmutableSortedDictionary.CreateRange(_allKeys.Select(k => new KeyValuePair<int, int>(k, k)));
_extMap = LanguageExt.Map.empty<int, int>();
_extHashMap = LanguageExt.HashMap.empty<int, int>();
foreach (var k in _allKeys)
{
_extMap = _extMap.AddOrUpdate(k, k);
_extHashMap = _extHashMap.AddOrUpdate(k, k);
}
var transient = BaseOrderedMap<int, int, IntStrategy>.CreateTransient(_intStrategy);
foreach (var k in _allKeys) transient.Set(k, k);
_persistentMap = transient.ToPersistent();
}
// --- 1. BUILD ---
[Benchmark]
public ImmutableDictionary<int, int> Build_ImmDict()
{
var map = ImmutableDictionary<int, int>.Empty;
foreach (var k in _allKeys) map = map.Add(k, k);
return map;
}
[Benchmark]
public ImmutableSortedDictionary<int, int> Build_ImmSortedDict()
{
var map = ImmutableSortedDictionary<int, int>.Empty;
foreach (var k in _allKeys) map = map.Add(k, k);
return map;
}
[Benchmark]
public LanguageExt.Map<int, int> Build_ExtMap()
{
var map = LanguageExt.Map.empty<int, int>();
foreach (var k in _allKeys) map = map.AddOrUpdate(k, k);
return map;
}
[Benchmark]
public LanguageExt.HashMap<int, int> Build_ExtHashMap()
{
var map = LanguageExt.HashMap.empty<int, int>();
foreach (var k in _allKeys) map = map.AddOrUpdate(k, k);
return map;
}
[Benchmark]
public PersistentMap<int, int, IntStrategy> Build_PersistentMap()
{
var map = PersistentMap<int, int, IntStrategy>.Empty(_intStrategy);
foreach (var k in _allKeys) map = map.Set(k, k);
return map;
}
[Benchmark]
public PersistentMap<int, int, IntStrategy> Build_TransientMap()
{
var map = BaseOrderedMap<int, int, IntStrategy>.CreateTransient(_intStrategy);
foreach (var k in _allKeys) map.Set(k, k);
return map.ToPersistent();
}
// --- 2. RETRIEVAL ---
[Benchmark]
public int Retrieve_ImmDict()
{
int count = 0;
foreach (var k in _retrieveKeys)
if (_immDict.TryGetValue(k, out _)) count++;
return count;
}
[Benchmark]
public int Retrieve_ImmSortedDict()
{
int count = 0;
foreach (var k in _retrieveKeys)
if (_immSortedDict.TryGetValue(k, out _)) count++;
return count;
}
[Benchmark]
public int Retrieve_ExtMap()
{
int count = 0;
foreach (var k in _retrieveKeys)
if (_extMap.Find(k).IsSome) count++;
return count;
}
[Benchmark]
public int Retrieve_ExtHashMap()
{
int count = 0;
foreach (var k in _retrieveKeys)
if (_extHashMap.Find(k).IsSome) count++;
return count;
}
[Benchmark]
public int Retrieve_PersistentMap()
{
int count = 0;
foreach (var k in _retrieveKeys)
if (_persistentMap.TryGetValue(k, out _)) count++;
return count;
}
// --- 3. UPDATING ---
[Benchmark]
public ImmutableDictionary<int, int> Update_ImmDict()
{
var map = _immDict;
foreach (var k in _updateKeys) map = map.SetItem(k, 999);
return map;
}
[Benchmark]
public PersistentMap<int, int, IntStrategy> Update_PersistentMap()
{
var map = _persistentMap;
foreach (var k in _updateKeys) map = map.Set(k, 999);
return map;
}
[Benchmark]
public PersistentMap<int, int, IntStrategy> Update_TransientMap()
{
var transient = _persistentMap.ToTransient();
foreach (var k in _updateKeys) transient.Set(k, 999);
return transient.ToPersistent();
}
[Benchmark]
public ImmutableSortedDictionary<int, int> Update_ImmSortedDict()
{
var map = _immSortedDict;
foreach (var k in _updateKeys) map = map.SetItem(k, 999);
return map;
}
[Benchmark]
public LanguageExt.Map<int, int> Update_ExtMap()
{
var map = _extMap;
foreach (var k in _updateKeys) map = map.SetItem(k, 999);
return map;
}
[Benchmark]
public LanguageExt.HashMap<int, int> Update_ExtHashMap()
{
var map = _extHashMap;
foreach (var k in _updateKeys) map = map.SetItem(k, 999);
return map;
}
// --- 4. UPDATE & SET (MIXED) ---
[Benchmark]
public ImmutableDictionary<int, int> UpdateSet_ImmDict()
{
var map = _immDict;
foreach (var k in _mixedKeys) map = map.SetItem(k, 999);
return map;
}
[Benchmark]
public PersistentMap<int, int, IntStrategy> UpdateSet_PersistentMap()
{
var map = _persistentMap;
foreach (var k in _mixedKeys) map = map.Set(k, 999);
return map;
}
[Benchmark]
public PersistentMap<int, int, IntStrategy> UpdateSet_TransientMap()
{
var transient = _persistentMap.ToTransient();
foreach (var k in _mixedKeys) transient.Set(k, 999);
return transient.ToPersistent();
}
[Benchmark]
public ImmutableSortedDictionary<int, int> UpdateSet_ImmSortedDict()
{
var map = _immSortedDict;
foreach (var k in _mixedKeys) map = map.SetItem(k, 999);
return map;
}
[Benchmark]
public LanguageExt.Map<int, int> UpdateSet_ExtMap()
{
var map = _extMap;
foreach (var k in _mixedKeys) map = map.AddOrUpdate(k, 999);
return map;
}
[Benchmark]
public LanguageExt.HashMap<int, int> UpdateSet_ExtHashMap()
{
var map = _extHashMap;
foreach (var k in _mixedKeys) map = map.AddOrUpdate(k, 999);
return map;
}
// --- 5. ITERATION ---
[Benchmark]
public int Iterate_ImmDict()
{
int sum = 0;
foreach (var kvp in _immDict) sum += kvp.Value;
return sum;
}
[Benchmark]
public int Iterate_PersistentMap()
{
int sum = 0;
foreach (var kvp in _persistentMap) sum += kvp.Value;
return sum;
}
[Benchmark]
public int Iterate_ImmSortedDict()
{
int sum = 0;
foreach (var kvp in _immSortedDict) sum += kvp.Value;
return sum;
}
[Benchmark]
public int Iterate_ExtMap()
{
int sum = 0;
foreach (var kvp in _extMap) sum += kvp.Value;
return sum;
}
[Benchmark]
public int Iterate_ExtHashMap()
{
int sum = 0;
foreach (var kvp in _extHashMap) sum += kvp.Value;
return sum;
}
// --- 6. REMOVAL ---
[Benchmark]
public ImmutableDictionary<int, int> Remove_ImmDict()
{
var map = _immDict;
foreach (var k in _removeKeys) map = map.Remove(k);
return map;
}
[Benchmark]
public PersistentMap<int, int, IntStrategy> Remove_PersistentMap()
{
var map = _persistentMap;
foreach (var k in _removeKeys) map = map.Remove(k);
return map;
}
[Benchmark]
public PersistentMap<int, int, IntStrategy> Remove_TransientMap()
{
var transient = _persistentMap.ToTransient();
foreach (var k in _removeKeys) transient.Remove(k);
return transient.ToPersistent();
}
[Benchmark]
public ImmutableSortedDictionary<int, int> Remove_ImmSortedDict()
{
var map = _immSortedDict;
foreach (var k in _removeKeys) map = map.Remove(k);
return map;
}
[Benchmark]
public LanguageExt.Map<int, int> Remove_ExtMap()
{
var map = _extMap;
foreach (var k in _removeKeys) map = map.Remove(k);
return map;
}
[Benchmark]
public LanguageExt.HashMap<int, int> Remove_ExtHashMap()
{
var map = _extHashMap;
foreach (var k in _removeKeys) map = map.Remove(k);
return map;
}
public static void Main(string[] args)
{
BenchmarkSwitcher
.FromAssembly(typeof(IntMapBenchmarks).Assembly)
.Run(args);
}
}