Skip to content

Commit bc91985

Browse files
Merge pull request #19051 from Snuffleupagus/Dict-Map
Convert the `Dict`-implementation to use a `Map` internally
2 parents 823e700 + 2c0cc48 commit bc91985

10 files changed

+49
-52
lines changed

.prettierignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ external/bcmaps/
66
external/builder/fixtures/
77
external/builder/fixtures_babel/
88
external/quickjs/
9+
test/stats/results/
910
test/tmp/
1011
test/pdfs/
1112
web/locale/

.stylelintignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ external/bcmaps/
66
external/builder/fixtures/
77
external/builder/fixtures_babel/
88
external/quickjs/
9+
test/stats/results/
910
test/tmp/
1011
test/pdfs/
1112
web/locale/

eslint.config.mjs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default [
3535
"external/builder/fixtures_babel/",
3636
"external/quickjs/",
3737
"external/openjpeg/",
38+
"test/stats/results/",
3839
"test/tmp/",
3940
"test/pdfs/",
4041
"web/locale/",

src/core/catalog.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -720,12 +720,12 @@ class Catalog {
720720
}
721721
}
722722
} else if (obj instanceof Dict) {
723-
obj.forEach(function (key, value) {
723+
for (const [key, value] of obj) {
724724
const dest = fetchDest(value);
725725
if (dest) {
726726
dests[key] = dest;
727727
}
728-
});
728+
}
729729
}
730730
return shadow(this, "destinations", dests);
731731
}

src/core/document.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -1282,13 +1282,8 @@ class PDFDocument {
12821282
},
12831283
};
12841284

