// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0x40, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
cmpq $0x0, -0x10(%rbp)
je 0xd1c9
jmp 0xd1e8
leaq 0x90a2(%rip), %rdi      # 0x16272
leaq 0x9025(%rip), %rsi      # 0x161fc
movl $0x223, %edx            # imm = 0x223
leaq 0x9277(%rip), %rcx      # 0x1645a
callq 0x1060
cmpq $0x0, -0x18(%rbp)
je 0xd1f1
jmp 0xd210
leaq 0x90f9(%rip), %rdi      # 0x162f1
leaq 0x8ffd(%rip), %rsi      # 0x161fc
movl $0x224, %edx            # imm = 0x224
leaq 0x924f(%rip), %rcx      # 0x1645a
callq 0x1060
movq $0x0, -0x20(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
je 0xd3bc
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq -0x18(%rbp), %rdi
movq -0x28(%rbp), %rcx
movq (%rcx), %rsi
callq *%rax
movl %eax, -0x3c(%rbp)
cmpl $0x0, -0x3c(%rbp)
jge 0xd265
movq -0x28(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x28(%rbp)
jmp 0xd3b7
cmpl $0x0, -0x3c(%rbp)
jle 0xd284
movq -0x28(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x28(%rbp)
jmp 0xd3b5
movq -0x28(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x38(%rbp)
movq -0x28(%rbp), %rax
cmpq $0x0, 0x8(%rax)
je 0xd2f0
movq -0x28(%rbp), %rax
cmpq $0x0, 0x10(%rax)
je 0xd2f0
movq -0x28(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
cmpq $0x0, 0x8(%rax)
je 0xd2e2
movq -0x28(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x28(%rbp)
jmp 0xd2c1
movq -0x28(%rbp), %rax
movq (%rax), %rcx
movq -0x30(%rbp), %rax
movq %rcx, (%rax)
movq -0x28(%rbp), %rax
cmpq $0x0, 0x8(%rax)
jne 0xd358
cmpq $0x0, -0x20(%rbp)
jne 0xd313
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rcx
movq -0x10(%rbp), %rax
movq %rcx, (%rax)
jmp 0xd345
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
cmpq -0x28(%rbp), %rax
jne 0xd333
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x8(%rax)
jmp 0xd343
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x10(%rax)
jmp 0xd345
movq -0x28(%rbp), %rdi
callq 0x10e0
movq -0x38(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0xd3c4
cmpq $0x0, -0x20(%rbp)
jne 0xd370
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0x10(%rbp), %rax
movq %rcx, (%rax)
jmp 0xd3a2
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
cmpq -0x28(%rbp), %rax
jne 0xd390
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x8(%rax)
jmp 0xd3a0
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x10(%rax)
jmp 0xd3a2
movq -0x28(%rbp), %rdi
callq 0x10e0
movq -0x38(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0xd3c4
jmp 0xd3b7
jmp 0xd223
movq $0x0, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x40, %rsp
popq %rbp
retq
nop