Home

Awesome

Faster.Map

The goal of Faster.Map is to create a more efficient and performant alternative to the Dictionary and ConcurrentDictionary classes provided by .NET. These standard collections are widely used for key-value pair storage in .NET applications, but they have certain limitations, particularly in high-performance and concurrent scenarios.

Available Implementations:

You can include Faster.Map in your C# project via NuGet Package Manager:

Install-Package Faster.Map

Basic Usage

Default Hasher

By default, DenseMap uses the DefaultHasher<TKey>, which computes hashes based on the .NET GetHashCode method and uses Knuth's Multiplicative Hashing

var map = new DenseMap<int, string>();
map.Emplace(1, "Value One");
map.Emplace(2, "Value Two");

if (map.Get(1, out var value))
{
    Console.WriteLine($"Key 1 has value: {value}");
}

map.Remove(1);

Custom Hasher

By default, Faster.Map provides four built-in hashers, each optimized for different performance characteristics:

DefaultHasher GxHasher XxHash3StringHasher XxHash3Hasher

You can provide your own IHasher<TKey> implementation to customize hash computation.

Step 1: Implement a Custom Hasher

public class CustomIntHasher : IHasher<int>
{
    public ulong ComputeHash(int key)
    {
        return (ulong)(key * 2654435761); // Multiplicative hashing
    }
}

Step 2: Use the Custom Hasher in DenseMap

var customHasher = new CustomIntHasher();
var map = new DenseMap<int, string>(customHasher);

map.Emplace(1, "Value One");
map.Emplace(42, "Value Two");

if (map.Get(42, out var value))
{
    Console.WriteLine($"Key 42 has value: {value}");
}

map.Update(42, "Updated Value Two");
map.Remove(1);

Advanced Example: Hashing Strings with XxHash

Custom String Hasher

public class XxHash3StringHasher : IHasher<string>
{
    public ulong ComputeHash(string key)
    {
        return XxHash3.HashToUInt64(MemoryMarshal.AsBytes(key.AsSpan()));
    }
}

Using the String Hasher

var stringHasher = new XxHash3StringHasher();
var stringMap = new DenseMap<string, int>(stringHasher);

stringMap.Emplace("Hello", 100);
stringMap.Emplace("World", 200);

if (stringMap.Get("Hello", out var value))
{
    Console.WriteLine($"Key 'Hello' has value: {value}");
}

stringMap.Remove("World");

Tested on platforms:

Benchmark

BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3)
12th Gen Intel Core i5-12500H, 1 CPU, 16 logical and 12 physical cores
.NET SDK 9.0.100-preview.2.24157.14
  [Host]     : .NET 9.0.0 (9.0.24.12805), X64 RyuJIT AVX2
  DefaultJob : .NET 9.0.0 (9.0.24.12805), X64 RyuJIT AVX2

Get Uint Benchmark

