// File: BenLangmead[P]bowtie/./ref_aligner.h
// Function: ExactRefAligner::anchor64Find(unsigned int, unsigned long, unsigned char*, SDnaStringExpandable<25, 2> const&, SStringExpandable<char, 25, 2, 0> const&, unsigned int, unsigned int, EList<Range, 128>&, EList<unsigned int, 128>&, std::set<std::pair<unsigned long, unsigned long>, std::less<std::pair<unsigned long, unsigned long>>, std::allocator<std::pair<unsigned long, unsigned long>>>*, unsigned int, bool) const
virtual void anchor64Find(uint32_t numToFind,
				  size_t tidx,
				  uint8_t *ref,
				  const BTDnaString& qry,
				  const BTString& quals,
				  TIndexOffU begin,
				  TIndexOffU end,
				  TRangeVec& ranges,
				  EList<TIndexOffU>& results,
				  TSetPairs* pairs,
				  TIndexOffU aoff, // offset of anchor mate
				  bool seedOnLeft) const
		{
			assert_gt(numToFind, 0);
			ASSERT_ONLY(const uint32_t rangesInitSz = (uint32_t)ranges.size());
			ASSERT_ONLY(uint32_t duplicates = 0);
			ASSERT_ONLY(uint32_t r2i = 0);
			const uint32_t qlen = (uint32_t)qry.length();
			assert_geq(end - begin, qlen); // caller should have checked this
			assert_gt(end, begin);
			assert_gt(qlen, 0);
#ifndef NDEBUG
			// Get all naive hits
			TRangeVec r2; EList<TIndexOffU> re2;
			naiveFind(numToFind, tidx, ref, qry, quals, begin, end, r2,
				  re2, pairs, aoff, seedOnLeft);
#endif
			const uint32_t anchorBitPairs = min<int>(qlen, 32);
			// anchorOverhang = # read bases not included in the anchor
			const TIndexOffU anchorOverhang = qlen <= 32 ? 0 : qlen - 32;
			const TIndexOffU lim = end - qlen - begin;
			const TIndexOffU halfway = begin + (lim >> 1);
			uint64_t anchor = 0llu;
			uint64_t buffw = 0llu;
			// Set up a mask that we'll apply to the two bufs every round
			// to discard bits that were rotated out of the anchor area
			uint64_t clearMask = 0xffffffffffffffffllu;
			bool useMask = false;
			if(anchorBitPairs < 32) {
				clearMask >>= ((32-anchorBitPairs) << 1);
				useMask = true;
			}
			const int lhsShift = ((anchorBitPairs - 1) << 1);
			// Build the contents of the 'anchor' dword and the initial
			// contents of the 'buffw' dword.  If there are fewer than 32
			// anchorBitPairs, the content will be packed into the least
			// significant bits of the word.
			size_t skipLeftToRights = 0;
			size_t skipRightToLefts = 0;
			for(size_t i = 0; i < anchorBitPairs; i++) {
				int c = (int)qry[i]; // next query character
				assert_leq(c, 4);
				if(c & 4) {
					assert_eq(r2.size(), ranges.size() - rangesInitSz);
					return; // can't match if query has Ns
				}
				int r = (int)ref[halfway - begin + i]; // next reference character
				if(r & 4) {
					r = 0;
					// The right-to-left direction absorbs the candidate
					// alignment based at 'halfway'; so skipLeftToRights is
					// i, not i+1
					skipLeftToRights = max(skipLeftToRights, i);
					skipRightToLefts = max(skipRightToLefts, anchorBitPairs - i);
				}
				assert_lt(r, 4);
				assert_lt(c, 4);
				anchor  = ((anchor  << 2llu) | c);
				buffw = ((buffw << 2llu) | r);
			}
			// Check whether read is disqualified by Ns outside of the anchor
			// region
			for(size_t i = anchorBitPairs; i < qlen; i++) {
				if((int)qry[i] == 4) {
					assert_eq(r2.size(), ranges.size() - rangesInitSz);
					return; // can't match if query has Ns
				}
			}
			uint64_t bufbw = buffw;
			// We're moving the right-hand edge of the anchor along until
			// it's 'anchorOverhang' chars from the end of the target region.
			// Note that we're not making a 3'/5' distinction here; if we
			// were, we might need to make the 'anchorOverhang' adjustment on
			// the left end of the range rather than the right.
			bool hi = false;
			TIndexOffU riHi  = halfway;
			TIndexOffU rirHi = halfway - begin;
			TIndexOffU rirHiAnchor = rirHi + anchorBitPairs - 1;
			TIndexOffU riLo  = halfway + 1;
			TIndexOffU rirLo = halfway - begin + 1;
			for(TIndexOffU i = 1; i <= lim + 1; i++) {
				int r;       // new reference char
				assert_lt(skipLeftToRights, qlen);
				assert_leq(skipRightToLefts, qlen);
				if(hi) {
					hi = false;
					// Moving left-to-right
					riHi++; rirHi++; rirHiAnchor++;
					r = (int)ref[rirHiAnchor];
					if(r & 4) {
						r = 0;
						skipLeftToRights = anchorBitPairs;
					}
					assert_lt(r, 4);
					// Bring in new base pair at the least significant
					// position
					buffw = ((buffw << 2llu) | r);
					if(useMask) buffw &= clearMask;
					if(skipLeftToRights > 0) {
						skipLeftToRights--;
						continue;
					}
					if(buffw != anchor) {
						continue;
					}
				} else {
					hi = true;
					// Moving right-to-left
					riLo--; rirLo--;
					r = (int)ref[rirLo];
					if(r & 4) {
						r = 0;
						skipRightToLefts = qlen;
					}
					assert_lt(r, 4);
					if(i >= 2) {
						bufbw >>= 2llu;
						// Bring in new base pair at the most significant
						// position
						bufbw |= ((uint64_t)r << lhsShift);
					}
					if(skipRightToLefts > 0) {
						skipRightToLefts--;
						continue;
					}
					if(bufbw != anchor) {
						continue;
					}
				}
				// Seed hit!
				bool foundHit = true;
				TIndexOffU ri = hi ? riLo : riHi;
				TIndexOffU rir = hi ? rirLo : rirHi;
				if(anchorOverhang > 0) {
					// Does the non-anchor part of the alignment (the
					// "overhang") ruin it?
					bool skipCandidate = false;
					for(size_t j = 0; j < anchorOverhang; j++) {
						assert_lt(ri + anchorBitPairs + j, end);
						int rc = (int)ref[rir + anchorBitPairs + j];
						if(rc == 4) {
							// Oops, encountered an N in the reference in
							// the overhang portion of the candidate
							// alignment
							// (Note that we inverted hi earlier)
							if(hi) {
								// Right-to-left
								skipRightToLefts = anchorOverhang - j - 1;
							} else {
								// Left-to-right
								skipLeftToRights = anchorBitPairs + j;
							}
							skipCandidate = true;
							break; // Skip this candidate
						}
						if((int)qry[32 + j] != rc) {
							// Yes, overhang ruins it
							foundHit = false;
							break;
						}
					}
					if(skipCandidate) continue;
				}
				if(foundHit) {
					if(pairs != NULL) {
						TU64Pair p;
						if(ri < aoff) {
							// By convention, the upstream mate's
							// coordinates go in the 'first' field
							p.first  = ((uint64_t)tidx << 32) | (uint64_t)ri;
							p.second = ((uint64_t)tidx << 32) | (uint64_t)aoff;
						} else {
							p.first  = ((uint64_t)tidx << 32) | (uint64_t)aoff;
							p.second = ((uint64_t)tidx << 32) | (uint64_t)ri;
						}
						if(pairs->find(p) != pairs->end()) {
							// We already found this hit!  Continue.
							ASSERT_ONLY(duplicates++);
							ASSERT_ONLY(r2i++);
							continue;
						} else {
							// Record this hit
							pairs->insert(p);
						}
					}
					assert_lt(r2i, r2.size());
					assert_eq(re2[r2i], ri);
					ranges.resize(ranges.size()+1);
					Range& range = ranges.back();
					range.stratum = 0;
					range.numMms = 0;
					assert_eq(0, range.mms.size());
					assert_eq(0, range.refcs.size());
					ASSERT_ONLY(r2i++);
					results.push_back(ri);
					if(--numToFind == 0) return;
				} else {
					// Keep scanning
				}
			}
			assert_leq(duplicates, r2.size());
			assert_geq(r2.size() - duplicates, ranges.size() - rangesInitSz);
			return; // no hit
		}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x140, %rsp            # imm = 0x140
