// File: nmmmnu[P]HM3/hm3/disktable.cc
// Function: hm3::DiskTable::btreeSearch_(StringRef const&, unsigned long&) const
bool DiskTable::btreeSearch_(const StringRef &key, size_type &result) const{
	using Node		= btreeindex::Node;
	using NodeData		= btreeindex::NodeData;

	using branch_type	= btreeindex::branch_type;

	constexpr auto VALUES   = btreeindex::VALUES;
	constexpr auto BRANCHES = btreeindex::BRANCHES;

	size_t const nodesCount = blobTree_.size() / sizeof(Node);

	const Node *nodes = blobTree_.as<const Node>(0, nodesCount);

	if (!nodes){
		// go try with binary search
		log__("Problem, switch to binary search (1)");
		return binarySearch_(key, result);
	}

	std::pair<size_type, size_type> bs{ 0, getCount() };

	size_type pos = 0;

	while(pos < nodesCount){
		const Node &node = nodes[pos];

		// MODIFIED LEVEL ORDERED MINI-BINARY SEARCH INSIDE BTREE NODE
		// OUTPUT PARAMETERS

		branch_type node_index = 0; // no need to have start value, but gcc gives a warning

		// MODIFIED LEVEL ORDERED MINI-BINARY SEARCH INSIDE BTREE NODE
		// CODE
		{
			const auto &ll = g_llholder.value;

			branch_type node_pos = 0;

			do{

				// ACCESS ELEMENT
				// ---
				const uint64_t offset = be64toh(node.values[ node_pos ]);

				if (offset == Node::NIL){
					// special case go left
					/*
					 *   1   0   2
					 * 1 2 n n n n n
					 *
					 *       n
					 *   2       n
					 * 1   n   n   n
					 *
					 */

					node_pos = branch_type(2 * node_pos + 1);

					log__("\t L: NIL");

					continue;
				}

				const NodeData *nd = blobKeys_.as<const NodeData>((size_t) offset);

				if (!nd){
					// go try with binary search
					log__("Problem, switch to binary search (2)");
					return binarySearch_(key, result);
				}

				size_t    const keysize = be16toh(nd->keysize);
				// if file is open, there will be guaranteed this to work on 32 bit system:
				size_type const dataid  = (size_type) be64toh(nd->dataid);

				// key is just after the NodeData
				const char *keyptr = blobKeys_.as<const char>((size_t) offset + sizeof(NodeData), keysize);

				if (!keyptr){
					// go try with binary search
					log__("Problem, switch to binary search (3)");
					return binarySearch_(key, result);
				}

				const StringRef keyx{ keyptr, keysize };
				// ---
				// EO ACCESS ELEMENT

				log__("node [", ll[node_pos], "]: POS:", node_pos, keyx);

				int const cmp = keyx.compare(key);

				if (cmp < 0){
					// this + 1 is because,
					// we want if possible to go LEFT instead of RIGHT
					// node_index will go out of bounds,
					// this is indicator for RIGHT
					node_index = branch_type( ll[node_pos] + 1 );

					// go right
					node_pos = branch_type( 2 * node_pos + 1 + 1 );

					bs.first = dataid + 1;

					log__("\t R:", node_pos, "BS:", bs.first, "-", bs.second, "KEYX", keyx);
				}else if (cmp > 0){
					node_index = ll[node_pos];

					// go left
					node_pos = branch_type( 2 * node_pos + 1 );

					bs.second = dataid;

					log__("\t L:", node_pos, "BS:", bs.first, "-", bs.second, "KEYX", keyx);
				}else{
					// found

					log__("\t F: POS:", node_pos);

					result = dataid;
					return true;
				}
			}while (node_pos < VALUES);
		}
		// EO MODIFIED LEVEL ORDERED MINI-BINARY SEARCH INSIDE BTREE NODE

		if ( node_index == VALUES ){
			// Go Right
			pos = pos * BRANCHES + VALUES + 1;

			log__("BTREE R:", pos);
		}else{
			// Go Left
			pos = pos * BRANCHES + node_index + 1;

			log__("BTREE L:", pos, "node[", node_index, "]");
		}
	}


	// leaf or similar
	// fallback to binary search :)

	log__("BTREE LEAF:", pos);
	log__("Fallback to binary search", bs.first, bs.second, "diff", bs.second - bs.first);

	return binarySearch(*this, bs.first, bs.second, key, BinarySearchCompList{}, result, BIN_SEARCH_MINIMUM_DISTANCE);
}