MethodLengthMean (ms)Error (ms)StdDev (ms)Median (ms)RatioRatioSDCode SizeAllocatedAlloc Ratio
DenseMap1000.0001940.0000010.0000010.0001940.960.01431 B-NA
DenseMap_XXhash31000.0002610.0000010.0000010.0002611.290.01544 B-NA
DenseMap_FastHash1000.0001810.0000020.0000020.0001800.890.01447 B-NA
DenseMap_GxHash1000.0003010.0000010.0000010.0003011.480.01587 B-NA
RobinhoodMap 🏆1000.0001300.0000010.0000010.0001300.640.00175 B-NA
Dictionary1000.0002030.0000010.0000010.0002031.000.01390 B-NA
DenseMap10000.0017530.0000080.0000080.0017550.640.01431 B-NA
DenseMap_XXhash310000.0025610.0000040.0000030.0025600.940.01549 B-NA
DenseMap_FastHash10000.0017360.0000050.0000050.0017350.640.01452 B-NA
DenseMap_GxHash10000.0106190.0000050.0000040.0106173.890.03595 B-NA
RobinhoodMap 🏆10000.0013570.0000040.0000030.0013570.500.00175 B-NA
Dictionary10000.0027320.0000240.0000210.0027271.000.01401 B-NA
DenseMap100000.0227290.0004490.0007490.0226210.300.01426 B-NA
DenseMap_XXhash3100000.0318290.0006260.0008140.0314660.420.01544 B-NA
DenseMap_FastHash100000.0231330.0004530.0004450.0229980.310.01447 B-NA
DenseMap_GxHash100000.0377980.0006570.0006150.0377320.500.01587 B-NA
RobinhoodMap 🏆100000.0137770.0001960.0001840.0137660.180.00175 B-NA
Dictionary100000.0750740.0014700.0015090.0753451.000.03401 B-NA
DenseMap1000000.5890760.0091910.0085980.5850250.490.01431 B1 B1.00
DenseMap_XXhash31000000.7557580.0113380.0106050.7504150.620.01549 B1 B1.00
DenseMap_FastHash1000000.6385760.0124300.0170150.6372270.530.01452 B1 B1.00
DenseMap_GxHash1000001.9094950.0138460.0122741.9024221.580.02595 B1 B1.00
RobinhoodMap 🏆1000000.5258580.0097470.0091170.5234860.430.01175 B1 B1.00
Dictionary1000001.2113520.0106310.0099441.2107961.000.01401 B1 B1.00
DenseMap2000001.3654160.0253820.0237421.3638050.560.01431 B1 B0.33
DenseMap_XXhash32000001.6811070.0162070.0143671.6790220.690.01549 B1 B0.33
DenseMap_FastHash2000001.4138410.0081230.0072011.4157980.580.00452 B1 B0.33
DenseMap_GxHash2000004.8163180.0935530.1113684.8050591.970.05595 B3 B1.00
RobinhoodMap 🏆2000001.0940530.0083700.0078291.0938870.450.00175 B1 B0.33
Dictionary2000002.4459830.0098540.0087362.4478051.000.00401 B3 B1.00
DenseMap4000002.8377090.0360800.0319842.8460670.550.01431 B3 B0.50
DenseMap_XXhash34000003.5287190.0403480.0377413.5184220.690.01549 B3 B0.50
DenseMap_FastHash4000002.8736340.0194790.0182212.8681610.560.01452 B3 B0.50
DenseMap_GxHash40000012.2252730.1452110.12872612.2303692.370.05595 B6 B1.00
RobinhoodMap 🏆4000002.4098490.0362860.0303012.4142730.470.01175 B3 B0.50
Dictionary4000005.1526730.1013030.0994935.1221771.000.03401 B6 B1.00
DenseMap 🏆8000007.5915420.1500570.2854997.6571270.480.03431 B6 B0.50
DenseMap_XXhash380000010.5585740.2918040.83253210.3735170.670.06549 B12 B1.00
DenseMap_FastHash8000007.8510490.1557180.2282507.9032580.500.02452 B7 B0.58
DenseMap_GxHash8000009.9829390.1991320.4959079.8161530.640.04595 B1 B0.08
RobinhoodMap8000008.6720660.1636410.1750948.6576650.550.02175 B12 B1.00
Dictionary80000015.7049790.3096620.63255715.6986691.000.06401 B12 B1.00
DenseMap100000013.6577580.2691280.25174313.6586800.690.02431 B12 B0.52
DenseMap_XXhash3100000018.7369590.3744380.38452018.7758840.940.02549 B23 B1.00
DenseMap_FastHash100000013.8950380.2696350.36907913.8902340.700.02452 B12 B0.52
DenseMap_GxHash100000093.2979061.8016002.27844892.5195694.690.13595 B23 B1.00
RobinhoodMap 🏆100000012.2206380.0966600.08568712.2259820.610.01175 B12 B0.52
Dictionary100000019.9009200.3366820.31493220.0249411.000.02401 B23 B1.00

Adding a million keys

MethodLengthMeanErrorStdDevMedianAllocated
DenseMap100000.06526 ms0.00130 ms0.00286 ms0.06490 ms736 B
RobinhoodMap100000.06092 ms0.00212 ms0.00602 ms0.06100 ms736 B
Dictionary100000.23942 ms0.00471 ms0.00691 ms0.23980 ms736 B
DenseMap1000000.46808 ms0.00830 ms0.01019 ms0.46855 ms736 B
RobinhoodMap1000000.61636 ms0.01201 ms0.01430 ms0.61195 ms448 B
Dictionary1000002.41674 ms0.04790 ms0.10104 ms2.38790 ms736 B
DenseMap4000002.09803 ms0.04190 ms0.08746 ms2.08300 ms736 B
RobinhoodMap4000003.50303 ms0.06982 ms0.09079 ms3.48000 ms736 B
Dictionary4000006.47455 ms0.33964 ms0.95238 ms6.73420 ms736 B
DenseMap8000006.37665 ms0.28745 ms0.79651 ms5.82920 ms736 B
RobinhoodMap8000008.28828 ms0.16465 ms0.27052 ms8.30780 ms736 B
Dictionary80000016.27052 ms0.89353 ms2.59229 ms16.42450 ms736 B
DenseMap9000006.79059 ms0.13023 ms0.13934 ms6.74320 ms736 B
RobinhoodMap9000009.87488 ms0.19034 ms0.26054 ms9.80475 ms736 B
Dictionary90000018.87343 ms1.00306 ms2.95755 ms18.42155 ms736 B

