triePruneBranch; preparation for echo-cancellation of SCNs

This commit is contained in:
Tony Garnock-Jones 2016-02-11 22:51:26 -05:00
parent d29fb17ad6
commit e9b431c50f
2 changed files with 94 additions and 26 deletions

View File

@ -423,35 +423,38 @@ function subtract(o1, o2, subtractSuccessesOpt) {
r2.forEach(function (val, key) { examineKey(key) });
}
// Here, the target is complete. If it has only two keys,
// one wild and one is_keyClose, and wild's continuation
// is a $WildcardSequence and the other continuation is
// identical to the sequence's continuation, then replace
// the whole thing with a nested $WildcardSequence.
// (We know w === rlookup(target, __) from before.)
//
// TODO: I suspect actually this applies even if there are
// more than two keys, so long as all their continuations
// are identical and there's at least one is_keyClose
// alongside a wild.
if (target.size === 2) {
var finalW = rlookup(target, __);
if (finalW instanceof $WildcardSequence) {
target.forEach(function (k, key) {
if ((key !== __) && is_keyClose(key)) {
if (Immutable.is(k, finalW.trie)) {
target = finalW;
return false; // terminate the iteration early
}
}
});
}
}
return target;
return collapseWildcardSequences(target);
}
}
function collapseWildcardSequences(target) {
// Here, the target is complete. If it has only two keys,
// one wild and one is_keyClose, and wild's continuation
// is a $WildcardSequence and the other continuation is
// identical to the sequence's continuation, then replace
// the whole thing with a nested $WildcardSequence.
// (We know w === rlookup(target, __) from before.)
//
// TODO: I suspect actually this applies even if there are
// more than two keys, so long as all their continuations
// are identical and there's at least one is_keyClose
// alongside a wild.
if (target.size === 2) {
var finalW = rlookup(target, __);
if (finalW instanceof $WildcardSequence) {
target.forEach(function (k, key) {
if ((key !== __) && is_keyClose(key)) {
if (Immutable.is(k, finalW.trie)) {
target = finalW;
return false; // terminate the iteration early
}
}
});
}
}
return target;
}
// Returns null on failed match, otherwise the appropriate success
// value contained in the trie r.
function matchValue(r, v) {
@ -616,6 +619,20 @@ function appendTrie(m, mTailFn) {
}
}
function triePruneBranch(m, keys) {
if (keys.isEmpty()) return emptyTrie;
if (is_emptyTrie(m)) return emptyTrie;
if (m instanceof $WildcardSequence) {
return collapseWildcardSequences(triePruneBranch(expandWildseq(m.trie), keys));
}
if (m instanceof $Success) return m;
var key = keys.first();
var rest = keys.shift();
return rupdate(m, key, triePruneBranch(rlookupWild(m, key), rest));
}
function trieStep(m, key) {
if (is_emptyTrie(m)) return emptyTrie;
if (m instanceof $WildcardSequence) return (is_keyClose(key) ? m.trie : m);
@ -1006,6 +1023,7 @@ module.exports.subtract = subtract;
module.exports.matchValue = matchValue;
module.exports.matchTrie = matchTrie;
module.exports.appendTrie = appendTrie;
module.exports.triePruneBranch = triePruneBranch;
module.exports.trieStep = trieStep;
module.exports.relabel = relabel;
module.exports.compileProjection = compileProjection;

View File

@ -439,3 +439,53 @@ describe('intersect', function () {
checkPrettyTrie(r.intersect(r.subtract(x, y), y), ['::: nothing']);
});
});
describe('triePruneBranch', function () {
it('should not affect empty trie', function () {
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List(["x"])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(r.emptyTrie, Immutable.List([r.SOA, "x"])), ['::: nothing']);
});
it('should leave a hole in a full trie', function () {
var full = r.compilePattern(true, r.__);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([r.SOA])),
[' ★ >{true}',
' <::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List(["x"])),
[' ★ >{true}',
' "x"::: nothing']);
checkPrettyTrie(r.triePruneBranch(full, Immutable.List([r.SOA, "x"])),
[' ★ >{true}',
' < ★...> >{true}',
' > >{true}',
' "x"::: nothing']);
});
it('should prune in a finite tree and leave the rest alone', function () {
var A = r.compilePattern(true, ["y"])
var B = r.union(r.compilePattern(true, ["x"]), A);
var C = r.union(r.compilePattern(true, "z"), B);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List(["z"])), [' < "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List(["z"])), [' < "x" > >{true}',
' "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List(["z"])), [' < "x" > >{true}',
' "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([r.SOA])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([r.SOA])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([r.SOA])), [' "z" >{true}']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([r.SOA, "x"])), [' < "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([r.SOA, "x"])), [' < "y" > >{true}']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([r.SOA, "x"])), [' < "y" > >{true}',
' "z" >{true}']);
checkPrettyTrie(r.triePruneBranch(A, Immutable.List([r.SOA, "y"])), ['::: nothing']);
checkPrettyTrie(r.triePruneBranch(B, Immutable.List([r.SOA, "y"])), [' < "x" > >{true}']);
checkPrettyTrie(r.triePruneBranch(C, Immutable.List([r.SOA, "y"])), [' < "x" > >{true}',
' "z" >{true}']);
});
});