Fix IndexStore: rename Finalize() to CompleteIndex() to fix CS0465 collision with Object.Finalize
Browse files
FastSeekWpf/Core/IndexStore.cs
CHANGED
|
@@ -38,32 +38,19 @@ public struct IndexEntry
|
|
| 38 |
public readonly FileKind Kind => IsDir ? FileKind.Directory : FileKind.File;
|
| 39 |
}
|
| 40 |
|
| 41 |
-
/// <summary>
|
| 42 |
-
/// High-performance index store matching the Rust design:
|
| 43 |
-
/// - Arena-backed name storage (List<byte> for O(1) append)
|
| 44 |
-
/// - Parallel cached lowercase strings for zero-allocation search
|
| 45 |
-
/// - Sorted ref_lookup for O(log n) parent lookups
|
| 46 |
-
/// - Multi-drive support via per-entry DriveIdx
|
| 47 |
-
/// </summary>
|
| 48 |
public class IndexStore
|
| 49 |
{
|
| 50 |
public List<IndexEntry> Entries = new();
|
| 51 |
-
// Arena stores UTF-8 bytes
|
| 52 |
public List<byte> NameArena = new();
|
| 53 |
public List<byte> NameLowerArena = new();
|
| 54 |
-
// Parallel string cache for hot-path search (no UTF8 decoding during search)
|
| 55 |
public List<string> NameCache = new();
|
| 56 |
public List<string> NameLowerCache = new();
|
| 57 |
-
// Sorted by file_ref for binary search
|
| 58 |
public List<(ulong fileRef, int idx)> RefLookup = new();
|
| 59 |
-
// One root per drive β entries reference via DriveIdx
|
| 60 |
public List<string> DriveRoots = new();
|
| 61 |
public List<JournalCheckpoint> Checkpoints = new();
|
| 62 |
|
| 63 |
public int Count => Entries.Count;
|
| 64 |
|
| 65 |
-
// ---- Hot path: cached name access (zero-allocation) ----
|
| 66 |
-
|
| 67 |
public string NameAt(int i) => NameCache[i];
|
| 68 |
public string NameLowerAt(int i) => NameLowerCache[i];
|
| 69 |
public string DriveRootAt(int i) => DriveRoots[Entries[i].DriveIdx];
|
|
@@ -93,7 +80,6 @@ public class IndexStore
|
|
| 93 |
|
| 94 |
public void PopulateFromScan(ScanResult scan, string driveRoot)
|
| 95 |
{
|
| 96 |
-
// Find or add drive root
|
| 97 |
byte driveIdx = 0;
|
| 98 |
int existing = DriveRoots.IndexOf(driveRoot);
|
| 99 |
if (existing >= 0)
|
|
@@ -155,9 +141,8 @@ public class IndexStore
|
|
| 155 |
/// Sort entries by lowercase name and rebuild lookup tables.
|
| 156 |
/// Matches Rust IndexStore::finalize().
|
| 157 |
/// </summary>
|
| 158 |
-
public void
|
| 159 |
{
|
| 160 |
-
// Sort by lowercase name for search
|
| 161 |
var indices = Enumerable.Range(0, Entries.Count).ToArray();
|
| 162 |
Array.Sort(indices, (a, b) => string.CompareOrdinal(NameLowerCache[a], NameLowerCache[b]));
|
| 163 |
|
|
@@ -177,7 +162,6 @@ public class IndexStore
|
|
| 177 |
NameLowerCache = sortedLower;
|
| 178 |
RebuildRefLookup();
|
| 179 |
|
| 180 |
-
// Shrink arenas to fit β matches Rust shrink_to_fit
|
| 181 |
NameArena.TrimExcess();
|
| 182 |
NameLowerArena.TrimExcess();
|
| 183 |
}
|
|
@@ -251,8 +235,6 @@ public class IndexStore
|
|
| 251 |
return store;
|
| 252 |
}
|
| 253 |
|
| 254 |
-
// ββ Live mutations βββββββββββββββββββββββββββββββββββββββββββββββ
|
| 255 |
-
|
| 256 |
public void Insert(FileRecord record)
|
| 257 |
{
|
| 258 |
string nameLower = record.Name.ToLowerInvariant();
|
|
@@ -268,7 +250,6 @@ public class IndexStore
|
|
| 268 |
ushort nlLen = (ushort)lowerBytes.Length;
|
| 269 |
NameLowerArena.AddRange(lowerBytes);
|
| 270 |
|
| 271 |
-
// Default to first drive if unknown
|
| 272 |
byte driveIdx = 0;
|
| 273 |
if (DriveRoots.Count == 0)
|
| 274 |
DriveRoots.Add("C:\\");
|
|
@@ -285,7 +266,6 @@ public class IndexStore
|
|
| 285 |
DriveIdx = driveIdx
|
| 286 |
};
|
| 287 |
|
| 288 |
-
// Insert in sorted position by lowercase name β matches Rust partition_point + insert
|
| 289 |
int pos = 0;
|
| 290 |
for (; pos < Entries.Count; pos++)
|
| 291 |
{
|
|
@@ -296,14 +276,11 @@ public class IndexStore
|
|
| 296 |
NameCache.Insert(pos, record.Name);
|
| 297 |
NameLowerCache.Insert(pos, nameLower);
|
| 298 |
|
| 299 |
-
// Rebuild lookup (rare operation, acceptable) β matches Rust
|
| 300 |
RebuildRefLookup();
|
| 301 |
}
|
| 302 |
|
| 303 |
public void Remove(ulong fileRef)
|
| 304 |
{
|
| 305 |
-
// Name bytes left as dead space in arena (negligible for rare deletes)
|
| 306 |
-
// β matches Rust comment exactly
|
| 307 |
int idx = -1;
|
| 308 |
for (int i = 0; i < Entries.Count; i++)
|
| 309 |
{
|
|
|
|
| 38 |
public readonly FileKind Kind => IsDir ? FileKind.Directory : FileKind.File;
|
| 39 |
}
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
public class IndexStore
|
| 42 |
{
|
| 43 |
public List<IndexEntry> Entries = new();
|
|
|
|
| 44 |
public List<byte> NameArena = new();
|
| 45 |
public List<byte> NameLowerArena = new();
|
|
|
|
| 46 |
public List<string> NameCache = new();
|
| 47 |
public List<string> NameLowerCache = new();
|
|
|
|
| 48 |
public List<(ulong fileRef, int idx)> RefLookup = new();
|
|
|
|
| 49 |
public List<string> DriveRoots = new();
|
| 50 |
public List<JournalCheckpoint> Checkpoints = new();
|
| 51 |
|
| 52 |
public int Count => Entries.Count;
|
| 53 |
|
|
|
|
|
|
|
| 54 |
public string NameAt(int i) => NameCache[i];
|
| 55 |
public string NameLowerAt(int i) => NameLowerCache[i];
|
| 56 |
public string DriveRootAt(int i) => DriveRoots[Entries[i].DriveIdx];
|
|
|
|
| 80 |
|
| 81 |
public void PopulateFromScan(ScanResult scan, string driveRoot)
|
| 82 |
{
|
|
|
|
| 83 |
byte driveIdx = 0;
|
| 84 |
int existing = DriveRoots.IndexOf(driveRoot);
|
| 85 |
if (existing >= 0)
|
|
|
|
| 141 |
/// Sort entries by lowercase name and rebuild lookup tables.
|
| 142 |
/// Matches Rust IndexStore::finalize().
|
| 143 |
/// </summary>
|
| 144 |
+
public void CompleteIndex()
|
| 145 |
{
|
|
|
|
| 146 |
var indices = Enumerable.Range(0, Entries.Count).ToArray();
|
| 147 |
Array.Sort(indices, (a, b) => string.CompareOrdinal(NameLowerCache[a], NameLowerCache[b]));
|
| 148 |
|
|
|
|
| 162 |
NameLowerCache = sortedLower;
|
| 163 |
RebuildRefLookup();
|
| 164 |
|
|
|
|
| 165 |
NameArena.TrimExcess();
|
| 166 |
NameLowerArena.TrimExcess();
|
| 167 |
}
|
|
|
|
| 235 |
return store;
|
| 236 |
}
|
| 237 |
|
|
|
|
|
|
|
| 238 |
public void Insert(FileRecord record)
|
| 239 |
{
|
| 240 |
string nameLower = record.Name.ToLowerInvariant();
|
|
|
|
| 250 |
ushort nlLen = (ushort)lowerBytes.Length;
|
| 251 |
NameLowerArena.AddRange(lowerBytes);
|
| 252 |
|
|
|
|
| 253 |
byte driveIdx = 0;
|
| 254 |
if (DriveRoots.Count == 0)
|
| 255 |
DriveRoots.Add("C:\\");
|
|
|
|
| 266 |
DriveIdx = driveIdx
|
| 267 |
};
|
| 268 |
|
|
|
|
| 269 |
int pos = 0;
|
| 270 |
for (; pos < Entries.Count; pos++)
|
| 271 |
{
|
|
|
|
| 276 |
NameCache.Insert(pos, record.Name);
|
| 277 |
NameLowerCache.Insert(pos, nameLower);
|
| 278 |
|
|
|
|
| 279 |
RebuildRefLookup();
|
| 280 |
}
|
| 281 |
|
| 282 |
public void Remove(ulong fileRef)
|
| 283 |
{
|
|
|
|
|
|
|
| 284 |
int idx = -1;
|
| 285 |
for (int i = 0; i < Entries.Count; i++)
|
| 286 |
{
|