@@ -44,7 +44,14 @@ public sealed class SortedKvStore : IDisposable, IEnumerable<KeyValuePair<int, i
4444 /// </summary>
4545 private readonly UnmanagedIntArray _values ;
4646
47+ /// <summary>
48+ /// The active indices cache
49+ /// </summary>
4750 private UnmanagedIntList _activeIndicesCache ;
51+
52+ /// <summary>
53+ /// The active indices dirty
54+ /// </summary>
4855 private bool _activeIndicesDirty = true ;
4956
5057 /// <summary>
@@ -162,6 +169,7 @@ IEnumerator IEnumerable.GetEnumerator()
162169 public void Add ( int key , int value )
163170 {
164171 var idx = BinarySearch ( key ) ;
172+ _activeIndicesDirty = true ;
165173
166174 if ( idx >= 0 )
167175 {
@@ -176,6 +184,7 @@ public void Add(int key, int value)
176184 _values [ idx ] = value ; // update
177185 }
178186
187+
179188 return ;
180189 }
181190
@@ -189,8 +198,6 @@ public void Add(int key, int value)
189198 _occupied . InsertAt ( idx , 1 ) ;
190199
191200 OccupiedCount ++ ;
192-
193- _activeIndicesDirty = true ;
194201 }
195202
196203 /// <summary>
@@ -259,10 +266,13 @@ public bool TryGetValue(int key, out int value)
259266 public void Remove ( int key )
260267 {
261268 var idx = BinarySearch ( key ) ;
262- if ( idx >= 0 && _occupied [ idx ] ! = 0 )
269+ if ( idx < 0 || _occupied [ idx ] = = 0 )
263270 {
264- _occupied [ idx ] = 0 ;
271+ return ;
265272 }
273+
274+ _occupied [ idx ] = 0 ;
275+ _activeIndicesDirty = true ;
266276 }
267277
268278 /// <summary>
@@ -393,9 +403,13 @@ public void Compact()
393403 ArrayPool < int > . Shared . Return ( rented ) ;
394404 }
395405
406+ /// <summary>
407+ /// Convert to span.
408+ /// </summary>
409+ /// <returns>Span of active Keys.</returns>
396410 public Span < int > AsSpan ( )
397411 {
398- var list = GetActiveIndices ( ) ;
412+ using var list = GetActiveKeys ( ) ;
399413 return list . AsSpan ( ) ;
400414 }
401415
@@ -408,11 +422,8 @@ public Span<int> AsSpan()
408422 /// </returns>
409423 public int BinarySearch ( int key )
410424 {
411- //var list = GetActiveIndices();
412- //return list.AsSpan().BinarySearch(key);
413-
414-
415- int left = 0 , right = OccupiedCount - 1 ;
425+ int left = 0 ;
426+ int right = OccupiedCount - 1 ;
416427 var keysSpan = _keys . AsSpan ( ) [ ..OccupiedCount ] ;
417428 var occupiedSpan = _occupied . AsSpan ( ) [ ..OccupiedCount ] ;
418429
@@ -424,25 +435,24 @@ public int BinarySearch(int key)
424435 if ( midKey == key )
425436 {
426437 if ( occupiedSpan [ mid ] != 0 )
427- return mid ; // found active key
438+ return mid ; // Found active key
428439
429- // Found deleted slot, try to probe neighbors near mid for active key with same key
430- // Usually deletions are rare, so probing few neighbors is cheap
431-
432- // probe left neighbors
440+ // If key found but not occupied, probe neighbors
441+ // probe left
433442 for ( int i = mid - 1 ; i >= left && keysSpan [ i ] == key ; i -- )
434443 {
435444 if ( occupiedSpan [ i ] != 0 )
436445 return i ;
437446 }
438- // probe right neighbors
447+
448+ // probe right
439449 for ( int i = mid + 1 ; i <= right && keysSpan [ i ] == key ; i ++ )
440450 {
441451 if ( occupiedSpan [ i ] != 0 )
442452 return i ;
443453 }
444454
445- // no active key found
455+ // No active key found
446456 return ~ left ;
447457 }
448458
@@ -456,14 +466,10 @@ public int BinarySearch(int key)
456466 }
457467 }
458468
459- // Key not found; try to move left forward to next occupied slot for insertion index
460- int insertionIndex = left ;
461- while ( insertionIndex < OccupiedCount && occupiedSpan [ insertionIndex ] == 0 )
462- insertionIndex ++ ;
463-
464- return ~ insertionIndex ;
469+ return ~ left ; // Not found, return bitwise complement of insertion point
465470 }
466471
472+
467473 /// <summary>
468474 /// Removes all entries from the store.
469475 /// </summary>
@@ -515,6 +521,10 @@ private void EnsureCapacity()
515521 _occupied . EnsureCapacity ( OccupiedCount + 1 ) ;
516522 }
517523
524+ /// <summary>
525+ /// Gets the active indices.
526+ /// </summary>
527+ /// <returns>UnmanagedIntArray of Active Keys</returns>
518528 private UnmanagedIntList GetActiveIndices ( )
519529 {
520530 if ( ! _activeIndicesDirty && _activeIndicesCache != null )
@@ -528,12 +538,31 @@ private UnmanagedIntList GetActiveIndices()
528538 return _activeIndicesCache ! ;
529539 }
530540
541+ /// <summary>
542+ /// Gets the active keys.
543+ /// </summary>
544+ /// <returns>UnmanagedIntArray of Active Keys</returns>
545+ public UnmanagedIntArray GetActiveKeys ( )
546+ {
547+ var activeIndices = GetActiveIndices ( ) ;
548+ var keys = new UnmanagedIntArray ( activeIndices . Length ) ;
549+ for ( int i = 0 ; i < activeIndices . Length ; i ++ )
550+ {
551+ keys [ i ] = _keys [ activeIndices [ i ] ] ;
552+ }
553+
554+ return keys ;
555+ }
556+
557+ /// <summary>
558+ /// Generates the active indices.
559+ /// </summary>
531560 private void GenerateActiveIndices ( )
532561 {
533562 _activeIndicesCache ? . Dispose ( ) ;
534- _activeIndicesCache = new UnmanagedIntList ( OccupiedCount ) ; // or Count if unsure
563+ _activeIndicesCache = new UnmanagedIntList ( OccupiedCount ) ;
535564
536- var occ = _occupied . AsSpan ( ) [ .._keys . Length ] ;
565+ var occ = _occupied . AsSpan ( ) [ ..OccupiedCount ] ;
537566 for ( int i = 0 ; i < occ . Length ; i ++ )
538567 {
539568 if ( occ [ i ] != 0 )
0 commit comments