Compare commits

..

No commits in common. "bf8298658cffd14038547824ea8ed3bd09b3be2d" and "a6e8ced7f7402c43e3bf79881ab7392b58176619" have entirely different histories.

3 changed files with 25 additions and 29 deletions

View file

@ -10,12 +10,9 @@ namespace PersistentMap
// Public API // Public API
// --------------------------------------------------------- // ---------------------------------------------------------
/// <summary>TryGetValue tries to get the value at mapping key. If it finds the key it sets th
/// out var to value and returns true. </summary>
public static bool TryGetValue<K, V, TStrategy>(Node<K> root, K key, TStrategy strategy, out V value) public static bool TryGetValue<K, V, TStrategy>(Node<K> root, K key, TStrategy strategy, out V value)
where TStrategy : IKeyStrategy<K> where TStrategy : IKeyStrategy<K>
{ {
// We always get a strategy to avoid branching already here
long keyPrefix = strategy.UsesPrefixes ? strategy.GetPrefix(key) : 0; long keyPrefix = strategy.UsesPrefixes ? strategy.GetPrefix(key) : 0;
Node<K> current = root; Node<K> current = root;
@ -46,7 +43,6 @@ namespace PersistentMap
{ {
root = root.EnsureEditable(owner); 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 splitResult = InsertRecursive(root, key, value, strategy, owner, out countChanged);
if (splitResult != null) if (splitResult != null)
@ -216,7 +212,7 @@ namespace PersistentMap
where TStrategy : IKeyStrategy<K> where TStrategy : IKeyStrategy<K>
{ {
if (typeof(K) == typeof(int)) if (typeof(K) == typeof(int))
{ {
Span<K> keys = node.GetKeys(); Span<K> keys = node.GetKeys();
ref K firstKeyRef = ref MemoryMarshal.GetReference(keys); ref K firstKeyRef = ref MemoryMarshal.GetReference(keys);
@ -333,11 +329,11 @@ namespace PersistentMap
// Insertion Logic // Insertion Logic
// --------------------------------------------------------- // ---------------------------------------------------------
private class SeplitResult<K> private class SplitResult<K>
{ {
public Node<K> NewNode; public Node<K> NewNode;
public K Separator; public K Separator;
public SeplitResult(Node<K> newNode, K separator) public SplitResult(Node<K> newNode, K separator)
{ {
NewNode = newNode; NewNode = newNode;
Separator = separator; Separator = separator;
@ -371,7 +367,7 @@ namespace PersistentMap
leaf.SetCount(count + 1); leaf.SetCount(count + 1);
} }
private static (Node<K>, K) SplitLeaf<K, V, TStrategy>(LeafNode<K, V> left, int insertIndex, K key, V value, TStrategy strategy, OwnerId owner) private static SplitResult<K> SplitLeaf<K, V, TStrategy>(LeafNode<K, V> left, int insertIndex, K key, V value, TStrategy strategy, OwnerId owner)
where TStrategy : IKeyStrategy<K> where TStrategy : IKeyStrategy<K>
{ {
var right = new LeafNode<K, V>(owner, strategy.UsesPrefixes); var right = new LeafNode<K, V>(owner, strategy.UsesPrefixes);
@ -395,15 +391,15 @@ namespace PersistentMap
right.SetCount(moveCount); right.SetCount(moveCount);
if (insertIndex < splitPoint || (splitPoint == 0 && insertIndex == 0)) if (insertIndex < splitPoint || (splitPoint == 0 && insertIndex == 0))
{ {
InsertIntoLeaf(left, insertIndex, key, value, strategy); InsertIntoLeaf(left, insertIndex, key, value, strategy);
} }
else else
{ {
InsertIntoLeaf(right, insertIndex - splitPoint, key, value, strategy); InsertIntoLeaf(right, insertIndex - splitPoint, key, value, strategy);
} }
return (right, right.Keys[0]); return new SplitResult<K>(right, right.Keys[0]);
} }
private static void InsertIntoInternal<K, TStrategy>(InternalNode<K> node, int index, K separator, Node<K> newChild, TStrategy strategy) private static void InsertIntoInternal<K, TStrategy>(InternalNode<K> node, int index, K separator, Node<K> newChild, TStrategy strategy)
@ -437,7 +433,7 @@ namespace PersistentMap
node.SetCount(count + 1); node.SetCount(count + 1);
} }
private static (Node<K>, K) SplitInternal<K, TStrategy>(InternalNode<K> left, int insertIndex, K separator, Node<K> newChild, TStrategy strategy, OwnerId owner) private static SplitResult<K> SplitInternal<K, TStrategy>(InternalNode<K> left, int insertIndex, K separator, Node<K> newChild, TStrategy strategy, OwnerId owner)
where TStrategy : IKeyStrategy<K> where TStrategy : IKeyStrategy<K>
{ {
var right = strategy.UsesPrefixes var right = strategy.UsesPrefixes
@ -477,7 +473,7 @@ namespace PersistentMap
InsertIntoInternal(right, insertIndex - (splitPoint + 1), separator, newChild, strategy); InsertIntoInternal(right, insertIndex - (splitPoint + 1), separator, newChild, strategy);
} }
return (right, upKey); return new SplitResult<K>(right, upKey);
} }
// --------------------------------------------------------- // ---------------------------------------------------------

View file

@ -44,7 +44,7 @@ public static class IntScanner
{ {
var vData = Avx2.LoadVector256(ptr + i); var vData = Avx2.LoadVector256(ptr + i);
var vResult = Avx2.CompareGreaterThan(vData, vTarget); var vResult = Avx2.CompareGreaterThan(vData, vTarget);
// MoveMask creates a 32-bit integer from the most significant bit of each byte. // MoveMask creates a 32-bit integer from the most significant bit of each byte.
var mask = (uint)Avx2.MoveMask(vResult.AsByte()); var mask = (uint)Avx2.MoveMask(vResult.AsByte());
@ -73,7 +73,7 @@ public static class IntScanner
fixed (int* ptr = keys) fixed (int* ptr = keys)
{ {
var vData = Avx512F.LoadVector512(ptr + i); var vData = Avx512F.LoadVector512(ptr + i);
// Vector512 API is used directly here to cleanly get the mask // Vector512 API is used directly here to cleanly get the mask
var mask = Vector512.GreaterThanOrEqual(vData, vTarget); var mask = Vector512.GreaterThanOrEqual(vData, vTarget);
@ -88,7 +88,7 @@ public static class IntScanner
return LinearScan(keys.Slice(i), target) + i; return LinearScan(keys.Slice(i), target) + i;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int FindFirstGreater(ReadOnlySpan<int> keys, int target) public static int FindFirstGreater(ReadOnlySpan<int> keys, int target)
{ {
if (!Avx2.IsSupported || keys.Length < 8) if (!Avx2.IsSupported || keys.Length < 8)
@ -107,7 +107,7 @@ public static class IntScanner
return i; return i;
return keys.Length; return keys.Length;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe int ScanAvx2Greater(ReadOnlySpan<int> keys, int target) private static unsafe int ScanAvx2Greater(ReadOnlySpan<int> keys, int target)
{ {
@ -122,7 +122,7 @@ public static class IntScanner
{ {
var vData = Avx2.LoadVector256(ptr + i); var vData = Avx2.LoadVector256(ptr + i);
var vResult = Avx2.CompareGreaterThan(vData, vTarget); var vResult = Avx2.CompareGreaterThan(vData, vTarget);
var mask = (uint)Avx2.MoveMask(vResult.AsByte()); var mask = (uint)Avx2.MoveMask(vResult.AsByte());
if (mask != 0) if (mask != 0)
@ -135,7 +135,7 @@ public static class IntScanner
return LinearScanGreater(keys.Slice(i), target) + i; return LinearScanGreater(keys.Slice(i), target) + i;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe int ScanAvx512Greater(ReadOnlySpan<int> keys, int target) private static unsafe int ScanAvx512Greater(ReadOnlySpan<int> keys, int target)
{ {
var vTarget = Vector512.Create(target); var vTarget = Vector512.Create(target);
@ -147,7 +147,7 @@ public static class IntScanner
fixed (int* ptr = keys) fixed (int* ptr = keys)
{ {
var vData = Avx512F.LoadVector512(ptr + i); var vData = Avx512F.LoadVector512(ptr + i);
// Use GreaterThan instead of GreaterThanOrEqual // Use GreaterThan instead of GreaterThanOrEqual
var mask = Vector512.GreaterThan(vData, vTarget); var mask = Vector512.GreaterThan(vData, vTarget);

View file

@ -90,10 +90,10 @@ public abstract class Node<K>
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public PrefixInternalNode<K> AsPrefixInternal() public PrefixInternalNode<K> AsPrefixInternal()
{ {
return Unsafe.As<PrefixInternalNode<K>>(this); return Unsafe.As<PrefixInternalNode<K>>(this);
} }
} }
public sealed class LeafNode<K, V> : Node<K> public sealed class LeafNode<K, V> : Node<K>