// File: splatlab[P]debgr/threadsafe-gqf/gqf.c
// Function: remove_replace_slots_and_shift_remainders_and_runends_and_offsets(quotient_filter*, int, unsigned long, unsigned long, unsigned long const*, unsigned long, unsigned long)
static inline void remove_replace_slots_and_shift_remainders_and_runends_and_offsets(QF		        *qf,
																																										 int		 operation,
																																										 uint64_t		 bucket_index,
																																										 uint64_t		 overwrite_index,
																																										 const uint64_t	*remainders,
																																										 uint64_t		 total_remainders,
																																										 uint64_t		 old_length)
{
	uint64_t i;

	// Update the slots
	for (i = 0; i < total_remainders; i++)
		set_slot(qf, overwrite_index + i, remainders[i]);

	// If this is the last thing in its run, then we may need to set a new runend bit
	if (is_runend(qf, overwrite_index + old_length - 1)) {
	  if (total_remainders > 0) { 
	    // If we're not deleting this entry entirely, then it will still the last entry in this run
	    METADATA_WORD(qf, runends, overwrite_index + total_remainders - 1) |= 1ULL << ((overwrite_index + total_remainders - 1) % 64);
	  } else if (overwrite_index > bucket_index &&
		     !is_runend(qf, overwrite_index - 1)) {
	    // If we're deleting this entry entirely, but it is not the first entry in this run,
	    // then set the preceding entry to be the runend
	    METADATA_WORD(qf, runends, overwrite_index - 1) |= 1ULL << ((overwrite_index - 1) % 64);
	  }
	}

	// shift slots back one run at a time
	uint64_t original_bucket = bucket_index;
	uint64_t current_bucket = bucket_index;
	uint64_t current_slot = overwrite_index + total_remainders;
	uint64_t current_distance = old_length - total_remainders;

	while (current_distance > 0) {
		if (is_runend(qf, current_slot + current_distance - 1)) {
			do {
				current_bucket++;
			} while (current_bucket < current_slot + current_distance &&
							 !is_occupied(qf, current_bucket));
		}

		if (current_bucket <= current_slot) {
			set_slot(qf, current_slot, get_slot(qf, current_slot + current_distance));
			if (is_runend(qf, current_slot) != 
					is_runend(qf, current_slot + current_distance))
				METADATA_WORD(qf, runends, current_slot) ^= 1ULL << (current_slot % 64);
			current_slot++;

		} else if (current_bucket <= current_slot + current_distance) {
			uint64_t i;
			for (i = current_slot; i < current_slot + current_distance; i++) {
				set_slot(qf, i, 0);
				METADATA_WORD(qf, runends, i) &= ~(1ULL << (i % 64));
			}

			current_distance = current_slot + current_distance - current_bucket;
			current_slot = current_bucket;
		} else {
			current_distance = 0;
		}
	}
	
	// reset the occupied bit of the hash bucket index if the hash is the
	// only item in the run and is removed completely.
	if (operation && !total_remainders)
		METADATA_WORD(qf, occupieds, bucket_index) &= ~(1ULL << (bucket_index % 64));
	
	// update the offset bits.
	// find the number of occupied slots in the original_bucket block.
	// Then find the runend slot corresponding to the last run in the
	// original_bucket block.
	// Update the offset of the block to which it belongs.
	uint64_t original_block = original_bucket / SLOTS_PER_BLOCK;
	while (1 && old_length > total_remainders) {	// we only update offsets if we shift/delete anything
		int32_t last_occupieds_bit = bitscanreverse(get_block(qf, original_block)->occupieds[0]);
		// there is nothing in the block
		if (last_occupieds_bit == -1) {
			if (get_block(qf, original_block + 1)->offset == 0)
				break;
			get_block(qf, original_block + 1)->offset = 0;
		} else {
			uint64_t last_occupieds_hash_index = SLOTS_PER_BLOCK * original_block + last_occupieds_bit;
			uint64_t runend_index = run_end(qf, last_occupieds_hash_index);
			// runend spans across the block
			// update the offset of the next block
			if (runend_index / SLOTS_PER_BLOCK == original_block) { // if the run ends in the same block
				if (get_block(qf, original_block + 1)->offset == 0)
					break;
				get_block(qf, original_block + 1)->offset = 0;
			} else if (runend_index / SLOTS_PER_BLOCK == original_block + 1) { // if the last run spans across one block
				if (get_block(qf, original_block + 1)->offset == (runend_index % SLOTS_PER_BLOCK) + 1)
					break;
				get_block(qf, original_block + 1)->offset = (runend_index % SLOTS_PER_BLOCK) + 1;
			} else { // if the last run spans across multiple blocks
				uint64_t i;
				for (i = original_block + 1; i < runend_index / SLOTS_PER_BLOCK - 1; i++)
					get_block(qf, i)->offset = SLOTS_PER_BLOCK;
				if (get_block(qf, runend_index / SLOTS_PER_BLOCK)->offset == (runend_index % SLOTS_PER_BLOCK) + 1)
					break;
				get_block(qf, runend_index / SLOTS_PER_BLOCK)->offset = (runend_index % SLOTS_PER_BLOCK) + 1;
			}
		}
		original_block++;
	}

	qf->metadata->noccupied_slots -= (old_length - total_remainders);
	if (!total_remainders) {
		qf->metadata->ndistinct_elts--;
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xd0, %rsp
movq 0x10(%rbp), %rax
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq %r9, -0x30(%rbp)
movq $0x0, -0x38(%rbp)
movq -0x38(%rbp), %rax
cmpq -0x30(%rbp), %rax
jae 0x293d3
movq -0x8(%rbp), %rdi
movq -0x20(%rbp), %rsi
addq -0x38(%rbp), %rsi
movq -0x28(%rbp), %rax
movq -0x38(%rbp), %rcx
movq (%rax,%rcx,8), %rdx
callq 0x280a0
movq -0x38(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x38(%rbp)
jmp 0x2939e
movq -0x8(%rbp), %rdi
movq -0x20(%rbp), %rsi
addq 0x10(%rbp), %rsi
subq $0x1, %rsi
callq 0x27380
cmpl $0x0, %eax
je 0x294cc
cmpq $0x0, -0x30(%rbp)
jbe 0x29457
movq -0x20(%rbp), %rcx
addq -0x30(%rbp), %rcx
subq $0x1, %rcx
andq $0x3f, %rcx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, -0x90(%rbp)
movq -0x8(%rbp), %rdi
movq -0x20(%rbp), %rsi
addq -0x30(%rbp), %rsi
subq $0x1, %rsi
shrq $0x6, %rsi
callq 0x27590
movq -0x90(%rbp), %rdx
movq -0x20(%rbp), %rcx
addq -0x30(%rbp), %rcx
subq $0x1, %rcx
andq $0x3f, %rcx
shrq $0x6, %rcx
orq 0x9(%rax,%rcx,8), %rdx
movq %rdx, 0x9(%rax,%rcx,8)
jmp 0x294ca
movq -0x20(%rbp), %rax
cmpq -0x18(%rbp), %rax
jbe 0x294c8
movq -0x8(%rbp), %rdi
movq -0x20(%rbp), %rsi
subq $0x1, %rsi
callq 0x27380
cmpl $0x0, %eax
jne 0x294c8
movq -0x20(%rbp), %rcx
subq $0x1, %rcx
andq $0x3f, %rcx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, -0x98(%rbp)
movq -0x8(%rbp), %rdi
movq -0x20(%rbp), %rsi
subq $0x1, %rsi
shrq $0x6, %rsi
callq 0x27590
movq -0x98(%rbp), %rdx
movq -0x20(%rbp), %rcx
subq $0x1, %rcx
andq $0x3f, %rcx
shrq $0x6, %rcx
orq 0x9(%rax,%rcx,8), %rdx
movq %rdx, 0x9(%rax,%rcx,8)
jmp 0x294ca
jmp 0x294cc
movq -0x18(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x20(%rbp), %rax
addq -0x30(%rbp), %rax
movq %rax, -0x50(%rbp)
movq 0x10(%rbp), %rax
subq -0x30(%rbp), %rax
movq %rax, -0x58(%rbp)
cmpq $0x0, -0x58(%rbp)
jbe 0x296f7
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rsi
addq -0x58(%rbp), %rsi
subq $0x1, %rsi
callq 0x27380
cmpl $0x0, %eax
je 0x29567
jmp 0x2951b
movq -0x48(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rcx
movq -0x50(%rbp), %rdx
addq -0x58(%rbp), %rdx
xorl %eax, %eax
cmpq %rdx, %rcx
movb %al, -0x99(%rbp)
jae 0x2955b
movq -0x8(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x26e50
cmpl $0x0, %eax
setne %al
xorb $-0x1, %al
movb %al, -0x99(%rbp)
movb -0x99(%rbp), %al
testb $0x1, %al
jne 0x2951b
jmp 0x29567
movq -0x48(%rbp), %rax
cmpq -0x50(%rbp), %rax
ja 0x29638
movq -0x8(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0xa8(%rbp)
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rsi
addq -0x58(%rbp), %rsi
callq 0x281b0
movq -0xb0(%rbp), %rdi
movq -0xa8(%rbp), %rsi
movq %rax, %rdx
callq 0x280a0
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rsi
callq 0x27380
movl %eax, -0xa0(%rbp)
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rsi
addq -0x58(%rbp), %rsi
callq 0x27380
movl %eax, %ecx
movl -0xa0(%rbp), %eax
cmpl %ecx, %eax
je 0x29627
movq -0x50(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, -0xb8(%rbp)
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rsi
shrq $0x6, %rsi
callq 0x27590
movq -0xb8(%rbp), %rdx
movq -0x50(%rbp), %rcx
andq $0x3f, %rcx
shrq $0x6, %rcx
xorq 0x9(%rax,%rcx,8), %rdx
movq %rdx, 0x9(%rax,%rcx,8)
movq -0x50(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x50(%rbp)
jmp 0x296f2
movq -0x48(%rbp), %rax
movq -0x50(%rbp), %rcx
addq -0x58(%rbp), %rcx
cmpq %rcx, %rax
ja 0x296e8
movq -0x50(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rax
movq -0x50(%rbp), %rcx
addq -0x58(%rbp), %rcx
cmpq %rcx, %rax
jae 0x296ce
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
callq 0x280a0
movq -0x60(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %eax
shlq %cl, %rax
xorq $-0x1, %rax
movq %rax, -0xc0(%rbp)
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
shrq $0x6, %rsi
callq 0x27590
movq -0xc0(%rbp), %rdx
movq -0x60(%rbp), %rcx
andq $0x3f, %rcx
shrq $0x6, %rcx
andq 0x9(%rax,%rcx,8), %rdx
movq %rdx, 0x9(%rax,%rcx,8)
movq -0x60(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x60(%rbp)
jmp 0x29655
movq -0x50(%rbp), %rax
addq -0x58(%rbp), %rax
subq -0x48(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x48(%rbp), %rax
movq %rax, -0x50(%rbp)
jmp 0x296f0
movq $0x0, -0x58(%rbp)
jmp 0x296f2
jmp 0x294f4
cmpl $0x0, -0xc(%rbp)
je 0x2974d
cmpq $0x0, -0x30(%rbp)
jne 0x2974d
movq -0x18(%rbp), %rcx
andq $0x3f, %rcx
movl $0x1, %eax
shlq %cl, %rax
xorq $-0x1, %rax
movq %rax, -0xc8(%rbp)
movq -0x8(%rbp), %rdi
movq -0x18(%rbp), %rsi
shrq $0x6, %rsi
callq 0x27590
movq -0xc8(%rbp), %rdx
movq -0x18(%rbp), %rcx
andq $0x3f, %rcx
shrq $0x6, %rcx
andq 0x1(%rax,%rcx,8), %rdx
movq %rdx, 0x1(%rax,%rcx,8)
movq -0x40(%rbp), %rax
shrq $0x6, %rax
movq %rax, -0x68(%rbp)
movq 0x10(%rbp), %rax
cmpq -0x30(%rbp), %rax
jbe 0x2994a
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
callq 0x27590
movq 0x1(%rax), %rdi
callq 0x29990
movl %eax, -0x6c(%rbp)
cmpl $-0x1, -0x6c(%rbp)
jne 0x297bd
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
addq $0x1, %rsi
callq 0x27590
movzbl (%rax), %eax
cmpl $0x0, %eax
jne 0x297a4
jmp 0x2994a
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
addq $0x1, %rsi
callq 0x27590
movb $0x0, (%rax)
jmp 0x29939
movq -0x68(%rbp), %rax
shlq $0x6, %rax
movslq -0x6c(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0x78(%rbp)
movq -0x8(%rbp), %rdi
movq -0x78(%rbp), %rsi
callq 0x26ea0
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rax
shrq $0x6, %rax
cmpq -0x68(%rbp), %rax
jne 0x29826
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
addq $0x1, %rsi
callq 0x27590
movzbl (%rax), %eax
cmpl $0x0, %eax
jne 0x2980d
jmp 0x2994a
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
addq $0x1, %rsi
callq 0x27590
movb $0x0, (%rax)
jmp 0x29937
movq -0x80(%rbp), %rax
shrq $0x6, %rax
movq -0x68(%rbp), %rcx
addq $0x1, %rcx
cmpq %rcx, %rax
jne 0x29895
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
addq $0x1, %rsi
callq 0x27590
movzbl (%rax), %eax
movq -0x80(%rbp), %rcx
andq $0x3f, %rcx
addq $0x1, %rcx
cmpq %rcx, %rax
jne 0x29865
jmp 0x2994a
movq -0x80(%rbp), %rax
andq $0x3f, %rax
addq $0x1, %rax
movb %al, -0xc9(%rbp)
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
addq $0x1, %rsi
callq 0x27590
movb -0xc9(%rbp), %cl
movb %cl, (%rax)
jmp 0x29935
movq -0x68(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x88(%rbp)
movq -0x88(%rbp), %rax
movq -0x80(%rbp), %rcx
shrq $0x6, %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
jae 0x298e3
movq -0x8(%rbp), %rdi
movq -0x88(%rbp), %rsi
callq 0x27590
movb $0x40, (%rax)
movq -0x88(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x88(%rbp)
jmp 0x298a4
movq -0x8(%rbp), %rdi
movq -0x80(%rbp), %rsi
shrq $0x6, %rsi
callq 0x27590
movzbl (%rax), %eax
movq -0x80(%rbp), %rcx
andq $0x3f, %rcx
addq $0x1, %rcx
cmpq %rcx, %rax
jne 0x2990a
jmp 0x2994a
movq -0x80(%rbp), %rax
andq $0x3f, %rax
addq $0x1, %rax
movb %al, -0xca(%rbp)
movq -0x8(%rbp), %rdi
movq -0x80(%rbp), %rsi
shrq $0x6, %rsi
callq 0x27590
movb -0xca(%rbp), %cl
movb %cl, (%rax)
jmp 0x29937
jmp 0x29939
movq -0x68(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x68(%rbp)
jmp 0x29759
movq 0x10(%rbp), %rdx
subq -0x30(%rbp), %rdx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x68(%rax), %rcx
subq %rdx, %rcx
movq %rcx, 0x68(%rax)
cmpq $0x0, -0x30(%rbp)
jne 0x29980
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x60(%rax), %rcx
addq $-0x1, %rcx
movq %rcx, 0x60(%rax)
addq $0xd0, %rsp
popq %rbp
retq
nopl (%rax)