// File: attractivechaos[P]udb2/tommyds/./tommyhashlin.c
// Function: hashlin_grow_step
tommy_inline void hashlin_grow_step(tommy_hashlin* hashlin)
{
	/* grow if more than 50% full */
	if (hashlin->state != TOMMY_HASHLIN_STATE_GROW
		&& hashlin->count > hashlin->bucket_max / 2
	) {
		/* if we are stable, setup a new grow state */
		/* otherwise continue with the already setup shrink one */
		/* but in backward direction */
		if (hashlin->state == TOMMY_HASHLIN_STATE_STABLE) {
			tommy_hashlin_node** segment;

			/* set the lower size */
			hashlin->low_max = hashlin->bucket_max;
			hashlin->low_mask = hashlin->bucket_mask;

			/* allocate the new vector using malloc() and not calloc() */
			/* because data is fully initialized in the split process */
			segment = tommy_cast(tommy_hashlin_node**, tommy_malloc(hashlin->low_max * sizeof(tommy_hashlin_node*)));

			/* store it adjusting the offset */
			/* cast to ptrdiff_t to ensure to get a negative value */
			hashlin->bucket[hashlin->bucket_bit] = &segment[-(tommy_ptrdiff_t)hashlin->low_max];

			/* grow the hash size */
			++hashlin->bucket_bit;
			hashlin->bucket_max = 1 << hashlin->bucket_bit;
			hashlin->bucket_mask = hashlin->bucket_max - 1;

			/* start from the beginning going forward */
			hashlin->split = 0;
		}

		/* grow state */
		hashlin->state = TOMMY_HASHLIN_STATE_GROW;
	}

	/* if we are growing */
	if (hashlin->state == TOMMY_HASHLIN_STATE_GROW) {
		/* compute the split target required to finish the reallocation before the next resize */
		tommy_count_t split_target = 2 * hashlin->count;

		/* reallocate buckets until the split target */
		while (hashlin->split + hashlin->low_max < split_target) {
			tommy_hashlin_node** split[2];
			tommy_hashlin_node* j;
			tommy_count_t mask;

			/* get the low bucket */
			split[0] = tommy_hashlin_pos(hashlin, hashlin->split);

			/* get the high bucket */
			split[1] = tommy_hashlin_pos(hashlin, hashlin->split + hashlin->low_max);

			/* save the low bucket */
			j = *split[0];

			/* reinitialize the buckets */
			*split[0] = 0;
			*split[1] = 0;

			/* the bit used to identify the bucket */
			mask = hashlin->low_max;

			/* flush the bucket */
			while (j) {
				tommy_hashlin_node* j_next = j->next;
				tommy_count_t pos = (j->key & mask) != 0;
				if (*split[pos])
					tommy_list_insert_tail_not_empty(*split[pos], j);
				else
					tommy_list_insert_first(split[pos], j);
				j = j_next;
			}

			/* go forward */
			++hashlin->split;

			/* if we have finished, change the state */
			if (hashlin->split == hashlin->low_max) {
				/* go in stable mode */
				tommy_hashlin_stable(hashlin);
				break;
			}
		}
	}
}

// Assembly:
subq $0x48, %rsp
movq %rdi, 0x40(%rsp)
movq 0x40(%rsp), %rax
cmpl $0x1, 0x11c(%rax)
je 0x5490
movq 0x40(%rsp), %rax
movl 0x118(%rax), %eax
movq 0x40(%rsp), %rcx
movl 0x104(%rcx), %ecx
shrl %ecx
cmpl %ecx, %eax
jbe 0x5490
movq 0x40(%rsp), %rax
cmpl $0x0, 0x11c(%rax)
jne 0x5481
movq 0x40(%rsp), %rax
movl 0x104(%rax), %ecx
movq 0x40(%rsp), %rax
movl %ecx, 0x10c(%rax)
movq 0x40(%rsp), %rax
movl 0x108(%rax), %ecx
movq 0x40(%rsp), %rax
movl %ecx, 0x110(%rax)
movq 0x40(%rsp), %rax
movl 0x10c(%rax), %eax
movl %eax, %edi
shlq $0x3, %rdi
callq 0x1090
movq %rax, 0x38(%rsp)
movq 0x38(%rsp), %rdx
movq 0x40(%rsp), %rax
movl 0x10c(%rax), %eax
movl %eax, %ecx
xorl %eax, %eax
subq %rcx, %rax
shlq $0x3, %rax
addq %rax, %rdx
movq 0x40(%rsp), %rax
movq 0x40(%rsp), %rcx
movl 0x100(%rcx), %ecx
movq %rdx, (%rax,%rcx,8)
movq 0x40(%rsp), %rax
movl 0x100(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x100(%rax)
movq 0x40(%rsp), %rax
movl 0x100(%rax), %ecx
movl $0x1, %eax
shll %cl, %eax
movl %eax, %ecx
movq 0x40(%rsp), %rax
movl %ecx, 0x104(%rax)
movq 0x40(%rsp), %rax
movl 0x104(%rax), %ecx
subl $0x1, %ecx
movq 0x40(%rsp), %rax
movl %ecx, 0x108(%rax)
movq 0x40(%rsp), %rax
movl $0x0, 0x114(%rax)
movq 0x40(%rsp), %rax
movl $0x1, 0x11c(%rax)
movq 0x40(%rsp), %rax
cmpl $0x1, 0x11c(%rax)
jne 0x55fb
movq 0x40(%rsp), %rax
movl 0x118(%rax), %eax
shll %eax
movl %eax, 0x34(%rsp)
movq 0x40(%rsp), %rax
movl 0x114(%rax), %eax
movq 0x40(%rsp), %rcx
addl 0x10c(%rcx), %eax
cmpl 0x34(%rsp), %eax
jae 0x55f9
movq 0x40(%rsp), %rdi
movq 0x40(%rsp), %rax
movl 0x114(%rax), %esi
callq 0x59d0
movq %rax, 0x20(%rsp)
movq 0x40(%rsp), %rdi
movq 0x40(%rsp), %rax
movl 0x114(%rax), %esi
movq 0x40(%rsp), %rax
addl 0x10c(%rax), %esi
callq 0x59d0
movq %rax, 0x28(%rsp)
movq 0x20(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x18(%rsp)
movq 0x20(%rsp), %rax
movq $0x0, (%rax)
movq 0x28(%rsp), %rax
movq $0x0, (%rax)
movq 0x40(%rsp), %rax
movl 0x10c(%rax), %eax
movl %eax, 0x14(%rsp)
cmpq $0x0, 0x18(%rsp)
je 0x55bc
movq 0x18(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x8(%rsp)
movq 0x18(%rsp), %rax
movl 0x18(%rax), %eax
andl 0x14(%rsp), %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, 0x4(%rsp)
movl 0x4(%rsp), %eax
movq 0x20(%rsp,%rax,8), %rax
cmpq $0x0, (%rax)
je 0x559d
movl 0x4(%rsp), %eax
movq 0x20(%rsp,%rax,8), %rax
movq (%rax), %rdi
movq 0x18(%rsp), %rsi
callq 0x60d0
jmp 0x55b0
movl 0x4(%rsp), %eax
movq 0x20(%rsp,%rax,8), %rdi
movq 0x18(%rsp), %rsi
callq 0x6090
movq 0x8(%rsp), %rax
movq %rax, 0x18(%rsp)
jmp 0x5546
movq 0x40(%rsp), %rax
movl 0x114(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x114(%rax)
movq 0x40(%rsp), %rax
movl 0x114(%rax), %eax
movq 0x40(%rsp), %rcx
cmpl 0x10c(%rcx), %eax
jne 0x55f4
movq 0x40(%rsp), %rdi
callq 0x51d0
jmp 0x55f9
jmp 0x54b3
jmp 0x55fb
addq $0x48, %rsp
retq