// File: splatlab[P]debgr/threadsafe-gqf/gqf.c
// Function: run_end(quotient_filter const*, unsigned long)
static inline uint64_t run_end(const QF *qf, uint64_t hash_bucket_index)
{
	uint64_t bucket_block_index       = hash_bucket_index / SLOTS_PER_BLOCK;
	uint64_t bucket_intrablock_offset = hash_bucket_index % SLOTS_PER_BLOCK;
	uint64_t bucket_blocks_offset = block_offset(qf, bucket_block_index);

	// uint64_t bucket_intrablock_rank   = bitrankv(get_block(qf, bucket_block_index)->occupieds, METADATA_WORDS_PER_BLOCK, bucket_intrablock_offset);
	uint64_t bucket_intrablock_rank   = bitrank(get_block(qf,
																												bucket_block_index)->occupieds[0],
																							bucket_intrablock_offset);

	if (bucket_intrablock_rank == 0) {
		if (bucket_blocks_offset <= bucket_intrablock_offset)
			return hash_bucket_index;
		else
			return SLOTS_PER_BLOCK * bucket_block_index + bucket_blocks_offset - 1;
	}

	/* FIXME: Should handle offset overflow  --- Ah screw it, just use 16-bit offset.  That'll never overflow.  */
	uint64_t runend_block_index  = bucket_block_index + bucket_blocks_offset /
		SLOTS_PER_BLOCK;
	uint64_t runend_ignore_bits  = bucket_blocks_offset % SLOTS_PER_BLOCK;
	uint64_t runend_rank         = bucket_intrablock_rank - 1;
	// uint64_t runend_block_offset = bitselectv(get_block(qf, runend_block_index)->runends, METADATA_WORDS_PER_BLOCK, runend_ignore_bits, runend_rank);
	uint64_t runend_block_offset = bitselectv(get_block(qf,
																											runend_block_index)->runends[0],
																						runend_ignore_bits, runend_rank);
	if (runend_block_offset == SLOTS_PER_BLOCK) {
		if (bucket_blocks_offset == 0 && bucket_intrablock_rank == 0) {
			/* The block begins in empty space, and this bucket is in that region of empty space */
			return hash_bucket_index;
		} else {
			do {
				// runend_rank        -= popcntv(get_block(qf, runend_block_index)->runends, METADATA_WORDS_PER_BLOCK, runend_ignore_bits);
				runend_rank        -= popcntv(get_block(qf,
																								runend_block_index)->runends[0],
																			runend_ignore_bits);
				runend_block_index++;
				runend_ignore_bits  = 0;
				// runend_block_offset = bitselectv(get_block(qf, runend_block_index)->runends, METADATA_WORDS_PER_BLOCK, runend_ignore_bits, runend_rank);
				runend_block_offset = bitselectv(get_block(qf,
																									 runend_block_index)->runends[0],
																				 runend_ignore_bits, runend_rank);
			} while (runend_block_offset == SLOTS_PER_BLOCK);
		}
	}

	uint64_t runend_index = SLOTS_PER_BLOCK * runend_block_index + runend_block_offset;
	if (runend_index < hash_bucket_index)
		return hash_bucket_index;
	else
		return runend_index;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x18(%rbp), %rax
shrq $0x6, %rax
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rax
andq $0x3f, %rax
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x299d0
movq %rax, -0x30(%rbp)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x27590
movq 0x1(%rax), %rdi
movq -0x28(%rbp), %rax
movl %eax, %esi
callq 0x278d0
cltq
movq %rax, -0x38(%rbp)
cmpq $0x0, -0x38(%rbp)
jne 0x26f32
movq -0x30(%rbp), %rax
cmpq -0x28(%rbp), %rax
ja 0x26f19
movq -0x18(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x27046
movq -0x20(%rbp), %rax
shlq $0x6, %rax
addq -0x30(%rbp), %rax
subq $0x1, %rax
movq %rax, -0x8(%rbp)
jmp 0x27046
movq -0x20(%rbp), %rax
movq -0x30(%rbp), %rcx
shrq $0x6, %rcx
addq %rcx, %rax
movq %rax, -0x40(%rbp)
movq -0x30(%rbp), %rax
andq $0x3f, %rax
movq %rax, -0x48(%rbp)
movq -0x38(%rbp), %rax
subq $0x1, %rax
movq %rax, -0x50(%rbp)
movq -0x10(%rbp), %rdi
movq -0x40(%rbp), %rsi
callq 0x27590
movq 0x9(%rax), %rdi
movq -0x48(%rbp), %rax
movl %eax, %esi
movq -0x50(%rbp), %rax
movl %eax, %edx
callq 0x29a00
movq %rax, -0x58(%rbp)
cmpq $0x40, -0x58(%rbp)
jne 0x2701a
cmpq $0x0, -0x30(%rbp)
jne 0x26fa9
cmpq $0x0, -0x38(%rbp)
jne 0x26fa9
movq -0x18(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x27046
jmp 0x26fab
movq -0x10(%rbp), %rdi
movq -0x40(%rbp), %rsi
callq 0x27590
movq 0x9(%rax), %rdi
movq -0x48(%rbp), %rax
movl %eax, %esi
callq 0x29a80
movslq %eax, %rcx
movq -0x50(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x50(%rbp)
movq -0x40(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x40(%rbp)
movq $0x0, -0x48(%rbp)
movq -0x10(%rbp), %rdi
movq -0x40(%rbp), %rsi
callq 0x27590
movq 0x9(%rax), %rdi
movq -0x48(%rbp), %rax
movl %eax, %esi
movq -0x50(%rbp), %rax
movl %eax, %edx
callq 0x29a00
movq %rax, -0x58(%rbp)
cmpq $0x40, -0x58(%rbp)
je 0x26fab
jmp 0x27018
jmp 0x2701a
movq -0x40(%rbp), %rax
shlq $0x6, %rax
addq -0x58(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rax
cmpq -0x18(%rbp), %rax
jae 0x2703e
movq -0x18(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x27046
movq -0x60(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x60, %rsp
popq %rbp
retq