PersistentMap/PersistentMap/Readme.org

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 PersistentMap in $O(1)$ time.
  • SIMD Prefix Scanning: Uses AVX2/AVX512 to vectorize B+ tree routing and binary searches via long key-prefixes.
  • Linear Time Set Operations: Sort-merge based Intersect, Except, and SymmetricExcept execute 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:

  1. Enables AVX512/AVX2 vector instructions to search internal nodes simultaneously.
  2. Avoids expensive IComparable<T> interface calls or string.Compare during 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.