mirror of
https://github.com/morluto/rea.git
synced 2026-10-12 02:19:24 +00:00
perf(artifacts): reuse trie membership for case-folded siblings
This commit is contained in:
@@ -60,6 +60,30 @@ describe("English Unicode case collisions", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("retains every spelling in a high-cardinality folded sibling group", () => {
|
||||
const count = 8_192;
|
||||
const variants = caseVariants("abcdefghijklm", count);
|
||||
const { limitation, byPath } = annotate(variants);
|
||||
const ordered = [...variants].sort();
|
||||
const first = ordered[0];
|
||||
const second = ordered[1];
|
||||
const original = variants[0];
|
||||
if (first === undefined || second === undefined || original === undefined) {
|
||||
throw new Error("Expected at least two case variants");
|
||||
}
|
||||
expect(limitation).toBe(ENGLISH_UNICODE_CASE_INVENTORY_LIMITATION);
|
||||
expect(byPath.size).toBe(count);
|
||||
expect(byPath.get(first)).toEqual([
|
||||
`Logical path ${first} collides under English (en-US) Unicode case folding with ${second} and ${String(count - 2)} other spellings; ${NOTE}`,
|
||||
]);
|
||||
expect(byPath.get(original)?.[0]).toContain(
|
||||
`with ${first} and ${String(count - 2)} other spellings;`,
|
||||
);
|
||||
expect(
|
||||
[...byPath.values()].every((limitations) => limitations.length === 1),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("stays linear for large case-variant subtrees", () => {
|
||||
const count = 5_000;
|
||||
const paths = Array.from({ length: count }, (_, index) => [
|
||||
@@ -81,3 +105,12 @@ describe("English Unicode case collisions", () => {
|
||||
expect(byPath.get(deep)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
const caseVariants = (lowercase: string, count: number): string[] =>
|
||||
Array.from({ length: count }, (_, mask) =>
|
||||
[...lowercase]
|
||||
.map((character, index) =>
|
||||
(mask & (1 << index)) === 0 ? character : character.toUpperCase(),
|
||||
)
|
||||
.join(""),
|
||||
);
|
||||
|
||||
@@ -177,12 +177,12 @@ const englishUnicodeCaseCollisions = (
|
||||
if (path.length === 0 || path === ".") continue;
|
||||
let node = root;
|
||||
for (const part of path.split("/")) {
|
||||
const folded = englishCaseFold(part);
|
||||
const spellings = node.spellingsByFold.get(folded);
|
||||
if (spellings === undefined) node.spellingsByFold.set(folded, [part]);
|
||||
else if (!spellings.includes(part)) spellings.push(part);
|
||||
let child = node.bySpelling.get(part);
|
||||
if (child === undefined) {
|
||||
const folded = englishCaseFold(part);
|
||||
const spellings = node.spellingsByFold.get(folded);
|
||||
if (spellings === undefined) node.spellingsByFold.set(folded, [part]);
|
||||
else spellings.push(part);
|
||||
child = emptyCaseNode();
|
||||
node.bySpelling.set(part, child);
|
||||
}
|
||||
|
||||
@@ -154,6 +154,61 @@ describe("entry-order validation and reader controls", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("retains high-cardinality case-folded directories and their descendants", async () => {
|
||||
const root = await createTestTempDirectory(
|
||||
"rea-entry-order-case-capacity-",
|
||||
);
|
||||
const archive = join(root, "case-capacity.zip");
|
||||
const variants = Array.from({ length: 256 }, (_, mask) =>
|
||||
[..."abcdefgh"]
|
||||
.map((character, index) =>
|
||||
(mask & (1 << index)) === 0 ? character : character.toUpperCase(),
|
||||
)
|
||||
.join(""),
|
||||
);
|
||||
await writeOrderedZip(
|
||||
archive,
|
||||
variants.flatMap((variant) => [variant + "/", variant + "/entry.txt"]),
|
||||
);
|
||||
|
||||
const inventory = await inventoryArtifact(archive);
|
||||
const directories = variants.map((variant) =>
|
||||
artifactOccurrenceAt(inventory, variant),
|
||||
);
|
||||
const descendants = variants.map((variant) =>
|
||||
artifactOccurrenceAt(inventory, `${variant}/entry.txt`),
|
||||
);
|
||||
const ordered = [...variants].sort();
|
||||
const first = ordered[0];
|
||||
const second = ordered[1];
|
||||
|
||||
expect(inventory.occurrences).toHaveLength(1 + variants.length * 2);
|
||||
expect(
|
||||
new Set(inventory.occurrences.map(({ logical_path }) => logical_path))
|
||||
.size,
|
||||
).toBe(1 + variants.length * 2);
|
||||
expect(
|
||||
new Set(
|
||||
[...directories, ...descendants].map(
|
||||
({ occurrence_id }) => occurrence_id,
|
||||
),
|
||||
).size,
|
||||
).toBe(variants.length * 2);
|
||||
expect(
|
||||
directories.every(({ limitations }) => limitations.length === 1),
|
||||
).toBe(true);
|
||||
expect(
|
||||
descendants.every(({ limitations }) => limitations.length === 1),
|
||||
).toBe(true);
|
||||
expect(
|
||||
directories.find(({ logical_path }) => logical_path === first)
|
||||
?.limitations[0],
|
||||
).toContain(`with ${second} and 254 other spellings;`);
|
||||
expect(descendants[0]?.limitations[0]).toContain(
|
||||
`is under ${variants[0]}, which collides under English (en-US) Unicode case folding with ${first} and 254 other spellings;`,
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves ordinary directory and ASAR structure", async () => {
|
||||
const root = await createTestTempDirectory("rea-entry-order-readers-");
|
||||
const directory = join(root, "source");
|
||||
|
||||
Reference in New Issue
Block a user