// File: /workspace/github_cpp_makefile_star2_O1/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 $0x98, %rsp
movl %esi, 0x2c(%rsp)
movq %rdi, 0x80(%rsp)
movslq 0x5c92(%rip), %rsi      # 0xb304
incq %rsi
leaq 0x10(%rsp), %rdi
leaq 0x48(%rsp), %rdx
callq 0x5dcc
movslq 0x5c79(%rip), %rsi      # 0xb304
incq %rsi
leaq 0x30(%rsp), %rdi
leaq 0x48(%rsp), %rdx
callq 0x5dcc
movq 0x10(%rsp), %rcx
cmpq %rcx, 0x18(%rsp)
je 0x56d3
xorl %eax, %eax
xorl %edx, %edx
movq %rax, (%rcx,%rdx,8)
movq 0x30(%rsp), %rcx
movq %rax, (%rcx,%rdx,8)
incq %rdx
movq 0x10(%rsp), %rcx
movq 0x18(%rsp), %rsi
subq %rcx, %rsi
sarq $0x3, %rsi
cmpq %rsi, %rdx
jb 0x56ad
movl $0xffffffff, %r14d      # imm = 0xFFFFFFFF
leaq 0x50(%rsp), %rbx
xorl %r13d, %r13d
xorl %r12d, %r12d
movl %eax, 0xc(%rsp)
movq 0x80(%rsp), %rdi
movl 0x2c(%rsp), %esi
leaq 0x10(%rsp), %rdx
leaq 0x30(%rsp), %rcx
callq 0x4ec8
cmpl $-0x1, %eax
je 0x5714
movslq %eax, %rcx
movq 0x30(%rsp), %rdx
movq (%rdx,%rcx,8), %r12
xorl %ecx, %ecx
cmpl $-0x1, %eax
je 0x5739
movb 0x69(%r12), %dl
testb $0x1, %dl
je 0x5739
cmpl %eax, 0x6c(%r12)
jne 0x5739
movb 0x68(%r12), %al
movzbl %al, %ecx
notl %ecx
andl $0x1, %ecx
movl %r13d, %eax
andb $0x1, %al
movzbl %al, %eax
movl $0x1, %r15d
orl %ecx, %eax
je 0x576f
testb $0x1, %r13b
jne 0x5786
movl 0x6c(%r12), %r14d
movq %r12, %rdi
callq 0x4bfe
movb 0x68(%r12), %al
testb $0x1, %al
je 0x577c
movq %r12, %rdi
callq 0x4c16
movl $0x0, 0xc(%rsp)
jmp 0x58f6
movb $0x1, %r13b
movb $0x1, %al
xchgb %al, 0x68(%r12)
movq %r13, 0x78(%rsp)
movl $0x0, 0x50(%rsp)
xorl %eax, %eax
movq %rax, 0x58(%rsp)
movq %rbx, 0x60(%rsp)
movq %rbx, 0x68(%rsp)
movq %rax, 0x70(%rsp)
movl %r14d, %r15d
testl %r14d, %r14d
js 0x585b
xorl %r13d, %r13d
movq 0x10(%rsp), %rax
movq (%rax,%r13,8), %rbp
movq 0x58(%rsp), %rcx
movq %rbx, %rax
testq %rcx, %rcx
je 0x57e8
movq %rbx, %rax
xorl %edx, %edx
cmpq %rbp, 0x20(%rcx)
setb %dl
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rdx,8), %rcx
testq %rcx, %rcx
jne 0x57d1
movq %rbx, %rcx
cmpq %rbx, %rax
je 0x57fb
cmpq 0x20(%rax), %rbp
cmovbq %rbx, %rax
movq %rax, %rcx
cmpq %rbx, %rcx
jne 0x582d
movq %rbp, %rdi
callq 0x4bfe
movq %rbp, 0x88(%rsp)
movl $0x1, 0x90(%rsp)
leaq 0x48(%rsp), %rdi
leaq 0x88(%rsp), %rsi
callq 0x5ea6
movb 0x68(%rbp), %al
testb $0x1, %al
je 0x5838
xorl %eax, %eax
jmp 0x5843
movq 0x28(%rbp), %rax
cmpq %r12, (%rax,%r13,8)
sete %al
testb %al, %al
je 0x5857
leaq 0x1(%r13), %rcx
cmpq %r15, %r13
movq %rcx, %r13
jb 0x57b8
testb %al, %al
je 0x58be
testl %r14d, %r14d
js 0x5885
incq %r15
movq 0x28(%r12), %rax
movq -0x8(%rax,%r15,8), %rax
movq 0x10(%rsp), %rcx
movq -0x8(%rcx,%r15,8), %rcx
movq 0x28(%rcx), %rcx
movq %rax, -0x8(%rcx,%r15,8)
decq %r15
jg 0x5863
movq %r12, %rdi
callq 0x4c16
movq 0x60(%rsp), %rbp
movl $0x1, %r15d
cmpq %rbx, %rbp
je 0x58b6
movq 0x20(%rbp), %rdi
callq 0x4c16
movq %rbp, %rdi
callq 0x2160
movq %rax, %rbp
cmpq %rbx, %rax
jne 0x589d
movb $0x1, %al
movl %eax, 0xc(%rsp)
jmp 0x58e7
movq 0x60(%rsp), %rbp
movl $0x5, %r15d
cmpq %rbx, %rbp
je 0x58e7
movq 0x20(%rbp), %rdi
callq 0x4c16
movq %rbp, %rdi
callq 0x2160
movq %rax, %rbp
cmpq %rbx, %rax
jne 0x58ce
leaq 0x48(%rsp), %rdi
callq 0x5e56
movq 0x78(%rsp), %r13
testl %r15d, %r15d
je 0x56e8
cmpl $0x5, %r15d
je 0x56e8
jmp 0x5954
jmp 0x5913
jmp 0x5913
jmp 0x5913
jmp 0x5913
movq %rax, %r15
cmpl $0x1, %edx
jne 0x59aa
movq %r15, %rdi
callq 0x20b0
movq 0x60(%rsp), %rbp
cmpq %rbx, %rbp
je 0x594a
movq 0x20(%rbp), %rdi
callq 0x4c16
movq %rbp, %rdi
callq 0x2160
movq %rax, %rbp
cmpq %rbx, %rax
jne 0x5931
xorl %r15d, %r15d
callq 0x22f0
jmp 0x58e7
movq 0x30(%rsp), %rdi
testq %rdi, %rdi
je 0x596b
movq 0x40(%rsp), %rsi
subq %rdi, %rsi
callq 0x2220
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
movl 0xc(%rsp), %ebx
je 0x5986
movq 0x20(%rsp), %rsi
subq %rdi, %rsi
callq 0x2220
andb $0x1, %bl
movl %ebx, %eax
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %r15
jmp 0x59aa
movq %rax, %r15
callq 0x22f0
leaq 0x48(%rsp), %rdi
callq 0x5e56
jmp 0x59cb
movq %rax, %rdi
callq 0x41c3
movq %rax, %r15
jmp 0x59e2
movq %rax, %r15
jmp 0x59f9
movq %rax, %r15
movq 0x30(%rsp), %rdi
testq %rdi, %rdi
je 0x59e2
movq 0x40(%rsp), %rsi
subq %rdi, %rsi
callq 0x2220
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x59f9
movq 0x20(%rsp), %rsi
subq %rdi, %rsi
callq 0x2220
movq %r15, %rdi
callq 0x2320
nop