// File: funny-falcon[P]fanom_hash/./check.inc.cpp
// Function: check_table(table*, int)
int check_table(table *tbl, int use_32) {
	uint32_t maxchain = 0;
	double expectedmaxchain = 2 * log(tbl->bins) / log(log(tbl->bins));
	std::map<uint64_t, uint32_t> counter;
	int ret = 0;
	int i;
	for (i = 0; i < tbl->bins; i++) {
		uint32_t chain = 0;
		entry* e = tbl->entries[i];
		while (e != NULL) {
			chain++;
			checksum_add(e->str, e->len);
			counter[e->hash]++;
			e = e->next;
		}
		if (chain > maxchain)
			maxchain = chain;
	}
	printf("checksum %08x %08x\n", checksum[0], checksum[1]);
	printf("maxchain: %u (expected %f)", maxchain, expectedmaxchain);
	if (maxchain > expectedmaxchain*2) {
		printf("(!!! maxchain overflow)");
		ret = 1;
	}
	printf("\n");
	if (counter.size() != tbl->size) {
		double ncoll = tbl->size - (uint32_t)counter.size();
		double expected = 0;
		uint32_t maxcnt = 0;
		if (use_32) {
			double d = pow(2,32);
			double n = tbl->size;
			/* https://en.wikipedia.org/wiki/Birthday_problem#Collision_counting */
			expected = n - d + d*pow((d-1)/d, n);
			if (expected > 0.01 && ncoll <= 2) {
				ret = 0;
			} else {
				ret = expected*4 < ncoll;
			}
		} else {
			ret = 1;
		}
		for (auto& pair: counter) {
			if (pair.second-1 > maxcnt) {
				maxcnt = pair.second-1;
			}
		}
		printf("Has full hash collision: %u same hashes for %u values (expected %f)\n",
				(uint32_t)ncoll, tbl->size, expected);
		if (maxcnt > 1) {
			printf("Max full collision: %u\n", maxcnt);
			ret = 1;
		}
	}
	return ret;
}

