// File: /workspace/github_c_makefile_star2_O2/CarlosLunaMota[P]BinaryTrees/BinaryTrees.c
// Function: bs_tree_remove
void *bs_tree_remove(bs_tree *tree, const void *data) {

    bs_node *parent;
    bs_node *node;
    bs_node *old_node;
    void    *old_data;
    int      comp;

    // Sanity Checks:
    assert(tree != NULL);
    assert(data != NULL);

    // Search the node to delete:
    parent   = NULL;
    node     = tree->root;
    while (node != NULL) {

        // Compare data:
        comp = (tree->comp)(data, node->data);

        // Data is smaller:
        if (comp < 0) {
            parent = node;
            node   = node->left;
        }

        // Data is bigger:
        else if (comp > 0) {
            parent = node;
            node   = node->right;
        }

        // We have found the node:
        else {

            old_data = node->data;

            // If node has both subtrees we must do some extra work:
            if (node->left != NULL && node->right != NULL) {

                // Remember the place and keep going down to find the successor
                old_node = node;                // Here we are looking for the
                parent   = node;                // inorder successor of node
                node     = node->right;         // but if we exchange left for
                while (node->left != NULL) {    // right (and viceversa) on
                    parent = node;              // thisblock of code we could
                    node   = node->left;        // implement the equaly valid
                }                               // predecesor version of remove

                // Once we find the "succesor" of "old_node"
                // we just move the data pointer and remove
                // the current "node":
                old_node->data = node->data;
            }

            // At this point we are sure that "node" has, at least,
            // one empty subtree, which greatly simplifies the removal:

            // Easy case 1: node->left is NULL
            if (node->left == NULL) {
                if      (parent       == NULL) { tree->root    = node->right; }
                else if (parent->left == node) { parent->left  = node->right; }
                else                           { parent->right = node->right; }
                free(node);
                return old_data;
            }

            // Easy case 2: node->right is NULL
            else {
                if      (parent       == NULL) { tree->root    = node->left; }
                else if (parent->left == node) { parent->left  = node->left; }
                else                           { parent->right = node->left; }
                free(node);
                return old_data;
            }
        }
    }
    return NULL;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
testq %rdi, %rdi
je 0x7bd9
movq %rsi, %r12
testq %rsi, %rsi
je 0x7bf8
movq %rdi, %r15
pushq $0x8
popq %rbp
pushq $0x10
popq %rbx
movq %rdi, %rcx
xorl %r13d, %r13d
movq (%rcx), %r14
testq %r14, %r14
je 0x7b4d
movq (%r14), %rsi
movq %r12, %rdi
callq *0x8(%r15)
movq %rbp, %rcx
testl %eax, %eax
js 0x7b45
movq %rbx, %rcx
je 0x7b51
addq %r14, %rcx
movq %r14, %r13
jmp 0x7b27
xorl %ebx, %ebx
jmp 0x7bc7
movq (%r14), %rbx
movq 0x8(%r14), %rax
testq %rax, %rax
je 0x7b80
movq 0x10(%r14), %rcx
testq %rcx, %rcx
je 0x7b98
movq %r14, %rax
movq %rax, %r13
movq %rcx, %rax
movq 0x8(%rcx), %rcx
testq %rcx, %rcx
jne 0x7b69
movq (%rax), %rcx
movq %rcx, (%r14)
jmp 0x7b88
testq %r13, %r13
je 0x7bb8
movq %r14, %rax
movq 0x10(%rax), %rcx
cmpq %rax, 0x8(%r13)
je 0x7baf
movq %rcx, 0x10(%r13)
jmp 0x7bb3
testq %r13, %r13
je 0x7bbc
leaq 0x8(%r13), %rcx
leaq 0x10(%r13), %r15
cmpq %r14, 0x8(%r13)
cmoveq %rcx, %r15
jmp 0x7bbc
movq %rcx, 0x8(%r13)
movq %rax, %r14
jmp 0x7bbf
movq 0x10(%r14), %rax
movq %rax, (%r15)
movq %r14, %rdi
callq 0x1120
movq %rbx, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x56a3(%rip), %rdi      # 0xd283
leaq 0x5626(%rip), %rsi      # 0xd20d
leaq 0x587d(%rip), %rcx      # 0xd46b
movl $0x223, %edx            # imm = 0x223
callq 0x1080
leaq 0x5703(%rip), %rdi      # 0xd302
leaq 0x5607(%rip), %rsi      # 0xd20d
leaq 0x585e(%rip), %rcx      # 0xd46b
movl $0x224, %edx            # imm = 0x224
callq 0x1080