// Assembly:
subq $0x118, %rsp            # imm = 0x118
movq %rdi, 0x108(%rsp)
movq %rsi, 0x100(%rsp)
movq %rdx, 0xf8(%rsp)
movq 0x108(%rsp), %rdi
movq %rdi, 0x18(%rsp)
movw $0x7f, 0xf6(%rsp)
movw $0x80, 0xf4(%rsp)
addq $0xc0, %rdi
callq 0x72c0
movq 0x18(%rsp), %rdi
movl $0x3f8, %ecx            # imm = 0x3F8
xorl %edx, %edx
divq %rcx
movq %rax, 0xe8(%rsp)
addq $0xc0, %rdi
movq 0xe8(%rsp), %rdx
xorl %esi, %esi
callq 0x72d0
movq %rax, 0xe0(%rsp)
cmpq $0x0, 0xe0(%rsp)
jne 0x59f0
leaq 0x37d4(%rip), %rdi      # 0x9197
callq 0x5f50
movq 0x18(%rsp), %rdi
movq 0x100(%rsp), %rsi
movq 0xf8(%rsp), %rdx
callq 0x7320
andb $0x1, %al
movb %al, 0x117(%rsp)
jmp 0x5f34
movq 0x18(%rsp), %rdi
movl $0x0, 0xcc(%rsp)
callq 0x3120
movq %rax, 0xc0(%rsp)
leaq 0xd0(%rsp), %rdi
leaq 0xcc(%rsp), %rsi
leaq 0xc0(%rsp), %rdx
callq 0x7370
movq $0x0, 0xb8(%rsp)
movq 0xb8(%rsp), %rax
cmpq 0xe8(%rsp), %rax
jae 0x5ead
movq 0xe0(%rsp), %rax
imulq $0x3f8, 0xb8(%rsp), %rcx # imm = 0x3F8
addq %rcx, %rax
movq %rax, 0xb0(%rsp)
movw $0x0, 0xae(%rsp)
leaq 0x382e(%rip), %rax      # 0x92aa
movq %rax, 0xa0(%rsp)
movw $0x0, 0x9e(%rsp)
movq 0xb0(%rsp), %rax
movzwl 0x9e(%rsp), %ecx
movq (%rax,%rcx,8), %rdi
callq 0x5f80
movq %rax, 0x90(%rsp)
cmpq $-0x1, 0x90(%rsp)
jne 0x5ae0
movzwl 0x9e(%rsp), %eax
shll %eax
addl $0x1, %eax
movw %ax, 0x9e(%rsp)
leaq 0x36e6(%rip), %rdi      # 0x91bc
callq 0x5f50
jmp 0x5e0b
movq 0x18(%rsp), %rdi
addq $0xd0, %rdi
movq 0x90(%rsp), %rsi
movl $0x1, %edx
callq 0x73a0
movq %rax, 0x88(%rsp)
cmpq $0x0, 0x88(%rsp)
jne 0x5b45
leaq 0x36ad(%rip), %rdi      # 0x91c5
callq 0x5f50
movq 0x18(%rsp), %rdi
movq 0x100(%rsp), %rsi
movq 0xf8(%rsp), %rdx
callq 0x7320
andb $0x1, %al
movb %al, 0x117(%rsp)
jmp 0x5f34
movq 0x88(%rsp), %rax
movzwl (%rax), %edi
callq 0x6030
movzwl %ax, %eax
movq %rax, 0x80(%rsp)
movq 0x88(%rsp), %rax
movq 0x2(%rax), %rdi
callq 0x5f80
movq 0x18(%rsp), %rdi
movq %rax, 0x78(%rsp)
addq $0xd0, %rdi
movq 0x90(%rsp), %rsi
addq $0xa, %rsi
movq 0x80(%rsp), %rdx
callq 0x73d0
movq %rax, 0x70(%rsp)
cmpq $0x0, 0x70(%rsp)
jne 0x5bdc
leaq 0x363b(%rip), %rdi      # 0x91ea
callq 0x5f50
movq 0x18(%rsp), %rdi
movq 0x100(%rsp), %rsi
movq 0xf8(%rsp), %rdx
callq 0x7320
andb $0x1, %al
movb %al, 0x117(%rsp)
jmp 0x5f34
movq 0x70(%rsp), %rsi
movq 0x80(%rsp), %rdx
leaq 0x60(%rsp), %rdi
callq 0x2dc0
movzwl 0x9e(%rsp), %eax
movl %eax, %ecx
leaq 0x36a6(%rip), %rax      # 0x92aa
movw (%rax,%rcx,2), %cx
movw 0x9e(%rsp), %ax
movq 0x60(%rsp), %rdx
movq %rdx, 0x50(%rsp)
movq 0x68(%rsp), %rdx
movq %rdx, 0x58(%rsp)
movq 0x50(%rsp), %r8
movq 0x58(%rsp), %r9
leaq 0x35da(%rip), %rdi      # 0x920f
leaq 0x35da(%rip), %rdx      # 0x9216
movzwl %cx, %esi
movzwl %ax, %ecx
callq 0x6060
movq 0x100(%rsp), %rsi
leaq 0x60(%rsp), %rdi
callq 0x7400
movl %eax, 0x4c(%rsp)
cmpl $0x0, 0x4c(%rsp)
jge 0x5d20
movzwl 0x9e(%rsp), %eax
movl %eax, %ecx
leaq 0x3631(%rip), %rax      # 0x92aa
movzwl (%rax,%rcx,2), %eax
addl $0x1, %eax
movw %ax, 0xae(%rsp)
movzwl 0x9e(%rsp), %eax
shll %eax
addl $0x1, %eax
addl $0x1, %eax
movw %ax, 0x9e(%rsp)
movq 0x78(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xd0(%rsp)
movw 0x9e(%rsp), %si
movq 0xd0(%rsp), %rcx
movq 0xd8(%rsp), %r9
movq 0x60(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x68(%rsp), %rax
movq %rax, 0x40(%rsp)
leaq 0x353a(%rip), %rdi      # 0x921e
leaq 0x3538(%rip), %rdx      # 0x9223
leaq 0x3535(%rip), %r8       # 0x9227
leaq 0x3530(%rip), %r10      # 0x9229
leaq 0x38(%rsp), %rax
movzwl %si, %esi
movq %r10, (%rsp)
movq (%rax), %r10
movq %r10, 0x8(%rsp)
movq 0x8(%rax), %rax
movq %rax, 0x10(%rsp)
callq 0x60f0
jmp 0x5e09
cmpl $0x0, 0x4c(%rsp)
jle 0x5dd6
movzwl 0x9e(%rsp), %eax
movl %eax, %ecx
leaq 0x356e(%rip), %rax      # 0x92aa
movw (%rax,%rcx,2), %ax
movw %ax, 0xae(%rsp)
movzwl 0x9e(%rsp), %eax
shll %eax
addl $0x1, %eax
movw %ax, 0x9e(%rsp)
movq 0x78(%rsp), %rax
movq %rax, 0xd8(%rsp)
movw 0x9e(%rsp), %si
movq 0xd0(%rsp), %rcx
movq 0xd8(%rsp), %r9
movq 0x60(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x68(%rsp), %rax
movq %rax, 0x30(%rsp)
leaq 0x3491(%rip), %rdi      # 0x922e
leaq 0x347f(%rip), %rdx      # 0x9223
leaq 0x347c(%rip), %r8       # 0x9227
leaq 0x3477(%rip), %r10      # 0x9229
leaq 0x28(%rsp), %rax
movzwl %si, %esi
movq %r10, (%rsp)
movq (%rax), %r10
movq %r10, 0x8(%rsp)
movq 0x8(%rax), %rax
movq %rax, 0x10(%rsp)
callq 0x60f0
jmp 0x5e07
leaq 0x3456(%rip), %rdi      # 0x9233
movzwl 0x9e(%rsp), %esi
callq 0x61a0
movq 0x78(%rsp), %rcx
movq 0xf8(%rsp), %rax
movq %rcx, (%rax)
movb $0x1, 0x117(%rsp)
jmp 0x5f34
jmp 0x5e09
jmp 0x5e0b
movzwl 0x9e(%rsp), %eax
cmpl $0x7f, %eax
jl 0x5a8e
movzwl 0xae(%rsp), %eax
cmpl $0x7f, %eax
jne 0x5e5b
movq 0xb8(%rsp), %rax
shlq $0x7, %rax
addq $0x7f, %rax
addq $0x1, %rax
movq %rax, 0xb8(%rsp)
movq 0xb8(%rsp), %rsi
leaq 0x33e9(%rip), %rdi      # 0x923d
callq 0x61e0
jmp 0x5ea8
movq 0xb8(%rsp), %rax
shlq $0x7, %rax
movzwl 0xae(%rsp), %ecx
addq %rcx, %rax
addq $0x1, %rax
movq %rax, 0xb8(%rsp)
movq 0xb8(%rsp), %rsi
leaq 0x33b9(%rip), %rdi      # 0x9246
leaq 0x33bb(%rip), %rdx      # 0x924f
leaq 0x33ba(%rip), %r8       # 0x9255
movzwl 0xae(%rsp), %ecx
callq 0x6220
jmp 0x5a36
movq 0xb8(%rsp), %rsi
leaq 0x339b(%rip), %rdi      # 0x9257
callq 0x61e0
movq 0xd0(%rsp), %rsi
movq 0xd8(%rsp), %rdx
movq 0xd8(%rsp), %r8
subq 0xd0(%rsp), %r8
leaq 0x337b(%rip), %rdi      # 0x9263
leaq 0x338e(%rip), %rcx      # 0x927d
callq 0x6280
movq 0x18(%rsp), %rdi
movq 0xd0(%rsp), %rsi
movq 0xd8(%rsp), %rdx
movq 0x100(%rsp), %rcx
movq 0xf8(%rsp), %r9
leaq 0x27(%rsp), %r8
movq $0x3, (%rsp)
callq 0x7450
andb $0x1, %al
movb %al, 0x117(%rsp)
movb 0x117(%rsp), %al
andb $0x1, %al
addq $0x118, %rsp            # imm = 0x118
retq
nopw %cs:(%rax,%rax)