Add and resize

MethodLengthMeanErrorStdDevMedianGen0Gen1Gen2Allocated
DenseMap10000.08942 ms0.00234 ms0.00675 ms0.08880 ms---37.75 KB
RobinhoodMap10000.09152 ms0.00414 ms0.01181 ms0.08890 ms---37.51 KB
Dictionary10000.06777 ms0.00519 ms0.01522 ms0.06260 ms---72.09 KB
DenseMap100000.22937 ms0.00458 ms0.01061 ms0.22780 ms---290.31 KB
RobinhoodMap100000.34865 ms0.00692 ms0.00769 ms0.34860 ms---578.18 KB
Dictionary100000.39528 ms0.01529 ms0.04484 ms0.37380 ms---657.93 KB
DenseMap1000001.29055 ms0.01850 ms0.01545 ms1.29280 ms---2306.88 KB
RobinhoodMap1000002.34004 ms0.03486 ms0.05428 ms2.32295 ms---4610.78 KB
Dictionary1000003.32307 ms0.06625 ms0.11776 ms3.29280 ms---5896.77 KB
DenseMap4000005.04851 ms0.09965 ms0.25364 ms5.05355 ms---9219.25 KB
RobinhoodMap4000009.31596 ms0.18625 ms0.30602 ms9.23980 ms---18435.23 KB
Dictionary40000011.52668 ms0.40434 ms1.12042 ms11.20910 ms---25374.59 KB
DenseMap90000012.38025 ms0.22981 ms0.62521 ms12.22785 ms---18435.44 KB
RobinhoodMap90000022.62544 ms0.69841 ms2.01507 ms21.66310 ms---36867.18 KB
Dictionary90000031.53625 ms0.85001 ms2.43885 ms31.31300 ms1000.00001000.00001000.000052626.84 KB
DenseMap100000021.15451 ms0.40257 ms0.43075 ms21.11780 ms---36867.63 KB
RobinhoodMap100000026.03638 ms0.41907 ms0.37149 ms26.13220 ms---36867.46 KB
Dictionary100000034.51489 ms0.68455 ms0.89011 ms34.59730 ms1000.00001000.00001000.000052626.84 KB

Updating a million keys

MethodLengthMeanErrorStdDevMedianAllocated
RobinhoodMap10000.00122 ms0.00001 ms0.00001 ms0.00122 ms-
DenseMap10000.00172 ms0.00003 ms0.00003 ms0.00171 ms-
Dictionary10000.00324 ms0.00003 ms0.00003 ms0.00325 ms-
DenseMap100000.02178 ms0.00013 ms0.00012 ms0.02181 ms-
RobinhoodMap100000.01164 ms0.00004 ms0.00003 ms0.01164 ms-
Dictionary100000.08113 ms0.00027 ms0.00023 ms0.08122 ms-
DenseMap1000000.71209 ms0.01294 ms0.01211 ms0.71421 ms1 B
RobinhoodMap1000000.46221 ms0.00153 ms0.00143 ms0.46254 ms-
Dictionary1000001.16354 ms0.00492 ms0.00436 ms1.16436 ms1 B
DenseMap4000003.22005 ms0.28612 ms0.84362 ms2.97777 ms6 B
RobinhoodMap4000002.21473 ms0.01258 ms0.00982 ms2.21459 ms3 B
Dictionary4000005.35118 ms0.03751 ms0.03325 ms5.34191 ms6 B
DenseMap9000009.97496 ms0.07694 ms0.07197 ms9.96754 ms12 B
RobinhoodMap9000007.88940 ms0.07391 ms0.06913 ms7.88264 ms12 B
Dictionary90000015.75044 ms0.10900 ms0.09102 ms15.72190 ms23 B
DenseMap100000011.15543 ms0.11340 ms0.10607 ms11.14867 ms12 B
RobinhoodMap10000009.78328 ms0.11723 ms0.10966 ms9.73837 ms12 B
Dictionary100000017.87004 ms0.11745 ms0.10412 ms17.90677 ms23 B

