Optimize PathSet for V8
PathSet.find has been rewritten without using ES6 generators in order to avoid V8's TurboFan/Crankshift optimization bailout.
This commit is contained in:
1 parent
a48984b909
commit
3223e9733a
5 files changed
+115
-138
No files matched your search
+91
-103
@@ -31,60 +31,28 @@ class PathSet {
|
||||
|
||||
|
||||
add(path) {
|
||||
let sets;
|
||||
let p = this.get(path);
|
||||
|
||||
if (p)
|
||||
return p;
|
||||
|
||||
if (!this.lengthIndex[path.length])
|
||||
this.lengthIndex[path.length] = new Set();
|
||||
else if (this.lengthIndex[path.length].has(path))
|
||||
return path;
|
||||
else
|
||||
sets = [this.lengthIndex[path.length]];
|
||||
|
||||
for (let i = 0; i < path.length; ++ i) {
|
||||
let fragment = path[i];
|
||||
|
||||
if (!fragment)
|
||||
throw new Error('All array elements must be non-empty string');
|
||||
|
||||
if (!this.fragmentIndex[i]) {
|
||||
sets = null;
|
||||
this.fragmentIndex[i] = {}
|
||||
}
|
||||
|
||||
if (!this.fragmentIndex[i][fragment]) {
|
||||
sets = null;
|
||||
this.fragmentIndex[i][fragment] = new Set();
|
||||
}
|
||||
else if (sets)
|
||||
sets.push(this.fragmentIndex[i][fragment])
|
||||
}
|
||||
|
||||
if (sets) {
|
||||
sets.sort(function(a, b) {
|
||||
return a.size - b.size;
|
||||
});
|
||||
|
||||
var smallest = sets.shift();
|
||||
for (let p of smallest) {
|
||||
for (let set of sets) {
|
||||
if (!set.has(p)) {
|
||||
p = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p)
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
var wildcard = 0;
|
||||
this.lengthIndex[path.length].add(path);
|
||||
|
||||
let wildcard = 0;
|
||||
for (let i = 0; i < path.length; ++ i) {
|
||||
let fragment = path[i];
|
||||
if (fragment === '*')
|
||||
if (fragment === "*")
|
||||
wildcard |= 1 << i;
|
||||
|
||||
if (!this.fragmentIndex[i])
|
||||
this.fragmentIndex[i] = {};
|
||||
|
||||
if (!this.fragmentIndex[i][fragment])
|
||||
this.fragmentIndex[i][fragment] = new Set();
|
||||
|
||||
this.fragmentIndex[i][fragment].add(path);
|
||||
}
|
||||
|
||||
@@ -97,90 +65,110 @@ class PathSet {
|
||||
}
|
||||
|
||||
|
||||
*subset(path, depth) {
|
||||
var p = path.slice();
|
||||
for (let i = 0; i < p.length; ++ i)
|
||||
if (p[i] === '*')
|
||||
p[i] = null;
|
||||
yield* this.find(p, depth || 0, false);
|
||||
}
|
||||
get(pattern) {
|
||||
if (!this.lengthIndex[pattern.length])
|
||||
return null;
|
||||
|
||||
if (this.lengthIndex[pattern.length].has(pattern))
|
||||
return pattern;
|
||||
|
||||
*superset(path, depth) {
|
||||
yield* this.find(path, depth || 0, true)
|
||||
}
|
||||
let sets = [];
|
||||
|
||||
|
||||
*all(path, depth) {
|
||||
var p = path.slice();
|
||||
for (let i = 0; i < p.length; ++ i)
|
||||
if (p[i] === '*')
|
||||
p[i] = null;
|
||||
yield* this.find(p, depth || 0, true);
|
||||
}
|
||||
|
||||
|
||||
*find(pattern, depth, wildcard) {
|
||||
var sets = [];
|
||||
|
||||
var s = [];
|
||||
for (let i = pattern.length + depth; i >= pattern.length; -- i) {
|
||||
if (this.lengthIndex[i])
|
||||
s.push(this.lengthIndex[i]);
|
||||
}
|
||||
|
||||
if (!s.length)
|
||||
return;
|
||||
|
||||
sets.push(s);
|
||||
sets.push(this.lengthIndex[pattern.length]);
|
||||
|
||||
for (let i = 0; i < pattern.length; ++ i) {
|
||||
if (pattern[i]) {
|
||||
let fragment = pattern[i];
|
||||
let s = [];
|
||||
if (!this.fragmentIndex[i])
|
||||
return null;
|
||||
|
||||
if (this.fragmentIndex[i]) {
|
||||
if (this.fragmentIndex[i][fragment])
|
||||
s.push(this.fragmentIndex[i][fragment]);
|
||||
let fragment = pattern[i];
|
||||
|
||||
if (wildcard && fragment != '*' && this.fragmentIndex[i]['*'])
|
||||
s.push(this.fragmentIndex[i]['*'])
|
||||
}
|
||||
if (!this.fragmentIndex[i][fragment])
|
||||
return null;
|
||||
|
||||
if (!s.length)
|
||||
return;
|
||||
|
||||
sets.push(s);
|
||||
}
|
||||
sets.push(this.fragmentIndex[i][fragment]);
|
||||
}
|
||||
|
||||
sets.sort(function(a, b) {
|
||||
return a.size - b.size;
|
||||
});
|
||||
|
||||
let smallestSet = sets.shift();
|
||||
for (let path of smallestSet) {
|
||||
for (let s of sets) {
|
||||
if (!s.has(path)) {
|
||||
path = null;
|
||||
break
|
||||
}
|
||||
}
|
||||
if (path)
|
||||
return path;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
find(pattern, superset = false, subset = false, depth = pattern.length) {
|
||||
let res = [];
|
||||
let groups = [[]];
|
||||
|
||||
for (let i = pattern.length; i <= depth; ++ i)
|
||||
if (this.lengthIndex[i])
|
||||
groups[0].push(this.lengthIndex[i]);
|
||||
|
||||
if (!groups[0].length)
|
||||
return res;
|
||||
|
||||
for (let i = 0; i < pattern.length; ++ i) {
|
||||
if (!this.fragmentIndex[i])
|
||||
return res;
|
||||
|
||||
let fragment = pattern[i];
|
||||
|
||||
if (fragment === "*" && subset)
|
||||
continue;
|
||||
|
||||
let g = [];
|
||||
|
||||
if (this.fragmentIndex[i][fragment])
|
||||
g.push(this.fragmentIndex[i][fragment]);
|
||||
|
||||
if (fragment !== "*" && superset && this.fragmentIndex[i]["*"])
|
||||
g.push(this.fragmentIndex[i]["*"]);
|
||||
|
||||
if (!g.length)
|
||||
return res;
|
||||
|
||||
groups.push(g);
|
||||
}
|
||||
|
||||
groups.sort(function(a, b) {
|
||||
return a.reduce(function(prev, cur) {return prev + cur.size;}, 0) -
|
||||
b.reduce(function(prev, cur) {return prev + cur.size;}, 0);
|
||||
});
|
||||
|
||||
var smallest = sets.shift();
|
||||
for (let pp of smallest) {
|
||||
for (let p of pp) {
|
||||
for (let ss of sets) {
|
||||
let smallestGroup = groups.shift();
|
||||
for (let set of smallestGroup) {
|
||||
for (let path of set) {
|
||||
for (let group of groups) {
|
||||
let found = false;
|
||||
for (let s of ss) {
|
||||
if (s.has(p)) {
|
||||
for (let s of group) {
|
||||
if (s.has(path)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
p = null;
|
||||
path = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p)
|
||||
yield p;
|
||||
if (path)
|
||||
res.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user