Skip to content

Commit 28d9589

Browse files
authored
Merge pull request #13154 from webpack/perf/iterable
cheaper getIterator
2 parents 4c55729 + c7b1471 commit 28d9589

1 file changed

Lines changed: 87 additions & 57 deletions

File tree

lib/FileSystemInfo.js

Lines changed: 87 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,92 @@ const DONE_ITERATOR_RESULT = new Set().keys().next();
7777
// Tsh = Timestamp + Hash
7878
// Tshs = Timestamp + Hash combinations
7979

80+
class SnapshotIterator {
81+
constructor(next) {
82+
this.next = next;
83+
}
84+
}
85+
86+
class SnapshotIterable {
87+
constructor(snapshot, getMaps) {
88+
this.snapshot = snapshot;
89+
this.getMaps = getMaps;
90+
}
91+
92+
[Symbol.iterator]() {
93+
let state = 0;
94+
/** @type {IterableIterator<string>} */
95+
let it;
96+
/** @type {(Snapshot) => (Map<string, any> | Set<string>)[]} */
97+
let getMaps;
98+
/** @type {(Map<string, any> | Set<string>)[]} */
99+
let maps;
100+
/** @type {Snapshot} */
101+
let snapshot;
102+
let queue;
103+
return new SnapshotIterator(() => {
104+
for (;;) {
105+
switch (state) {
106+
case 0:
107+
snapshot = this.snapshot;
108+
getMaps = this.getMaps;
109+
maps = getMaps(snapshot);
110+
state = 1;
111+
/* falls through */
112+
case 1:
113+
if (maps.length > 0) {
114+
const map = maps.pop();
115+
if (map !== undefined) {
116+
it = map.keys();
117+
state = 2;
118+
} else {
119+
break;
120+
}
121+
} else {
122+
state = 3;
123+
break;
124+
}
125+
/* falls through */
126+
case 2: {
127+
const result = it.next();
128+
if (!result.done) return result;
129+
state = 1;
130+
break;
131+
}
132+
case 3: {
133+
const children = snapshot.children;
134+
if (children !== undefined) {
135+
if (children.size === 1) {
136+
// shortcut for a single child
137+
// avoids allocation of queue
138+
for (const child of children) snapshot = child;
139+
maps = getMaps(snapshot);
140+
state = 1;
141+
break;
142+
}
143+
if (queue === undefined) queue = [];
144+
for (const child of children) {
145+
queue.push(child);
146+
}
147+
}
148+
if (queue !== undefined && queue.length > 0) {
149+
snapshot = queue.pop();
150+
maps = getMaps(snapshot);
151+
state = 1;
152+
break;
153+
} else {
154+
state = 4;
155+
}
156+
}
157+
/* falls through */
158+
case 4:
159+
return DONE_ITERATOR_RESULT;
160+
}
161+
}
162+
});
163+
}
164+
}
165+
80166
class Snapshot {
81167
constructor() {
82168
this._flags = 0;
@@ -283,63 +369,7 @@ class Snapshot {
283369
* @returns {Iterable<string>} iterable
284370
*/
285371
_createIterable(getMaps) {
286-
let snapshot = this;
287-
return {
288-
[Symbol.iterator]() {
289-
let state = 0;
290-
/** @type {IterableIterator<string>} */
291-
let it;
292-
let maps = getMaps(snapshot);
293-
const queue = [];
294-
return {
295-
next() {
296-
for (;;) {
297-
switch (state) {
298-
case 0:
299-
if (maps.length > 0) {
300-
const map = maps.pop();
301-
if (map !== undefined) {
302-
it = map.keys();
303-
state = 1;
304-
} else {
305-
break;
306-
}
307-
} else {
308-
state = 2;
309-
break;
310-
}
311-
/* falls through */
312-
case 1: {
313-
const result = it.next();
314-
if (!result.done) return result;
315-
state = 0;
316-
break;
317-
}
318-
case 2: {
319-
const children = snapshot.children;
320-
if (children !== undefined) {
321-
for (const child of children) {
322-
queue.push(child);
323-
}
324-
}
325-
if (queue.length > 0) {
326-
snapshot = queue.pop();
327-
maps = getMaps(snapshot);
328-
state = 0;
329-
break;
330-
} else {
331-
state = 3;
332-
}
333-
}
334-
/* falls through */
335-
case 3:
336-
return DONE_ITERATOR_RESULT;
337-
}
338-
}
339-
}
340-
};
341-
}
342-
};
372+
return new SnapshotIterable(this, getMaps);
343373
}
344374

345375
/**

0 commit comments

Comments
 (0)