// File: /workspace/github_cpp_makefile_star2_O3/shreyas-gopalakrishna[P]Concurrent-Skip-list/skip_list.cpp
// Function: SkipList::remove(int)
bool SkipList::remove(int key){
    // Initialization
    Node* victim = NULL;
    bool is_marked = false;
    int top_level = -1;

    // Initialization of references of the predecessors and successors
    vector<Node*> preds(max_level + 1); 
    vector<Node*> succs(max_level + 1);

    for (size_t i = 0; i < preds.size(); i++){
        preds[i] = NULL;
        succs[i] = NULL;
    }

    // Keep trying to delete the element from the list. In case predecessors and successors are changed,
    // this loop helps to try the delete again
    while(true){
        
        // Find the predecessors and successors of where the key to be deleted
        int found = find(key, preds, succs);

        // If found, select the node to delete. else return
        if(found != -1){
            victim = succs[found];
        }

        // If node not found and the node to be deleted is fully linked and not marked return
        if(is_marked | 
                (found != -1 &&
                (victim->fully_linked && victim->top_level == found && !(victim->marked))
                )
            ){
                // If not marked, the we lock the node and mark the node to delete
                if(!is_marked){
                    top_level = victim->top_level;
                    victim->lock();
                    if(victim->marked){
                        victim->unlock();
                        return false;
                    }
                    victim->marked = true;
                    is_marked = true;
                }

                // Store all the Nodes which lock we acquire in a map
                // Map used so that we don't try to acquire lock to a Node we have already acquired
                // This may happen when we have the same predecessor at different levels
                map<Node*, int> locked_nodes;

                // Traverse the skip list and try to acquire the lock of predecessor at every level
                try{
                    Node* pred;
                    //Node* succ;

                    // Used to check if the predecessors are not marked for delete and if the predecessor next is the node we are trying to delete or if it is changed.
                    bool valid = true;

                    for(int level = 0; valid && (level <= top_level); level++){
                        pred = preds[level];
                        
                        // If not already acquired lock, then acquire the lock 
                        if(!(locked_nodes.count( pred ))){
                            pred->lock();
                            locked_nodes.insert(make_pair(pred, 1));
                        }
                        
                        // If predecessor marked or if the predecessor's next has changed, then abort and try again
                        valid = !(pred->marked) && pred->next[level] == victim;
                    }

                    // Conditons are not met, release locks, abort and try again.
                    if(!valid){
                        for (auto const& x : locked_nodes){
                            x.first->unlock();
                        }
                        continue;
                    }

                    // All conditions satisfied, delete the Node and link them to the successors appropriately
                    for(int level = top_level; level >= 0; level--){
                        preds[level]->next[level] = victim->next[level];
                    }

                    victim->unlock();

                    // delete victim;

                    // Delete is completed, release the locks held.
                    for (auto const& x : locked_nodes){
                        x.first->unlock();
                    }

                    return true;
                }catch(const std::exception& e){
                    // If any exception occurs during the above delete, release locks of the held nodes and try again.
                    for (auto const& x : locked_nodes){
                        x.first->unlock();
                    }
                }

            }else{
                return false;
            }
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x88, %rsp
movl %esi, %ebp
movq %rdi, %r14
movslq 0x5c73(%rip), %rsi      # 0xb304
incq %rsi
leaq 0x8(%rsp), %rdi
leaq 0x48(%rsp), %rdx
callq 0x5de0
movslq 0x5c5a(%rip), %rsi      # 0xb304
incq %rsi
leaq 0x30(%rsp), %rdi
leaq 0x48(%rsp), %rdx
callq 0x5de0
movq 0x8(%rsp), %rcx
cmpq %rcx, 0x10(%rsp)
je 0x56f2
xorl %eax, %eax
xorl %edx, %edx
movq %rax, (%rcx,%rdx,8)
movq 0x30(%rsp), %rcx
movq %rax, (%rcx,%rdx,8)
incq %rdx
movq 0x8(%rsp), %rcx
movq 0x10(%rsp), %rsi
subq %rcx, %rsi
sarq $0x3, %rsi
cmpq %rsi, %rdx
jb 0x56cc
movl $0xffffffff, %r12d      # imm = 0xFFFFFFFF
leaq 0x50(%rsp), %rbx
leaq 0x8(%rsp), %rdx
leaq 0x30(%rsp), %rcx
leaq 0x48(%rsp), %r13
movq $0x0, 0x28(%rsp)
xorl %r15d, %r15d
movl %ebp, (%rsp)
movq %r14, 0x20(%rsp)
movq %r14, %rdi
movl %ebp, %esi
callq 0x4f0c
xorl %ecx, %ecx
cmpl $-0x1, %eax
je 0x5757
movl %eax, %edx
movq 0x30(%rsp), %rsi
movq (%rsi,%rdx,8), %r15
movb 0x69(%r15), %dl
testb $0x1, %dl
je 0x5757
cmpl %eax, 0x6c(%r15)
jne 0x5757
movb 0x68(%r15), %al
movzbl %al, %ecx
notl %ecx
andl $0x1, %ecx
movq 0x28(%rsp), %rdx
movl %edx, %eax
andb $0x1, %al
movzbl %al, %eax
orl %ecx, %eax
je 0x59aa
testb $0x1, %dl
jne 0x5795
movl 0x6c(%r15), %r12d
movq %r15, %rdi
callq 0x4c3e
movb 0x68(%r15), %al
testb $0x1, %al
jne 0x59a2
movb $0x1, %al
movq %rax, 0x28(%rsp)
movb $0x1, %al
xchgb %al, 0x68(%r15)
movl $0x0, 0x50(%rsp)
xorl %eax, %eax
movq %rax, 0x58(%rsp)
movq %rbx, 0x60(%rsp)
movq %rbx, 0x68(%rsp)
movq %rax, 0x70(%rsp)
testl %r12d, %r12d
movl %r12d, 0x4(%rsp)
js 0x58d4
movl %r12d, %r14d
xorl %ebp, %ebp
movq 0x8(%rsp), %rax
movq (%rax,%rbp,8), %r12
movq 0x58(%rsp), %rsi
testq %rsi, %rsi
je 0x5812
movq %rbx, %rdi
movq %rdi, %rax
movq %rsi, %rcx
movq 0x20(%rsi), %rdx
xorl %esi, %esi
cmpq %r12, %rdx
setb %sil
movq %rcx, %rdi
cmovbq %rax, %rdi
movq 0x10(%rcx,%rsi,8), %rsi
testq %rsi, %rsi
jne 0x57dc
cmpq %rbx, %rdi
je 0x5812
cmpq %r12, %rdx
cmovbq %rax, %rcx
cmpq 0x20(%rcx), %r12
jae 0x5837
movq %r12, %rdi
callq 0x4c3e
movq %r12, 0x78(%rsp)
movl $0x1, 0x80(%rsp)
movq %r13, %rdi
leaq 0x78(%rsp), %rsi
callq 0x5ebe
movb 0x68(%r12), %al
testb $0x1, %al
jne 0x5863
movq 0x28(%r12), %rax
movq (%rax,%rbp,8), %rax
cmpq %r15, %rax
jne 0x585e
leaq 0x1(%rbp), %rcx
cmpq %r14, %rbp
movq %rcx, %rbp
jb 0x57c6
cmpq %r15, %rax
je 0x58ab
movq 0x60(%rsp), %r12
cmpq %rbx, %r12
movl (%rsp), %ebp
movq 0x20(%rsp), %r14
je 0x588f
movq 0x20(%r12), %rdi
callq 0x4c56
movq %r12, %rdi
callq 0x2160
movq %rax, %r12
cmpq %rbx, %rax
jne 0x5875
movq %r13, %rdi
callq 0x5e6e
movl 0x4(%rsp), %r12d
leaq 0x8(%rsp), %rdx
leaq 0x30(%rsp), %rcx
jmp 0x5720
movl 0x4(%rsp), %r12d
testl %r12d, %r12d
js 0x58d4
movq 0x28(%r15), %rax
movq (%rax,%r14,8), %rax
movq 0x8(%rsp), %rcx
movq (%rcx,%r14,8), %rcx
movq 0x28(%rcx), %rcx
movq %rax, (%rcx,%r14,8)
addq $-0x1, %r14
jb 0x58b5
movq %r15, %rdi
callq 0x4c56
movq 0x60(%rsp), %r12
cmpq %rbx, %r12
je 0x5954
movq 0x20(%r12), %rdi
callq 0x4c56
movq %r12, %rdi
callq 0x2160
movq %rax, %r12
cmpq %rbx, %rax
jne 0x58e6
jmp 0x5954
jmp 0x590a
jmp 0x590a
jmp 0x590a
jmp 0x590a
movq %rax, %r14
cmpl $0x1, %edx
jne 0x59bb
movq %r14, %rdi
callq 0x20b0
movq 0x60(%rsp), %r12
cmpq %rbx, %r12
je 0x5942
movq 0x20(%r12), %rdi
callq 0x4c56
movq %r12, %rdi
callq 0x2160
movq %rax, %r12
cmpq %rbx, %rax
jne 0x5928
callq 0x22f0
movl (%rsp), %ebp
movq 0x20(%rsp), %r14
jmp 0x588f
leaq 0x48(%rsp), %rdi
callq 0x5e6e
movb $0x1, %bl
movq 0x30(%rsp), %rdi
testq %rdi, %rdi
je 0x5977
movq 0x40(%rsp), %rsi
subq %rdi, %rsi
callq 0x2220
movq 0x8(%rsp), %rdi
testq %rdi, %rdi
je 0x598e
movq 0x18(%rsp), %rsi
subq %rdi, %rsi
callq 0x2220
movl %ebx, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r15, %rdi
callq 0x4c56
xorl %ebx, %ebx
jmp 0x5960
movq %rax, %r14
jmp 0x59bb
movq %rax, %r14
callq 0x22f0
leaq 0x48(%rsp), %rdi
callq 0x5e6e
jmp 0x59de
movq %rax, %rdi
callq 0x41f1
jmp 0x59db
movq %rax, %r14
jmp 0x59f5
movq %rax, %r14
jmp 0x5a0c
movq %rax, %r14
movq 0x30(%rsp), %rdi
testq %rdi, %rdi
je 0x59f5
movq 0x40(%rsp), %rsi
subq %rdi, %rsi
callq 0x2220
movq 0x8(%rsp), %rdi
testq %rdi, %rdi
je 0x5a0c
movq 0x18(%rsp), %rsi
subq %rdi, %rsi
callq 0x2220
movq %r14, %rdi
callq 0x2320