Skip to content

Commit 77508a6

Browse files
Improve my SortedKvStore
Add a new function to Intlist
1 parent edf4300 commit 77508a6

5 files changed

Lines changed: 83 additions & 25 deletions

File tree

CommonExtendedObjectsTests/IntListTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,5 +262,19 @@ public void PeekShouldReturnLastElementWithoutRemoving()
262262

263263
Assert.AreEqual(42, list.Peek());
264264
}
265+
266+
[TestMethod]
267+
public void CloneSortedReturnsSortedList()
268+
{
269+
var list = new UnmanagedIntList {5, 2, 8, 3};
270+
271+
using var sorted = list.Sorted();
272+
273+
Assert.AreEqual(4, sorted.Length);
274+
Assert.AreEqual(2, sorted[0]);
275+
Assert.AreEqual(3, sorted[1]);
276+
Assert.AreEqual(5, sorted[2]);
277+
Assert.AreEqual(8, sorted[3]);
278+
}
265279
}
266280
}
0 Bytes
Loading
0 Bytes
Loading

ExtendedSystemObjects/SortedKvStore.cs

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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)

ExtendedSystemObjects/UnmanagedIntList.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,21 @@ public Span<int> AsSpan()
302302
return new Span<int>(_ptr, Capacity);
303303
}
304304

305+
/// <summary>
306+
/// Returns a new UnmanagedIntList that is a sorted copy of the current list.
307+
/// </summary>
308+
/// <returns>A new UnmanagedIntList instance with sorted values.</returns>
309+
public UnmanagedIntList Sorted()
310+
{
311+
var copy = new UnmanagedIntList(Length);
312+
for (int i = 0; i < Length; i++)
313+
{
314+
copy.Add(_ptr[i]);
315+
}
316+
317+
copy.Sort(); // Uses internal AsSpan().Sort()
318+
return copy;
319+
}
305320

306321
/// <summary>
307322
/// Converts to string.

0 commit comments

Comments
 (0)