commenting is done
This commit is contained in:
parent
34afff74a0
commit
9f38e17752
1 changed files with 41 additions and 27 deletions
68
Map.hpp
68
Map.hpp
|
|
@ -214,6 +214,10 @@ template <typename Key_T, typename Mapped_T> class Map {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// erase_child fully deletes the child node, this includes
|
||||||
|
// having the child's memory be freed so any data the child holds
|
||||||
|
// which is needed for future calculations must be gathered before
|
||||||
|
// it is erased
|
||||||
void erase_child(Node *n) { this->erase_child(this->which_child(n)); }
|
void erase_child(Node *n) { this->erase_child(this->which_child(n)); }
|
||||||
void erase_child(Direction dir) {
|
void erase_child(Direction dir) {
|
||||||
// if the child being erased is the min or the max we need to update
|
// if the child being erased is the min or the max we need to update
|
||||||
|
|
@ -754,23 +758,22 @@ private:
|
||||||
|
|
||||||
// the hard case of removing a black leaf node in a red black tree
|
// the hard case of removing a black leaf node in a red black tree
|
||||||
// All other cases are handled in core_erase
|
// All other cases are handled in core_erase
|
||||||
void hard_erase(Node *n) {
|
void hard_erase(Node *target) {
|
||||||
assert(n->parent);
|
assert(target->parent);
|
||||||
Node *parent = n->parent;
|
|
||||||
Direction dir = parent->which_child(n);
|
|
||||||
parent->erase_child(n);
|
|
||||||
|
|
||||||
// case 1 should be handled first for all but the first loop
|
// parent and direction need to be gathered here due to imminent
|
||||||
// so it's skipped in the first loop
|
// deletion of the target from memory
|
||||||
goto skip;
|
Node *parent = target->parent;
|
||||||
|
Direction dir = parent->which_child(target);
|
||||||
|
|
||||||
|
// Note: target is now deallocated and should not be used again
|
||||||
|
// until we reassign it in the loop
|
||||||
|
parent->erase_child(target);
|
||||||
|
|
||||||
|
// refer to
|
||||||
|
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#Notes_to_the_delete_diagrams
|
||||||
|
// for more details on what all of this is ultimately doing
|
||||||
while (true) {
|
while (true) {
|
||||||
parent = n->parent;
|
|
||||||
if (parent == nullptr) {
|
|
||||||
// we're at root we're done (case 1)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dir = parent->which_child(n);
|
|
||||||
skip:
|
|
||||||
Color par_color = parent->color;
|
Color par_color = parent->color;
|
||||||
|
|
||||||
Node *sibling = parent->child(!dir);
|
Node *sibling = parent->child(!dir);
|
||||||
|
|
@ -782,15 +785,11 @@ private:
|
||||||
Color close_color = close ? close->color : Color::Black;
|
Color close_color = close ? close->color : Color::Black;
|
||||||
Color distant_color = distant ? distant->color : Color::Black;
|
Color distant_color = distant ? distant->color : Color::Black;
|
||||||
|
|
||||||
// Macro is used for simplicity and avoiding repetition
|
// Macro is used for avoiding repetition
|
||||||
#define redcheck(v) if ((v) == Color::Red)
|
#define redcheck(v) if ((v) == Color::Red)
|
||||||
|
|
||||||
// TODO: continue comment writing here
|
|
||||||
// it kinda sucks but I think that goto is genuinely the best solution
|
|
||||||
// here, making methods for cases 4,5 and 6 is a lot of unneeded
|
|
||||||
// bookkeeping
|
|
||||||
redcheck(sibling_color) {
|
redcheck(sibling_color) {
|
||||||
// case 3
|
// Case 3
|
||||||
if (parent->parent) {
|
if (parent->parent) {
|
||||||
parent->rotate(dir);
|
parent->rotate(dir);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -801,6 +800,14 @@ private:
|
||||||
sibling = close;
|
sibling = close;
|
||||||
|
|
||||||
distant = sibling->child(!dir);
|
distant = sibling->child(!dir);
|
||||||
|
// Checking after conditions
|
||||||
|
// GOTO is used due to heavy sharing of state between
|
||||||
|
// cases which would be annoying to pass as procedure
|
||||||
|
// argument(s) especially for handling the various places
|
||||||
|
// cases 4, 5 and 6 show up at
|
||||||
|
// In theory this could've been better handled as an
|
||||||
|
// explicit FSM object but it was easier to do this via
|
||||||
|
// GOTO in the moment
|
||||||
if (distant != nullptr && distant->color == Color::Red) {
|
if (distant != nullptr && distant->color == Color::Red) {
|
||||||
goto case_6;
|
goto case_6;
|
||||||
}
|
}
|
||||||
|
|
@ -811,7 +818,6 @@ private:
|
||||||
goto case_4;
|
goto case_4;
|
||||||
}
|
}
|
||||||
else redcheck(close_color) {
|
else redcheck(close_color) {
|
||||||
// case 5
|
|
||||||
case_5:
|
case_5:
|
||||||
assert(sibling);
|
assert(sibling);
|
||||||
assert(close);
|
assert(close);
|
||||||
|
|
@ -823,7 +829,6 @@ private:
|
||||||
goto case_6;
|
goto case_6;
|
||||||
}
|
}
|
||||||
else redcheck(distant_color) {
|
else redcheck(distant_color) {
|
||||||
// case 6
|
|
||||||
case_6:
|
case_6:
|
||||||
assert(parent);
|
assert(parent);
|
||||||
assert(sibling);
|
assert(sibling);
|
||||||
|
|
@ -840,7 +845,6 @@ private:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else redcheck(par_color) {
|
else redcheck(par_color) {
|
||||||
// case 4
|
|
||||||
case_4:
|
case_4:
|
||||||
assert(sibling);
|
assert(sibling);
|
||||||
sibling->color = Color::Red;
|
sibling->color = Color::Red;
|
||||||
|
|
@ -848,12 +852,22 @@ private:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// case 2
|
// Case 2: we need to keep cranking through
|
||||||
|
// the motions backtracking up the tree so we
|
||||||
|
// reassign target appropriately after recoloring
|
||||||
assert(sibling);
|
assert(sibling);
|
||||||
sibling->color = Color::Red;
|
sibling->color = Color::Red;
|
||||||
n = parent;
|
target = parent;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
// Case 1: After backtracking up the tree we may reach the root
|
||||||
|
// node in which case we've finished resetting our invariants
|
||||||
|
// if we aren't at the root node this code will update parent
|
||||||
|
// and dir to appropriate values
|
||||||
|
parent = target->parent;
|
||||||
|
if (parent == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dir = parent->which_child(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue