// File: BenLangmead[P]bowtie/./zbox.h
// Function: void calcZ<SString<char>>(SString<char> const&, unsigned int, EList<unsigned int, 128>&, bool, bool)
void calcZ(const T& s,
		TIndexOffU off,
	   EList<TIndexOffU>& z,
           bool verbose = false,
           bool sanityCheck = false)
{
	size_t lCur = 0, rCur = 0;
	size_t zlen = z.size();
	size_t slen = s.length();
	assert_gt(zlen, 0);
	assert_eq(z[0], 0);
	//assert_leq(zlen, slen);
	for (size_t k = 1; k < zlen && k+off < slen; k++) {
		assert_lt(lCur, k);
		assert(z[lCur] == 0 || z[lCur] == rCur - lCur + 1);
		if(k > rCur) {
			// compare starting at k with prefix starting at 0
			size_t ki = k;
			while(off+ki < s.length() && s[off+ki] == s[off+ki-k]) ki++;
			z[k] = (TIndexOffU)(ki - k);
			assert_lt(off+z[k], slen);
			if(z[k] > 0) {
				lCur = k;
				rCur = k + z[k] - 1;
			}
		} else {
			// position k is contained in a Z-box
			size_t betaLen = rCur - k + 1;
			size_t kPrime = k - lCur;
			assert_eq(s[off+k], s[off+kPrime]);
			if(z[kPrime] < betaLen) {
				z[k] = z[kPrime];
				assert_lt(off+z[k], slen);
				// lCur, rCur unchanged
			} else if (z[kPrime] > 0) {
				int q = 0;
				while (off+q+rCur+1 < s.length() && s[off+q+rCur+1] == s[off+betaLen+q]) q++;
				z[k] = (TIndexOffU)(betaLen + q);
				assert_lt(off+z[k], slen);
				rCur = rCur + q;
				assert_geq(k, lCur);
				lCur = k;
			} else {
				z[k] = 0;
				assert_lt(off+z[k], slen);
				// lCur, rCur unchanged
			}
		}
	}
#ifndef NDEBUG
	if(sanityCheck) {
		// Recalculate Z-boxes using naive quadratic-time algorithm and
		// compare to linear-time result
		assert_eq(0, z[0]);
		for(size_t i = 1; i < z.size(); i++) {
			size_t j;
			for(j = i; off+j < s.length(); j++) {
				if(s[off+j] != s[off+j-i]) break;
			}
			assert_eq(j-i, z[i]);
		}
	}
#endif
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movb %r8b, %al
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq %rdx, -0x18(%rbp)
andb $0x1, %cl
movb %cl, -0x19(%rbp)
andb $0x1, %al
movb %al, -0x1a(%rbp)
movq $0x0, -0x28(%rbp)
movq $0x0, -0x30(%rbp)
movq -0x18(%rbp), %rdi
callq 0x14440
movq %rax, -0x38(%rbp)
movq -0x8(%rbp), %rdi
callq 0x14c10
movq %rax, -0x40(%rbp)
movq $0x1, -0x48(%rbp)
movq -0x48(%rbp), %rcx
xorl %eax, %eax
cmpq -0x38(%rbp), %rcx
movb %al, -0x65(%rbp)
jae 0x30399
movq -0x48(%rbp), %rax
movl -0xc(%rbp), %ecx
addq %rcx, %rax
cmpq -0x40(%rbp), %rax
setb %al
movb %al, -0x65(%rbp)
movb -0x65(%rbp), %al
testb $0x1, %al
jne 0x303a5
jmp 0x30626
movq -0x48(%rbp), %rax
cmpq -0x30(%rbp), %rax
jbe 0x3049b
movq -0x48(%rbp), %rax
movq %rax, -0x50(%rbp)
movl -0xc(%rbp), %eax
addq -0x50(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x8(%rbp), %rdi
callq 0x14c10
movq -0x70(%rbp), %rcx
movq %rax, %rdx
xorl %eax, %eax
cmpq %rdx, %rcx
movb %al, -0x66(%rbp)
jae 0x3041f
movq -0x8(%rbp), %rdi
movl -0xc(%rbp), %eax
movl %eax, %esi
addq -0x50(%rbp), %rsi
callq 0x14c30
movsbl (%rax), %eax
movl %eax, -0x74(%rbp)
movq -0x8(%rbp), %rdi
movl -0xc(%rbp), %eax
movl %eax, %esi
addq -0x50(%rbp), %rsi
subq -0x48(%rbp), %rsi
callq 0x14c30
movq %rax, %rcx
movl -0x74(%rbp), %eax
movsbl (%rcx), %ecx
cmpl %ecx, %eax
sete %al
movb %al, -0x66(%rbp)
movb -0x66(%rbp), %al
testb $0x1, %al
jne 0x30428
jmp 0x30436
movq -0x50(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x50(%rbp)
jmp 0x303bb
movq -0x50(%rbp), %rax
subq -0x48(%rbp), %rax
movl %eax, -0x78(%rbp)
movq -0x18(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x14410
movl -0x78(%rbp), %ecx
movl %ecx, (%rax)
movq -0x18(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x14410
cmpl $0x0, (%rax)
jbe 0x30496
movq -0x48(%rbp), %rax
movq %rax, -0x28(%rbp)
movq -0x48(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x18(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x14410
movq %rax, %rcx
movq -0x80(%rbp), %rax
movl (%rcx), %ecx
addq %rcx, %rax
subq $0x1, %rax
movq %rax, -0x30(%rbp)
jmp 0x30613
movq -0x30(%rbp), %rax
subq -0x48(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x58(%rbp)
movq -0x48(%rbp), %rax
subq -0x28(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x18(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x14410
movl (%rax), %eax
cmpq -0x58(%rbp), %rax
jae 0x304fb
movq -0x18(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x14410
movl (%rax), %eax
movl %eax, -0x84(%rbp)
movq -0x18(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x14410
movl -0x84(%rbp), %ecx
movl %ecx, (%rax)
jmp 0x30611
movq -0x18(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x14410
cmpl $0x0, (%rax)
jbe 0x305fc
movl $0x0, -0x64(%rbp)
movl -0xc(%rbp), %eax
addl -0x64(%rbp), %eax
movl %eax, %eax
addq -0x30(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x90(%rbp)
movq -0x8(%rbp), %rdi
callq 0x14c10
movq -0x90(%rbp), %rcx
movq %rax, %rdx
xorl %eax, %eax
cmpq %rdx, %rcx
movb %al, -0x85(%rbp)
jae 0x305a3
movq -0x8(%rbp), %rdi
movl -0xc(%rbp), %eax
addl -0x64(%rbp), %eax
movl %eax, %eax
movl %eax, %esi
addq -0x30(%rbp), %rsi
addq $0x1, %rsi
callq 0x14c30
movsbl (%rax), %eax
movl %eax, -0x94(%rbp)
movq -0x8(%rbp), %rdi
movl -0xc(%rbp), %eax
movl %eax, %esi
addq -0x58(%rbp), %rsi
movslq -0x64(%rbp), %rax
addq %rax, %rsi
callq 0x14c30
movq %rax, %rcx
movl -0x94(%rbp), %eax
movsbl (%rcx), %ecx
cmpl %ecx, %eax
sete %al
movb %al, -0x85(%rbp)
movb -0x85(%rbp), %al
testb $0x1, %al
jne 0x305af
jmp 0x305bd
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x30518
movq -0x58(%rbp), %rax
movslq -0x64(%rbp), %rcx
addq %rcx, %rax
movl %eax, -0x98(%rbp)
movq -0x18(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x14410
movl -0x98(%rbp), %ecx
movl %ecx, (%rax)
movq -0x30(%rbp), %rax
movslq -0x64(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0x30(%rbp)
movq -0x48(%rbp), %rax
movq %rax, -0x28(%rbp)
jmp 0x3060f
movq -0x18(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x14410
movl $0x0, (%rax)
jmp 0x30611
jmp 0x30613
jmp 0x30615
movq -0x48(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x48(%rbp)
jmp 0x30376
addq $0xa0, %rsp
popq %rbp
retq
nop