diff --git a/PersistentOrderedMap/BTreeFunctions.cs b/PersistentOrderedMap/BTreeFunctions.cs index 2f7617a..34c2222 100644 --- a/PersistentOrderedMap/BTreeFunctions.cs +++ b/PersistentOrderedMap/BTreeFunctions.cs @@ -1,4 +1,3 @@ -using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -42,27 +41,28 @@ namespace PersistentOrderedMap } } - public static Node Set(Node root, K key, V value, IKeyStrategy strategy, OwnerId owner, out bool countChanged) + public static Node Set(Node root, K key, V value, TStrategy strategy, OwnerId owner, out bool countChanged) + where TStrategy : IKeyStrategy { root = root.EnsureEditable(owner); // Todo, this should really be made a tuple return value to not stress the GC - var splitResult = InsertRecursive(root, key, value, strategy, owner, out countChanged); + var (newNode, sep) = InsertRecursive(root, key, value, strategy, owner, out countChanged); - if (splitResult != null) + if (newNode != null) { var newRoot = strategy.UsesPrefixes ? new PrefixInternalNode(owner) : new InternalNode(owner); - newRoot.Keys[0] = splitResult.Separator; + newRoot.Keys[0] = sep; newRoot.Children[0] = root; - newRoot.Children[1] = splitResult.NewNode; + newRoot.Children[1] = newNode; newRoot.SetCount(1); if (strategy.UsesPrefixes) { - newRoot.AllPrefixes[0] = strategy.GetPrefix(splitResult.Separator); + newRoot.AllPrefixes[0] = strategy.GetPrefix(sep); } return newRoot; @@ -71,7 +71,7 @@ namespace PersistentOrderedMap return root; } - private static SplitResult? InsertRecursive(Node node, K key, V value, IKeyStrategy strategy, OwnerId owner, out bool added) + private static (Node? newNode, K separator ) InsertRecursive(Node node, K key, V value, IKeyStrategy strategy, OwnerId owner, out bool added) { long keyPrefix = strategy.UsesPrefixes ? strategy.GetPrefix(key) : 0; @@ -84,14 +84,14 @@ namespace PersistentOrderedMap { leaf.Values[index] = value; added = false; - return null; + return (null, default); } added = true; if (leaf.Header.Count < LeafNode.Capacity) { InsertIntoLeaf(leaf, index, key, value, strategy); - return null; + return (null, default); } else { @@ -106,21 +106,21 @@ namespace PersistentOrderedMap var child = internalNode.Children[index]!.EnsureEditable(owner); internalNode.Children[index] = child; - var split = InsertRecursive(child, key, value, strategy, owner, out added); + var (newNode, sep) = InsertRecursive(child, key, value, strategy, owner, out added); - if (split != null) + if (newNode != null) { if (internalNode.Header.Count < InternalNode.Capacity - 1) { - InsertIntoInternal(internalNode, index, split.Separator, split.NewNode, strategy); - return null; + InsertIntoInternal(internalNode, index, sep, newNode, strategy); + return (null, default); } else { - return SplitInternal(internalNode, index, split.Separator, split.NewNode, strategy, owner); + return SplitInternal(internalNode, index, sep, newNode, strategy, owner); } } - return null; + return (null, default); } } @@ -189,7 +189,7 @@ namespace PersistentOrderedMap // --------------------------------------------------------- [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static int FindIndex(Node node, K key, long keyPrefix, TStrategy strategy) + internal static int FindIndex(LeafNode node, K key, long keyPrefix, TStrategy strategy) where TStrategy : IKeyStrategy { if (typeof(K) == typeof(int)) diff --git a/PersistentOrderedMap/Iterator.cs b/PersistentOrderedMap/Iterator.cs index 4adaebc..d8e776b 100644 --- a/PersistentOrderedMap/Iterator.cs +++ b/PersistentOrderedMap/Iterator.cs @@ -31,6 +31,9 @@ where TStrategy : IKeyStrategy // Fixed-size buffer for the path. // Depth 16 * 32 (branching factor) = Exabytes of capacity. +// The B tree is, theoretically, not limited by the size of an int, like +// all int-indexed data structures (or bit partitioned ones). +// This should be enough for anyone. [InlineArray(16)] internal struct IterNodeBuffer { @@ -138,7 +141,7 @@ public struct BTreeEnumerator : IEnumerator> // Find index in Leaf _currentLeaf = node.AsLeaf(); - int index = BTreeFunctions.FindIndex(_currentLeaf, key, keyPrefix, _strategy); + int index = BTreeFunctions.FindIndex(_currentLeaf, key, keyPrefix, _strategy); // Set position to (index - 1) so that the first MoveNext() lands on 'index' _currentLeafIndex = index - 1;