movb 0x40(%rbp), %al
movl 0x38(%rbp), %r10d
movq 0x30(%rbp), %r10
movq 0x28(%rbp), %r10
movq 0x20(%rbp), %r10
movl 0x18(%rbp), %r10d
movl 0x10(%rbp), %r10d
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq %r9, -0x30(%rbp)
andb $0x1, %al
movb %al, -0x31(%rbp)
movq -0x28(%rbp), %rdi
callq 0x2ef90
movl %eax, -0x38(%rbp)
movl -0x38(%rbp), %eax
movl %eax, -0x40(%rbp)
movl $0x20, -0x44(%rbp)
leaq -0x40(%rbp), %rdi
leaq -0x44(%rbp), %rsi
callq 0x59f80
movl (%rax), %eax
movl %eax, -0x3c(%rbp)
cmpl $0x20, -0x38(%rbp)
ja 0x7840d
xorl %eax, %eax
movl %eax, -0x124(%rbp)
jmp 0x78419
movl -0x38(%rbp), %eax
subl $0x20, %eax
movl %eax, -0x124(%rbp)
movl -0x124(%rbp), %eax
movl %eax, -0x48(%rbp)
movl 0x18(%rbp), %eax
subl -0x38(%rbp), %eax
subl 0x10(%rbp), %eax
movl %eax, -0x4c(%rbp)
movl 0x10(%rbp), %eax
movl -0x4c(%rbp), %ecx
shrl %ecx
addl %ecx, %eax
movl %eax, -0x50(%rbp)
movq $0x0, -0x58(%rbp)
movq $0x0, -0x60(%rbp)
movq $-0x1, -0x68(%rbp)
movb $0x0, -0x69(%rbp)
cmpl $0x20, -0x3c(%rbp)
jae 0x78478
movl $0x20, %ecx
subl -0x3c(%rbp), %ecx
shll %ecx
movq -0x68(%rbp), %rax
movl %ecx, %ecx
shrq %cl, %rax
movq %rax, -0x68(%rbp)
movb $0x1, -0x69(%rbp)
movl -0x3c(%rbp), %eax
subl $0x1, %eax
shll %eax
movl %eax, -0x70(%rbp)
movq $0x0, -0x78(%rbp)
movq $0x0, -0x80(%rbp)
movq $0x0, -0x88(%rbp)
movq -0x88(%rbp), %rax
movl -0x3c(%rbp), %ecx
cmpq %rcx, %rax
jae 0x78594
movq -0x28(%rbp), %rdi
movq -0x88(%rbp), %rsi
callq 0x4fea0
movsbl (%rax), %eax
movl %eax, -0x8c(%rbp)
movl -0x8c(%rbp), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x784dd
jmp 0x78a94
movq -0x20(%rbp), %rax
movl -0x50(%rbp), %ecx
subl 0x10(%rbp), %ecx
movl %ecx, %ecx
addq -0x88(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, -0x90(%rbp)
movl -0x90(%rbp), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x78551
movl $0x0, -0x90(%rbp)
leaq -0x78(%rbp), %rdi
leaq -0x88(%rbp), %rsi
callq 0x43520
movq (%rax), %rax
movq %rax, -0x78(%rbp)
movl -0x3c(%rbp), %eax
subq -0x88(%rbp), %rax
movq %rax, -0x98(%rbp)
leaq -0x80(%rbp), %rdi
leaq -0x98(%rbp), %rsi
callq 0x43520
movq (%rax), %rax
movq %rax, -0x80(%rbp)
movq -0x58(%rbp), %rax
shlq $0x2, %rax
movslq -0x8c(%rbp), %rcx
orq %rcx, %rax
movq %rax, -0x58(%rbp)
movq -0x60(%rbp), %rax
shlq $0x2, %rax
movslq -0x90(%rbp), %rcx
orq %rcx, %rax
movq %rax, -0x60(%rbp)
movq -0x88(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x88(%rbp)
jmp 0x7849e
movl -0x3c(%rbp), %eax
movq %rax, -0xa0(%rbp)
movq -0xa0(%rbp), %rax
movl -0x38(%rbp), %ecx
cmpq %rcx, %rax
jae 0x785e0
movq -0x28(%rbp), %rdi
movq -0xa0(%rbp), %rsi
callq 0x4fea0
movsbl (%rax), %eax
cmpl $0x4, %eax
jne 0x785ca
jmp 0x78a94
jmp 0x785cc
movq -0xa0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xa0(%rbp)
jmp 0x7859e
movq -0x60(%rbp), %rax
movq %rax, -0xa8(%rbp)
movb $0x0, -0xa9(%rbp)
movl -0x50(%rbp), %eax
movl %eax, -0xb0(%rbp)
movl -0x50(%rbp), %eax
subl 0x10(%rbp), %eax
movl %eax, -0xb4(%rbp)
movl -0xb4(%rbp), %eax
addl -0x3c(%rbp), %eax
subl $0x1, %eax
movl %eax, -0xb8(%rbp)
movl -0x50(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xbc(%rbp)
movl -0x50(%rbp), %eax
subl 0x10(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xc0(%rbp)
movl $0x1, -0xc4(%rbp)
movl -0xc4(%rbp), %eax
movl -0x4c(%rbp), %ecx
addl $0x1, %ecx
cmpl %ecx, %eax
ja 0x78a92
testb $0x1, -0xa9(%rbp)
je 0x7871a
movb $0x0, -0xa9(%rbp)
movl -0xb0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xb0(%rbp)
movl -0xb4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xb4(%rbp)
movl -0xb8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xb8(%rbp)
movq -0x20(%rbp), %rax
movl -0xb8(%rbp), %ecx
movzbl (%rax,%rcx), %eax
movl %eax, -0xc8(%rbp)
movl -0xc8(%rbp), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x786c6
movl $0x0, -0xc8(%rbp)
movl -0x3c(%rbp), %eax
movq %rax, -0x78(%rbp)
movq -0x60(%rbp), %rax
shlq $0x2, %rax
movslq -0xc8(%rbp), %rcx
orq %rcx, %rax
movq %rax, -0x60(%rbp)
testb $0x1, -0x69(%rbp)
je 0x786ee
movq -0x68(%rbp), %rax
andq -0x60(%rbp), %rax
movq %rax, -0x60(%rbp)
cmpq $0x0, -0x78(%rbp)
jbe 0x78706
movq -0x78(%rbp), %rax
addq $-0x1, %rax
movq %rax, -0x78(%rbp)
jmp 0x78a7e
movq -0x60(%rbp), %rax
cmpq -0x58(%rbp), %rax
je 0x78715
jmp 0x78a7e
jmp 0x787d4
movb $0x1, -0xa9(%rbp)
movl -0xbc(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0xbc(%rbp)
movl -0xc0(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0xc0(%rbp)
movq -0x20(%rbp), %rax
movl -0xc0(%rbp), %ecx
movzbl (%rax,%rcx), %eax
movl %eax, -0xc8(%rbp)
movl -0xc8(%rbp), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x78772
movl $0x0, -0xc8(%rbp)
movl -0x38(%rbp), %eax
movq %rax, -0x80(%rbp)
cmpl $0x2, -0xc4(%rbp)
jb 0x787a8
movq -0xa8(%rbp), %rax
shrq $0x2, %rax
movq %rax, -0xa8(%rbp)
movslq -0xc8(%rbp), %rax
movl -0x70(%rbp), %ecx
shlq %cl, %rax
orq -0xa8(%rbp), %rax
movq %rax, -0xa8(%rbp)
cmpq $0x0, -0x80(%rbp)
jbe 0x787c0
movq -0x80(%rbp), %rax
addq $-0x1, %rax
movq %rax, -0x80(%rbp)
jmp 0x78a7e
movq -0xa8(%rbp), %rax
cmpq -0x58(%rbp), %rax
je 0x787d2
jmp 0x78a7e
jmp 0x787d4
movb $0x1, -0xc9(%rbp)
testb $0x1, -0xa9(%rbp)
je 0x787f2
movl -0xbc(%rbp), %eax
movl %eax, -0x128(%rbp)
jmp 0x787fe
movl -0xb0(%rbp), %eax
movl %eax, -0x128(%rbp)
movl -0x128(%rbp), %eax
movl %eax, -0xd0(%rbp)
testb $0x1, -0xa9(%rbp)
je 0x78821
movl -0xc0(%rbp), %eax
movl %eax, -0x12c(%rbp)
jmp 0x7882d
movl -0xb4(%rbp), %eax
movl %eax, -0x12c(%rbp)
movl -0x12c(%rbp), %eax
movl %eax, -0xd4(%rbp)
cmpl $0x0, -0x48(%rbp)
jbe 0x78916
movb $0x0, -0xd5(%rbp)
movq $0x0, -0xe0(%rbp)
movq -0xe0(%rbp), %rax
movl -0x48(%rbp), %ecx
cmpq %rcx, %rax
jae 0x78906
movq -0x20(%rbp), %rax
movl -0xd4(%rbp), %ecx
addl -0x3c(%rbp), %ecx
movl %ecx, %ecx
addq -0xe0(%rbp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, -0xe4(%rbp)
cmpl $0x4, -0xe4(%rbp)
jne 0x788c5
testb $0x1, -0xa9(%rbp)
je 0x788ae
movl -0x48(%rbp), %eax
subq -0xe0(%rbp), %rax
subq $0x1, %rax
movq %rax, -0x80(%rbp)
jmp 0x788bc
movl -0x3c(%rbp), %eax
addq -0xe0(%rbp), %rax
movq %rax, -0x78(%rbp)
movb $0x1, -0xd5(%rbp)
jmp 0x78906
movq -0x28(%rbp), %rdi
movq -0xe0(%rbp), %rsi
addq $0x20, %rsi
callq 0x4fea0
movsbl (%rax), %eax
cmpl -0xe4(%rbp), %eax
je 0x788ed
movb $0x0, -0xc9(%rbp)
jmp 0x78906
jmp 0x788ef
movq -0xe0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xe0(%rbp)
jmp 0x78855
testb $0x1, -0xd5(%rbp)
je 0x78914
jmp 0x78a7e
jmp 0x78916
testb $0x1, -0xc9(%rbp)
je 0x78a7a
cmpq $0x0, 0x30(%rbp)
je 0x78a05
leaq -0xf8(%rbp), %rdi
callq 0x281e0
movl -0xd0(%rbp), %eax
cmpl 0x38(%rbp), %eax
jae 0x78974
movq -0x18(%rbp), %rax
shlq $0x20, %rax
movl -0xd0(%rbp), %ecx
orq %rcx, %rax
movq %rax, -0xf8(%rbp)
movq -0x18(%rbp), %rax
shlq $0x20, %rax
movl 0x38(%rbp), %ecx
orq %rcx, %rax
movq %rax, -0xf0(%rbp)
jmp 0x789a1
movq -0x18(%rbp), %rax
shlq $0x20, %rax
movl 0x38(%rbp), %ecx
orq %rcx, %rax
movq %rax, -0xf8(%rbp)
movq -0x18(%rbp), %rax
shlq $0x20, %rax
movl -0xd0(%rbp), %ecx
orq %rcx, %rax
movq %rax, -0xf0(%rbp)
movq 0x30(%rbp), %rdi
leaq -0xf8(%rbp), %rsi
callq 0x59ff0
movq %rax, -0x100(%rbp)
movq 0x30(%rbp), %rdi
callq 0x5a030
movq %rax, -0x108(%rbp)
leaq -0x100(%rbp), %rdi
leaq -0x108(%rbp), %rsi
callq 0x59fc0
testb $0x1, %al
jne 0x789e1
jmp 0x789e6
jmp 0x78a7e
movq 0x30(%rbp), %rdi
leaq -0xf8(%rbp), %rsi
callq 0x5a060
movq %rax, -0x118(%rbp)
movb %dl, -0x110(%rbp)
jmp 0x78a05
movq 0x20(%rbp), %rax
movq %rax, -0x138(%rbp)
movq 0x20(%rbp), %rdi
callq 0x5a130
movq -0x138(%rbp), %rdi
movq %rax, %rsi
addq $0x1, %rsi
callq 0x5a0b0
movq 0x20(%rbp), %rdi
callq 0x5a150
movq %rax, -0x120(%rbp)
movq -0x120(%rbp), %rax
movl $0x0, 0xc(%rax)
movq -0x120(%rbp), %rax
movl $0x0, 0x10(%rax)
movq 0x28(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
callq 0x32160
movl -0xc(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0xc(%rbp)
cmpl $0x0, %eax
jne 0x78a78
jmp 0x78a94
jmp 0x78a7c
jmp 0x78a7c
jmp 0x78a7e
movl -0xc4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xc4(%rbp)
jmp 0x7863e
jmp 0x78a94
addq $0x140, %rsp            # imm = 0x140
popq %rbp
retq
nopl (%rax)