rbyd-rr: Eagerly prune unreachable root alts
In a traditional B-tree/2-3-4 tree/red-black tree, balance is maintained
by enforcing a set of rules such that no operation changes the balance
of the tree. In such a ruleset, you quickly learn that the only way to
actually change the height of the tree is through the root, since the
root is the only node shared by all branches of the tree.
This is why B/2-3-4/red-black insert/removes usually end in "and then
if you hit the root of the tree, increase/decrease the height by one".
Our range removal algorithm is a bit different in that we aren't
guaranteed to reach the root, the requested range could be empty after
all, but we also aren't _prohibited_ from decreasing the height of the
tree if it only involves removing the root.
Removing the root still maintains the 2-3-4 structure and balance of our
tree.
---
This commit adds opportunistic root pruning to our set of possible
pruning conditions.
This also tweaks diverging-lower pruning to take advantage of root
pruning. Since we prune the entire diverging-lower path, we can pretend
diverging-lower alts are prunable roots up until we find the diverging
alt. This leads to a bit nicer code since root pruning is so simple.
This actually ended up revealing an issue with how we indirectly
trigger diverged pruning by triming diverging alts: Trimming works, but
we also need to zero any weight, or else later calculations get all
screwy...
I guess the extra coverage from reusing logic is a plus.
Code changes:
code stack
before: 34236 2864
after: 34256 (+0.1%) 2864 (+0.0%)
This commit is contained in:
@@ -2910,78 +2910,71 @@ again:;
|
||||
jump = branch - jump;
|
||||
lfs_size_t branch_ = branch + d;
|
||||
|
||||
// progress diverging state machine?
|
||||
if (!lfsr_d_isdiverged(d_state)) {
|
||||
// do bounds want to take different paths? begin diverging
|
||||
bool diverge
|
||||
= lfsr_tag_follow2(alt, weight,
|
||||
// do bounds want to take different paths? begin diverging
|
||||
if (!lfsr_d_isdiverged(d_state)
|
||||
&& (lfsr_tag_follow2(alt, weight,
|
||||
p_alts[0], p_weights[0],
|
||||
lower_rid, upper_rid,
|
||||
a_rid, a_tag)
|
||||
^ lfsr_tag_follow2(alt, weight,
|
||||
p_alts[0], p_weights[0],
|
||||
lower_rid, upper_rid,
|
||||
b_rid, b_tag);
|
||||
b_rid, b_tag))) {
|
||||
LFS_ASSERT(d_state != LFSR_D_NOTDIVERGING);
|
||||
|
||||
// skip common alts on lower pass and the diverging alt
|
||||
// itself on both paths
|
||||
if (d_state == LFSR_D_DIVERGINGLOWER || diverge) {
|
||||
LFS_ASSERT(d_state != LFSR_D_NOTDIVERGING);
|
||||
// transition to the diverged state
|
||||
//
|
||||
// note that if red alt diverged if would have been
|
||||
// caught on the previous pass
|
||||
d_state = lfsr_d_diverge(d_state);
|
||||
|
||||
if (lfsr_tag_follow2(
|
||||
alt, weight,
|
||||
if (lfsr_tag_follow2(
|
||||
alt, weight,
|
||||
p_alts[0], p_weights[0],
|
||||
lower_rid, upper_rid,
|
||||
a_rid, a_tag)) {
|
||||
lfsr_tag_flip2(
|
||||
&alt, &weight,
|
||||
p_alts[0], p_weights[0],
|
||||
lower_rid, upper_rid,
|
||||
a_rid, a_tag)) {
|
||||
lfsr_tag_flip2(
|
||||
&alt, &weight,
|
||||
p_alts[0], p_weights[0],
|
||||
lower_rid, upper_rid);
|
||||
lfs_swap32(&jump, &branch_);
|
||||
}
|
||||
lfsr_tag_trim2(
|
||||
alt, weight,
|
||||
p_alts[0], p_weights[0],
|
||||
&lower_rid, &upper_rid,
|
||||
&lower_tag, &upper_tag);
|
||||
|
||||
// transition to the diverged state
|
||||
//
|
||||
// note that if red alt diverged if would have been
|
||||
// caught on the previous pass
|
||||
if (diverge) {
|
||||
d_state = lfsr_d_diverge(d_state);
|
||||
|
||||
// stitch together diverged branches
|
||||
if (d_state == LFSR_D_DIVERGEDUPPER) {
|
||||
err = lfsr_rbyd_p_push(lfs, rbyd,
|
||||
p_alts, p_weights, p_jumps,
|
||||
LFSR_TAG_ALT(
|
||||
LFSR_TAG_LE,
|
||||
LFSR_TAG_B,
|
||||
d_tag),
|
||||
d_rid - lower_rid + weight,
|
||||
d_branch);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
branch = branch_;
|
||||
continue;
|
||||
lower_rid, upper_rid);
|
||||
lfs_swap32(&jump, &branch_);
|
||||
}
|
||||
lfsr_tag_trim2(
|
||||
alt, weight,
|
||||
p_alts[0], p_weights[0],
|
||||
&lower_rid, &upper_rid,
|
||||
&lower_tag, &upper_tag);
|
||||
|
||||
// stitch together diverged branches
|
||||
if (d_state == LFSR_D_DIVERGEDUPPER) {
|
||||
err = lfsr_rbyd_p_push(lfs, rbyd,
|
||||
p_alts, p_weights, p_jumps,
|
||||
LFSR_TAG_ALT(
|
||||
LFSR_TAG_LE,
|
||||
LFSR_TAG_B,
|
||||
d_tag),
|
||||
d_rid - lower_rid + weight,
|
||||
d_branch);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
branch = branch_;
|
||||
continue;
|
||||
}
|
||||
|
||||
// trim unreachable diverged alts so they end up pruned
|
||||
if (lfsr_d_isdiverged(d_state)
|
||||
if ((lfsr_d_isdiverged(d_state)
|
||||
&& (d_state == LFSR_D_DIVERGEDUPPER)
|
||||
^ lfsr_tag_isgt(alt)
|
||||
^ lfsr_tag_follow2(
|
||||
alt, weight,
|
||||
p_alts[0], p_weights[0],
|
||||
lower_rid, upper_rid,
|
||||
a_rid, a_tag)) {
|
||||
a_rid, a_tag))
|
||||
// this includes all diverging-lower alts
|
||||
|| d_state == LFSR_D_DIVERGINGLOWER) {
|
||||
if (lfsr_tag_follow2(
|
||||
alt, weight,
|
||||
p_alts[0], p_weights[0],
|
||||
@@ -2997,6 +2990,7 @@ again:;
|
||||
alt, weight,
|
||||
&lower_rid, &upper_rid,
|
||||
&lower_tag, &upper_tag);
|
||||
weight = 0;
|
||||
}
|
||||
|
||||
// prune?
|
||||
@@ -3034,8 +3028,13 @@ again:;
|
||||
branch_ = branch;
|
||||
lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps);
|
||||
|
||||
// make unreachable black alts alt-nevers, if we prune these
|
||||
// it would break the coloring of our tree
|
||||
// collapse unreachable _root_ alts
|
||||
} else if (!p_alts[0] && d_state != LFSR_D_DIVERGEDLOWER) {
|
||||
branch = branch_;
|
||||
continue;
|
||||
|
||||
// make unreachable non-root black alts alt-nevers, if we
|
||||
// prune these it would break the coloring of our tree
|
||||
} else {
|
||||
alt = LFSR_TAG_ALT(LFSR_TAG_LE, LFSR_TAG_B, 0);
|
||||
weight = 0;
|
||||
|
||||
Reference in New Issue
Block a user