1285-
const fonts = new Map();
1286-
fontRes.forEach((fontName, font) => {
1287-
fonts.set(fontName, font);
1288-
});
12891285
const promises = [];
1290-
1291-
for (const [fontName, font] of fonts) {
1286+
for (const [fontName, font] of fontRes) {
12921287
const descriptor = font.get("FontDescriptor");
12931288
if (!(descriptor instanceof Dict)) {
12941289
continue;

src/core/primitives.js

+30-25
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const nonSerializable = function nonSerializableClosure() {
6969
class Dict {
7070
constructor(xref = null) {
7171
// Map should only be used internally, use functions below to access.
72-
this._map = Object.create(null);
72+
this._map = new Map();
7373
this.xref = xref;
7474
this.objId = null;
7575
this.suppressEncryption = false;
@@ -81,28 +81,28 @@ class Dict {
8181
}
8282

8383
get size() {
84-
return Object.keys(this._map).length;
84+
return this._map.size;
8585
}
8686

8787
// Automatically dereferences Ref objects.
8888
get(key1, key2, key3) {
89-
let value = this._map[key1];
89+
let value = this._map.get(key1);
9090
if (value === undefined && key2 !== undefined) {
9191
if (
9292
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
9393
key2.length < key1.length
9494
) {
9595
unreachable("Dict.get: Expected keys to be ordered by length.");
9696
}
97-
value = this._map[key2];
97+
value = this._map.get(key2);
9898
if (value === undefined && key3 !== undefined) {
9999
if (
100100
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
101101
key3.length < key2.length
102102
) {
103103
unreachable("Dict.get: Expected keys to be ordered by length.");
104104
}
105-
value = this._map[key3];
105+
value = this._map.get(key3);
106106
}
107107
}
108108
if (value instanceof Ref && this.xref) {
@@ -113,23 +113,23 @@ class Dict {
113113

114114
// Same as get(), but returns a promise and uses fetchIfRefAsync().
115115
async getAsync(key1, key2, key3) {
116-
let value = this._map[key1];
116+
let value = this._map.get(key1);
117117
if (value === undefined && key2 !== undefined) {
118118
if (
119119
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
120120
key2.length < key1.length
121121
) {
122122
unreachable("Dict.getAsync: Expected keys to be ordered by length.");
123123
}
124-
value = this._map[key2];
124+
value = this._map.get(key2);
125125
if (value === undefined && key3 !== undefined) {
126126
if (
127127
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
128128
key3.length < key2.length
129129
) {
130130
unreachable("Dict.getAsync: Expected keys to be ordered by length.");
131131
}
132-
value = this._map[key3];
132+
value = this._map.get(key3);
133133
}
134134
}
135135
if (value instanceof Ref && this.xref) {
@@ -140,23 +140,23 @@ class Dict {
140140

141141
// Same as get(), but dereferences all elements if the result is an Array.
142142
getArray(key1, key2, key3) {
143-
let value = this._map[key1];
143+
let value = this._map.get(key1);
144144
if (value === undefined && key2 !== undefined) {
145145
if (
146146
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
147147
key2.length < key1.length
148148
) {
149149
unreachable("Dict.getArray: Expected keys to be ordered by length.");
150150
}
151-
value = this._map[key2];
151+
value = this._map.get(key2);
152152
if (value === undefined && key3 !== undefined) {
153153
if (
154154
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
155155
key3.length < key2.length
156156
) {
157157
unreachable("Dict.getArray: Expected keys to be ordered by length.");
158158
}
159-
value = this._map[key3];
159+
value = this._map.get(key3);
160160
}
161161
}
162162
if (value instanceof Ref && this.xref) {
@@ -176,16 +176,16 @@ class Dict {
176176

177177
// No dereferencing.
178178
getRaw(key) {
179-
return this._map[key];
179+
return this._map.get(key);
180180
}
181181

182182
getKeys() {
183-
return Object.keys(this._map);
183+
return [...this._map.keys()];
184184
}
185185

186186
// No dereferencing.
187187
getRawValues() {
188-
return Object.values(this._map);
188+
return [...this._map.values()];
189189
}
190190

191191
set(key, value) {
@@ -196,16 +196,21 @@ class Dict {
196196
unreachable('Dict.set: The "value" cannot be undefined.');
197197
}
198198
}
199-
this._map[key] = value;
199+
this._map.set(key, value);
200200
}
201201

202202
has(key) {
203-
return this._map[key] !== undefined;
203+
return this._map.has(key);
204204
}
205205

206-
forEach(callback) {
207-
for (const key in this._map) {
208-
callback(key, this.get(key));
206+
*[Symbol.iterator]() {
207+
for (const [key, value] of this._map) {
208+
yield [
209+
key,
210+
value instanceof Ref && this.xref
211+
? this.xref.fetch(value, this.suppressEncryption)
212+
: value,
213+
];
209214
}
210215
}
211216

@@ -226,7 +231,7 @@ class Dict {
226231
if (!(dict instanceof Dict)) {
227232
continue;
228233
}
229-
for (const [key, value] of Object.entries(dict._map)) {
234+
for (const [key, value] of dict._map) {
230235
let property = properties.get(key);
231236
if (property === undefined) {
232237
property = [];
@@ -242,20 +247,20 @@ class Dict {
242247
}
243248
for (const [name, values] of properties) {
244249
if (values.length === 1 || !(values[0] instanceof Dict)) {
245-
mergedDict._map[name] = values[0];
250+
mergedDict._map.set(name, values[0]);
246251
continue;
247252
}
248253
const subDict = new Dict(xref);
249254

250255
for (const dict of values) {
251-
for (const [key, value] of Object.entries(dict._map)) {
252-
if (subDict._map[key] === undefined) {
253-
subDict._map[key] = value;
256+
for (const [key, value] of dict._map) {
257+
if (!subDict._map.has(key)) {
258+
subDict._map.set(key, value);
254259
}
255260
}
256261
}
257262
if (subDict.size > 0) {
258-
mergedDict._map[name] = subDict;
263+
mergedDict._map.set(name, subDict);
259264
}
260265
}
261266
properties.clear();

src/core/struct_tree.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,11 @@ class StructTreeRoot {
6262
if (!(roleMapDict instanceof Dict)) {
6363
return;
6464
}
65-
roleMapDict.forEach((key, value) => {
66-
if (!(value instanceof Name)) {
67-
return;
65+
for (const [key, value] of roleMapDict) {
66+
if (value instanceof Name) {
67+
this.roleMap.set(key, value.name);
6868
}
69-
this.roleMap.set(key, value.name);
70-
});
69+
}
7170
}
7271

7372
static async canCreateStructureTree({

src/core/worker.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -688,11 +688,11 @@ class WorkerMessageHandler {
688688
const infoObj = Object.create(null);
689689
const xrefInfo = xref.trailer.get("Info") || null;
690690
if (xrefInfo instanceof Dict) {
691-
xrefInfo.forEach((key, value) => {
691+
for (const [key, value] of xrefInfo) {
692692
if (typeof value === "string") {
693693
infoObj[key] = stringToPDFString(value);
694694
}
695-
});
695+
}
696696
}
697697

698698
newXrefInfo = {

src/pdf.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ const pdfjsVersion =
8080
const pdfjsBuild =
8181
typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0;
8282

83-
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
83+
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING || GENERIC")) {
8484
globalThis.pdfjsTestingUtils = {
8585
HighlightOutliner,
8686
};

test/unit/primitives_spec.js

+6-11
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,12 @@ describe("primitives", function () {
221221
expect(values[2]).toEqual(testFontFile);
222222
});
223223

224-
it("should callback for each stored key", function () {
225-
const callbackSpy = jasmine.createSpy("spy on callback in dictionary");
226-
227-
dictWithManyKeys.forEach(callbackSpy);
228-
229-
expect(callbackSpy).toHaveBeenCalled();
230-
const callbackSpyCalls = callbackSpy.calls;
231-
expect(callbackSpyCalls.argsFor(0)).toEqual(["FontFile", testFontFile]);
232-
expect(callbackSpyCalls.argsFor(1)).toEqual(["FontFile2", testFontFile2]);
233-
expect(callbackSpyCalls.argsFor(2)).toEqual(["FontFile3", testFontFile3]);
234-
expect(callbackSpyCalls.count()).toEqual(3);
224+
it("should iterate through each stored key", function () {
225+
expect([...dictWithManyKeys]).toEqual([
226+
["FontFile", testFontFile],
227+
["FontFile2", testFontFile2],
228+
["FontFile3", testFontFile3],
229+
]);
235230
});
236231

237232
it("should handle keys pointing to indirect objects, both sync and async", async function () {

0 commit comments

Comments
 (0)