// File: /workspace/github_cpp_makefile_star2_O3/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
movq %rdx, 0x18(%rsp)
movl %esi, 0x38(%rsp)
movl 0xe8(%rsp), %ecx
movl 0xe0(%rsp), %eax
movq 0x20(%r8), %rbp
cmpl $0x20, %ebp
movl $0x20, %r9d
cmovll %ebp, %r9d
leal -0x20(%rbp), %edx
xorl %r12d, %r12d
cmpl $0x21, %ebp
cmovbl %r12d, %edx
movl %edx, 0x10(%rsp)
addl %ebp, %eax
subl %eax, %ecx
movl %ecx, 0x14(%rsp)
movl %ecx, %edx
shrl %edx
leal (%r9,%r9), %ecx
negb %cl
movq $-0x1, %rax
shrq %cl, %rax
testl %ebp, %ebp
movq %rdi, 0x78(%rsp)
movq %r8, 0x68(%rsp)
movq %rdx, 0x20(%rsp)
je 0x47676
movq 0x8(%r8), %rcx
leaq (%rdi,%rdx), %rsi
cmpq $0x1, %r9
movq %r9, %rdi
adcq $0x0, %rdi
xorl %r13d, %r13d
movq %r9, %rdx
movq %r9, %r8
xorl %r10d, %r10d
xorl %r9d, %r9d
xorl %r15d, %r15d
xorl %r12d, %r12d
movsbq (%rcx,%r9), %r11
testb $0x4, %r11b
jne 0x479c6
movzbl (%rsi,%r9), %ebx
testb $0x4, %bl
je 0x47655
cmpq %r9, %r15
cmovbeq %r9, %r15
cmpq %r8, %r12
cmovbeq %r8, %r12
xorl %ebx, %ebx
shlq $0x2, %r13
orq %r11, %r13
shlq $0x2, %r10
movl %ebx, %r14d
orq %r10, %r14
incq %r9
decq %r8
movq %r14, %r10
cmpq %r9, %rdi
jne 0x4762c
jmp 0x47682
movq %r9, %rdx
xorl %r15d, %r15d
xorl %r14d, %r14d
xorl %r13d, %r13d
movl %ebp, %r9d
cmpl %edx, %r9d
jbe 0x476a8
movq 0x68(%rsp), %rcx
movq 0x8(%rcx), %rcx
movq %rdx, %rsi
cmpb $0x4, (%rcx,%rsi)
je 0x479c6
incq %rsi
cmpq %rsi, %r9
jne 0x47696
incl 0x14(%rsp)
je 0x479c6
movq 0x100(%rsp), %rdi
movl 0xe0(%rsp), %ecx
movq %rcx, %rsi
movq 0x20(%rsp), %r8
addl %r8d, %esi
leal -0x2(,%rdx,2), %ecx
leal 0x1(%r8), %r11d
movq %rsi, 0x30(%rsp)
leal 0x1(%rsi), %r10d
cmpl $0x20, %edx
movq %rdx, 0x28(%rsp)
leal -0x1(%rdx,%r8), %edx
movq %rdx, 0x70(%rsp)
movl %ecx, %ecx
movq %rcx, 0x98(%rsp)
movq $-0x1, %rcx
cmovbq %rax, %rcx
movq %rcx, 0x90(%rsp)
movl 0x10(%rsp), %eax
movq 0x18(%rsp), %rdx
shlq $0x20, %rdx
movl 0x108(%rsp), %ecx
movq %rdx, 0x18(%rsp)
orq %rdx, %rcx
movq %rcx, 0x50(%rsp)
leaq 0x8(%rdi), %rcx
movq %rcx, 0x88(%rsp)
movq %rax, 0xa0(%rsp)
decq %rax
movq %rax, 0x80(%rsp)
movl $0x1, %ebp
xorl %ebx, %ebx
movq %r14, %r8
movq %r9, 0x58(%rsp)
testb $0x1, %bl
je 0x477bb
movq 0x30(%rsp), %rax
incl %eax
movq %rax, 0x30(%rsp)
movq 0x20(%rsp), %rax
incl %eax
movq %rax, 0x20(%rsp)
movq 0x70(%rsp), %rax
incl %eax
movq 0x78(%rsp), %rsi
movq %rax, 0x70(%rsp)
movzbl (%rsi,%rax), %eax
testb $0x4, %al
cmovneq 0x28(%rsp), %r15
movl $0x0, %ecx
cmovnel %ecx, %eax
shlq $0x2, %r14
orq %r14, %rax
andq 0x90(%rsp), %rax
testq %r15, %r15
je 0x47807
decq %r15
xorl %ebx, %ebx
jmp 0x47814
decl %r10d
decl %r11d
movq 0x78(%rsp), %rsi
movzbl (%rsi,%r11), %eax
testb $0x4, %al
cmovneq %r9, %r12
movl $0x0, %ecx
cmovnel %ecx, %eax
movq %r8, %rdx
shrq $0x2, %rdx
movq 0x98(%rsp), %rcx
shlq %cl, %rax
orq %rdx, %rax
cmpl $0x2, %ebp
cmovbq %r8, %rax
testq %r12, %r12
je 0x4781c
decq %r12
movb $0x1, %bl
movq %rax, %r8
jmp 0x479ba
xorl %r15d, %r15d
xorl %ebx, %ebx
movq %r13, %r14
cmpq %r13, %rax
je 0x47830
movq %rax, %r14
jmp 0x479ba
movb $0x1, %bl
movl $0x0, %r12d
movq %r13, %r8
cmpq %r13, %rax
jne 0x478c7
movq %r8, 0x8(%rsp)
testb %bl, %bl
movq 0x30(%rsp), %rax
movl %r10d, 0x4(%rsp)
cmovnel %r10d, %eax
movl %eax, 0x3c(%rsp)
cmpl $0x0, 0x10(%rsp)
je 0x47894
testb %bl, %bl
movq 0x20(%rsp), %rdx
cmovnel %r11d, %edx
addl 0x28(%rsp), %edx
addq %rsi, %rdx
movq 0x68(%rsp), %rcx
movq 0x8(%rcx), %rsi
xorl %ecx, %ecx
movzbl (%rdx,%rcx), %r10d
cmpl $0x4, %r10d
je 0x478d2
movsbl 0x20(%rsi,%rcx), %r8d
cmpl %r10d, %r8d
jne 0x479b0
incq %rcx
cmpq %rcx, 0xa0(%rsp)
jne 0x4786d
testq %rdi, %rdi
movq %r11, 0x60(%rsp)
je 0x4793d
movq $0x0, 0x40(%rsp)
cmpl 0x108(%rsp), %eax
jae 0x478ea
movl %eax, %eax
orq 0x18(%rsp), %rax
movq %rax, 0x40(%rsp)
movq 0x50(%rsp), %rax
jmp 0x478fb
movq %rax, %r8
xorl %r12d, %r12d
jmp 0x479ba
testb %bl, %bl
je 0x479a8
movq 0x80(%rsp), %r12
subq %rcx, %r12
jmp 0x479b0
movq 0x50(%rsp), %rcx
movq %rcx, 0x40(%rsp)
movl %eax, %eax
orq 0x18(%rsp), %rax
leaq 0x40(%rsp), %rsi
movq %rax, 0x48(%rsp)
callq 0x37976
cmpq 0x88(%rsp), %rax
je 0x4792b
movq 0x58(%rsp), %r9
movq 0x100(%rsp), %rdi
movq 0x60(%rsp), %r11
jmp 0x479b0
movq 0x100(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x379dc
movq 0xf0(%rsp), %rdi
movq 0x18(%rdi), %rsi
incq %rsi
callq 0x37910
movq 0xf0(%rsp), %rcx
movq 0x8(%rcx), %rax
movq 0x18(%rcx), %rcx
leaq (%rcx,%rcx,2), %rcx
shlq $0x5, %rcx
movq $0x0, -0x54(%rax,%rcx)
movq 0xf8(%rsp), %rdi
leaq 0x3c(%rsp), %rsi
callq 0x22bde
movq 0x60(%rsp), %r11
movq 0x100(%rsp), %rdi
movq 0x58(%rsp), %r9
decl 0x38(%rsp)
movl 0x4(%rsp), %r10d
movq 0x8(%rsp), %r8
jne 0x479ba
jmp 0x479c6
addq 0x28(%rsp), %rcx
movq %rcx, %r15
movl 0x4(%rsp), %r10d
movq 0x8(%rsp), %r8
incl %ebp
cmpl 0x14(%rsp), %ebp
jbe 0x4775e
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq