支持 W3X
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Caches shared by the indexer.
|
||||
*
|
||||
* The workspace owns one instance of each cache and passes them into every
|
||||
* ModIndexer, so a rebuild (which creates a fresh indexer) does not re-read
|
||||
* files whose stat (mtime/size) is unchanged. This is what makes indexing
|
||||
* large art-asset corpora (Corona: ~3800 .w3x files, 2.6 GB) practical:
|
||||
* after the first build, save-triggered rebuilds only re-scan files that
|
||||
* actually changed.
|
||||
*/
|
||||
|
||||
import { resolve } from "node:path";
|
||||
import type { ParsedFile } from "./types";
|
||||
|
||||
/** Case-insensitive absolute path key. */
|
||||
export function normKey(path: string): string {
|
||||
return resolve(path).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* LRU cache for fully parsed XML documents. Parse trees of huge mods can be
|
||||
* memory-heavy, so only a bounded number of recent documents is retained;
|
||||
* evicted entries are re-read from disk on demand.
|
||||
*/
|
||||
export class DocumentCache {
|
||||
private map = new Map<string, ParsedFile>();
|
||||
|
||||
constructor(private capacity = 64) {}
|
||||
|
||||
get(path: string): ParsedFile | undefined {
|
||||
const key = normKey(path);
|
||||
const hit = this.map.get(key);
|
||||
if (!hit) return undefined;
|
||||
this.map.delete(key);
|
||||
this.map.set(key, hit);
|
||||
return hit;
|
||||
}
|
||||
|
||||
set(parsed: ParsedFile): void {
|
||||
const key = normKey(parsed.file.path);
|
||||
this.map.delete(key);
|
||||
this.map.set(key, parsed);
|
||||
if (this.map.size > this.capacity) {
|
||||
const oldest = this.map.keys().next().value;
|
||||
if (oldest !== undefined) this.map.delete(oldest);
|
||||
}
|
||||
}
|
||||
|
||||
invalidate(path: string): void {
|
||||
this.map.delete(normKey(path));
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.map.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache for shallow-scanned art-asset documents (.w3x and content-sniffed
|
||||
* XML files). The retained records are tiny (top-level assets, includes,
|
||||
* defines) compared to a full DOM, so the capacity can be much larger.
|
||||
*/
|
||||
export class ShallowScanCache {
|
||||
private map = new Map<string, ParsedFile>();
|
||||
|
||||
constructor(private capacity = 8192) {}
|
||||
|
||||
get(path: string): ParsedFile | undefined {
|
||||
const key = normKey(path);
|
||||
const hit = this.map.get(key);
|
||||
if (!hit) return undefined;
|
||||
this.map.delete(key);
|
||||
this.map.set(key, hit);
|
||||
return hit;
|
||||
}
|
||||
|
||||
set(parsed: ParsedFile): void {
|
||||
const key = normKey(parsed.file.path);
|
||||
this.map.delete(key);
|
||||
this.map.set(key, parsed);
|
||||
if (this.map.size > this.capacity) {
|
||||
const oldest = this.map.keys().next().value;
|
||||
if (oldest !== undefined) this.map.delete(oldest);
|
||||
}
|
||||
}
|
||||
|
||||
invalidate(path: string): void {
|
||||
this.map.delete(normKey(path));
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.map.clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user