Compare commits
2 commits
a6e8ced7f7
...
bf8298658c
| Author | SHA1 | Date | |
|---|---|---|---|
| bf8298658c | |||
| b5b363ae9f |
3 changed files with 29 additions and 25 deletions
|
|
@ -10,9 +10,12 @@ namespace PersistentMap
|
|||
// 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)
|
||||
where TStrategy : IKeyStrategy<K>
|
||||
{
|
||||
// We always get a strategy to avoid branching already here
|
||||
long keyPrefix = strategy.UsesPrefixes ? strategy.GetPrefix(key) : 0;
|
||||
|
||||
Node<K> current = root;
|
||||
|
|
@ -43,6 +46,7 @@ namespace PersistentMap
|
|||
{
|
||||
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);
|
||||
|
||||
if (splitResult != null)
|
||||
|
|
@ -212,7 +216,7 @@ namespace PersistentMap
|
|||
where TStrategy : IKeyStrategy<K>
|
||||
{
|
||||
|
||||
if (typeof(K) == typeof(int))
|
||||
if (typeof(K) == typeof(int))
|
||||
{
|
||||
Span<K> keys = node.GetKeys();
|
||||
ref K firstKeyRef = ref MemoryMarshal.GetReference(keys);
|
||||
|
|
@ -329,11 +333,11 @@ if (typeof(K) == typeof(int))
|
|||
// Insertion Logic
|
||||
// ---------------------------------------------------------
|
||||
|
||||
private class SplitResult<K>
|
||||
private class SeplitResult<K>
|
||||
{
|
||||
public Node<K> NewNode;
|
||||
public K Separator;
|
||||
public SplitResult(Node<K> newNode, K separator)
|
||||
public SeplitResult(Node<K> newNode, K separator)
|
||||
{
|
||||
NewNode = newNode;
|
||||
Separator = separator;
|
||||
|
|
@ -367,7 +371,7 @@ if (typeof(K) == typeof(int))
|
|||
leaf.SetCount(count + 1);
|
||||
}
|
||||
|
||||
private static SplitResult<K> SplitLeaf<K, V, TStrategy>(LeafNode<K, V> left, int insertIndex, K key, V value, TStrategy strategy, OwnerId owner)
|
||||
private static (Node<K>, K) SplitLeaf<K, V, TStrategy>(LeafNode<K, V> left, int insertIndex, K key, V value, TStrategy strategy, OwnerId owner)
|
||||
where TStrategy : IKeyStrategy<K>
|
||||
{
|
||||
var right = new LeafNode<K, V>(owner, strategy.UsesPrefixes);
|
||||
|
|
@ -391,15 +395,15 @@ if (typeof(K) == typeof(int))
|
|||
right.SetCount(moveCount);
|
||||
|
||||
if (insertIndex < splitPoint || (splitPoint == 0 && insertIndex == 0))
|
||||
{
|
||||
InsertIntoLeaf(left, insertIndex, key, value, strategy);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertIntoLeaf(right, insertIndex - splitPoint, key, value, strategy);
|
||||
}
|
||||
{
|
||||
InsertIntoLeaf(left, insertIndex, key, value, strategy);
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertIntoLeaf(right, insertIndex - splitPoint, key, value, strategy);
|
||||
}
|
||||
|
||||
return new SplitResult<K>(right, right.Keys[0]);
|
||||
return (right, right.Keys[0]);
|
||||
}
|
||||
|
||||
private static void InsertIntoInternal<K, TStrategy>(InternalNode<K> node, int index, K separator, Node<K> newChild, TStrategy strategy)
|
||||
|
|
@ -433,7 +437,7 @@ else
|
|||
node.SetCount(count + 1);
|
||||
}
|
||||
|
||||
private static SplitResult<K> SplitInternal<K, TStrategy>(InternalNode<K> left, int insertIndex, K separator, Node<K> newChild, TStrategy strategy, OwnerId owner)
|
||||
private static (Node<K>, K) SplitInternal<K, TStrategy>(InternalNode<K> left, int insertIndex, K separator, Node<K> newChild, TStrategy strategy, OwnerId owner)
|
||||
where TStrategy : IKeyStrategy<K>
|
||||
{
|
||||
var right = strategy.UsesPrefixes
|
||||
|
|
@ -473,7 +477,7 @@ else
|
|||
InsertIntoInternal(right, insertIndex - (splitPoint + 1), separator, newChild, strategy);
|
||||
}
|
||||
|
||||
return new SplitResult<K>(right, upKey);
|
||||
return (right, upKey);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public static class IntScanner
|
|||
{
|
||||
var vData = Avx2.LoadVector256(ptr + i);
|
||||
var vResult = Avx2.CompareGreaterThan(vData, vTarget);
|
||||
|
||||
|
||||
// MoveMask creates a 32-bit integer from the most significant bit of each byte.
|
||||
var mask = (uint)Avx2.MoveMask(vResult.AsByte());
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ public static class IntScanner
|
|||
fixed (int* ptr = keys)
|
||||
{
|
||||
var vData = Avx512F.LoadVector512(ptr + i);
|
||||
|
||||
|
||||
// Vector512 API is used directly here to cleanly get the mask
|
||||
var mask = Vector512.GreaterThanOrEqual(vData, vTarget);
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ public static class IntScanner
|
|||
return LinearScan(keys.Slice(i), target) + i;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int FindFirstGreater(ReadOnlySpan<int> keys, int target)
|
||||
{
|
||||
if (!Avx2.IsSupported || keys.Length < 8)
|
||||
|
|
@ -107,7 +107,7 @@ public static class IntScanner
|
|||
return i;
|
||||
return keys.Length;
|
||||
}
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
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 vResult = Avx2.CompareGreaterThan(vData, vTarget);
|
||||
|
||||
|
||||
var mask = (uint)Avx2.MoveMask(vResult.AsByte());
|
||||
|
||||
if (mask != 0)
|
||||
|
|
@ -135,7 +135,7 @@ public static class IntScanner
|
|||
return LinearScanGreater(keys.Slice(i), target) + i;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe int ScanAvx512Greater(ReadOnlySpan<int> keys, int target)
|
||||
{
|
||||
var vTarget = Vector512.Create(target);
|
||||
|
|
@ -147,7 +147,7 @@ public static class IntScanner
|
|||
fixed (int* ptr = keys)
|
||||
{
|
||||
var vData = Avx512F.LoadVector512(ptr + i);
|
||||
|
||||
|
||||
// Use GreaterThan instead of GreaterThanOrEqual
|
||||
var mask = Vector512.GreaterThan(vData, vTarget);
|
||||
|
||||
|
|
|
|||
|
|
@ -90,10 +90,10 @@ public abstract class Node<K>
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public PrefixInternalNode<K> AsPrefixInternal()
|
||||
{
|
||||
return Unsafe.As<PrefixInternalNode<K>>(this);
|
||||
}
|
||||
public PrefixInternalNode<K> AsPrefixInternal()
|
||||
{
|
||||
return Unsafe.As<PrefixInternalNode<K>>(this);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class LeafNode<K, V> : Node<K>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue