// File: ksabry[P]bfbrute/src/ProgramIterator.h
// Function: ProgramIterator<400ul, 32ul, 12ul, 32ul>::Execute(char const*, unsigned long)
bool Execute(const char* initialData, const uint_fast32_t initialDataSize)
	{
		// TODO: short-circuit unbalanced linear loop if beyond bounds and ends on nonzero

		lastExecutionSuccessful = false;
		lastExecutionMaxProgramIdx = 0;

		uint_fast32_t programIdx = 0;
		dataIdx = data_size / 2 + cache_data_size;
		//dataBoundLow = dataIdx;
		//dataBoundHigh = dataIdx + 1;
		
		memset(data, 0, data_size + 2 * cache_data_size);
		memcpy(data + dataIdx, initialData, initialDataSize);

		uint_fast32_t remainingJumps = MAX_JUMPS;
		while (remainingJumps--)
		{
			assert(programIdx < iteratorCount);
			auto iteratorData = iterators[programIdx].Data();
			bool isLinear = jumps[programIdx].nonzero == programIdx;

			// Technically may be incorrect if iterator size is greater than 256
			//if (isLinear && dataIdx + iteratorData.idx < dataBoundLow && 
			//	iteratorData.data[iteratorData.idx] != 0) return false;
			//if (isLinear && dataIdx + iteratorData.idx >= dataBoundHigh &&
			//	iteratorData.data[iteratorData.idx] != 0) return false;
			//dataBoundLow = Min(dataBoundLow, dataIdx + iteratorData.start);
			//dataBoundHigh = Max(dataBoundHigh, dataIdx + iteratorData.end);

			if (isLinear && iterators[programIdx].IsBalanced())
			{
				uint8_t centerCell = iteratorData.data[iteratorData.idx + cache_data_size / 2];
				int cnt = divisionTable->Get(data[dataIdx], centerCell);
				if (cnt == -1)
				{
					return false;
				}

#ifdef SHORT_CIRCUIT_LINEAR_SINGULAR
				auto programSize = iteratorSizes[programIdx];
				if (programSize == centerCell || programSize == 256 - centerCell)
				{
					data[dataIdx] = 0; 
				}
				else ApplyDataMult(iteratorData, cnt);
#else
				ApplyDataMult(iteratorData.data, cnt);
#endif
				programIdx = jumps[programIdx].zero;
				continue;
			}

			uint_fast32_t newDataIdx = dataIdx + iteratorData.idx;
			if (newDataIdx < cache_data_size || newDataIdx >= data_size + cache_data_size)
			{
				return false;
			}
			
			ApplyData(iteratorData);
		
			dataIdx = newDataIdx;
			if (programIdx == iteratorCount - 1)
			{
				lastExecutionSuccessful = true;
				return true;
			}

			// TODO: test zero, nonzero in array
			programIdx = (data[dataIdx] == 0) ? jumps[programIdx].zero : jumps[programIdx].nonzero;
			if (programIdx > lastExecutionMaxProgramIdx)
			{
				lastExecutionMaxProgramIdx = programIdx;
			}
		}
		return false;
	}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x90, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq -0x10(%rbp), %rdi
movq %rdi, -0x88(%rbp)
movb $0x0, 0x4468(%rdi)
movq $0x0, 0x4470(%rdi)
movq $0x0, -0x28(%rbp)
movq $0xe8, 0x4448(%rdi)
addq $0x4278, %rdi           # imm = 0x4278
xorl %esi, %esi
movl $0x1d0, %edx            # imm = 0x1D0
callq 0x3110
movq -0x88(%rbp), %rax
movq %rax, %rdi
addq $0x4278, %rdi           # imm = 0x4278
addq 0x4448(%rax), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x3200
movq $0xc350, -0x30(%rbp)    # imm = 0xC350
movq -0x30(%rbp), %rax
movq %rax, %rcx
addq $-0x1, %rcx
movq %rcx, -0x30(%rbp)
cmpq $0x0, %rax
je 0x100eb
movq -0x88(%rbp), %rcx
movq -0x28(%rbp), %rax
cmpq 0x20(%rcx), %rax
jae 0xfe63
jmp 0xfe82
leaq 0x39b4(%rip), %rdi      # 0x1381e
leaq 0x3490(%rip), %rsi      # 0x13301
movl $0x211, %edx            # imm = 0x211
leaq 0x39bc(%rip), %rcx      # 0x13839
callq 0x3180
movq -0x88(%rbp), %rdi
addq $0x128, %rdi            # imm = 0x128
imulq $0x1e8, -0x28(%rbp), %rax # imm = 0x1E8
addq %rax, %rdi
callq 0x10630
movq %rax, %rsi
leaq -0x68(%rbp), %rdi
movl $0x38, %edx
callq 0x3200
movq -0x88(%rbp), %rax
addq $0x4030, %rax           # imm = 0x4030
movq -0x28(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rax
cmpq -0x28(%rbp), %rax
sete %al
andb $0x1, %al
movb %al, -0x69(%rbp)
testb $0x1, -0x69(%rbp)
je 0xffd9
movq -0x88(%rbp), %rdi
addq $0x128, %rdi            # imm = 0x128
imulq $0x1e8, -0x28(%rbp), %rax # imm = 0x1E8
addq %rax, %rdi
callq 0x11010
testb $0x1, %al
jne 0xff0a
jmp 0xffd9
movq -0x88(%rbp), %rax
movq -0x48(%rbp), %rcx
movb -0x58(%rbp,%rcx), %cl
movb %cl, -0x6a(%rbp)
movq 0x4460(%rax), %rdi
movq 0x4448(%rax), %rcx
movb 0x4278(%rax,%rcx), %al
movzbl %al, %esi
movzbl -0x6a(%rbp), %edx
callq 0x11030
movl %eax, -0x70(%rbp)
cmpl $-0x1, -0x70(%rbp)
jne 0xff4f
movb $0x0, -0x1(%rbp)
jmp 0x100ef
movq -0x88(%rbp), %rax
movq -0x28(%rbp), %rcx
movq 0x28(%rax,%rcx,8), %rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rax
movzbl -0x6a(%rbp), %ecx
cmpq %rcx, %rax
je 0xff87
movq -0x78(%rbp), %rax
movzbl -0x6a(%rbp), %edx
movl $0x100, %ecx            # imm = 0x100
subl %edx, %ecx
movslq %ecx, %rcx
cmpq %rcx, %rax
jne 0xff9f
movq -0x88(%rbp), %rax
movq 0x4448(%rax), %rcx
movb $0x0, 0x4278(%rax,%rcx)
jmp 0xffb5
movq -0x88(%rbp), %rdi
movl -0x70(%rbp), %eax
leaq -0x68(%rbp), %rsi
movzbl %al, %edx
callq 0x11060
movq -0x88(%rbp), %rax
addq $0x4030, %rax           # imm = 0x4030
movq -0x28(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rax
movq %rax, -0x28(%rbp)
jmp 0xfe37
movq -0x88(%rbp), %rax
movq 0x4448(%rax), %rax
addq -0x48(%rbp), %rax
movq %rax, -0x80(%rbp)
cmpq $0x20, -0x80(%rbp)
jb 0x10000
cmpq $0x1b0, -0x80(%rbp)     # imm = 0x1B0
jb 0x10009
movb $0x0, -0x1(%rbp)
jmp 0x100ef
movq -0x88(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x110e0
movq -0x88(%rbp), %rcx
movq -0x80(%rbp), %rax
movq %rax, 0x4448(%rcx)
movq -0x28(%rbp), %rax
movq 0x20(%rcx), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
jne 0x10053
movq -0x88(%rbp), %rax
movb $0x1, 0x4468(%rax)
movb $0x1, -0x1(%rbp)
jmp 0x100ef
movq -0x88(%rbp), %rax
movq 0x4448(%rax), %rcx
movzbl 0x4278(%rax,%rcx), %eax
cmpl $0x0, %eax
jne 0x10092
movq -0x88(%rbp), %rax
addq $0x4030, %rax           # imm = 0x4030
movq -0x28(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rax
movq %rax, -0x90(%rbp)
jmp 0x100b5
movq -0x88(%rbp), %rax
addq $0x4030, %rax           # imm = 0x4030
movq -0x28(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rax
movq %rax, -0x90(%rbp)
movq -0x88(%rbp), %rcx
movq -0x90(%rbp), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
cmpq 0x4470(%rcx), %rax
jbe 0x100e6
movq -0x88(%rbp), %rax
movq -0x28(%rbp), %rcx
movq %rcx, 0x4470(%rax)
jmp 0xfe37
movb $0x0, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x90, %rsp
popq %rbp
retq
nopl (%rax)