Skip to content

Commit 512d534

Browse files
committed
Load vector even faster
1 parent 1b0dac7 commit 512d534

File tree

1 file changed

+13
-36
lines changed

1 file changed

+13
-36
lines changed

src/DenseMap.cs

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ public DenseMap(uint length, double loadFactor, IHasher<TKey> hasher = null)
278278
/// <param name="value">The value.</param>
279279
/// <returns>Returns the old value</returns>
280280
[MethodImpl(MethodImplOptions.AggressiveInlining)]
281-
public void Emplace(TKey key, TValue value)
281+
public unsafe void Emplace(TKey key, TValue value)
282282
{
283283
// Check if the table is full based on the maximum lookups before needing to resize.
284284
// Resize if the count exceeds the threshold.
@@ -303,7 +303,10 @@ public void Emplace(TKey key, TValue value)
303303
{
304304
// Load a vector from the control bytes starting at the computed index.
305305
// Control bytes hold metadata about the entries in the map.
306-
var source = ReadVector128Aligned(_controlBytes, index);
306+
// var source = ReadVector128Aligned(_controlBytes, index);
307+
var source = ReadVector128(_controlBytes, index);
308+
// Compare `source` and `target` vectors to find any positions with a matching control byte.
309+
307310
// Compare `source` and `target` vectors to find any positions with a matching control byte.
308311
var resultMask = Vector128.Equals(source, target).ExtractMostSignificantBits();
309312
// Loop over each set bit in `mask` (indicating matching positions).
@@ -402,7 +405,7 @@ public unsafe bool Get(TKey key, out TValue value)
402405
{
403406
// Load a vector from the control bytes starting at the computed index.
404407
// Control bytes hold metadata about the entries in the map.
405-
var source = ReadVector128Aligned(_controlBytes, index);
408+
var source = ReadVector128(_controlBytes, index);
406409
// Compare the target vector (hashed key) with the loaded source vector to find matches.
407410
// `ExtractMostSignificantBits()` returns a mask where each bit set indicates a match.
408411
var mask = Vector128.Equals(target, source).ExtractMostSignificantBits();
@@ -487,7 +490,7 @@ public ref TValue GetValueRefOrAddDefault(TKey key)
487490
{
488491
// Load a vector from the control bytes starting at the computed index.
489492
// Control bytes hold metadata about the entries in the map.
490-
var source = ReadVector128Aligned(_controlBytes, index);
493+
var source = ReadVector128(_controlBytes, index);
491494
// Compare `source` and `target` vectors to find any positions with a matching control byte.
492495
var mask = Vector128.Equals(source, target).ExtractMostSignificantBits();
493496
// Loop over each set bit in `mask` (indicating matching positions).
@@ -578,7 +581,7 @@ public bool Update(TKey key, TValue value)
578581
{
579582
// Load a vector from the control bytes starting at the computed index.
580583
// Control bytes hold metadata about the entries in the map.
581-
var source = ReadVector128Aligned(_controlBytes, index);
584+
var source = ReadVector128(_controlBytes, index);
582585

583586
// Compare the `source` vector with the `target` vector. `ExtractMostSignificantBits` produces a bit mask
584587
// where each set bit corresponds to a position that matches the target hash.
@@ -661,7 +664,7 @@ public bool Remove(TKey key)
661664
{
662665
// Load a vector from the control bytes starting at the computed index.
663666
// Control bytes hold metadata about the entries in the map.
664-
var source = ReadVector128Aligned(_controlBytes, index);
667+
var source = ReadVector128(_controlBytes, index);
665668

666669
// Compare `source` with `target`. `ExtractMostSignificantBits` returns a bitmask
667670
// where each set bit represents a potential match with `target`.
@@ -765,7 +768,7 @@ public bool Contains(TKey key)
765768
{
766769
// Load a vector from the control bytes starting at the computed index.
767770
// Control bytes hold metadata about the entries in the map.
768-
var source = ReadVector128Aligned(_controlBytes, index);
771+
var source = ReadVector128(_controlBytes, index);
769772
// Compare `source` with `target`, and `ExtractMostSignificantBits` returns a bitmask
770773
// where each set bit indicates a position in `source` that matches `target`.
771774
var mask = Vector128.Equals(source, target).ExtractMostSignificantBits();
@@ -962,37 +965,11 @@ private static ref T Find<T>(T[] array, int index)
962965
return ref Unsafe.Add(ref arr0, index);
963966
}
964967

965-
/// <summary>
966-
/// Using a read aligned approach instead of ReadUnaligned, under the assumption that:
967-
/// 1. The underlying array is pinned and stable in memory.
968-
/// 2. The offset (index) is guaranteed to be 16‑byte aligned.
969-
/// As a result, this method performs a direct pointer-based load of a 128-bit vector.
970-
/// </summary>
971-
/// <param name="array">
972-
/// The source array containing sbyte data. Must be pinned in memory to guarantee
973-
/// the pointer remains valid.
974-
/// </param>
975-
/// <param name="index">
976-
/// The byte offset into the array at which the 128-bit vector starts.
977-
/// This offset must be 16‑byte aligned for proper aligned access.
978-
/// </param>
979-
/// <returns>
980-
/// A <see cref="System.Runtime.Intrinsics.Vector128{T}"/> of <see cref="sbyte"/>
981-
/// read from the specified aligned offset.
982-
/// </returns>
983968
[MethodImpl(MethodImplOptions.AggressiveInlining)]
984-
public static unsafe Vector128<sbyte> ReadVector128Aligned(sbyte[] array, ulong index)
969+
public static Vector128<sbyte> ReadVector128(sbyte[] array, ulong index)
985970
{
986-
// Convert the index to a native-sized unsigned integer (nuint) for pointer arithmetic.
987-
nuint offset = (nuint)index;
988-
989-
// Acquire an unsafe pointer to the first element of the array.
990-
// Because 'array' is assumed to be pinned and vector-aligned, we can
991-
// safely add 'offset' bytes to this pointer for direct memory access.
992-
//
993-
// Cast the resulting address to a pointer of type Vector128<sbyte>,
994-
// and then dereference (*) to retrieve the 128-bit vector.
995-
return *(Vector128<sbyte>*)((byte*)Unsafe.AsPointer(ref array[0]) + offset);
971+
// Fast reinterpret-cast without copying
972+
return Unsafe.As<sbyte, Vector128<sbyte>>(ref Find(array, index));
996973
}
997974

998975
/// <summary>

0 commit comments

Comments
 (0)