Fix perf issues with lazy sets

This commit is contained in:
Mark Molinaro 2021-06-17 18:42:39 +00:00 committed by GitHub
parent e5ccd070f6
commit b58e0799e2
2 changed files with 49 additions and 17 deletions

View File

@ -24,21 +24,17 @@ const merge = (targetSet, toMerge) => {
/**
* @template T
* @param {Set<Iterable<T>>} targetSet set where iterables should be added
* @param {Array<Iterable<T> | LazySet<T>>} toDeepMerge iterables or lazy set to be flattened
* @param {Array<LazySet<T>>} toDeepMerge lazy sets to be flattened
* @returns {void}
*/
const flatten = (targetSet, toDeepMerge) => {
for (const set of toDeepMerge) {
if (set instanceof LazySet) {
if (set._set.size > 0) targetSet.add(set._set);
if (set._needMerge) {
for (const mergedSet of set._toMerge) {
targetSet.add(mergedSet);
}
flatten(targetSet, set._toDeepMerge);
if (set._set.size > 0) targetSet.add(set._set);
if (set._needMerge) {
for (const mergedSet of set._toMerge) {
targetSet.add(mergedSet);
}
} else {
targetSet.add(set);
flatten(targetSet, set._toDeepMerge);
}
}
};
@ -58,7 +54,7 @@ class LazySet {
this._set = new Set(iterable);
/** @type {Set<Iterable<T>>} */
this._toMerge = new Set();
/** @type {Array<Iterable<T> | LazySet<T>>} */
/** @type {Array<LazySet<T>>} */
this._toDeepMerge = [];
this._needMerge = false;
this._deopt = false;
@ -76,6 +72,14 @@ class LazySet {
this._needMerge = false;
}
_isEmpty() {
return (
this._set.size === 0 &&
this._toMerge.size === 0 &&
this._toDeepMerge.length === 0
);
}
get size() {
if (this._needMerge) this._merge();
return this._set.size;
@ -101,13 +105,19 @@ class LazySet {
_set.add(item);
}
} else {
this._toDeepMerge.push(iterable);
this._needMerge = true;
// Avoid being too memory hungry
if (this._toDeepMerge.length > 100000) {
this._flatten();
if (this._toMerge.size > 100000) this._merge();
if (iterable instanceof LazySet) {
if (!iterable._isEmpty()) {
this._toDeepMerge.push(iterable);
this._needMerge = true;
if (this._toDeepMerge.length > 100000) {
this._flatten();
}
}
} else {
this._toMerge.add(iterable);
this._needMerge = true;
}
if (this._toMerge.size > 100000) this._merge();
}
return this;
}

22
test/LazySet.unittest.js Normal file
View File

@ -0,0 +1,22 @@
const LazySet = require("../lib/util/LazySet");
describe("LazySet", () => {
it("addAll", () => {
const a = new Set(["a"]);
const sut = new LazySet(a);
const empty = new LazySet([]);
expect(sut.size).toBe(1);
sut.addAll(empty);
expect(sut._toDeepMerge).toStrictEqual([]);
expect(sut.size).toBe(1);
const b = new Set(["b"]);
sut.addAll(b);
expect(sut._toMerge).toContain(b);
expect(sut.size).toBe(2);
const c = new LazySet(["c"]);
sut.addAll(c);
expect(sut._toDeepMerge).toContain(c);
expect(sut.size).toBe(3);
expect(sut._toDeepMerge).toStrictEqual([]);
});
});