// File: /workspace/github_cpp_makefile_star2_O2/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 $0xa8, %rsp
movq %rcx, %rdi
movl %esi, 0x48(%rsp)
movl 0xe8(%rsp), %ecx
movl 0xe0(%rsp), %esi
movq 0x20(%r8), %rax
movl %eax, %r9d
movq %r9, 0x80(%rsp)
cmpl $0x20, %eax
pushq $0x20
popq %r9
cmovll %eax, %r9d
leal -0x20(%rax), %r10d
xorl %r14d, %r14d
cmpl $0x21, %eax
cmovbl %r14d, %r10d
movl %r10d, 0x18(%rsp)
addl %esi, %eax
subl %eax, %ecx
movl %ecx, 0x1c(%rsp)
movl %ecx, %r10d
shrl %r10d
leal (%r9,%r9), %ecx
negb %cl
pushq $-0x1
popq %rax
movq %rax, 0x38(%rsp)
shrq %cl, %rax
addl %r10d, %esi
movq %rsi, 0x30(%rsp)
movq %r8, 0x98(%rsp)
movq 0x8(%r8), %r15
leal -0x2(,%r9,2), %ecx
movq %rdi, 0x40(%rsp)
movq %r10, 0x28(%rsp)
leaq (%r10,%rdi), %rsi
movq %r9, 0x8(%rsp)
xorl %r13d, %r13d
xorl %edi, %edi
xorl %ebp, %ebp
xorl %ebx, %ebx
movq %r9, %r8
subq $0x1, %r8
jb 0x3e16b
movsbq (%r15,%rdi), %r10
testb $0x4, %r10b
jne 0x3e185
movzbl (%rsi,%rdi), %r11d
testb $0x4, %r11b
je 0x3e152
cmpq %rdi, %r13
cmovbeq %rdi, %r13
cmpq %r9, %r14
cmovbeq %r9, %r14
xorl %r11d, %r11d
shlq $0x2, %rbx
orq %r10, %rbx
shlq $0x2, %rbp
movl %r11d, %r9d
orq %r9, %rbp
incq %rdi
movq %r8, %r9
jmp 0x3e125
movq 0x8(%rsp), %rsi
cmpq 0x80(%rsp), %rsi
jae 0x3e197
cmpb $0x4, (%r15,%rsi)
leaq 0x1(%rsi), %rsi
jne 0x3e170
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x30(%rsp), %rsi
leal 0x1(%rsi), %r9d
movq 0x28(%rsp), %rdi
leal 0x1(%rdi), %r10d
incl 0x1c(%rsp)
movq 0x8(%rsp), %rsi
cmpl $0x20, %esi
leal -0x1(%rsi,%rdi), %r11d
movl %ecx, %esi
movq 0x38(%rsp), %rcx
cmovbq %rax, %rcx
movq %rcx, 0x38(%rsp)
movl 0x18(%rsp), %ecx
shlq $0x20, %rdx
movl 0x108(%rsp), %eax
movq %rdx, 0x68(%rsp)
orq %rdx, %rax
movq %rax, 0x60(%rsp)
movq 0x100(%rsp), %rax
addq $0x8, %rax
movq %rax, 0x90(%rsp)
movq %rcx, 0xa0(%rsp)
leaq -0x1(%rcx), %rax
movq %rax, 0x88(%rsp)
pushq $0x1
popq %r12
xorl %r15d, %r15d
movq %rbp, 0x20(%rsp)
movq %rsi, (%rsp)
cmpl 0x1c(%rsp), %r12d
ja 0x3e185
testb $0x1, %r15b
je 0x3e282
movq 0x30(%rsp), %rax
incl %eax
movq %rax, 0x30(%rsp)
movq 0x28(%rsp), %rax
incl %eax
movq %rax, 0x28(%rsp)
incl %r11d
movq 0x40(%rsp), %rax
movzbl (%rax,%r11), %eax
testb $0x4, %al
cmovneq 0x8(%rsp), %r13
movl $0x0, %ecx
cmovnel %ecx, %eax
movq 0x20(%rsp), %rcx
shlq $0x2, %rcx
orq %rcx, %rax
andq 0x38(%rsp), %rax
testq %r13, %r13
je 0x3e2cf
decq %r13
xorl %r15d, %r15d
jmp 0x3e2df
decl %r9d
decl %r10d
movq 0x40(%rsp), %rax
movzbl (%rax,%r10), %eax
testb $0x4, %al
cmovneq 0x80(%rsp), %r14
movl $0x0, %ecx
cmovnel %ecx, %eax
movq %rbp, %rdx
shrq $0x2, %rdx
movl %esi, %ecx
shlq %cl, %rax
orq %rdx, %rax
cmpl $0x2, %r12d
cmovbq %rbp, %rax
testq %r14, %r14
je 0x3e2e9
decq %r14
movb $0x1, %r15b
movq %rax, %rbp
jmp 0x3e477
xorl %r13d, %r13d
xorl %r15d, %r15d
movq %rbx, 0x20(%rsp)
cmpq %rbx, %rax
je 0x3e2fe
movq %rax, 0x20(%rsp)
jmp 0x3e477
movb $0x1, %r15b
movl $0x0, %r14d
movq %rbx, %rbp
cmpq %rbx, %rax
jne 0x3e3a1
testb %r15b, %r15b
movq 0x30(%rsp), %rax
cmovnel %r9d, %eax
movl %eax, 0x4c(%rsp)
cmpl $0x0, 0x18(%rsp)
je 0x3e35f
testb %r15b, %r15b
movq 0x28(%rsp), %rdx
cmovnel %r10d, %edx
addl 0x8(%rsp), %edx
addq 0x40(%rsp), %rdx
movq 0x98(%rsp), %rcx
movq 0x8(%rcx), %rsi
xorl %ecx, %ecx
cmpq %rcx, 0xa0(%rsp)
je 0x3e35f
movzbl (%rdx,%rcx), %edi
cmpl $0x4, %edi
je 0x3e3ac
movsbl 0x20(%rsi,%rcx), %r8d
cmpl %edi, %r8d
jne 0x3e473
incq %rcx
jmp 0x3e338
movq 0x100(%rsp), %rdi
testq %rdi, %rdi
movl %r9d, 0x14(%rsp)
movq %r10, 0x78(%rsp)
movq %r11, 0x70(%rsp)
je 0x3e410
andq $0x0, 0x50(%rsp)
movl %eax, %ecx
cmpl 0x108(%rsp), %eax
jae 0x3e3c5
orq 0x68(%rsp), %rcx
movq %rcx, 0x50(%rsp)
movq 0x60(%rsp), %rcx
jmp 0x3e3d4
movq %rax, %rbp
xorl %r14d, %r14d
jmp 0x3e477
testb %r15b, %r15b
je 0x3e46b
movq 0x88(%rsp), %r14
subq %rcx, %r14
jmp 0x3e473
movq 0x60(%rsp), %rax
movq %rax, 0x50(%rsp)
orq 0x68(%rsp), %rcx
leaq 0x50(%rsp), %rsi
movq %rcx, 0x58(%rsp)
callq 0x2ea84
cmpq 0x90(%rsp), %rax
je 0x3e3fe
movl 0x14(%rsp), %r9d
movq 0x78(%rsp), %r10
movq 0x70(%rsp), %r11
jmp 0x3e473
movq 0x100(%rsp), %rdi
leaq 0x50(%rsp), %rsi
callq 0x2eb18
movq 0xf0(%rsp), %rdi
movq 0x18(%rdi), %rsi
incq %rsi
callq 0x2ea42
movq 0xf0(%rsp), %rcx
imulq $0x60, 0x18(%rcx), %rax
movq 0x8(%rcx), %rcx
andq $0x0, -0x54(%rcx,%rax)
movq 0xf8(%rsp), %rdi
leaq 0x4c(%rsp), %rsi
callq 0x1bf46
movq 0x70(%rsp), %r11
movq 0x78(%rsp), %r10
movl 0x14(%rsp), %r9d
decl 0x48(%rsp)
movq (%rsp), %rsi
jne 0x3e477
jmp 0x3e185
addq 0x8(%rsp), %rcx
movq %rcx, %r13
movq (%rsp), %rsi
incl %r12d
jmp 0x3e21e
nop