Merge pull request #19051 from Snuffleupagus/Dict-Map

Convert the `Dict`-implementation to use a `Map` internally
This commit is contained in:
Jonas Jenwald 2024-11-17 12:59:02 +01:00 committed by GitHub
commit bc91985941
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 49 additions and 52 deletions

View File

@ -6,6 +6,7 @@ external/bcmaps/
external/builder/fixtures/ external/builder/fixtures/
external/builder/fixtures_babel/ external/builder/fixtures_babel/
external/quickjs/ external/quickjs/
test/stats/results/
test/tmp/ test/tmp/
test/pdfs/ test/pdfs/
web/locale/ web/locale/

View File

@ -6,6 +6,7 @@ external/bcmaps/
external/builder/fixtures/ external/builder/fixtures/
external/builder/fixtures_babel/ external/builder/fixtures_babel/
external/quickjs/ external/quickjs/
test/stats/results/
test/tmp/ test/tmp/
test/pdfs/ test/pdfs/
web/locale/ web/locale/

View File

@ -35,6 +35,7 @@ export default [
"external/builder/fixtures_babel/", "external/builder/fixtures_babel/",
"external/quickjs/", "external/quickjs/",
"external/openjpeg/", "external/openjpeg/",
"test/stats/results/",
"test/tmp/", "test/tmp/",
"test/pdfs/", "test/pdfs/",
"web/locale/", "web/locale/",

View File

@ -720,12 +720,12 @@ class Catalog {
} }
} }
} else if (obj instanceof Dict) { } else if (obj instanceof Dict) {
obj.forEach(function (key, value) { for (const [key, value] of obj) {
const dest = fetchDest(value); const dest = fetchDest(value);
if (dest) { if (dest) {
dests[key] = dest; dests[key] = dest;
} }
}); }
} }
return shadow(this, "destinations", dests); return shadow(this, "destinations", dests);
} }

View File

