// File: /workspace/github_cpp_makefile_star2_O1/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb8, %rsp
movq %rcx, %rdi
movq %rdx, 0x20(%rsp)
movl %esi, 0x48(%rsp)
movl 0xf8(%rsp), %esi
movl 0xf0(%rsp), %eax
movq 0x20(%r8), %rdx
cmpl $0x20, %edx
movl $0x20, %r13d
cmovll %edx, %r13d
leal -0x20(%rdx), %ecx
xorl %ebx, %ebx
cmpl $0x21, %edx
cmovbl %ebx, %ecx
movl %ecx, 0x14(%rsp)
addl %edx, %eax
subl %eax, %esi
leal (,%r13,2), %ecx
negb %cl
movq $-0x1, %rax
shrq %cl, %rax
movq %rax, 0x40(%rsp)
movl %esi, 0x1c(%rsp)
movl %esi, %r9d
shrl %r9d
testl %edx, %edx
setne %cl
movq %rdi, 0x8(%rsp)
movq %r8, 0x80(%rsp)
movq %r9, (%rsp)
je 0x487ae
movq 0x8(%r8), %rsi
addq %r9, %rdi
cmpq $0x1, %r13
movq %r13, %r8
adcq $0x0, %r8
xorl %r15d, %r15d
movq %r13, %r9
xorl %r12d, %r12d
xorl %r10d, %r10d
xorl %eax, %eax
xorl %ebx, %ebx
movsbq (%rsi,%r10), %r11
testb $0x4, %r11b
jne 0x48795
movzbl (%rdi,%r10), %ebp
testb $0x4, %bpl
je 0x48784
cmpq %r10, %rax
cmovbeq %r10, %rax
cmpq %r9, %rbx
cmovbeq %r9, %rbx
xorl %ebp, %ebp
shlq $0x2, %r15
orq %r11, %r15
shlq $0x2, %r12
movl %ebp, %r14d
orq %r14, %r12
testb $0x4, %r11b
jne 0x487b6
incq %r10
cmpq %r13, %r10
setb %cl
decq %r9
cmpq %r10, %r8
jne 0x4875e
jmp 0x487b6
xorl %eax, %eax
xorl %r12d, %r12d
xorl %r15d, %r15d
testb $0x1, %cl
movq 0x8(%rsp), %rsi
movl 0xf0(%rsp), %r8d
movq (%rsp), %r9
jne 0x48b88
movq %rax, %r10
movl %edx, %eax
movq %rax, 0x90(%rsp)
cmpl %r13d, %eax
jbe 0x48808
movq 0x80(%rsp), %rcx
movq 0x8(%rcx), %rcx
movq %r13, %rdx
cmpb $0x4, (%rcx,%rdx)
je 0x48b88
incq %rdx
cmpq %rdx, 0x90(%rsp)
jne 0x487f1
incl 0x1c(%rsp)
je 0x48b88
movq 0x110(%rsp), %rdx
addl %r9d, %r8d
leal -0x2(,%r13,2), %ecx
leal 0x1(%r9), %eax
movq %rax, 0x38(%rsp)
leal 0x1(%r8), %eax
movl %eax, 0x18(%rsp)
cmpl $0x20, %r13d
leal -0x1(%r13,%r9), %eax
movq %rax, 0x88(%rsp)
movl %ecx, %eax
movq %rax, 0xb0(%rsp)
movq $-0x1, %rax
cmovbq 0x40(%rsp), %rax
movq %rax, 0xa8(%rsp)
movl 0x14(%rsp), %ecx
movq 0x20(%rsp), %rax
shlq $0x20, %rax
movl 0x118(%rsp), %r11d
movq %rax, 0x20(%rsp)
orq %rax, %r11
movq %r11, 0x68(%rsp)
leaq 0x8(%rdx), %rax
movq %rax, 0x70(%rsp)
movq %rcx, 0x40(%rsp)
leaq -0x1(%rcx), %rax
movq %rax, 0x98(%rsp)
movl $0x1, %r14d
xorl %ebp, %ebp
movq %r12, %rdx
testb $0x1, %bpl
je 0x48906
movq %rdx, %r11
incl %r8d
incl %r9d
movq 0x88(%rsp), %rcx
incl %ecx
movzbl (%rsi,%rcx), %eax
testb $0x4, %al
cmovneq %r13, %r10
movl $0x0, %edx
cmovnel %edx, %eax
shlq $0x2, %r12
orq %rax, %r12
andq 0xa8(%rsp), %r12
testq %r10, %r10
movq %rcx, 0x88(%rsp)
je 0x48962
decq %r10
movl $0xa, %edi
xorl %ebp, %ebp
movq %r11, %rdx
jmp 0x48b71
decl 0x18(%rsp)
movq 0x38(%rsp), %rax
decl %eax
movq %rax, 0x38(%rsp)
movzbl (%rsi,%rax), %eax
testb $0x4, %al
cmovneq 0x90(%rsp), %rbx
movl $0x0, %ecx
cmovnel %ecx, %eax
movq %rdx, %r11
shrq $0x2, %rdx
movq 0xb0(%rsp), %rcx
shlq %cl, %rax
orq %rdx, %rax
movq %r11, %rdx
cmpl $0x2, %r14d
cmovaeq %rax, %rdx
testq %rbx, %rbx
je 0x48976
decq %rbx
movb $0x1, %bpl
movl $0xa, %edi
jmp 0x48b71
movl $0xa, %edi
xorl %ebp, %ebp
cmpq %r15, %r12
movq %r11, %rdx
je 0x48987
jmp 0x48b71
movl $0xa, %edi
movb $0x1, %bpl
cmpq %r15, %rdx
jne 0x48b71
movq %rdx, 0xa0(%rsp)
testb %bpl, %bpl
movl %r8d, %eax
cmovnel 0x18(%rsp), %eax
movl %eax, 0x28(%rsp)
movl %eax, 0x4c(%rsp)
cmpl $0x0, 0x14(%rsp)
movq %r8, 0x30(%rsp)
movq %r9, (%rsp)
je 0x48a55
movq %r10, %rcx
testb %bpl, %bpl
movl %r9d, %eax
cmovnel 0x38(%rsp), %eax
addl %r13d, %eax
addq %rsi, %rax
movq 0x80(%rsp), %rdx
movq 0x8(%rdx), %rsi
movb $0x1, %dl
xorl %edi, %edi
movq 0x98(%rsp), %r8
xorl %r9d, %r9d
movzbl (%rax,%rdi), %r10d
cmpl $0x4, %r10d
jne 0x48a00
movb $0x1, %r9b
testb %bpl, %bpl
je 0x48a1c
xorl %r10d, %r10d
movq %r8, %rbx
jmp 0x48a23
movsbl 0x20(%rsi,%rdi), %r11d
cmpl %r10d, %r11d
sete %r10b
movzbl %dl, %edx
movl $0x0, %r11d
cmovnel %r11d, %edx
jmp 0x48a23
leaq (%rdi,%r13), %rcx
xorl %r10d, %r10d
testb %r10b, %r10b
je 0x48a35
incq %rdi
decq %r8
cmpq 0x40(%rsp), %rdi
jb 0x489e5
movl $0x0, %edi
testb $0x1, %r9b
movl $0xa, %esi
cmovnel %esi, %edi
movq 0x30(%rsp), %r8
movq %rcx, %r10
je 0x48a57
jmp 0x48b60
movb $0x1, %dl
xorl %edi, %edi
testb $0x1, %dl
je 0x48b60
cmpq $0x0, 0x110(%rsp)
movq %r10, 0x78(%rsp)
je 0x48b05
xorps %xmm0, %xmm0
movaps %xmm0, 0x50(%rsp)
movl 0x28(%rsp), %ecx
movl %ecx, %eax
cmpl 0x118(%rsp), %ecx
jae 0x48a9e
orq 0x20(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0x68(%rsp), %rax
jmp 0x48aad
movq 0x68(%rsp), %rcx
movq %rcx, 0x50(%rsp)
orq 0x20(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x110(%rsp), %rdi
leaq 0x50(%rsp), %rsi
callq 0x383e8
movl $0xa, %edi
movq 0x70(%rsp), %rcx
cmpq %rcx, %rax
jne 0x48af6
movq 0x110(%rsp), %rdi
leaq 0x50(%rsp), %rsi
movq %rax, 0x28(%rsp)
callq 0x38458
movq 0x28(%rsp), %rax
movq 0x70(%rsp), %rcx
xorl %edi, %edi
cmpq %rcx, %rax
movq 0x30(%rsp), %r8
movq 0x78(%rsp), %r10
jne 0x48b60
movq 0x100(%rsp), %rdi
movq 0x18(%rdi), %rsi
incq %rsi
callq 0x38382
movq 0x100(%rsp), %rcx
movq 0x8(%rcx), %rax
movq 0x18(%rcx), %rcx
leaq (%rcx,%rcx,2), %rcx
shlq $0x5, %rcx
movq $0x0, -0x54(%rax,%rcx)
movq 0x108(%rsp), %rdi
leaq 0x4c(%rsp), %rsi
callq 0x22e84
movq 0x78(%rsp), %r10
movq 0x30(%rsp), %r8
xorl %edi, %edi
decl 0x48(%rsp)
sete %dil
movq 0x8(%rsp), %rsi
movq (%rsp), %r9
movq 0xa0(%rsp), %rdx
cmpl $0xa, %edi
je 0x48b7a
testl %edi, %edi
jne 0x48b88
incl %r14d
cmpl 0x1c(%rsp), %r14d
jbe 0x488ad
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq