\internal Remove node from Red-Black tree. Returns node that should be freed, but it doesn't have to be necessarily the `node` passed.
| 393 | //! Returns node that should be freed, but it doesn't have to be necessarily |
| 394 | //! the `node` passed. |
| 395 | static MemNode* vMemMgrRemoveNode(VMemMgr* self, MemNode* node) noexcept { |
| 396 | // False tree root. |
| 397 | RbNode head = { { nullptr, nullptr }, 0, 0 }; |
| 398 | |
| 399 | // Helpers. |
| 400 | RbNode* q = &head; |
| 401 | RbNode* p = nullptr; |
| 402 | RbNode* g = nullptr; |
| 403 | |
| 404 | // Found item. |
| 405 | RbNode* f = nullptr; |
| 406 | int dir = 1; |
| 407 | |
| 408 | // Set up. |
| 409 | q->node[1] = self->_root; |
| 410 | |
| 411 | // Search and push a red down. |
| 412 | while (q->node[dir]) { |
| 413 | int last = dir; |
| 414 | |
| 415 | // Update helpers. |
| 416 | g = p; |
| 417 | p = q; |
| 418 | q = q->node[dir]; |
| 419 | dir = q->mem < node->mem; |
| 420 | |
| 421 | // Save found node. |
| 422 | if (q == node) |
| 423 | f = q; |
| 424 | |
| 425 | // Push the red node down. |
| 426 | if (!rbIsRed(q) && !rbIsRed(q->node[dir])) { |
| 427 | if (rbIsRed(q->node[!dir])) { |
| 428 | p = p->node[last] = rbRotateSingle(q, dir); |
| 429 | } |
| 430 | else if (!rbIsRed(q->node[!dir])) { |
| 431 | RbNode* s = p->node[!last]; |
| 432 | |
| 433 | if (s) { |
| 434 | if (!rbIsRed(s->node[!last]) && !rbIsRed(s->node[last])) { |
| 435 | // Color flip. |
| 436 | p->red = 0; |
| 437 | s->red = 1; |
| 438 | q->red = 1; |
| 439 | } |
| 440 | else { |
| 441 | int dir2 = g->node[1] == p; |
| 442 | |
| 443 | if (rbIsRed(s->node[last])) |
| 444 | g->node[dir2] = rbRotateDouble(p, last); |
| 445 | else if (rbIsRed(s->node[!last])) |
| 446 | g->node[dir2] = rbRotateSingle(p, last); |
| 447 | |
| 448 | // Ensure correct coloring. |
| 449 | q->red = g->node[dir2]->red = 1; |
| 450 | g->node[dir2]->node[0]->red = 0; |
| 451 | g->node[dir2]->node[1]->red = 0; |
| 452 | } |
no test coverage detected