@@ -14,11 +14,20 @@ public HashTablePerfectContext<TKey, TValue> Create(TKey[] keys, TValue[]? value
1414 throw new InvalidOperationException ( "HashSetPerfectStructure can only be created with a perfect hash function." ) ;
1515
1616 ulong size = ( ulong ) ( keys . Length * hashData . CapacityFactor ) ;
17-
17+ bool hasEmptySlots = size != ( ulong ) keys . Length ;
18+ bool storeHashCode = ! keyType . IsIdentityHash ( ) || hasEmptySlots ;
1819 ulong [ ] hashCodes = hashData . HashCodes ;
1920 KeyValuePair < TKey , ulong > [ ] pairs = new KeyValuePair < TKey , ulong > [ size ] ;
2021 TValue [ ] ? denseValues = values == null ? null : new TValue [ size ] ;
2122
23+ if ( storeHashCode && hasEmptySlots )
24+ {
25+ ulong sentinel = GetSentinel ( hashData , hashCodes , keys . Length ) ;
26+
27+ for ( ulong i = 0 ; i < size ; i ++ )
28+ pairs [ i ] = new KeyValuePair < TKey , ulong > ( default ! , sentinel ) ;
29+ }
30+
2231 //We need to reorder the data to match hashes
2332 for ( int i = 0 ; i < keys . Length ; i ++ )
2433 {
@@ -29,6 +38,38 @@ public HashTablePerfectContext<TKey, TValue> Create(TKey[] keys, TValue[]? value
2938 denseValues [ index ] = values ! [ i ] ;
3039 }
3140
32- return new HashTablePerfectContext < TKey , TValue > ( pairs , ! keyType . IsIdentityHash ( ) , denseValues ) ;
41+ return new HashTablePerfectContext < TKey , TValue > ( pairs , storeHashCode , denseValues ) ;
42+ }
43+
44+ private static ulong GetSentinel ( HashData hashData , ulong [ ] hashCodes , int count )
45+ {
46+ if ( hashData . MaxHashCode != ulong . MaxValue )
47+ return hashData . MaxHashCode + 1 ;
48+
49+ if ( hashData . MinHashCode != 0 )
50+ return hashData . MinHashCode - 1 ;
51+
52+ ulong candidate = 1 ;
53+ while ( true )
54+ {
55+ bool found = false ;
56+
57+ for ( int i = 0 ; i < count ; i ++ )
58+ {
59+ if ( hashCodes [ i ] == candidate )
60+ {
61+ found = true ;
62+ break ;
63+ }
64+ }
65+
66+ if ( ! found )
67+ return candidate ;
68+
69+ candidate ++ ;
70+
71+ if ( candidate == 0 )
72+ throw new InvalidOperationException ( "Unable to find a sentinel hash value." ) ;
73+ }
3374 }
3475}
0 commit comments