@ -1282,13 +1282,8 @@ class PDFDocument {
}, },
}; };
const fonts = new Map();
fontRes.forEach((fontName, font) => {
fonts.set(fontName, font);
});
const promises = []; const promises = [];
for (const [fontName, font] of fontRes) {
for (const [fontName, font] of fonts) {
const descriptor = font.get("FontDescriptor"); const descriptor = font.get("FontDescriptor");
if (!(descriptor instanceof Dict)) { if (!(descriptor instanceof Dict)) {
continue; continue;

View File

@ -69,7 +69,7 @@ const nonSerializable = function nonSerializableClosure() {
class Dict { class Dict {
constructor(xref = null) { constructor(xref = null) {
// Map should only be used internally, use functions below to access. // Map should only be used internally, use functions below to access.
this._map = Object.create(null); this._map = new Map();
this.xref = xref; this.xref = xref;
this.objId = null; this.objId = null;
this.suppressEncryption = false; this.suppressEncryption = false;
@ -81,12 +81,12 @@ class Dict {
} }
get size() { get size() {
return Object.keys(this._map).length; return this._map.size;
} }
// Automatically dereferences Ref objects. // Automatically dereferences Ref objects.
get(key1, key2, key3) { get(key1, key2, key3) {
let value = this._map[key1]; let value = this._map.get(key1);
if (value === undefined && key2 !== undefined) { if (value === undefined && key2 !== undefined) {
if ( if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) && (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
@ -94,7 +94,7 @@ class Dict {
) { ) {
unreachable("Dict.get: Expected keys to be ordered by length."); unreachable("Dict.get: Expected keys to be ordered by length.");
} }
value = this._map[key2]; value = this._map.get(key2);
if (value === undefined && key3 !== undefined) { if (value === undefined && key3 !== undefined) {
if ( if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) && (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
@ -102,7 +102,7 @@ class Dict {
) { ) {
unreachable("Dict.get: Expected keys to be ordered by length."); unreachable("Dict.get: Expected keys to be ordered by length.");
} }
value = this._map[key3]; value = this._map.get(key3);
} }
} }
if (value instanceof Ref && this.xref) { if (value instanceof Ref && this.xref) {
@ -113,7 +113,7 @@ class Dict {
// Same as get(), but returns a promise and uses fetchIfRefAsync(). // Same as get(), but returns a promise and uses fetchIfRefAsync().
async getAsync(key1, key2, key3) { async getAsync(key1, key2, key3) {
let value = this._map[key1]; let value = this._map.get(key1);
if (value === undefined && key2 !== undefined) { if (value === undefined && key2 !== undefined) {
if ( if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) && (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
@ -121,7 +121,7 @@ class Dict {
) { ) {
unreachable("Dict.getAsync: Expected keys to be ordered by length."); unreachable("Dict.getAsync: Expected keys to be ordered by length.");
} }
value = this._map[key2]; value = this._map.get(key2);
if (value === undefined && key3 !== undefined) { if (value === undefined && key3 !== undefined) {
if ( if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) && (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
@ -129,7 +129,7 @@ class Dict {
) { ) {
unreachable("Dict.getAsync: Expected keys to be ordered by length."); unreachable("Dict.getAsync: Expected keys to be ordered by length.");
} }
value = this._map[key3]; value = this._map.get(key3);
} }
} }
if (value instanceof Ref && this.xref) { if (value instanceof Ref && this.xref) {
@ -140,7 +140,7 @@ class Dict {
// Same as get(), but dereferences all elements if the result is an Array. // Same as get(), but dereferences all elements if the result is an Array.
getArray(key1, key2, key3) { getArray(key1, key2, key3) {
let value = this._map[key1]; let value = this._map.get(key1);
if (value === undefined && key2 !== undefined) { if (value === undefined && key2 !== undefined) {
if ( if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) && (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
@ -148,7 +148,7 @@ class Dict {
) { ) {
unreachable("Dict.getArray: Expected keys to be ordered by length."); unreachable("Dict.getArray: Expected keys to be ordered by length.");
} }
value = this._map[key2]; value = this._map.get(key2);
if (value === undefined && key3 !== undefined) { if (value === undefined && key3 !== undefined) {
if ( if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) && (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
@ -156,7 +156,7 @@ class Dict {
) { ) {
unreachable("Dict.getArray: Expected keys to be ordered by length."); unreachable("Dict.getArray: Expected keys to be ordered by length.");
} }
value = this._map[key3]; value = this._map.get(key3);
} }
} }
if (value instanceof Ref && this.xref) { if (value instanceof Ref && this.xref) {
@ -176,16 +176,16 @@ class Dict {
// No dereferencing. // No dereferencing.
getRaw(key) { getRaw(key) {
return this._map[key]; return this._map.get(key);
} }
getKeys() { getKeys() {
return Object.keys(this._map); return [...this._map.keys()];
} }
// No dereferencing. // No dereferencing.
getRawValues() { getRawValues() {
return Object.values(this._map); return [...this._map.values()];
} }
set(key, value) { set(key, value) {
@ -196,16 +196,21 @@ class Dict {
unreachable('Dict.set: The "value" cannot be undefined.'); unreachable('Dict.set: The "value" cannot be undefined.');
} }
} }
this._map[key] = value; this._map.set(key, value);
} }
has(key) { has(key) {
return this._map[key] !== undefined; return this._map.has(key);
} }
forEach(callback) { *[Symbol.iterator]() {
for (const key in this._map) { for (const [key, value] of this._map) {
callback(key, this.get(key)); yield [
key,
value instanceof Ref && this.xref
? this.xref.fetch(value, this.suppressEncryption)
: value,
];
} }
} }
@ -226,7 +231,7 @@ class Dict {
if (!(dict instanceof Dict)) { if (!(dict instanceof Dict)) {
continue; continue;
} }
for (const [key, value] of Object.entries(dict._map)) { for (const [key, value] of dict._map) {
let property = properties.get(key); let property = properties.get(key);
if (property === undefined) { if (property === undefined) {
property = []; property = [];
@ -242,20 +247,20 @@ class Dict {
} }
for (const [name, values] of properties) { for (const [name, values] of properties) {
if (values.length === 1 || !(values[0] instanceof Dict)) { if (values.length === 1 || !(values[0] instanceof Dict)) {
mergedDict._map[name] = values[0]; mergedDict._map.set(name, values[0]);
continue; continue;
} }
const subDict = new Dict(xref); const subDict = new Dict(xref);
for (const dict of values) { for (const dict of values) {
for (const [key, value] of Object.entries(dict._map)) { for (const [key, value] of dict._map) {
if (subDict._map[key] === undefined) { if (!subDict._map.has(key)) {
subDict._map[key] = value; subDict._map.set(key, value);
} }
} }
} }
if (subDict.size > 0) { if (subDict.size > 0) {
mergedDict._map[name] = subDict; mergedDict._map.set(name, subDict);
} }
} }
properties.clear(); properties.clear();

View File

@ -62,12 +62,11 @@ class StructTreeRoot {
if (!(roleMapDict instanceof Dict)) { if (!(roleMapDict instanceof Dict)) {
return; return;
} }
roleMapDict.forEach((key, value) => { for (const [key, value] of roleMapDict) {
if (!(value instanceof Name)) { if (value instanceof Name) {
return;
}
this.roleMap.set(key, value.name); this.roleMap.set(key, value.name);
}); }
}
} }
static async canCreateStructureTree({ static async canCreateStructureTree({

View File

@ -688,11 +688,11 @@ class WorkerMessageHandler {
const infoObj = Object.create(null); const infoObj = Object.create(null);
const xrefInfo = xref.trailer.get("Info") || null; const xrefInfo = xref.trailer.get("Info") || null;
if (xrefInfo instanceof Dict) { if (xrefInfo instanceof Dict) {
xrefInfo.forEach((key, value) => { for (const [key, value] of xrefInfo) {
if (typeof value === "string") { if (typeof value === "string") {
infoObj[key] = stringToPDFString(value); infoObj[key] = stringToPDFString(value);
} }
}); }
} }
newXrefInfo = { newXrefInfo = {

View File

@ -80,7 +80,7 @@ const pdfjsVersion =
const pdfjsBuild = const pdfjsBuild =
typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0; typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0;
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) { if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING || GENERIC")) {
globalThis.pdfjsTestingUtils = { globalThis.pdfjsTestingUtils = {
HighlightOutliner, HighlightOutliner,
}; };

View File

@ -221,17 +221,12 @@ describe("primitives", function () {
expect(values[2]).toEqual(testFontFile); expect(values[2]).toEqual(testFontFile);
}); });
it("should callback for each stored key", function () { it("should iterate through each stored key", function () {
const callbackSpy = jasmine.createSpy("spy on callback in dictionary"); expect([...dictWithManyKeys]).toEqual([
["FontFile", testFontFile],
dictWithManyKeys.forEach(callbackSpy); ["FontFile2", testFontFile2],
["FontFile3", testFontFile3],
expect(callbackSpy).toHaveBeenCalled(); ]);
const callbackSpyCalls = callbackSpy.calls;
expect(callbackSpyCalls.argsFor(0)).toEqual(["FontFile", testFontFile]);
expect(callbackSpyCalls.argsFor(1)).toEqual(["FontFile2", testFontFile2]);
expect(callbackSpyCalls.argsFor(2)).toEqual(["FontFile3", testFontFile3]);
expect(callbackSpyCalls.count()).toEqual(3);
}); });
it("should handle keys pointing to indirect objects, both sync and async", async function () { it("should handle keys pointing to indirect objects, both sync and async", async function () {