// File: BenLangmead[P]bowtie/./binary_sa_search.h
// Function: unsigned int binarySASearch<SString<char>, unsigned int>(SString<char> const&, unsigned int, EList<unsigned int, 128> const&)
inline
TIndexOffU binarySASearch(const TStr& host,
			  TIndexOffU qry,
			  const EList<TSufElt>& sa)
{
	TIndexOffU lLcp = 0, rLcp = 0; // greatest observed LCPs on left and right
	TIndexOffU l = 0, r = (TIndexOffU)sa.size()+1; // binary-search window
	TIndexOffU hostLen = TIndexOffU(host.length());
	while(true) {
		assert_gt(r, l);
		TIndexOffU m = (l+r) >> 1;
		if(m == l) {
			// Binary-search window has closed: we have an answer
			if(m > 0 && sa[m-1] == qry) return std::numeric_limits<TIndexOffU>::max(); // qry matches
			assert_leq(m, sa.size());
			return m; // Return index of right-hand suffix
		}
		assert_gt(m, 0);
		TIndexOffU suf = sa[m-1];
		if(suf == qry) return std::numeric_limits<TIndexOffU>::max(); // query matches an elt of sa
		TIndexOffU lcp = min(lLcp, rLcp);
#ifndef NDEBUG
                if (sstr_suf_upto_neq(host, qry, host, suf, lcp)) {
			assert(0);
                }
#endif
		// Keep advancing lcp, but stop when query mismatches host or
		// when the counter falls off either the query or the suffix
		while(suf+lcp < hostLen && qry+lcp < hostLen && host[suf+lcp] == host[qry+lcp]) {
			lcp++;
		}
		// Fell off the end of either the query or the sa elt?
		bool fell = (suf+lcp == hostLen || qry+lcp == hostLen);
		if((fell && qry+lcp == hostLen) || (!fell && host[suf+lcp] < host[qry+lcp])) {
			// Query is greater than sa elt
			l = m;                 // update left bound
			lLcp = max(lLcp, lcp); // update left lcp
		}
		else if((fell && suf+lcp == hostLen) || (!fell && host[suf+lcp] > host[qry+lcp])) {
			// Query is less than sa elt
			r = m;                 // update right bound
			rLcp = max(rLcp, lcp); // update right lcp
		} else {
			assert(false); // Must be one or the other!
		}
	}
	// Shouldn't get here
	assert(false);
	return std::numeric_limits<TIndexOffU>::max();
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movq %rdx, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movl $0x0, -0x28(%rbp)
movl $0x0, -0x2c(%rbp)
movq -0x20(%rbp), %rdi
callq 0x14440
addl $0x1, %eax
movl %eax, -0x30(%rbp)
movq -0x10(%rbp), %rdi
callq 0x14c10
movl %eax, -0x34(%rbp)
movl -0x2c(%rbp), %eax
addl -0x30(%rbp), %eax
shrl %eax
movl %eax, -0x38(%rbp)
movl -0x38(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jne 0x3009e
cmpl $0x0, -0x38(%rbp)
jbe 0x30093
movq -0x20(%rbp), %rdi
movl -0x38(%rbp), %eax
subl $0x1, %eax
movl %eax, %eax
movl %eax, %esi
callq 0x19d10
movl (%rax), %eax
cmpl -0x14(%rbp), %eax
jne 0x30093
callq 0x30260
movl %eax, -0x4(%rbp)
jmp 0x30252
movl -0x38(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x30252
movq -0x20(%rbp), %rdi
movl -0x38(%rbp), %eax
subl $0x1, %eax
movl %eax, %eax
movl %eax, %esi
callq 0x19d10
movl (%rax), %eax
movl %eax, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x14(%rbp), %eax
jne 0x300cb
callq 0x30260
movl %eax, -0x4(%rbp)
jmp 0x30252
leaq -0x24(%rbp), %rdi
leaq -0x28(%rbp), %rsi
callq 0x16700
movl (%rax), %eax
movl %eax, -0x40(%rbp)
movl -0x3c(%rbp), %ecx
addl -0x40(%rbp), %ecx
xorl %eax, %eax
cmpl -0x34(%rbp), %ecx
movb %al, -0x42(%rbp)
jae 0x3013a
movl -0x14(%rbp), %ecx
addl -0x40(%rbp), %ecx
xorl %eax, %eax
cmpl -0x34(%rbp), %ecx
movb %al, -0x42(%rbp)
jae 0x3013a
movq -0x10(%rbp), %rdi
movl -0x3c(%rbp), %eax
addl -0x40(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
callq 0x14c30
movsbl (%rax), %eax
movl %eax, -0x48(%rbp)
movq -0x10(%rbp), %rdi
movl -0x14(%rbp), %eax
addl -0x40(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
callq 0x14c30
movq %rax, %rcx
movl -0x48(%rbp), %eax
movsbl (%rcx), %ecx
cmpl %ecx, %eax
sete %al
movb %al, -0x42(%rbp)
movb -0x42(%rbp), %al
testb $0x1, %al
jne 0x30143
jmp 0x3014e
movl -0x40(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
jmp 0x300dd
movl -0x3c(%rbp), %ecx
addl -0x40(%rbp), %ecx
movb $0x1, %al
cmpl -0x34(%rbp), %ecx
movb %al, -0x49(%rbp)
je 0x3016d
movl -0x14(%rbp), %eax
addl -0x40(%rbp), %eax
cmpl -0x34(%rbp), %eax
sete %al
movb %al, -0x49(%rbp)
movb -0x49(%rbp), %al
andb $0x1, %al
movb %al, -0x41(%rbp)
testb $0x1, -0x41(%rbp)
je 0x30186
movl -0x14(%rbp), %eax
addl -0x40(%rbp), %eax
cmpl -0x34(%rbp), %eax
je 0x301c5
testb $0x1, -0x41(%rbp)
jne 0x301df
movq -0x10(%rbp), %rdi
movl -0x3c(%rbp), %eax
addl -0x40(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
callq 0x14c30
movsbl (%rax), %eax
movl %eax, -0x50(%rbp)
movq -0x10(%rbp), %rdi
movl -0x14(%rbp), %eax
addl -0x40(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
callq 0x14c30
movq %rax, %rcx
movl -0x50(%rbp), %eax
movsbl (%rcx), %ecx
cmpl %ecx, %eax
jge 0x301df
movl -0x38(%rbp), %eax
movl %eax, -0x2c(%rbp)
leaq -0x24(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x1fd60
movl (%rax), %eax
movl %eax, -0x24(%rbp)
jmp 0x3024d
testb $0x1, -0x41(%rbp)
je 0x301f0
movl -0x3c(%rbp), %eax
addl -0x40(%rbp), %eax
cmpl -0x34(%rbp), %eax
je 0x3022f
testb $0x1, -0x41(%rbp)
jne 0x30249
movq -0x10(%rbp), %rdi
movl -0x3c(%rbp), %eax
addl -0x40(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
callq 0x14c30
movsbl (%rax), %eax
movl %eax, -0x54(%rbp)
movq -0x10(%rbp), %rdi
movl -0x14(%rbp), %eax
addl -0x40(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
callq 0x14c30
movq %rax, %rcx
movl -0x54(%rbp), %eax
movsbl (%rcx), %ecx
cmpl %ecx, %eax
jle 0x30249
movl -0x38(%rbp), %eax
movl %eax, -0x30(%rbp)
leaq -0x28(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x1fd60
movl (%rax), %eax
movl %eax, -0x28(%rbp)
jmp 0x3024b
jmp 0x3024b
jmp 0x3024d
jmp 0x30053
movl -0x4(%rbp), %eax
addq $0x60, %rsp
popq %rbp
retq
nopl (%rax,%rax)