Removing a million keys

MethodLengthMeanErrorStdDevMedianAllocated
DenseMap1000.00455 ms0.00009 ms0.00023 ms0.00460 ms448 B
RobinhoodMap1000.00482 ms0.00024 ms0.00069 ms0.00460 ms736 B
Dictionary1000.00510 ms0.00029 ms0.00086 ms0.00470 ms448 B
DenseMap100000.07086 ms0.00140 ms0.00219 ms0.07105 ms736 B
RobinhoodMap100000.07587 ms0.00150 ms0.00321 ms0.07550 ms736 B
Dictionary100000.15835 ms0.00860 ms0.02494 ms0.15090 ms736 B
DenseMap1000000.52464 ms0.01039 ms0.01197 ms0.52030 ms736 B
RobinhoodMap1000000.80547 ms0.01996 ms0.05824 ms0.81955 ms736 B
Dictionary1000001.20308 ms0.02320 ms0.03016 ms1.19430 ms736 B
DenseMap4000004.15055 ms0.16913 ms0.49869 ms4.35160 ms736 B
RobinhoodMap4000004.75463 ms0.12934 ms0.37730 ms4.77535 ms736 B
Dictionary4000005.94284 ms0.11669 ms0.21918 ms5.91770 ms736 B
DenseMap90000014.50084 ms0.26427 ms0.28276 ms14.55160 ms18875296 B
RobinhoodMap90000012.61194 ms0.24400 ms0.27121 ms12.56030 ms736 B
Dictionary90000017.13184 ms0.29442 ms0.22987 ms17.20345 ms736 B
DenseMap100000014.90536 ms0.29377 ms0.53717 ms14.76885 ms736 B
RobinhoodMap100000014.54652 ms0.24280 ms0.27960 ms14.55285 ms736 B
Dictionary100000019.09788 ms0.37338 ms0.39952 ms19.06965 ms736 B

Get String Benchmark

This benchmark compares the performance of different hash map implementations for various input sizes. The Mean (ms) column represents the average time taken for each operation. The fastest implementation for each input size is highlighted in bold.

MethodLengthMean (ms)Error (ms)StdDev (ms)Allocated
DenseMap_Default1000.0007880.0000050.000004-
DenseMap_Xxhash31000.0005640.0000020.000002-
DenseMap_GxHash1000.0004930.0000050.000005-
DenseMap_FastHash 🏆1000.0004420.0000020.000001-
RobinhoodMap1000.0006760.0000080.000008-
Dictionary1000.0006570.0000130.000014-
DenseMap_Default10000.0079540.0001550.000138-
DenseMap_Xxhash310000.0059860.0001120.000110-
DenseMap_GxHash10000.0052580.0000360.000034-
DenseMap_FastHash 🏆10000.0045140.0000860.000096-
RobinhoodMap10000.0078290.0000560.000049-
Dictionary10000.0074060.0001380.000129-
DenseMap_Default100000.1157670.0003760.000334-
DenseMap_Xxhash3100000.0893340.0003040.000237-
DenseMap_GxHash100000.0893100.0005200.000461-
DenseMap_FastHash 🏆100000.0817970.0006170.000547-
RobinhoodMap100000.1110060.0010390.000972-
Dictionary100000.1427460.0005620.000498-
DenseMap_Default1000001.5670900.0173830.0145161 B
DenseMap_Xxhash31000001.1543520.0030830.0027331 B
DenseMap_GxHash1000001.2154790.0040520.0031631 B
DenseMap_FastHash 🏆1000001.0320670.0107720.0089951 B
RobinhoodMap1000001.8642590.0228530.0190831 B
Dictionary1000001.8828310.0353380.0420681 B
DenseMap_Default2000003.6273380.0687710.0869733 B
DenseMap_Xxhash32000002.5581720.0104720.0087443 B
DenseMap_GxHash2000002.6618780.0495370.0439143 B
DenseMap_FastHash 🏆2000002.2523690.0356320.0333303 B
RobinhoodMap2000005.2016670.0559030.0495566 B
Dictionary2000003.9008610.0185990.0155313 B
DenseMap_Default4000008.7874560.1026710.09603912 B
DenseMap_Xxhash34000006.6200020.1012680.08977112 B
DenseMap_GxHash4000006.2525250.0240240.0224726 B
DenseMap_FastHash 🏆4000005.6093090.0280980.0234636 B
RobinhoodMap40000017.4406200.1156560.10818523 B
Dictionary4000008.8385930.0523060.04636812 B
DenseMap_Default80000029.8976680.1837200.16286323 B
DenseMap_Xxhash380000023.7406420.4610640.51247123 B
DenseMap_GxHash80000018.6628380.1635170.13654423 B
DenseMap_FastHash 🏆80000017.5167710.1736950.14504323 B
RobinhoodMap80000045.3990410.7524720.70386367 B
Dictionary80000026.3286340.1225970.09571623 B
DenseMap_Default100000043.7468460.2554470.23894567 B
DenseMap_Xxhash3100000030.9889970.1389410.12996546 B
DenseMap_GxHash100000023.9015050.0918980.08146523 B
DenseMap_FastHash 🏆100000022.5792330.0602230.05028923 B
RobinhoodMap100000062.2352920.3392880.31737092 B
Dictionary100000034.0919250.3873760.34339849 B

