// File: lemire[P]validateutf8-experiments/benchmarks/hoehrmann.h
// Function: shiftless_validate_dfa_utf8_double(signed char const*, unsigned long)
static inline fastvalidate::error_code
shiftless_validate_dfa_utf8_double(const signed char *c, size_t len) {
  if (len < 32) { // if too small, do not bother
    return shiftless_validate_dfa_utf8(c, len);
  }
  // go to the middle:
  size_t middle_point = len / 2;
  // backtrack until we find a leading byte
  while (!is_leading(c[middle_point])) {
    if (middle_point == 0) {
      // we have determined that there is an error
      return fastvalidate::error_code::UTF8_ERROR;
    }
    middle_point -= 1;
  }
  uint32_t state1 = 0;
  uint32_t state2 = 0;
  const unsigned char *cu1 = (const unsigned char *)c;
  const unsigned char *cu2 = (const unsigned char *)(c + middle_point);

  for (size_t i = 0; i < middle_point; i++) {
    uint32_t byteval1 = (uint32_t)cu1[i];
    uint32_t byteval2 = (uint32_t)cu2[i];
    if ((shiftless_updatestate(&state1, byteval1) == SHIFTLESS_UTF8_REJECT) ||
        (shiftless_updatestate(&state2, byteval2) == SHIFTLESS_UTF8_REJECT)) {
      return fastvalidate::error_code::UTF8_ERROR;
    }
  }
  if (shiftless_updatestate(&state1, 0) == SHIFTLESS_UTF8_REJECT) {
    return fastvalidate::error_code::UTF8_ERROR;
  }
  for (size_t i = middle_point; i < len - middle_point; i++) {
    uint32_t byteval2 = (uint32_t)cu2[i];
    if (shiftless_updatestate(&state2, byteval2) == SHIFTLESS_UTF8_REJECT) {
      return fastvalidate::error_code::UTF8_ERROR;
    }
  }
  if (shiftless_updatestate(&state2, 0) == SHIFTLESS_UTF8_REJECT) {
    return fastvalidate::error_code::UTF8_ERROR;
  }
  return fastvalidate::error_code::SUCCESS;
}

// Assembly:
subq $0xb8, %rsp
movq %rdi, 0x50(%rsp)
movq %rsi, 0x48(%rsp)
cmpq $0x20, 0x48(%rsp)
jae 0x4671
movq 0x50(%rsp), %rdi
movq 0x48(%rsp), %rsi
callq 0x4510
movl %eax, 0x5c(%rsp)
jmp 0x49a9
movq 0x48(%rsp), %rax
shrq %rax
movq %rax, 0x40(%rsp)
movq 0x50(%rsp), %rax
movq 0x40(%rsp), %rcx
movb (%rax,%rcx), %al
movb %al, 0xb7(%rsp)
movsbl 0xb7(%rsp), %eax
cmpl $-0x40, %eax
setge %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x46a8
jmp 0x46cd
cmpq $0x0, 0x40(%rsp)
jne 0x46bd
movl $0x1, 0x5c(%rsp)
jmp 0x49a9
movq 0x40(%rsp), %rax
subq $0x1, %rax
movq %rax, 0x40(%rsp)
jmp 0x467e
movl $0x0, 0x3c(%rsp)
movl $0x0, 0x38(%rsp)
movq 0x50(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x50(%rsp), %rax
addq 0x40(%rsp), %rax
movq %rax, 0x28(%rsp)
movq $0x0, 0x20(%rsp)
movq 0x20(%rsp), %rax
cmpq 0x40(%rsp), %rax
jae 0x4829
movq 0x30(%rsp), %rax
movq 0x20(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x1c(%rsp)
movq 0x28(%rsp), %rax
movq 0x20(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x18(%rsp)
movl 0x1c(%rsp), %eax
leaq 0x3c(%rsp), %rcx
movq %rcx, 0xa8(%rsp)
movl %eax, 0xa4(%rsp)
movl 0xa4(%rsp), %eax
movl %eax, %ecx
leaq 0xfacf5(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0xa0(%rsp)
movq 0xa8(%rsp), %rax
movl (%rax), %eax
addl 0xa0(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xfadce(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xa8(%rsp), %rax
movl %ecx, (%rax)
movq 0xa8(%rsp), %rax
cmpl $0x10, (%rax)
je 0x4807
movl 0x18(%rsp), %eax
leaq 0x38(%rsp), %rcx
movq %rcx, 0x98(%rsp)
movl %eax, 0x94(%rsp)
movl 0x94(%rsp), %eax
movl %eax, %ecx
leaq 0xfac8b(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x90(%rsp)
movq 0x98(%rsp), %rax
movl (%rax), %eax
addl 0x90(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xfad64(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x98(%rsp), %rax
movl %ecx, (%rax)
movq 0x98(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x4814
movl $0x1, 0x5c(%rsp)
jmp 0x49a9
jmp 0x4816
movq 0x20(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x20(%rsp)
jmp 0x46ff
leaq 0x3c(%rsp), %rax
movq %rax, 0x88(%rsp)
movl $0x0, 0x84(%rsp)
movl 0x84(%rsp), %eax
movl %eax, %ecx
leaq 0xfabff(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x80(%rsp)
movq 0x88(%rsp), %rax
movl (%rax), %eax
addl 0x80(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xfacd8(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x88(%rsp), %rax
movl %ecx, (%rax)
movq 0x88(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x48a0
movl $0x1, 0x5c(%rsp)
jmp 0x49a9
movq 0x40(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x10(%rsp), %rax
movq 0x48(%rsp), %rcx
subq 0x40(%rsp), %rcx
cmpq %rcx, %rax
jae 0x4945
movq 0x28(%rsp), %rax
movq 0x10(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0xc(%rsp)
movl 0xc(%rsp), %eax
leaq 0x38(%rsp), %rcx
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
movl 0x74(%rsp), %eax
movl %eax, %ecx
leaq 0xfab5d(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x70(%rsp)
movq 0x78(%rsp), %rax
movl (%rax), %eax
addl 0x70(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xfac3f(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x78(%rsp), %rax
movl %ecx, (%rax)
movq 0x78(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x4930
movl $0x1, 0x5c(%rsp)
jmp 0x49a9
jmp 0x4932
movq 0x10(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x10(%rsp)
jmp 0x48aa
leaq 0x38(%rsp), %rax
movq %rax, 0x68(%rsp)
movl $0x0, 0x64(%rsp)
movl 0x64(%rsp), %eax
movl %eax, %ecx
leaq 0xfaaec(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x60(%rsp)
movq 0x68(%rsp), %rax
movl (%rax), %eax
addl 0x60(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xfabce(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x68(%rsp), %rax
movl %ecx, (%rax)
movq 0x68(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x49a1
movl $0x1, 0x5c(%rsp)
jmp 0x49a9
movl $0x0, 0x5c(%rsp)
movl 0x5c(%rsp), %eax
addq $0xb8, %rsp
retq
nopw %cs:(%rax,%rax)