Avoid smearLevels inefficiency; instead, union after intersection

This commit is contained in:
Tony Garnock-Jones 2014-05-26 13:45:09 -04:00
parent 6f21190383
commit 00b92fdf1c
1 changed files with 58 additions and 33 deletions

View File

@ -1148,13 +1148,6 @@ function Routing(exports) {
}; };
}; };
function crossedGestaltLevelOp(op) {
return function (p1, p2) {
return new GestaltLevel(op(p1.subscriptions, p2.advertisements),
op(p1.advertisements, p2.subscriptions));
};
};
var emptyLevel = new GestaltLevel(emptyMatcher, emptyMatcher); var emptyLevel = new GestaltLevel(emptyMatcher, emptyMatcher);
var emptyMetaLevel = []; var emptyMetaLevel = [];
@ -1241,9 +1234,21 @@ function Routing(exports) {
return true; return true;
}; };
Gestalt.prototype.mapZip = function (other, lengthCombiner, f, function maybePushLevel(levels, i, level) {
levelsTransformer1, levelsTransformer2) if (!level.isEmpty()) {
{ while (levels.length < i) levels.push(emptyLevel);
levels.push(level);
}
}
function maybePushMetaLevel(metaLevels, i, metaLevel) {
if (metaLevel.length > 0) {
while (metaLevels.length < i) metaLevels.push(emptyMetaLevel);
metaLevels.push(metaLevel);
}
}
Gestalt.prototype.mapZip = function (other, lengthCombiner, f) {
var metaLevels = []; var metaLevels = [];
var mls1 = this.metaLevels; var mls1 = this.metaLevels;
var mls2 = other.metaLevels; var mls2 = other.metaLevels;
@ -1252,22 +1257,14 @@ function Routing(exports) {
var levels = []; var levels = [];
var ls1 = mls1[i] || emptyMetaLevel; var ls1 = mls1[i] || emptyMetaLevel;
var ls2 = mls2[i] || emptyMetaLevel; var ls2 = mls2[i] || emptyMetaLevel;
if (levelsTransformer1) ls1 = levelsTransformer1(ls1);
if (levelsTransformer2) ls2 = levelsTransformer2(ls2);
var nl = lengthCombiner(ls1.length, ls2.length); var nl = lengthCombiner(ls1.length, ls2.length);
for (var j = 0; j < nl; j++) { for (var j = 0; j < nl; j++) {
var p1 = ls1[j] || emptyLevel; var p1 = ls1[j] || emptyLevel;
var p2 = ls2[j] || emptyLevel; var p2 = ls2[j] || emptyLevel;
var p = f(p1, p2); var p = f(p1, p2);
if (!p.isEmpty()) { maybePushLevel(levels, j, p);
while (levels.length < j) levels.push(emptyLevel);
levels.push(p);
}
}
if (levels.length > 0) {
while (metaLevels.length < i) metaLevels.push(emptyMetaLevel);
metaLevels.push(levels);
} }
maybePushMetaLevel(metaLevels, i, levels);
} }
return new Gestalt(metaLevels); return new Gestalt(metaLevels);
}; };
@ -1289,12 +1286,10 @@ function Routing(exports) {
return arguments.length > 0 ? this.union1(gestaltUnion(arguments)) : this; return arguments.length > 0 ? this.union1(gestaltUnion(arguments)) : this;
}; };
// Returns ls, with one level dropped, and with the remaining // Accumulates matchers from higher-numbered levels into
// matchers "smeared" across lower levels. This could end up being // lower-numbered levels.
// reasonably expensive - possibly cache it? function telescopeLevels(levels) {
function smearLevels(levels) {
var result = shallowCopyArray(levels); var result = shallowCopyArray(levels);
if (result.length > 0) result.shift();
for (var i = result.length - 2; i >= 0; i--) { for (var i = result.length - 2; i >= 0; i--) {
result[i] = result[i] =
new GestaltLevel(union(result[i].subscriptions, result[i+1].subscriptions), new GestaltLevel(union(result[i].subscriptions, result[i+1].subscriptions),
@ -1303,10 +1298,38 @@ function Routing(exports) {
return result; return result;
}; };
Gestalt.prototype.telescoped = function () {
var mls = [];
for (var i = 0; i < this.metaLevels.length; i++) {
mls.push(telescopeLevels(this.metaLevels[i]));
}
return new Gestalt(mls);
};
Gestalt.prototype.filter = function (perspective) { Gestalt.prototype.filter = function (perspective) {
return this.mapZip(perspective, Math.min, crossedGestaltLevelOp(intersect), var metaLevels = [];
null, var mls1 = this.metaLevels;
smearLevels); var mls2 = perspective.metaLevels;
var nm = Math.min(mls1.length, mls2.length);
for (var i = 0; i < nm; i++) {
var levels = [];
var ls1 = mls1[i] || emptyMetaLevel;
var ls2 = mls2[i] || emptyMetaLevel;
var nl = Math.min(ls1.length, ls2.length - 1);
for (var j = 0; j < nl; j++) {
var p1 = ls1[j] || emptyLevel;
var subs = emptyMatcher;
var advs = emptyMatcher;
for (var k = j + 1; k < ls2.length; k++) {
var p2 = ls2[k] || emptyLevel;
subs = union(subs, intersect(p1.subscriptions, p2.advertisements));
advs = union(advs, intersect(p1.advertisements, p2.subscriptions));
}
maybePushLevel(levels, j, new GestaltLevel(subs, advs));
}
maybePushMetaLevel(metaLevels, i, levels);
}
return new Gestalt(metaLevels);
}; };
Gestalt.prototype.match = function (perspective) { Gestalt.prototype.match = function (perspective) {
@ -1314,13 +1337,15 @@ function Routing(exports) {
var nm = Math.min(this.metaLevels.length, perspective.metaLevels.length); var nm = Math.min(this.metaLevels.length, perspective.metaLevels.length);
for (var i = 0; i < nm; i++) { for (var i = 0; i < nm; i++) {
var ls1 = this.metaLevels[i] || emptyMetaLevel; var ls1 = this.metaLevels[i] || emptyMetaLevel;
var ls2 = smearLevels(perspective.metaLevels[i] || emptyMetaLevel); var ls2 = perspective.metaLevels[i] || emptyMetaLevel;
var nl = Math.min(ls1.length, ls2.length); var nl = Math.min(ls1.length, ls2.length - 1);
for (var j = 0; j < nl; j++) { for (var j = 0; j < nl; j++) {
var p1 = ls1[j] || emptyLevel; var p1 = ls1[j] || emptyLevel;
var p2 = ls2[j] || emptyLevel; for (var k = j + 1; k < ls2.length; k++) {
matchMatcher(p1.subscriptions, p2.advertisements, pids); var p2 = ls2[k] || emptyLevel;
matchMatcher(p1.advertisements, p2.subscriptions, pids); matchMatcher(p1.subscriptions, p2.advertisements, pids);
matchMatcher(p1.advertisements, p2.subscriptions, pids);
}
} }
} }
return setToArray(pids); return setToArray(pids);