22using System . Collections ;
33using System . Collections . Generic ;
44using System . Runtime . CompilerServices ;
5+ using System . Runtime . InteropServices ;
56
67namespace Nino . Core
78{
@@ -17,14 +18,20 @@ public sealed class FastMap<TKey, TValue> : IDisposable, IEnumerable<KeyValuePai
1718 private const int MaxKickCount = 16 ;
1819 private const int MinCapacity = 8 ;
1920
21+ // Optimized layout: Pack=1 eliminates padding, improving cache utilization
22+ // Trade-off: potential unaligned access (acceptable on modern CPUs) for better memory density
23+ [ StructLayout ( LayoutKind . Sequential , Pack = 1 ) ]
2024 private struct Entry
2125 {
2226 public uint HashCode ;
27+ public bool IsOccupied ;
2328 public TKey Key ;
2429 public TValue Value ;
25- public bool IsOccupied ;
2630 }
2731
32+ // Cache the equality comparer to avoid repeated lookups in hot paths
33+ private static readonly IEqualityComparer < TKey > KeyComparer = EqualityComparer < TKey > . Default ;
34+
2835 private Entry [ ] _table1 ;
2936 private Entry [ ] _table2 ;
3037 private int _capacity ;
@@ -36,22 +43,27 @@ private struct Entry
3643 public int Capacity => _capacity ;
3744 public bool IsCreated => _table1 != null ;
3845
46+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
47+ private static int TransformHashCode ( int hashCode )
48+ {
49+ return hashCode ^ ( hashCode >> 16 ) ;
50+ }
51+
3952 public ref TValue this [ in TKey key ]
4053 {
4154 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
4255 get
4356 {
44- var hashCode = key . GetHashCode ( ) ;
45- hashCode ^= hashCode >> 16 ;
57+ var hashCode = TransformHashCode ( key . GetHashCode ( ) ) ;
4658
4759 var index1 = hashCode & _capacityMask ;
4860 ref Entry entry1 = ref _table1 [ index1 ] ;
49- if ( entry1 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry1 . Key , key ) )
61+ if ( entry1 . HashCode == hashCode && KeyComparer . Equals ( entry1 . Key , key ) )
5062 return ref entry1 . Value ;
5163
5264 var index2 = ( hashCode >> 8 ) & _capacityMask ;
5365 ref Entry entry2 = ref _table2 [ index2 ] ;
54- if ( entry2 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry2 . Key , key ) )
66+ if ( entry2 . HashCode == hashCode && KeyComparer . Equals ( entry2 . Key , key ) )
5567 return ref entry2 . Value ;
5668 throw new KeyNotFoundException ( ) ;
5769 }
@@ -147,7 +159,7 @@ public bool TryAdd(in TKey key, in TValue value)
147159 _version ++ ;
148160 return true ;
149161 }
150- else if ( entry1 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry1 . Key , key ) )
162+ else if ( entry1 . HashCode == hashCode && KeyComparer . Equals ( entry1 . Key , key ) )
151163 return false ;
152164
153165 var index2 = ( hashCode >> 8 ) & _capacityMask ;
@@ -162,7 +174,7 @@ public bool TryAdd(in TKey key, in TValue value)
162174 _version ++ ;
163175 return true ;
164176 }
165- else if ( entry2 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry2 . Key , key ) )
177+ else if ( entry2 . HashCode == hashCode && KeyComparer . Equals ( entry2 . Key , key ) )
166178 return false ;
167179
168180 bool res = CuckooInsert ( hashCode , key , value , false ) ;
@@ -188,7 +200,7 @@ private bool TryAddOrUpdate(in TKey key, in TValue value)
188200 _version ++ ;
189201 return true ;
190202 }
191- else if ( entry1 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry1 . Key , key ) )
203+ else if ( entry1 . HashCode == hashCode && KeyComparer . Equals ( entry1 . Key , key ) )
192204 {
193205 entry1 . Value = value ;
194206 _version ++ ;
@@ -207,7 +219,7 @@ private bool TryAddOrUpdate(in TKey key, in TValue value)
207219 _version ++ ;
208220 return true ;
209221 }
210- else if ( entry2 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry2 . Key , key ) )
222+ else if ( entry2 . HashCode == hashCode && KeyComparer . Equals ( entry2 . Key , key ) )
211223 {
212224 entry2 . Value = value ;
213225 _version ++ ;
@@ -242,7 +254,7 @@ private bool CuckooInsert(int hashCode, in TKey key, in TValue value, bool updat
242254 _count ++ ;
243255 return true ;
244256 }
245- else if ( updateIfExists && entry . HashCode == currentHashCode && EqualityComparer < TKey > . Default . Equals ( entry . Key , currentKey ) )
257+ else if ( updateIfExists && entry . HashCode == currentHashCode && KeyComparer . Equals ( entry . Key , currentKey ) )
246258 {
247259 entry . Value = currentValue ;
248260 return true ;
@@ -266,7 +278,7 @@ private bool CuckooInsert(int hashCode, in TKey key, in TValue value, bool updat
266278 _count ++ ;
267279 return true ;
268280 }
269- else if ( updateIfExists && entry . HashCode == currentHashCode && EqualityComparer < TKey > . Default . Equals ( entry . Key , currentKey ) )
281+ else if ( updateIfExists && entry . HashCode == currentHashCode && KeyComparer . Equals ( entry . Key , currentKey ) )
270282 {
271283 entry . Value = currentValue ;
272284 return true ;
@@ -291,7 +303,7 @@ public ref TValue GetValueRefOrAddDefault(TKey key, out bool exists)
291303
292304 var index1 = hashCode & _capacityMask ;
293305 ref Entry entry1 = ref _table1 [ index1 ] ;
294- if ( entry1 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry1 . Key , key ) )
306+ if ( entry1 . HashCode == hashCode && KeyComparer . Equals ( entry1 . Key , key ) )
295307 {
296308 exists = true ;
297309 return ref entry1 . Value ;
@@ -300,7 +312,7 @@ public ref TValue GetValueRefOrAddDefault(TKey key, out bool exists)
300312 var index2 = ( hashCode >> 8 ) & _capacityMask ;
301313
302314 ref Entry entry2 = ref _table2 [ index2 ] ;
303- if ( entry2 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry2 . Key , key ) )
315+ if ( entry2 . HashCode == hashCode && KeyComparer . Equals ( entry2 . Key , key ) )
304316 {
305317 exists = true ;
306318 return ref entry2 . Value ;
@@ -344,15 +356,15 @@ public bool TryGetValue(in TKey key, out TValue value)
344356
345357 var index1 = hashCode & _capacityMask ;
346358 ref Entry entry1 = ref _table1 [ index1 ] ;
347- if ( entry1 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry1 . Key , key ) )
359+ if ( entry1 . HashCode == hashCode && KeyComparer . Equals ( entry1 . Key , key ) )
348360 {
349361 value = entry1 . Value ;
350362 return true ;
351363 }
352364
353365 var index2 = ( hashCode >> 8 ) & _capacityMask ;
354366 ref Entry entry2 = ref _table2 [ index2 ] ;
355- if ( entry2 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry2 . Key , key ) )
367+ if ( entry2 . HashCode == hashCode && KeyComparer . Equals ( entry2 . Key , key ) )
356368 {
357369 value = entry2 . Value ;
358370 return true ;
@@ -370,12 +382,12 @@ public ref TValue GetValueRef(in TKey key)
370382
371383 var index1 = hashCode & _capacityMask ;
372384 ref Entry entry1 = ref _table1 [ index1 ] ;
373- if ( entry1 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry1 . Key , key ) )
385+ if ( entry1 . HashCode == hashCode && KeyComparer . Equals ( entry1 . Key , key ) )
374386 return ref entry1 . Value ;
375387
376388 var index2 = ( hashCode >> 8 ) & _capacityMask ;
377389 ref Entry entry2 = ref _table2 [ index2 ] ;
378- if ( entry2 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry2 . Key , key ) )
390+ if ( entry2 . HashCode == hashCode && KeyComparer . Equals ( entry2 . Key , key ) )
379391 return ref entry2 . Value ;
380392
381393 throw new KeyNotFoundException ( ) ;
@@ -389,12 +401,12 @@ public bool ContainsKey(in TKey key)
389401
390402 var index1 = hashCode & _capacityMask ;
391403 ref Entry entry1 = ref _table1 [ index1 ] ;
392- if ( entry1 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry1 . Key , key ) )
404+ if ( entry1 . HashCode == hashCode && KeyComparer . Equals ( entry1 . Key , key ) )
393405 return true ;
394406
395407 var index2 = ( hashCode >> 8 ) & _capacityMask ;
396408 ref Entry entry2 = ref _table2 [ index2 ] ;
397- return entry2 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry2 . Key , key ) ;
409+ return entry2 . HashCode == hashCode && KeyComparer . Equals ( entry2 . Key , key ) ;
398410 }
399411
400412 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -423,7 +435,7 @@ public bool Remove(TKey key)
423435
424436 var index1 = hashCode & _capacityMask ;
425437 ref Entry entry1 = ref _table1 [ index1 ] ;
426- if ( entry1 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry1 . Key , key ) )
438+ if ( entry1 . HashCode == hashCode && KeyComparer . Equals ( entry1 . Key , key ) )
427439 {
428440 entry1 . IsOccupied = false ;
429441 _count -- ;
@@ -433,7 +445,7 @@ public bool Remove(TKey key)
433445
434446 var index2 = ( hashCode >> 8 ) & _capacityMask ;
435447 ref Entry entry2 = ref _table2 [ index2 ] ;
436- if ( entry2 . HashCode == hashCode && EqualityComparer < TKey > . Default . Equals ( entry2 . Key , key ) )
448+ if ( entry2 . HashCode == hashCode && KeyComparer . Equals ( entry2 . Key , key ) )
437449 {
438450 entry2 . IsOccupied = false ;
439451 _count -- ;
0 commit comments