// Assembly:
subq $0xf8, %rsp
movq %rdi, 0xf0(%rsp)
movl %esi, 0xec(%rsp)
movl $0x0, 0xe8(%rsp)
movq 0xf0(%rsp), %rax
movl 0x4(%rax), %edi
callq 0x44e0
movaps %xmm0, %xmm1
movsd 0x55ac(%rip), %xmm0     # 0x8008
mulsd %xmm1, %xmm0
movsd %xmm0, 0x38(%rsp)
movq 0xf0(%rsp), %rax
movl 0x4(%rax), %edi
callq 0x44e0
callq 0x2140
movaps %xmm0, %xmm1
movsd 0x38(%rsp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0xe0(%rsp)
leaq 0xb0(%rsp), %rdi
callq 0x4500
movl $0x0, 0xac(%rsp)
movl $0x0, 0xa8(%rsp)
movl 0xa8(%rsp), %eax
movq 0xf0(%rsp), %rcx
cmpl 0x4(%rcx), %eax
jae 0x2bc8
movl $0x0, 0xa4(%rsp)
movq 0xf0(%rsp), %rax
movq 0x8(%rax), %rax
movslq 0xa8(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x98(%rsp)
cmpq $0x0, 0x98(%rsp)
je 0x2b92
movl 0xa4(%rsp), %eax
incl %eax
movl %eax, 0xa4(%rsp)
movq 0x98(%rsp), %rax
movq %rax, %rdi
addq $0x20, %rdi
movq 0x18(%rax), %rsi
callq 0x2750
movq 0x98(%rsp), %rsi
leaq 0xb0(%rsp), %rdi
callq 0x4510
movq %rax, 0x30(%rsp)
jmp 0x2b4a
movq 0x30(%rsp), %rax
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
movq 0x98(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x98(%rsp)
jmp 0x2af7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x90(%rsp)
movl %eax, 0x8c(%rsp)
leaq 0xb0(%rsp), %rdi
callq 0x4700
jmp 0x2eb9
movl 0xa4(%rsp), %eax
cmpl 0xe8(%rsp), %eax
jbe 0x2bb0
movl 0xa4(%rsp), %eax
movl %eax, 0xe8(%rsp)
jmp 0x2bb2
movl 0xa8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xa8(%rsp)
jmp 0x2ab4
movl 0x95e2(%rip), %esi      # 0xc1b0
movl 0x95e0(%rip), %edx      # 0xc1b4
leaq 0x54dc(%rip), %rdi      # 0x80b7
xorl %eax, %eax
callq 0x2030
jmp 0x2be4
movl 0xe8(%rsp), %esi
movsd 0xe0(%rsp), %xmm0
leaq 0x54d0(%rip), %rdi      # 0x80cb
movb $0x1, %al
callq 0x2030
jmp 0x2c04
movl 0xe8(%rsp), %eax
cvtsi2sd %rax, %xmm0
movsd 0x53f0(%rip), %xmm1     # 0x8008
mulsd 0xe0(%rsp), %xmm1
ucomisd %xmm1, %xmm0
jbe 0x2c42
leaq 0x54b8(%rip), %rdi      # 0x80e6
xorl %eax, %eax
callq 0x2030
jmp 0x2c37
movl $0x1, 0xac(%rsp)
leaq 0x54f8(%rip), %rdi      # 0x8141
xorl %eax, %eax
callq 0x2030
jmp 0x2c52
leaq 0xb0(%rsp), %rdi
callq 0x4600
movq 0xf0(%rsp), %rcx
movl (%rcx), %ecx
cmpq %rcx, %rax
je 0x2e95
movq 0xf0(%rsp), %rax
movl (%rax), %eax
movl %eax, 0x2c(%rsp)
leaq 0xb0(%rsp), %rdi
callq 0x4600
movq %rax, %rcx
movl 0x2c(%rsp), %eax
subl %ecx, %eax
cvtsi2sd %rax, %xmm0
movsd %xmm0, 0x80(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x78(%rsp)
movl $0x0, 0x74(%rsp)
cmpl $0x0, 0xec(%rsp)
je 0x2db9
movl $0x2, %edi
movl $0x20, %esi
callq 0x4610
movsd %xmm0, 0x20(%rsp)
jmp 0x2cda
movsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x68(%rsp)
movq 0xf0(%rsp), %rax
movl (%rax), %eax
cvtsi2sd %rax, %xmm0
movsd %xmm0, 0x60(%rsp)
movsd 0x60(%rsp), %xmm0
subsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x68(%rsp), %xmm0
movsd 0x52f1(%rip), %xmm1     # 0x8018
subsd %xmm1, %xmm0
divsd 0x68(%rsp), %xmm0
movsd 0x60(%rsp), %xmm1
callq 0x22a0
movsd 0x10(%rsp), %xmm1
movaps %xmm0, %xmm2
movsd 0x18(%rsp), %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x78(%rsp)
movsd 0x78(%rsp), %xmm0
movsd 0x52a9(%rip), %xmm1     # 0x8010
ucomisd %xmm1, %xmm0
jbe 0x2d8d
movsd 0x5293(%rip), %xmm0     # 0x8008
ucomisd 0x80(%rsp), %xmm0
jb 0x2d8d
movl $0x0, 0xac(%rsp)
jmp 0x2db7
movsd 0x528b(%rip), %xmm1     # 0x8020
mulsd 0x78(%rsp), %xmm1
movsd 0x80(%rsp), %xmm0
ucomisd %xmm1, %xmm0
seta %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, 0xac(%rsp)
jmp 0x2dc4
movl $0x1, 0xac(%rsp)
leaq 0xb0(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x58(%rsp), %rdi
callq 0x4630
movq %rax, 0x50(%rsp)
movq 0x58(%rsp), %rdi
callq 0x4660
movq %rax, 0x48(%rsp)
leaq 0x50(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x4690
testb $0x1, %al
jne 0x2e04
jmp 0x2e41
leaq 0x50(%rsp), %rdi
callq 0x46b0
movq %rax, 0x40(%rsp)
movq 0x40(%rsp), %rax
movl 0x8(%rax), %eax
subl $0x1, %eax
cmpl 0x74(%rsp), %eax
jbe 0x2e33
movq 0x40(%rsp), %rax
movl 0x8(%rax), %eax
subl $0x1, %eax
movl %eax, 0x74(%rsp)
jmp 0x2e35
leaq 0x50(%rsp), %rdi
callq 0x46d0
jmp 0x2def
cvttsd2si 0x80(%rsp), %rax
movl %eax, %esi
movq 0xf0(%rsp), %rax
movl (%rax), %edx
movsd 0x78(%rsp), %xmm0
leaq 0x529a(%rip), %rdi      # 0x80fe
movb $0x1, %al
callq 0x2030
jmp 0x2e6d
cmpl $0x1, 0x74(%rsp)
jbe 0x2e93
movl 0x74(%rsp), %esi
leaq 0x52c4(%rip), %rdi      # 0x8143
xorl %eax, %eax
callq 0x2030
jmp 0x2e88
movl $0x1, 0xac(%rsp)
jmp 0x2e95
movl 0xac(%rsp), %eax
movl %eax, 0xc(%rsp)
leaq 0xb0(%rsp), %rdi
callq 0x4700
movl 0xc(%rsp), %eax
addq $0xf8, %rsp
retq
movq 0x90(%rsp), %rdi
callq 0x22b0
nopw %cs:(%rax,%rax)