63 KiB
PersistentMap
A high-performance, persistent (Copy-on-Write) B+ Tree implemented in C#.
It is designed for zero-overhead reads, SIMD-accelerated key routing, and allocation-free range queries. It supports both fully immutable usage and "Transient" mode for high-throughput bulk mutations. The primary use case is for when editing operations are in bulk. Updating single elements many times will fail to distinguish this collection from other more mature collections. Bulk writes are very fast using transient interfaces, random reads are fastish depending on key type and entropy, Sequential reads and min/max queries are very fast.
Features
- Copy-on-Write Semantics: Thread-safe, immutable tree states. Modifying the tre yields a new version while sharing unmodified nodes.
- Transient Mode: Perform bulk mutations in-place with standard mutable performance, then freeze it into a
PersistentMapin $O(1)$ time. - SIMD Prefix Scanning: Uses AVX2/AVX512 to vectorize B+ tree routing and binary searches via
longkey-prefixes. - Linear Time Set Operations: Sort-merge based
Intersect,Except, andSymmetricExceptexecute in $O(N+M)$ time using lazy evaluation.
When should I use this?
Never, probably. This was just a fun little project. If you want a really fast immutable sorted map you should consider it. Despite this map being faster than LanguageExt.HashMap for some key types, you should definitely use that if you don't need a sorted collection. It is well tested and does have a very nice API, and it also has a performance model that is easy to understand. If you look at the performance characteristics of it below, it scales much more linear with collection size. For example: I don't know why PersistentMap lookups suddenly becomes so much slower when we reach 100000 integer keys. There might be a gazillion things like that, that make PersistentMap much slower for real world usage.
The general version of this, using StandardStrategy<K> does not benefit from the prefix optimization, although might benefit from a usage of binary search in the future.
Quick Start
1. Basic Immutable Usage
By default, the map is immutable. Every write operation returns a new, updated version of the map.
// Create a map with a specific key strategy (e.g., Int, Unicode, Double)
var map1 = BaseOrderedMap<int, string, IntStrategy>.Create(new IntStrategy());
// Set returns a new tree instance. map1 remains empty.
var map2 = map1.Set(1, "Apple")
.Set(2, "Banana")
.Set(3, "Cherry");
if (map2.TryGetValue(2, out var value))
{
Console.WriteLine(value); // "Banana"
}
2. Transient Mode (Bulk Mutations
If you need to insert thousands of elements, creating a new persistent tree on every insert is too slow. Use a TransientMap to mutate the tree in-place, then lock it into a persistent snapshot. This does not edit an existing map, but will make bulk operations a lot faster on nodes "owned" by the current map.
var transientMap = BaseOrderedMap<int, string, IntStrategy>.CreateTransient(new IntStrategy());
// Mutates in-place. No allocations for unchanged tree paths.
for (int i = 0; i < 10_000; i++)
{
transientMap.Set(i, $"Value_{i}");
}
// O(1) freeze. Returns a thread-safe immutable PersistentMap.
var persistentSnapshot = transientMap.ToPersistent();
3. Range Queries and Iteration
Because it is a B+ tree range queries require zero allocations and simply walk the leaves.
var map = GetPopulatedMap();
// Iterate exact bounds
foreach (var kvp in map.Range(min: 10, max: 50))
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
// Open-ended queries
var greaterThan100 = map.From(100);
var lessThan50 = map.Until(50);
var allElements = map.AsEnumerable();
#+end_sr
*** 4. Tree Navigation
Find bounds and adjacent elements instantly. Missing keys will correctly resolve to the mathematical lower/upper bound.
#+begin_src csharp
// Get extremes
map.TryGetMin(out int minKey, out string minVal);
map.TryGetMax(out int maxKey, out string maxVal);
// Get the immediate next/previous element (works even if '42' doesn't exist)
if (map.TryGetSuccessor(42, out int nextKey, out string nextVal))
{
Console.WriteLine($"The key immediately after 42 is {nextKey}");
}
if (map.TryGetPredecessor(42, out int prevKey, out string prevVal))
{
Console.WriteLine($"The key immediately before 42 is {prevKey}");
}
5. Set Operations
Set operations take advantage of the tree's underlying sorted structure to merge trees in linear $O(N+M)$ time.
var mapA = CreateMap(1, 2, 3, 4);
var mapB = CreateMap(3, 4, 5, 6);
// Returns { 3, 4 }
var common = mapA.Intersect(mapB);
// Returns { 1, 2 }
var onlyInA = mapA.Except(mapB);
// Returns { 1, 2, 5, 6 }
var symmetricDiff = mapA.SymmetricExcept(mapB);
Benchmarks
These benchmarks tries a variety of operations. The Int benchmarks (the first ones) use avx for lookups. On a computer without avx this is bound to be slower. In benchmarks where there are many writes to the tree, the transient version is used, since this is the workload this datastructure is optimized for.
Build: builds a map of size N. I did not benchmark the builders used by the built in collections, but they are almost certainly at least as fast as the transients used by this library. For integers, the map was sorted (triggering a small optimization in PersistentMap). For the string benchmark it was random.
The retrieval benchmarks reads a subset of the keys in random order.
The update benchmarks updates a subset of the keys in random order.
The update and set benchmarks updates and sets keys in random order. Half of the keys are new.
The iteration benchmarks iterate from start to finish. The ordered collections are of course in order.
The removal benchmarks removes a subset of the keys in random order.
Integer keys
This is pretty much the best case scenario for everyone. Key comparisons are fast, hashing is minimal. For b+trees this means we can do a lot of key comparisons at once using avx. The machine this is done on is an amd 5900x, which supports some kind of bastardized avx512. It is not really a gain over avx256 in this benchmark though on that processor. With regards to building, the microsoft collections have builders, and they are about as fast as the TransientMap, but a little little slower on my computer. LanguageExt lacks transients, and thus these comparisons are not fair.
ImmDict is System.Collections.Immutable dictionary. ImmSortedDict is it's sorted sibling. ExtMap is the sorted map from LanguageExt. ExtHashMap is the unsorted HashMap from LanguageExt.
| Method | N | Mean | Gen0 | Gen1 | Gen2 | Allocated |
|-------------------------|--------|-----------------:|-----------:|----------:|--------:|------------:|
| Build_ImmDict | 100 | 11,307.04 ns | 4.9744 | 0.0458 | - | 41688 B |
| Build_ImmSortedDict | 100 | 8,493.79 ns | 4.4250 | 0.0458 | - | 37104 B |
| Build_ExtMap | 100 | 8,519.63 ns | 5.3101 | 0.0458 | - | 44432 B |
| Build_ExtHashMap | 100 | 9,855.33 ns | 7.5378 | 0.0458 | - | 63104 B |
| Build_PersistentMap | 100 | 8,698.33 ns | 16.3879 | 0.1526 | - | 137072 B |
| Build_TransientMap | 100 | 1,665.90 ns | 0.6332 | 0.0038 | - | 5304 B |
| Retrieve_ImmDict | 100 | 39.19 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 100 | 64.32 ns | - | - | - | - |
| Retrieve_ExtMap | 100 | 117.61 ns | - | - | - | - |
| Retrieve_ExtHashMap | 100 | 84.19 ns | - | - | - | - |
| Retrieve_PersistentMap | 100 | 47.25 ns | - | - | - | - |
| Update_ImmDict | 100 | 1,145.75 ns | 0.4616 | 0.0019 | - | 3872 B |
| Update_PersistentMap | 100 | 1.107 μs | 1.9398 | 0.0248 | - | 15.86 KB |
| Update_TransientMap | 100 | 347.49 ns | 0.3576 | 0.0033 | - | 2992 B |
| Update_ImmSortedDict | 100 | 849.39 ns | 0.3958 | 0.0010 | - | 3312 B |
| Update_ExtMap | 100 | 642.50 ns | 0.3939 | 0.0010 | - | 3296 B |
| Update_ExtHashMap | 100 | 541.84 ns | 0.5283 | 0.0010 | - | 4424 B |
| UpdateSet_ImmDict | 100 | 1,236.82 ns | 0.5226 | 0.0019 | - | 4376 B |
| UpdateSet_PersistentMap | 100 | 1189 ns | 1.9398 | 0.0248 | - | 15.86 KB |
| UpdateSet_TransientMap | 100 | 380.70 ns | 0.3576 | 0.0033 | - | 2992 B |
| UpdateSet_ImmSortedDict | 100 | 887.07 ns | 0.4587 | 0.0010 | - | 3840 B |
| UpdateSet_ExtMap | 100 | 856.76 ns | 0.4797 | 0.0010 | - | 4016 B |
| UpdateSet_ExtHashMap | 100 | 582.31 ns | 0.5312 | 0.0019 | - | 4448 B |
| Iterate_ImmDict | 100 | 1,324.41 ns | - | - | - | - |
| Iterate_PersistentMap | 100 | 175.98 ns | - | - | - | - |
| Iterate_ImmSortedDict | 100 | 488.69 ns | - | - | - | - |
| Iterate_ExtMap | 100 | 337.40 ns | 0.0038 | - | - | 32 B |
| Iterate_ExtHashMap | 100 | 1,209.77 ns | 0.2518 | - | - | 2112 B |
| Remove_ImmDict | 100 | 899.57 ns | 0.4425 | 0.0010 | - | 3704 B |
| Remove_TransientMap | 100 | 433.52 ns | 0.3290 | 0.0029 | - | 2752 B |
| Remove_ImmSortedDict | 100 | 728.77 ns | 0.3786 | 0.0010 | - | 3168 B |
| Remove_ExtMap | 100 | 653.72 ns | 0.3767 | 0.0010 | - | 3152 B |
| Remove_ExtHashMap | 100 | 589.03 ns | 0.5178 | - | - | 4336 B |
| Build_ImmDict | 1000 | 168,692.47 ns | 71.5332 | 6.8359 | - | 598712 B |
| Build_ImmSortedDict | 1000 | 125,591.01 ns | 62.9883 | 5.1270 | - | 526896 B |
| Build_ExtMap | 1000 | 117,763.81 ns | 72.3877 | 6.1035 | - | 605936 B |
| Build_ExtHashMap | 1000 | 64,443.19 ns | 67.5049 | 1.5869 | - | 564864 B |
| Build_PersistentMap | 1000 | 133,156.05 ns | 192.1387 | 7.8125 | - | 1607744 B |
| Build_TransientMap | 1000 | 25,945.72 ns | 4.2725 | 0.1526 | - | 35976 B |
| Retrieve_ImmDict | 1000 | 686.48 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 1000 | 1,145.83 ns | - | - | - | - |
| Retrieve_ExtMap | 1000 | 2,276.07 ns | - | - | - | - |
| Retrieve_ExtHashMap | 1000 | 808.53 ns | - | - | - | - |
| Retrieve_PersistentMap | 1000 | 680.50 ns | - | - | - | - |
| Update_ImmDict | 1000 | 16,863.81 ns | 6.5613 | 0.2136 | - | 54960 B |
| Update_PersistentMap | 1000 | 13,617.12 ns | 19.4092 | 1.1597 | - | 158.59 KB |
| Update_TransientMap | 1000 | 3,611.03 ns | 2.5406 | 0.1564 | - | 21280 B |
| Update_ImmSortedDict | 1000 | 12,428.90 ns | 5.5542 | 0.1526 | - | 46464 B |
| Update_ExtMap | 1000 | 10,091.51 ns | 5.6000 | 0.1678 | - | 46880 B |
| Update_ExtHashMap | 1000 | 6,758.96 ns | 7.9575 | 0.2136 | - | 66616 B |
| UpdateSet_ImmDict | 1000 | 21,489.70 ns | 7.0496 | 0.1831 | - | 59160 B |
| UpdateSet_PersistentMap | 1000 | 14,890.21 ns | 19.4855 | 1.0529 | - | 159.23 KB |
| UpdateSet_TransientMap | 1000 | 5,063.11 ns | 2.4796 | 0.1450 | - | 20776 B |
| UpdateSet_ImmSortedDict | 1000 | 13,333.61 ns | 6.3782 | 0.1526 | - | 53472 B |
| UpdateSet_ExtMap | 1000 | 11,221.39 ns | 6.5918 | 0.1526 | - | 55184 B |
| UpdateSet_ExtHashMap | 1000 | 15,967.43 ns | 13.1836 | 0.4578 | - | 110440 B |
| Iterate_ImmDict | 1000 | 15,325.93 ns | - | - | - | - |
| Iterate_PersistentMap | 1000 | 1,574.20 ns | - | - | - | - |
| Iterate_ImmSortedDict | 1000 | 5,110.07 ns | - | - | - | - |
| Iterate_ExtMap | 1000 | 3,432.88 ns | 0.0038 | - | - | 32 B |
| Iterate_ExtHashMap | 1000 | 8,207.75 ns | 0.2441 | - | - | 2112 B |
| Remove_ImmDict | 1000 | 15,205.95 ns | 6.4392 | 0.2136 | - | 54064 B |
| Remove_TransientMap | 1000 | 4,036.18 ns | 2.2507 | 0.1373 | - | 18880 B |
| Remove_ImmSortedDict | 1000 | 10,664.14 ns | 5.7068 | 0.1678 | - | 47760 B |
| Remove_ExtMap | 1000 | 9,993.90 ns | 5.5084 | 0.1526 | - | 46160 B |
| Remove_ExtHashMap | 1000 | 7,475.24 ns | 7.7209 | 0.1907 | - | 64608 B |
| Build_ImmDict | 10000 | 2,571,753.12 ns | 41.4063 | 390.6250 | - | 7882552 B |
| Build_ImmSortedDict | 10000 | 1,975,364.14 ns | 820.3125 | 296.8750 | - | 6893616 B |
| Build_ExtMap | 10000 | 1,866,221.83 ns | 917.9688 | 320.3125 | - | 7692272 B |
| Build_ExtHashMap | 10000 | 1,215,103.58 ns | 1009.7656 | 240.2344 | - | 8446080 B |
| Build_PersistentMap | 10000 | 1,930,457.96 ns | 2345.7031 | 494.1406 | - | 19626728 B |
| Build_TransientMap | 10000 | 640,413.08 ns | 41.0156 | 8.7891 | - | 347344 B |
| Retrieve_ImmDict | 10000 | 14,880.32 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 10000 | 15,595.68 ns | - | - | - | - |
| Retrieve_ExtMap | 10000 | 36,225.60 ns | - | - | - | - |
| Retrieve_ExtHashMap | 10000 | 11,987.70 ns | - | - | - | - |
| Retrieve_PersistentMap | 10000 | 10,227.73 ns | - | - | - | - |
| Update_ImmDict | 10000 | 318,905.00 ns | 86.9141 | 23.4375 | - | 730200 B |
| Update_PersistentMap | 10000 | 202,244.42 ns | 243.6523 | 73.2422 | - | 1992.19 KB |
| Update_TransientMap | 10000 | 73,203.50 ns | 24.9023 | 7.3242 | - | 209056 B |
| Update_ImmSortedDict | 10000 | 216,638.87 ns | 77.1484 | 16.1133 | - | 645360 B |
| Update_ExtMap | 10000 | 176,737.24 ns | 74.4629 | 17.5781 | - | 623600 B |
| Update_ExtHashMap | 10000 | 105,445.84 ns | 97.2900 | 17.3340 | - | 814376 B |
| UpdateSet_ImmDict | 10000 | 333,260.72 ns | 92.2852 | 19.0430 | - | 775784 B |
| UpdateSet_PersistentMap | 10000 | 221,958.91 ns | 244.6289 | 71.2891 | - | 1998.95 KB |
| UpdateSet_TransientMap | 10000 | 93,484.07 ns | 24.9023 | 7.3242 | - | 209072 B |
| UpdateSet_ImmSortedDict | 10000 | 224,214.31 ns | 83.2520 | 14.6484 | - | 697920 B |
| UpdateSet_ExtMap | 10000 | 186,761.55 ns | 83.7402 | 14.4043 | - | 700880 B |
| UpdateSet_ExtHashMap | 10000 | 112,371.27 ns | 97.7783 | 20.2637 | - | 818240 B |
| Iterate_ImmDict | 10000 | 152,686.50 ns | - | - | - | - |
| Iterate_PersistentMap | 10000 | 14,841.56 ns | - | - | - | - |
| Iterate_ImmSortedDict | 10000 | 53,372.05 ns | - | - | - | - |
| Iterate_ExtMap | 10000 | 38,673.93 ns | - | - | - | 32 B |
| Iterate_ExtHashMap | 10000 | 111,676.15 ns | 8.0566 | - | - | 67648 B |
| Remove_ImmDict | 10000 | 303,798.22 ns | 86.4258 | 19.5313 | - | 726560 B |
| Remove_TransientMap | 10000 | 58,890.93 ns | 22.0947 | 6.5308 | - | 185056 B |
| Remove_ImmSortedDict | 10000 | 219,974.63 ns | 77.8809 | 15.1367 | - | 653184 B |
| Remove_ExtMap | 10000 | 188,713.80 ns | 74.2188 | 14.4043 | - | 621248 B |
| Remove_ExtHashMap | 10000 | 120,113.97 ns | 95.9473 | 15.9912 | - | 802944 B |
| Build_ImmDict | 100000 | 38,394,437.95 ns | 11714.2857 | 1071.4286 | 71.4286 | 97460075 B |
| Build_ImmSortedDict | 100000 | 30,860,676.12 ns | 10187.5000 | 906.2500 | 62.5000 | 84908636 B |
| Build_ExtMap | 100000 | 28,415,796.22 ns | 11156.2500 | 937.5000 | 62.5000 | 92907004 B |
| Build_ExtHashMap | 100000 | 29,149,824.12 ns | 15375.0000 | 2750.0000 | 62.5000 | 128198060 B |
| Build_PersistentMap | 100000 | 24,745,757.59 ns | 27687.5000 | 375.0000 | - | 231722008 B |
| Build_TransientMap | 100000 | 9,137,195.74 ns | 406.2500 | 234.3750 | - | 3460512 B |
| Retrieve_ImmDict | 100000 | 1,259,618.31 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 100000 | 975,518.14 ns | - | - | - | - |
| Retrieve_ExtMap | 100000 | 1,535,487.85 ns | - | - | - | - |
| Retrieve_ExtHashMap | 100000 | 284,590.55 ns | - | - | - | - |
| Retrieve_PersistentMap | 100000 | 429,001.27 ns | - | - | - | - |
| Update_ImmDict | 100000 | 5,705,786.31 ns | 1093.7500 | 906.2500 | - | 9183488 B |
| Update_PersistentMap | 100000 | 4,056,612.12 ns | 2945.3125 | 2781.2500 | 15.6250 | 23984.39 KB |
| Update_TransientMap | 100000 | 1,145,551.13 ns | 248.0469 | 199.2188 | - | 2081568 B |
| Update_ImmSortedDict | 100000 | 4,433,611.11 ns | 953.1250 | 796.8750 | - | 8021136 B |
| Update_ExtMap | 100000 | 3,901,065.86 ns | 937.5000 | 789.0625 | - | 7848704 B |
| Update_ExtHashMap | 100000 | 2,696,228.39 ns | 1289.0625 | 960.9375 | - | 10805952 B |
| UpdateSet_ImmDict | 100000 | 5,340,382.88 ns | 1109.3750 | 867.1875 | - | 9318896 B |
| UpdateSet_PersistentMap | 100000 | 4,629,564.21 ns | 2984.3750 | 1906.2500 | 39.0625 | 24060.44 KB |
| UpdateSet_TransientMap | 100000 | 1,332,859.76 ns | 250.0000 | 208.9844 | - | 2099520 B |
| UpdateSet_ImmSortedDict | 100000 | 4,418,076.49 ns | 1000.0000 | 992.1875 | - | 8396544 B |
| UpdateSet_ExtMap | 100000 | 3,107,339.72 ns | 996.0938 | 507.8125 | - | 8349248 B |
| UpdateSet_ExtHashMap | 100000 | 2,630,473.81 ns | 1292.9688 | 976.5625 | - | 10845480 B |
| Iterate_ImmDict | 100000 | 1,550,040.28 ns | - | - | - | - |
| Iterate_PersistentMap | 100000 | 149,743.16 ns | - | - | - | - |
| Iterate_ImmSortedDict | 100000 | 723,978.27 ns | - | - | - | - |
| Iterate_ExtMap | 100000 | 504,204.91 ns | - | - | - | 32 B |
| Iterate_ExtHashMap | 100000 | 1,936,574.10 ns | 257.8125 | - | - | 2164800 B |
| Remove_ImmDict | 100000 | 5,419,879.00 ns | 1093.7500 | 914.0625 | - | 9149160 B |
| Remove_TransientMap | 100000 | 951,332.63 ns | 219.7266 | 155.2734 | - | 1839264 B |
| Remove_ImmSortedDict | 100000 | 4,203,794.51 ns | 953.1250 | 781.2500 | - | 8028144 B |
| Remove_ExtMap | 100000 | 3,896,109.04 ns | 929.6875 | 789.0625 | - | 7824560 B |
| Remove_ExtHashMap | 100000 | 2,816,957.99 ns | 1277.3438 | 914.0625 | - | 10709360 B |
String keys
These benchmarks act like above, but do not insert keys in a specific order. Sorting them before will yield a speed boost. One uses the standardkeystrategy (does a binary search) and one uses the unicodstrategy which encodes the first 8 bytes as a long and uses avx to search for keys.
| Method | Size | keylen | Mean | Gen0 | Gen1 | Gen2 | Allocated |
|----------------------------------|--------|--------|------------------:|-----------:|----------:|---------:|------------:|
| Build_TransientMap_Standard | 100 | 8 | 17,993.68 ns | 0.7324 | - | - | 6216 B |
| Build_TransientMap_Unicode | 100 | 8 | 12,240.69 ns | 0.8850 | 0.0153 | - | 7528 B |
| Build_ImmDict | 100 | 8 | 13,807.87 ns | 5.3406 | 0.0610 | - | 44704 B |
| Build_ImmSortedDict | 100 | 8 | 21,920.45 ns | 4.2114 | 0.0305 | - | 35472 B |
| Build_ExtMap | 100 | 8 | 22,192.67 ns | 5.6152 | 0.0610 | - | 47104 B |
| Build_ExtHashMap | 100 | 8 | 10,569.35 ns | 4.5013 | 0.0305 | - | 37680 B |
| Retrieve_ImmDict | 100 | 8 | 79.60 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 100 | 8 | 112.5 ns | - | - | - | - |
| Retrieve_PersistentMap_Unicode | 100 | 8 | 148.82 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 100 | 8 | 1,198.42 ns | - | - | - | - |
| Retrieve_ExtMap | 100 | 8 | 1,305.45 ns | - | - | - | - |
| Retrieve_ExtHashMap | 100 | 8 | 197.96 ns | - | - | - | - |
| Update_ImmDict | 100 | 8 | 1,232.22 ns | 0.4826 | 0.0019 | - | 4048 B |
| Update_PersistentMap_Standard | 100 | 8 | 2,884.71 ns | 2.4071 | 0.0420 | - | 20160 B |
| Update_PersistentMap_Unicode | 100 | 8 | 1,955.50 ns | 2.7046 | 0.0496 | - | 22640 B |
| Update_TransientMap_Standard | 100 | 8 | 1,621.74 ns | 0.4349 | 0.0038 | - | 3640 B |
| Update_TransientMap_Unicode | 100 | 8 | 674.43 ns | 0.4644 | 0.0057 | - | 3888 B |
| Update_ImmSortedDict | 100 | 8 | 1,701.62 ns | 0.3662 | - | - | 3072 B |
| Update_ExtMap | 100 | 8 | 1,803.33 ns | 0.4120 | - | - | 3456 B |
| Update_ExtHashMap | 100 | 8 | 752.46 ns | 0.5083 | 0.0010 | - | 4256 B |
| UpdateSet_ImmDict | 100 | 8 | 1,450.07 ns | 0.5512 | 0.0019 | - | 4624 B |
| UpdateSet_PersistentMap_Standard | 100 | 8 | 3,246.39 ns | 2.4071 | 0.0420 | - | 20160 B |
| UpdateSet_PersistentMap_Unicode | 100 | 8 | 2,587.39 ns | 2.7046 | 0.0534 | - | 22640 B |
| UpdateSet_TransientMap_Standard | 100 | 8 | 1,970.08 ns | 0.4349 | 0.0038 | - | 3640 B |
| UpdateSet_TransientMap_Unicode | 100 | 8 | 1,184.37 ns | 0.4635 | 0.0057 | - | 3888 B |
| UpdateSet_ImmSortedDict | 100 | 8 | 2,352.86 ns | 0.4578 | - | - | 3840 B |
| UpdateSet_ExtMap | 100 | 8 | 2,089.91 ns | 0.4730 | - | - | 3960 B |
| UpdateSet_ExtHashMap | 100 | 8 | 819.11 ns | 0.5445 | 0.0010 | - | 4560 B |
| Iterate_ImmDict | 100 | 8 | 1,338.64 ns | - | - | - | - |
| Iterate_PersistentMap_Standard | 100 | 8 | 183.94 ns | - | - | - | - |
| Iterate_ImmSortedDict | 100 | 8 | 490.25 ns | - | - | - | - |
| Iterate_ExtMap | 100 | 8 | 332.42 ns | 0.0038 | - | - | 32 B |
| Iterate_ExtHashMap | 100 | 8 | 1,162.47 ns | 0.2747 | - | - | 2304 B |
| Iterate_PersistentMap_Unicode | 100 | 8 | 186.95 ns | - | - | - | - |
| Remove_ImmDict | 100 | 8 | 1,396.87 ns | 0.4978 | 0.0019 | - | 4176 B |
| Remove_PersistentMap_Standard | 100 | 8 | 3,197.32 ns | 2.3804 | 0.0420 | - | 19920 B |
| Remove_PersistentMap_Unicode | 100 | 8 | 2,522.69 ns | 2.6779 | 0.0496 | - | 22400 B |
| Remove_TransientMap_Standard | 100 | 8 | 1,973.57 ns | 0.4120 | 0.0038 | - | 3448 B |
| Remove_TransientMap_Unicode | 100 | 8 | 1,320.29 ns | 0.4406 | 0.0057 | - | 3688 B |
| Remove_ImmSortedDict | 100 | 8 | 1,950.87 ns | 0.3777 | - | - | 3168 B |
| Remove_ExtMap | 100 | 8 | 2,240.33 ns | 0.5798 | - | - | 4856 B |
| Remove_ExtHashMap | 100 | 8 | 746.28 ns | 0.5140 | 0.0019 | - | 4304 B |
| Build_TransientMap_Standard | 100 | 50 | 18,239.16 ns | 0.7324 | - | - | 6216 B |
| Build_TransientMap_Unicode | 100 | 50 | 11,800.99 ns | 0.8850 | 0.0153 | - | 7528 B |
| Build_ImmDict | 100 | 50 | 16,343.07 ns | 5.3406 | 0.0610 | - | 44832 B |
| Build_ImmSortedDict | 100 | 50 | 21,709.91 ns | 4.2114 | 0.0305 | - | 35232 B |
| Build_ExtMap | 100 | 50 | 22,948.94 ns | 5.6458 | 0.0610 | - | 47328 B |
| Build_ExtHashMap | 100 | 50 | 12,107.35 ns | 4.0894 | 0.0305 | - | 34280 B |
| Retrieve_ImmDict | 100 | 50 | 286.13 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 100 | 50 | 984.90 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 100 | 50 | 105.3 ns | - | - | - | - |
| Retrieve_PersistentMap_Unicode | 100 | 50 | 151.45 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 100 | 50 | 1,308.09 ns | - | - | - | - |
| Retrieve_ExtMap | 100 | 50 | 1,164.25 ns | - | - | - | - |
| Retrieve_ExtHashMap | 100 | 50 | 398.29 ns | - | - | - | - |
| Update_ImmDict | 100 | 50 | 1,390.29 ns | 0.4749 | 0.0019 | - | 3984 B |
| Update_PersistentMap_Standard | 100 | 50 | 2,932.88 ns | 2.4071 | 0.0381 | - | 20160 B |
| Update_PersistentMap_Unicode | 100 | 50 | 1,947.26 ns | 2.7046 | 0.0534 | - | 22640 B |
| Update_TransientMap_Standard | 100 | 50 | 1,545.90 ns | 0.4349 | 0.0038 | - | 3640 B |
| Update_TransientMap_Unicode | 100 | 50 | 646.55 ns | 0.4644 | 0.0057 | - | 3888 B |
| Update_ImmSortedDict | 100 | 50 | 2,010.40 ns | 0.4120 | - | - | 3456 B |
| Update_ExtMap | 100 | 50 | 1,961.80 ns | 0.4234 | - | - | 3568 B |
| Update_ExtHashMap | 100 | 50 | 1,013.87 ns | 0.5188 | 0.0019 | - | 4344 B |
| UpdateSet_ImmDict | 100 | 50 | 1,753.26 ns | 0.5665 | 0.0019 | - | 4752 B |
| UpdateSet_PersistentMap_Standard | 100 | 50 | 3,393.56 ns | 2.4071 | 0.0420 | - | 20160 B |
| UpdateSet_PersistentMap_Unicode | 100 | 50 | 2,495.39 ns | 2.7046 | 0.0496 | - | 22640 B |
| UpdateSet_TransientMap_Standard | 100 | 50 | 2,073.78 ns | 0.4349 | 0.0038 | - | 3640 B |
| UpdateSet_TransientMap_Unicode | 100 | 50 | 1,258.03 ns | 0.4635 | 0.0057 | - | 3888 B |
| UpdateSet_ImmSortedDict | 100 | 50 | 2,456.28 ns | 0.4730 | - | - | 3984 B |
| UpdateSet_ExtMap | 100 | 50 | 2,420.97 ns | 0.5913 | - | - | 4968 B |
| UpdateSet_ExtHashMap | 100 | 50 | 894.89 ns | 0.4902 | 0.0019 | - | 4104 B |
| Iterate_ImmDict | 100 | 50 | 1,311.46 ns | - | - | - | - |
| Iterate_PersistentMap_Standard | 100 | 50 | 189.59 ns | - | - | - | - |
| Iterate_ImmSortedDict | 100 | 50 | 482.89 ns | - | - | - | - |
| Iterate_ExtMap | 100 | 50 | 357.71 ns | 0.0038 | - | - | 32 B |
| Iterate_ExtHashMap | 100 | 50 | 1,241.61 ns | 0.2918 | - | - | 2448 B |
| Iterate_PersistentMap_Unicode | 100 | 50 | 195.23 ns | - | - | - | - |
| Remove_ImmDict | 100 | 50 | 1,412.10 ns | 0.4826 | 0.0019 | - | 4048 B |
| Remove_PersistentMap_Standard | 100 | 50 | 3,421.53 ns | 2.3804 | 0.0420 | - | 19920 B |
| Remove_PersistentMap_Unicode | 100 | 50 | 2,640.76 ns | 2.6779 | 0.0458 | - | 22400 B |
| Remove_TransientMap_Standard | 100 | 50 | 2,333.67 ns | 0.4120 | 0.0038 | - | 3448 B |
| Remove_TransientMap_Unicode | 100 | 50 | 1,393.38 ns | 0.4406 | 0.0057 | - | 3688 B |
| Remove_ImmSortedDict | 100 | 50 | 2,034.54 ns | 0.3891 | - | - | 3264 B |
| Remove_ExtMap | 100 | 50 | 2,105.53 ns | 0.4387 | - | - | 3680 B |
| Remove_ExtHashMap | 100 | 50 | 914.57 ns | 0.4635 | 0.0010 | - | 3880 B |
| Build_TransientMap_Standard | 1000 | 8 | 337,908.27 ns | 5.8594 | - | - | 49512 B |
| Build_TransientMap_Unicode | 1000 | 8 | 174,485.27 ns | 7.3242 | 0.7324 | - | 62248 B |
| Build_ImmDict | 1000 | 8 | 258,419.20 ns | 79.1016 | 8.7891 | - | 664448 B |
| Build_ImmSortedDict | 1000 | 8 | 425,563.19 ns | 61.0352 | 4.8828 | - | 513312 B |
| Build_ExtMap | 1000 | 8 | 405,979.91 ns | 79.1016 | 7.3242 | - | 662448 B |
| Build_ExtHashMap | 1000 | 8 | 149,392.88 ns | 70.5566 | 4.6387 | - | 590896 B |
| Retrieve_ImmDict | 1000 | 8 | 1,055.73 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 1000 | 8 | 1,778.70 ns | - | - | - | - |
| Retrieve_PersistentMap_Unicode | 1000 | 8 | 1,920.99 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 1000 | 8 | 21,922.86 ns | - | - | - | - |
| Retrieve_ExtMap | 1000 | 8 | 24,281.46 ns | - | - | - | - |
| Retrieve_ExtHashMap | 1000 | 8 | 2,588.04 ns | - | - | - | - |
| Update_ImmDict | 1000 | 8 | 19,804.39 ns | 7.3853 | 0.3052 | - | 61792 B |
| Update_PersistentMap_Standard | 1000 | 8 | 39,488.86 ns | 24.0479 | 2.3193 | - | 201600 B |
| Update_PersistentMap_Unicode | 1000 | 8 | 28,346.74 ns | 27.0386 | 2.5330 | - | 226400 B |
| Update_TransientMap_Standard | 1000 | 8 | 24,653.11 ns | 4.5471 | 0.4883 | - | 38184 B |
| Update_TransientMap_Unicode | 1000 | 8 | 7,849.22 ns | 4.4250 | 0.4425 | - | 37024 B |
| Update_ImmSortedDict | 1000 | 8 | 31,925.02 ns | 5.7373 | 0.1221 | - | 48288 B |
| Update_ExtMap | 1000 | 8 | 31,958.66 ns | 6.4087 | 0.1831 | - | 53824 B |
| Update_ExtHashMap | 1000 | 8 | 10,986.98 ns | 7.2327 | 0.2441 | - | 60568 B |
| UpdateSet_ImmDict | 1000 | 8 | 23,205.06 ns | 8.4839 | 0.4272 | - | 71072 B |
| UpdateSet_PersistentMap_Standard | 1000 | 8 | 46,680.76 ns | 24.0479 | 2.1973 | - | 201600 B |
| UpdateSet_PersistentMap_Unicode | 1000 | 8 | 33,833.67 ns | 27.0386 | 2.6245 | - | 226400 B |
| UpdateSet_TransientMap_Standard | 1000 | 8 | 30,683.30 ns | 4.2114 | 0.4272 | - | 35368 B |
| UpdateSet_TransientMap_Unicode | 1000 | 8 | 12,650.99 ns | 4.5929 | 0.4883 | - | 38432 B |
| UpdateSet_ImmSortedDict | 1000 | 8 | 37,438.25 ns | 6.3477 | 0.2441 | - | 53232 B |
| UpdateSet_ExtMap | 1000 | 8 | 37,901.44 ns | 7.6904 | 0.3052 | - | 64576 B |
| UpdateSet_ExtHashMap | 1000 | 8 | 18,651.16 ns | 7.4768 | 0.2441 | - | 62768 B |
| Iterate_ImmDict | 1000 | 8 | 12,693.24 ns | - | - | - | - |
| Iterate_PersistentMap_Standard | 1000 | 8 | 1,629.13 ns | - | - | - | - |
| Iterate_ImmSortedDict | 1000 | 8 | 4,901.80 ns | - | - | - | - |
| Iterate_ExtMap | 1000 | 8 | 3,685.00 ns | 0.0038 | - | - | 32 B |
| Iterate_ExtHashMap | 1000 | 8 | 14,519.26 ns | 2.6550 | - | - | 22320 B |
| Iterate_PersistentMap_Unicode | 1000 | 8 | 1,612.41 ns | - | - | - | - |
| Remove_ImmDict | 1000 | 8 | 19,718.44 ns | 7.6294 | 0.3052 | - | 63840 B |
| Remove_PersistentMap_Standard | 1000 | 8 | 45,580.39 ns | 23.8037 | 2.0752 | - | 199200 B |
| Remove_PersistentMap_Unicode | 1000 | 8 | 29,970.54 ns | 26.7639 | 2.4414 | - | 224000 B |
| Remove_TransientMap_Standard | 1000 | 8 | 29,451.58 ns | 4.0894 | 0.3967 | - | 34424 B |
| Remove_TransientMap_Unicode | 1000 | 8 | 14,136.83 ns | 3.7994 | 0.3662 | - | 31848 B |
| Remove_ImmSortedDict | 1000 | 8 | 33,400.75 ns | 5.6763 | 0.1221 | - | 47616 B |
| Remove_ExtMap | 1000 | 8 | 36,167.45 ns | 6.8970 | 0.1831 | - | 57744 B |
| Remove_ExtHashMap | 1000 | 8 | 12,681.31 ns | 8.0414 | 0.2289 | - | 67288 B |
| Build_TransientMap_Standard | 1000 | 50 | 342,796.72 ns | 5.3711 | - | - | 44992 B |
| Build_TransientMap_Unicode | 1000 | 50 | 173,477.79 ns | 7.0801 | 0.4883 | - | 59368 B |
| Build_ImmDict | 1000 | 50 | 275,481.11 ns | 79.1016 | 9.2773 | - | 662528 B |
| Build_ImmSortedDict | 1000 | 50 | 417,349.29 ns | 61.0352 | 5.3711 | - | 511344 B |
| Build_ExtMap | 1000 | 50 | 406,348.46 ns | 78.1250 | 7.3242 | - | 656288 B |
| Build_ExtHashMap | 1000 | 50 | 180,890.87 ns | 69.5801 | 4.8828 | - | 582472 B |
| Retrieve_ImmDict | 1000 | 50 | 3,137.95 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 1000 | 50 | 1,798.00 ns | - | - | - | - |
| Retrieve_PersistentMap_Unicode | 1000 | 50 | 2,096.52 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 1000 | 50 | 20,986.51 ns | - | - | - | - |
| Retrieve_ExtMap | 1000 | 50 | 23,287.17 ns | - | - | - | - |
| Retrieve_ExtHashMap | 1000 | 50 | 4,776.52 ns | - | - | - | - |
| Update_ImmDict | 1000 | 50 | 25,749.96 ns | 7.5989 | 0.3052 | - | 63776 B |
| Update_PersistentMap_Standard | 1000 | 50 | 39,878.09 ns | 24.0479 | 2.0752 | - | 201600 B |
| Update_PersistentMap_Unicode | 1000 | 50 | 28,771.02 ns | 27.0386 | 2.2888 | - | 226400 B |
| Update_TransientMap_Standard | 1000 | 50 | 24,641.84 ns | 3.8757 | 0.3357 | - | 32552 B |
| Update_TransientMap_Unicode | 1000 | 50 | 7,785.56 ns | 4.0894 | 0.3967 | - | 34208 B |
| Update_ImmSortedDict | 1000 | 50 | 32,625.21 ns | 5.6763 | 0.1221 | - | 47952 B |
| Update_ExtMap | 1000 | 50 | 33,656.18 ns | 6.5308 | 0.1831 | - | 54720 B |
| Update_ExtHashMap | 1000 | 50 | 13,197.36 ns | 7.1869 | 0.2289 | - | 60168 B |
| UpdateSet_ImmDict | 1000 | 50 | 24,838.46 ns | 8.2397 | 0.3967 | - | 68960 B |
| UpdateSet_PersistentMap_Standard | 1000 | 50 | 47,257.42 ns | 24.1699 | 2.0142 | - | 202504 B |
| UpdateSet_PersistentMap_Unicode | 1000 | 50 | 34,871.45 ns | 27.2217 | 2.6245 | - | 227840 B |
| UpdateSet_TransientMap_Standard | 1000 | 50 | 30,705.12 ns | 3.9673 | 0.3662 | - | 33456 B |
| UpdateSet_TransientMap_Unicode | 1000 | 50 | 13,306.26 ns | 4.4250 | 0.4578 | - | 37056 B |
| UpdateSet_ImmSortedDict | 1000 | 50 | 37,358.03 ns | 6.2866 | 0.1831 | - | 53088 B |
| UpdateSet_ExtMap | 1000 | 50 | 39,040.99 ns | 7.8735 | 0.3052 | - | 66200 B |
| UpdateSet_ExtHashMap | 1000 | 50 | 18,993.92 ns | 7.9346 | 0.2747 | - | 66584 B |
| Iterate_ImmDict | 1000 | 50 | 12,796.55 ns | - | - | - | - |
| Iterate_PersistentMap_Standard | 1000 | 50 | 1,601.24 ns | - | - | - | - |
| Iterate_ImmSortedDict | 1000 | 50 | 4,897.01 ns | - | - | - | - |
| Iterate_ExtMap | 1000 | 50 | 3,590.09 ns | 0.0038 | - | - | 32 B |
| Iterate_ExtHashMap | 1000 | 50 | 14,570.64 ns | 2.6550 | - | - | 22320 B |
| Iterate_PersistentMap_Unicode | 1000 | 50 | 1,624.65 ns | - | - | - | - |
| Remove_ImmDict | 1000 | 50 | 22,247.23 ns | 7.7209 | 0.3357 | - | 64800 B |
| Remove_PersistentMap_Standard | 1000 | 50 | 47,236.28 ns | 23.8037 | 2.0752 | - | 199200 B |
| Remove_PersistentMap_Unicode | 1000 | 50 | 30,337.50 ns | 26.7639 | 2.2583 | - | 224000 B |
| Remove_TransientMap_Standard | 1000 | 50 | 30,224.03 ns | 3.4180 | 0.3052 | - | 28792 B |
| Remove_TransientMap_Unicode | 1000 | 50 | 13,980.33 ns | 3.2959 | 0.2899 | - | 27624 B |
| Remove_ImmSortedDict | 1000 | 50 | 34,150.76 ns | 5.6763 | 0.1221 | - | 47664 B |
| Remove_ExtMap | 1000 | 50 | 36,453.25 ns | 6.9580 | 0.2441 | - | 58640 B |
| Remove_ExtHashMap | 1000 | 50 | 14,511.93 ns | 7.9041 | 0.2136 | - | 66176 B |
| Build_TransientMap_Standard | 10000 | 8 | 4,972,737.60 ns | 46.8750 | 7.8125 | - | 453272 B |
| Build_TransientMap_Unicode | 10000 | 8 | 2,273,723.34 ns | 66.4063 | 19.5313 | - | 576584 B |
| Build_ImmDict | 10000 | 8 | 4,474,574.70 ns | 1039.0625 | 507.8125 | - | 8751104 B |
| Build_ImmSortedDict | 10000 | 8 | 6,548,873.72 ns | 804.6875 | 281.2500 | - | 6767232 B |
| Build_ExtMap | 10000 | 8 | 6,462,311.12 ns | 1015.6250 | 437.5000 | - | 8542480 B |
| Build_ExtHashMap | 10000 | 8 | 1,921,265.07 ns | 945.3125 | 326.1719 | - | 7907368 B |
| Retrieve_ImmDict | 10000 | 8 | 21,054.43 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 10000 | 8 | 386,477.89 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 10000 | 8 | 46,945.00 ns | - | - | - | - |
| Retrieve_PersistentMap_Unicode | 10000 | 8 | 32,919.53 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 10000 | 8 | 383,296.28 ns | - | - | - | - |
| Retrieve_ExtMap | 10000 | 8 | 447,733.80 ns | - | - | - | - |
| Retrieve_ExtHashMap | 10000 | 8 | 38,576.71 ns | - | - | - | - |
| Update_ImmDict | 10000 | 8 | 395,715.60 ns | 101.0742 | 27.3438 | - | 848128 B |
| Update_PersistentMap_Standard | 10000 | 8 | 662,654.83 ns | 305.6641 | 131.8359 | - | 2560000 B |
| Update_PersistentMap_Unicode | 10000 | 8 | 425,935.07 ns | 366.2109 | 160.1563 | - | 3064000 B |
| Update_TransientMap_Standard | 10000 | 8 | 442,700.87 ns | 41.0156 | 14.1602 | - | 346280 B |
| Update_TransientMap_Unicode | 10000 | 8 | 152,961.90 ns | 40.7715 | 16.6016 | - | 341792 B |
| Update_ImmSortedDict | 10000 | 8 | 599,396.52 ns | 76.1719 | 15.6250 | - | 640368 B |
| Update_ExtMap | 10000 | 8 | 565,510.82 ns | 87.8906 | 22.4609 | - | 735640 B |
| Update_ExtHashMap | 10000 | 8 | 165,164.46 ns | 102.5391 | 20.9961 | - | 859160 B |
| UpdateSet_ImmDict | 10000 | 8 | 436,729.87 ns | 108.3984 | 29.2969 | - | 908672 B |
| UpdateSet_PersistentMap_Standard | 10000 | 8 | 751,649.78 ns | 306.6406 | 131.8359 | - | 2572328 B |
| UpdateSet_PersistentMap_Unicode | 10000 | 8 | 499,253.41 ns | 368.1641 | 154.2969 | - | 3086432 B |
| UpdateSet_TransientMap_Standard | 10000 | 8 | 538,898.72 ns | 41.9922 | 16.6016 | - | 357200 B |
| UpdateSet_TransientMap_Unicode | 10000 | 8 | 227,890.12 ns | 43.7012 | 16.3574 | - | 365632 B |
| UpdateSet_ImmSortedDict | 10000 | 8 | 650,234.49 ns | 82.0313 | 19.5313 | - | 687648 B |
| UpdateSet_ExtMap | 10000 | 8 | 641,265.51 ns | 99.6094 | 25.3906 | - | 833752 B |
| UpdateSet_ExtHashMap | 10000 | 8 | 194,749.46 ns | 104.9805 | 23.9258 | - | 878808 B |
| Iterate_ImmDict | 10000 | 8 | 174,946.48 ns | - | - | - | - |
| Iterate_PersistentMap_Standard | 10000 | 8 | 17,152.00 ns | - | - | - | - |
| Iterate_ImmSortedDict | 10000 | 8 | 52,817.11 ns | - | - | - | - |
| Iterate_ExtMap | 10000 | 8 | 66,083.05 ns | - | - | - | 32 B |
| Iterate_ExtHashMap | 10000 | 8 | 174,496.27 ns | 20.2637 | - | - | 169704 B |
| Iterate_PersistentMap_Unicode | 10000 | 8 | 17,945.71 ns | - | - | - | - |
| Remove_ImmDict | 10000 | 8 | 402,693.02 ns | 102.0508 | 23.4375 | - | 855488 B |
| Remove_PersistentMap_Standard | 10000 | 8 | 731,170.91 ns | 302.7344 | 117.1875 | - | 2536000 B |
| Remove_PersistentMap_Unicode | 10000 | 8 | 493,821.11 ns | 363.2813 | 180.6641 | - | 3041408 B |
| Remove_TransientMap_Standard | 10000 | 8 | 511,709.67 ns | 37.1094 | 13.6719 | - | 316696 B |
| Remove_TransientMap_Unicode | 10000 | 8 | 223,881.92 ns | 38.0859 | 15.1367 | - | 319240 B |
| Remove_ImmSortedDict | 10000 | 8 | 600,831.24 ns | 77.1484 | 15.6250 | - | 652944 B |
| Remove_ExtMap | 10000 | 8 | 617,128.15 ns | 91.7969 | 20.5078 | - | 774000 B |
| Remove_ExtHashMap | 10000 | 8 | 179,929.34 ns | 104.4922 | 22.4609 | - | 874984 B |
| Build_TransientMap_Standard | 10000 | 50 | 5,124,826.21 ns | 46.8750 | 7.8125 | - | 453272 B |
| Build_TransientMap_Unicode | 10000 | 50 | 2,251,023.03 ns | 66.4063 | 23.4375 | - | 567112 B |
| Build_ImmDict | 10000 | 50 | 4,751,856.80 ns | 1046.8750 | 507.8125 | - | 8757376 B |
| Build_ImmSortedDict | 10000 | 50 | 6,556,900.60 ns | 804.6875 | 265.6250 | - | 6751584 B |
| Build_ExtMap | 10000 | 50 | 6,985,344.36 ns | 1015.6250 | 429.6875 | - | 8544720 B |
| Build_ExtHashMap | 10000 | 50 | 2,218,415.86 ns | 945.3125 | 308.5938 | - | 7925728 B |
| Retrieve_ImmDict | 10000 | 50 | 46,389.46 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 10000 | 50 | 46,342.93 ns | - | - | - | - |
| Retrieve_PersistentMap_Unicode | 10000 | 50 | 33,945.57 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 10000 | 50 | 385,767.81 ns | - | - | - | - |
| Retrieve_ExtMap | 10000 | 50 | 426,750.47 ns | - | - | - | - |
| Retrieve_ExtHashMap | 10000 | 50 | 61,891.51 ns | - | - | - | - |
| Update_ImmDict | 10000 | 50 | 419,181.33 ns | 101.0742 | 27.3438 | - | 848768 B |
| Update_PersistentMap_Standard | 10000 | 50 | 674,365.10 ns | 305.6641 | 125.9766 | - | 2560000 B |
| Update_PersistentMap_Unicode | 10000 | 50 | 423,829.00 ns | 366.2109 | 158.2031 | - | 3064000 B |
| Update_TransientMap_Standard | 10000 | 50 | 455,884.40 ns | 40.5273 | 13.6719 | - | 339240 B |
| Update_TransientMap_Unicode | 10000 | 50 | 151,927.19 ns | 39.5508 | 13.9160 | - | 331136 B |
| Update_ImmSortedDict | 10000 | 50 | 599,787.55 ns | 76.1719 | 14.6484 | - | 641616 B |
| Update_ExtMap | 10000 | 50 | 576,111.14 ns | 86.9141 | 20.5078 | - | 732896 B |
| Update_ExtHashMap | 10000 | 50 | 186,299.39 ns | 102.5391 | 20.2637 | - | 859392 B |
| UpdateSet_ImmDict | 10000 | 50 | 459,230.81 ns | 108.3984 | 29.2969 | - | 908672 B |
| UpdateSet_PersistentMap_Standard | 10000 | 50 | 758,257.06 ns | 307.6172 | 133.7891 | - | 2575040 B |
| UpdateSet_PersistentMap_Unicode | 10000 | 50 | 499,618.94 ns | 368.1641 | 152.3438 | - | 3085600 B |
| UpdateSet_TransientMap_Standard | 10000 | 50 | 552,006.66 ns | 41.9922 | 15.6250 | - | 355688 B |
| UpdateSet_TransientMap_Unicode | 10000 | 50 | 225,461.43 ns | 42.2363 | 15.8691 | - | 354144 B |
| UpdateSet_ImmSortedDict | 10000 | 50 | 660,239.03 ns | 82.0313 | 19.5313 | - | 691728 B |
| UpdateSet_ExtMap | 10000 | 50 | 642,281.65 ns | 98.6328 | 23.4375 | - | 829552 B |
| UpdateSet_ExtHashMap | 10000 | 50 | 213,376.13 ns | 104.9805 | 23.4375 | - | 878248 B |
| Iterate_ImmDict | 10000 | 50 | 181,714.98 ns | - | - | - | - |
| Iterate_PersistentMap_Standard | 10000 | 50 | 17,120.93 ns | - | - | - | - |
| Iterate_ImmSortedDict | 10000 | 50 | 54,752.59 ns | - | - | - | - |
| Iterate_ExtMap | 10000 | 50 | 66,116.25 ns | - | - | - | 32 B |
| Iterate_ExtHashMap | 10000 | 50 | 175,406.16 ns | 19.7754 | - | - | 166824 B |
| Iterate_PersistentMap_Unicode | 10000 | 50 | 17,271.03 ns | - | - | - | - |
| Remove_ImmDict | 10000 | 50 | 424,174.08 ns | 102.0508 | 23.9258 | - | 854784 B |
| Remove_PersistentMap_Standard | 10000 | 50 | 739,059.87 ns | 302.7344 | 119.1406 | - | 2538816 B |
| Remove_PersistentMap_Unicode | 10000 | 50 | 491,577.81 ns | 363.2813 | 158.2031 | - | 3042816 B |
| Remove_TransientMap_Standard | 10000 | 50 | 522,589.23 ns | 38.0859 | 12.6953 | - | 319512 B |
| Remove_TransientMap_Unicode | 10000 | 50 | 223,052.49 ns | 37.3535 | 13.1836 | - | 312808 B |
| Remove_ImmSortedDict | 10000 | 50 | 612,756.00 ns | 77.1484 | 15.6250 | - | 651840 B |
| Remove_ExtMap | 10000 | 50 | 622,977.64 ns | 91.7969 | 21.4844 | - | 771256 B |
| Remove_ExtHashMap | 10000 | 50 | 202,442.11 ns | 104.0039 | 20.9961 | - | 871064 B |
| Build_TransientMap_Standard | 100000 | 8 | 72,441,876.47 ns | 428.5714 | 285.7143 | - | 4524208 B |
| Build_TransientMap_Unicode | 100000 | 8 | 39,704,110.55 ns | 692.3077 | 538.4615 | - | 5798728 B |
| Build_ImmDict | 100000 | 8 | 92,116,430.52 ns | 13166.6667 | 4833.3333 | 166.6667 | 109376373 B |
| Build_ImmSortedDict | 100000 | 8 | 119,704,496.44 ns | 10000.0000 | 3800.0000 | - | 83946432 B |
| Build_ExtMap | 100000 | 8 | 119,087,830.57 ns | 12400.0000 | 5600.0000 | - | 104660688 B |
| Build_ExtHashMap | 100000 | 8 | 45,457,387.28 ns | 12000.0000 | 2583.3333 | 83.3333 | 99806394 B |
| Retrieve_ImmDict | 100000 | 8 | 1,516,808.05 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 100000 | 8 | 1,760,464.44 ns | - | - | - | - |
| Retrieve_PersistentMap_Unicode | 100000 | 8 | 1,351,906.08 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 100000 | 8 | 6,176,362.41 ns | - | - | - | - |
| Retrieve_ExtMap | 100000 | 8 | 6,613,900.92 ns | - | - | - | - |
| Retrieve_ExtHashMap | 100000 | 8 | 1,046,707.73 ns | - | - | - | - |
| Update_ImmDict | 100000 | 8 | 8,149,123.59 ns | 1265.6250 | 1046.8750 | - | 10618880 B |
| Update_PersistentMap_Standard | 100000 | 8 | 14,827,486.05 ns | 3750.0000 | 2953.1250 | 46.8750 | 31040047 B |
| Update_PersistentMap_Unicode | 100000 | 8 | 11,607,930.86 ns | 4671.8750 | 2500.0000 | 62.5000 | 38640058 B |
| Update_TransientMap_Standard | 100000 | 8 | 7,358,177.48 ns | 406.2500 | 335.9375 | - | 3415688 B |
| Update_TransientMap_Unicode | 100000 | 8 | 3,826,038.54 ns | 414.0625 | 351.5625 | - | 3487168 B |
| Update_ImmSortedDict | 100000 | 8 | 10,318,908.01 ns | 953.1250 | 781.2500 | - | 8020080 B |
| Update_ExtMap | 100000 | 8 | 10,354,686.58 ns | 1093.7500 | 937.5000 | - | 9246400 B |
| Update_ExtHashMap | 100000 | 8 | 3,752,714.02 ns | 1269.5313 | 988.2813 | - | 10626504 B |
| UpdateSet_ImmDict | 100000 | 8 | 8,658,752.54 ns | 1343.7500 | 1046.8750 | - | 11262464 B |
| UpdateSet_PersistentMap_Standard | 100000 | 8 | 16,011,001.98 ns | 3750.0000 | 2593.7500 | 31.2500 | 31143252 B |
| UpdateSet_PersistentMap_Unicode | 100000 | 8 | 12,524,719.72 ns | 4687.5000 | 2281.2500 | 62.5000 | 38809433 B |
| UpdateSet_TransientMap_Standard | 100000 | 8 | 8,280,433.69 ns | 406.2500 | 328.1250 | - | 3514688 B |
| UpdateSet_TransientMap_Unicode | 100000 | 8 | 4,465,123.76 ns | 429.6875 | 382.8125 | - | 3636832 B |
| UpdateSet_ImmSortedDict | 100000 | 8 | 11,403,173.00 ns | 1015.6250 | 875.0000 | - | 8495856 B |
| UpdateSet_ExtMap | 100000 | 8 | 11,808,286.34 ns | 1218.7500 | 1015.6250 | - | 10287328 B |
| UpdateSet_ExtHashMap | 100000 | 8 | 4,073,301.12 ns | 1281.2500 | 992.1875 | - | 10759216 B |
| Iterate_ImmDict | 100000 | 8 | 2,210,260.69 ns | - | - | - | - |
| Iterate_PersistentMap_Standard | 100000 | 8 | 221,859.64 ns | - | - | - | - |
| Iterate_ImmSortedDict | 100000 | 8 | 712,098.18 ns | - | - | - | - |
| Iterate_ExtMap | 100000 | 8 | 1,122,895.56 ns | - | - | - | 32 B |
| Iterate_ExtHashMap | 100000 | 8 | 2,722,789.29 ns | 273.4375 | - | - | 2314696 B |
| Iterate_PersistentMap_Unicode | 100000 | 8 | 235,131.71 ns | - | - | - | - |
| Remove_ImmDict | 100000 | 8 | 7,950,218.64 ns | 1281.2500 | 1125.0000 | - | 10756416 B |
| Remove_PersistentMap_Standard | 100000 | 8 | 15,366,222.73 ns | 3718.7500 | 3328.1250 | 46.8750 | 30821152 B |
| Remove_PersistentMap_Unicode | 100000 | 8 | 12,092,756.69 ns | 4656.2500 | 2875.0000 | 62.5000 | 38412727 B |
| Remove_TransientMap_Standard | 100000 | 8 | 7,973,868.64 ns | 375.0000 | 312.5000 | - | 3174328 B |
| Remove_TransientMap_Unicode | 100000 | 8 | 3,161,959.43 ns | 382.8125 | 324.2188 | - | 3226088 B |
| Remove_ImmSortedDict | 100000 | 8 | 10,396,202.26 ns | 953.1250 | 781.2500 | - | 8031888 B |
| Remove_ExtMap | 100000 | 8 | 11,561,856.15 ns | 1140.6250 | 937.5000 | - | 9630448 B |
| Remove_ExtHashMap | 100000 | 8 | 4,009,364.62 ns | 1265.6250 | 921.8750 | - | 10607248 B |
| Build_TransientMap_Standard | 100000 | 50 | 81,360,172.13 ns | 428.5714 | 285.7143 | - | 4511632 B |
| Build_TransientMap_Unicode | 100000 | 50 | 41,339,351.49 ns | 666.6667 | 500.0000 | - | 5763784 B |
| Build_ImmDict | 100000 | 50 | 97,054,583.11 ns | 13166.6667 | 4833.3333 | 166.6667 | 109218477 B |
| Build_ImmSortedDict | 100000 | 50 | 129,585,060.60 ns | 10000.0000 | 4000.0000 | - | 83731632 B |
| Build_ExtMap | 100000 | 50 | 130,490,141.33 ns | 12250.0000 | 5250.0000 | - | 104371560 B |
| Build_ExtHashMap | 100000 | 50 | 49,945,252.31 ns | 11900.0000 | 2400.0000 | - | 99832472 B |
| Retrieve_ImmDict | 100000 | 50 | 1,933,934.21 ns | - | - | - | - |
| Retrieve_PersistentMap_Standard | 100000 | 50 | 2,275,491.43 ns | - | - | - | - |
| Retrieve_PersistentMap_Unicode | 100000 | 50 | 1,439,009.47 ns | - | - | - | - |
| Retrieve_ImmSortedDict | 100000 | 50 | 7,341,270.59 ns | - | - | - | - |
| Retrieve_ExtMap | 100000 | 50 | 7,144,334.50 ns | - | - | - | - |
| Retrieve_ExtHashMap | 100000 | 50 | 1,359,724.09 ns | - | - | - | - |
| Update_ImmDict | 100000 | 50 | 8,224,368.98 ns | 1265.6250 | 1062.5000 | - | 10585792 B |
| Update_PersistentMap_Standard | 100000 | 50 | 16,195,436.66 ns | 3718.7500 | 2875.0000 | 31.2500 | 31040034 B |
| Update_PersistentMap_Unicode | 100000 | 50 | 11,872,157.79 ns | 4656.2500 | 2765.6250 | 46.8750 | 38640047 B |
| Update_TransientMap_Standard | 100000 | 50 | 8,421,668.39 ns | 406.2500 | 343.7500 | - | 3414056 B |
| Update_TransientMap_Unicode | 100000 | 50 | 3,920,098.30 ns | 406.2500 | 335.9375 | - | 3440288 B |
| Update_ImmSortedDict | 100000 | 50 | 11,196,973.30 ns | 953.1250 | 781.2500 | - | 8012928 B |
| Update_ExtMap | 100000 | 50 | 10,904,107.16 ns | 1093.7500 | 906.2500 | - | 9233632 B |
| Update_ExtHashMap | 100000 | 50 | 4,099,435.72 ns | 1265.6250 | 976.5625 | - | 10625992 B |
| UpdateSet_ImmDict | 100000 | 50 | 8,815,363.39 ns | 1343.7500 | 1031.2500 | - | 11286912 B |
| UpdateSet_PersistentMap_Standard | 100000 | 50 | 17,059,344.47 ns | 3718.7500 | 2562.5000 | - | 31141992 B |
| UpdateSet_PersistentMap_Unicode | 100000 | 50 | 13,129,653.12 ns | 4687.5000 | 2437.5000 | 46.8750 | 38835954 B |
| UpdateSet_TransientMap_Standard | 100000 | 50 | 9,618,034.32 ns | 406.2500 | 328.1250 | - | 3509008 B |
| UpdateSet_TransientMap_Unicode | 100000 | 50 | 4,850,003.99 ns | 429.6875 | 359.3750 | - | 3630560 B |
| UpdateSet_ImmSortedDict | 100000 | 50 | 12,656,577.42 ns | 1015.6250 | 890.6250 | - | 8501136 B |
| UpdateSet_ExtMap | 100000 | 50 | 12,813,242.59 ns | 1218.7500 | 1015.6250 | - | 10265544 B |
| UpdateSet_ExtHashMap | 100000 | 50 | 4,430,259.78 ns | 1281.2500 | 1000.0000 | - | 10765376 B |
| Iterate_ImmDict | 100000 | 50 | 2,381,194.68 ns | - | - | - | 96 B |
| Iterate_PersistentMap_Standard | 100000 | 50 | 211,225.33 ns | - | - | - | - |
| Iterate_ImmSortedDict | 100000 | 50 | 713,700.90 ns | - | - | - | - |
| Iterate_ExtMap | 100000 | 50 | 1,157,631.41 ns | - | - | - | 32 B |
| Iterate_ExtHashMap | 100000 | 50 | 2,676,695.95 ns | 273.4375 | - | - | 2310024 B |
| Iterate_PersistentMap_Unicode | 100000 | 50 | 212,687.91 ns | - | - | - | - |
| Remove_ImmDict | 100000 | 50 | 8,177,782.10 ns | 1281.2500 | 984.3750 | - | 10749824 B |
| Remove_PersistentMap_Standard | 100000 | 50 | 16,635,857.83 ns | 3687.5000 | 3343.7500 | 31.2500 | 30814118 B |
| Remove_PersistentMap_Unicode | 100000 | 50 | 12,383,735.25 ns | 4625.0000 | 2859.3750 | 46.8750 | 38402877 B |
| Remove_TransientMap_Standard | 100000 | 50 | 8,797,592.89 ns | 375.0000 | 312.5000 | - | 3167064 B |
| Remove_TransientMap_Unicode | 100000 | 50 | 3,335,966.12 ns | 382.8125 | 312.5000 | - | 3205960 B |
| Remove_ImmSortedDict | 100000 | 50 | 11,619,906.87 ns | 953.1250 | 781.2500 | - | 8032656 B |
| Remove_ExtMap | 100000 | 50 | 12,051,548.01 ns | 1140.6250 | 921.8750 | - | 9617232 B |
| Remove_ExtHashMap | 100000 | 50 | 4,258,918.68 ns | 1265.6250 | 929.6875 | - | 10612072 B |
Architecture Notes: Key Strategies
NiceBtree uses IKeyStrategy<K> to map generic keys (like string or double) into sortable long prefixes. This achieves two things:
- Enables AVX512/AVX2 vector instructions to search internal nodes simultaneously.
- Avoids expensive
IComparable<T>interface calls orstring.Compareduring the initial descent of the tree, only falling back to exact comparisons when refining the search within a leaf.
This means that it will be fast for integers and anything you can pack in 8 bytes. If you use stings with high prefix entropy, this will be very performant. If you don't, it is just another b+tree.