🏆 indicates the fastest implementation for each input size.


Add string benchmark

MethodLengthMean (ms)Error (ms)StdDev (ms)Median (ms)Allocated
DenseMap8000.040590.0071240.0208920.0535564 B
DenseMap_Xxhash38000.017060.0006160.0017580.0166064 B
DenseMap_GxHash8000.052740.0009560.0023630.052703040 B
DenseMap_FastHash8000.041920.0007210.0015040.0421064 B
RobinhoodMap8000.039950.0007970.0018320.0400064 B
DenseMap_Xxhash3 🏆8000.017060.0006160.0017580.0166064 B
DenseMap100000.122740.0024610.0068610.121353040 B
DenseMap_Xxhash3100000.119980.0038710.0109180.120403040 B
DenseMap_GxHash100000.115720.0032810.0095720.112953040 B
DenseMap_FastHash100000.104450.0034520.0101250.101103040 B
RobinhoodMap100000.171320.0034130.0079100.171803040 B
Dictionary100000.159040.0029610.0026250.159253040 B
DenseMap_FastHash 🏆100000.104450.0034520.0101250.101103040 B
DenseMap1000001.358080.0271440.0690901.359853040 B
DenseMap_Xxhash31000001.284640.0250210.0418041.268753040 B
DenseMap_GxHash1000001.364490.0335640.0957601.330853040 B
DenseMap_FastHash 🏆1000001.157280.0227440.0614891.143903040 B
RobinhoodMap1000002.219790.0439740.1019162.197203040 B
Dictionary1000001.946690.0275390.0215011.948553040 B
DenseMap2000002.982780.0591150.1370092.940603040 B
DenseMap_Xxhash32000003.189360.0875980.2541393.066253040 B
DenseMap_GxHash2000003.155340.0941240.2715703.038503040 B
DenseMap_FastHash 🏆2000002.950210.1576100.4647172.715003040 B
RobinhoodMap2000005.643690.1385190.3952035.534803040 B
Dictionary2000004.687170.1128040.3218354.626103040 B
DenseMap4000007.681230.1515880.2532707.617753040 B
DenseMap_Xxhash34000007.786370.1383500.3261087.731703040 B
DenseMap_GxHash4000007.517990.1495170.2191607.491403040 B
DenseMap_FastHash 🏆4000007.158700.1831030.5104187.073203040 B
RobinhoodMap40000015.244560.3040430.64794115.071103040 B
Dictionary40000011.704880.5428591.50426011.323203040 B
DenseMap80000019.184970.4643681.36920118.319503040 B
DenseMap_Xxhash380000018.793780.3741260.29209318.756953040 B
DenseMap_GxHash80000017.755750.1964690.16406017.744503040 B
DenseMap_FastHash 🏆80000016.908480.3367200.36028716.749903040 B
RobinhoodMap80000036.955770.7201061.12111836.450303040 B
Dictionary80000028.712530.5676151.41355928.261503040 B

🏆 indicates the fastest implementation for each input size.