// File: ghallak[P]regex-to-dfa/src/DFA.cpp
// Function: DFA::DFA(RegexTree const&)
DFA::DFA(const RegexTree& tree) {
  std::vector<DState> dstates;

  // add the initial state
  dstates.emplace_back(std::make_unique<State>(), tree.FirstPosRoot());

  auto& alphabet = tree.Alphabet();

  for (std::size_t i = 0; i < dstates.size(); ++i) {
    // accepting states have the end of the regex in their followpos
    if (std::any_of(dstates[i].followpos.cbegin(), dstates[i].followpos.cend(),
                    [endpos = tree.EndPos()](auto next_pos) {
                      return next_pos == endpos;
                    })) {
      dstates[i].state->MakeAcceptState();
    }

    for (auto character : alphabet) {
      std::unordered_set<std::size_t> new_next_positions;

      for (auto next_pos : dstates[i].followpos) {
        if (tree.CharAtPos(character, next_pos)) {
          auto followpos = tree.FollowPos(next_pos);
          new_next_positions.insert(followpos.cbegin(), followpos.cend());
        }
      }

      if (new_next_positions.empty()) continue;

      auto old_dstate = std::find_if(
          dstates.cbegin(), dstates.cend(),
          [& nnp = std::as_const(new_next_positions)](const auto& dstate) {
            return nnp == dstate.followpos;
          });

      if (old_dstate == dstates.end()) {
        dstates.emplace_back(std::make_unique<State>(),
                             std::move(new_next_positions));
        dstates[i].state->AddTransition(dstates.back().state.get(), character);
      } else {
        dstates[i].state->AddTransition(old_dstate->state.get(), character);
      }
    }
  }

  // move the states ownership to the DFA
  for (auto& dstate : dstates) states.emplace_back(std::move(dstate.state));
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x200, %rsp            # imm = 0x200
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x190(%rbp)
movq %rdi, %rax
movq %rax, -0x188(%rbp)
callq 0x4aa0
leaq -0x28(%rbp), %rdi
callq 0x2a40
leaq -0x30(%rbp), %rdi
callq 0x4ac0
jmp 0x2471
movq -0x10(%rbp), %rdi
callq 0x4b20
movq %rax, -0x198(%rbp)
jmp 0x2483
movq -0x198(%rbp), %rdx
leaq -0x28(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x2a60
jmp 0x2499
leaq -0x30(%rbp), %rdi
callq 0x4b50
movq -0x10(%rbp), %rdi
callq 0x4bc0
movq %rax, -0x1a0(%rbp)
jmp 0x24b4
movq -0x1a0(%rbp), %rax
movq %rax, -0x48(%rbp)
movq $0x0, -0x50(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0x1a8(%rbp)
leaq -0x28(%rbp), %rdi
callq 0x2ae0
movq %rax, %rcx
movq -0x1a8(%rbp), %rax
cmpq %rcx, %rax
jae 0x2980
movq -0x50(%rbp), %rsi
leaq -0x28(%rbp), %rdi
movq %rdi, -0x1c0(%rbp)
callq 0x2b50
movq %rax, %rdi
addq $0x8, %rdi
callq 0x4be0
movq -0x1c0(%rbp), %rdi
movq %rax, -0x58(%rbp)
movq -0x50(%rbp), %rsi
callq 0x2b50
movq %rax, %rdi
addq $0x8, %rdi
callq 0x4c10
movq %rax, -0x60(%rbp)
leaq -0x68(%rbp), %rax
movq %rax, -0x1b8(%rbp)
movq -0x10(%rbp), %rdi
callq 0x4c40
movq %rax, -0x1b0(%rbp)
jmp 0x254f
movq -0x1b8(%rbp), %rax
movq -0x1b0(%rbp), %rcx
movq %rcx, (%rax)
movq -0x58(%rbp), %rdi
movq -0x60(%rbp), %rsi
movq -0x68(%rbp), %rdx
callq 0x2b00
movb %al, -0x1c1(%rbp)
jmp 0x2579
movb -0x1c1(%rbp), %al
testb $0x1, %al
jne 0x2585
jmp 0x25d1
movq -0x50(%rbp), %rsi
leaq -0x28(%rbp), %rdi
callq 0x2b50
movq %rax, %rdi
callq 0x4c60
movq %rax, %rdi
callq 0x4c80
jmp 0x25a4
jmp 0x25d1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
jmp 0x2a14
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x4b50
jmp 0x2a14
movq -0x48(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rdi
callq 0x4ca0
movq %rax, -0x78(%rbp)
movq -0x70(%rbp), %rdi
callq 0x4cd0
movq %rax, -0x80(%rbp)
leaq -0x78(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0x4d00
testb $0x1, %al
jne 0x2609
jmp 0x296d
leaq -0x78(%rbp), %rdi
callq 0x4d30
movb (%rax), %al
movb %al, -0x81(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0x4a60
movq -0x50(%rbp), %rsi
leaq -0x28(%rbp), %rdi
callq 0x2b50
addq $0x8, %rax
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rdi
callq 0x4d60
movq %rax, -0xd0(%rbp)
movq -0xc8(%rbp), %rdi
callq 0x4d90
movq %rax, -0xd8(%rbp)
leaq -0xd0(%rbp), %rdi
leaq -0xd8(%rbp), %rsi
callq 0x4dc0
testb $0x1, %al
jne 0x2680
jmp 0x278a
leaq -0xd0(%rbp), %rdi
callq 0x4df0
movq (%rax), %rax
movq %rax, -0xe0(%rbp)
movq -0x10(%rbp), %rdi
movsbl -0x81(%rbp), %esi
movq -0xe0(%rbp), %rdx
callq 0x4e20
movb %al, -0x1c2(%rbp)
jmp 0x26b5
movb -0x1c2(%rbp), %al
testb $0x1, %al
jne 0x26c4
jmp 0x2777
movq -0x10(%rbp), %rdi
movq -0xe0(%rbp), %rsi
callq 0x4e90
movq %rax, -0x1d0(%rbp)
jmp 0x26dd
movq -0x1d0(%rbp), %rsi
leaq -0x118(%rbp), %rdi
callq 0x4f00
jmp 0x26f2
leaq -0x118(%rbp), %rdi
movq %rdi, -0x1d8(%rbp)
callq 0x4be0
movq -0x1d8(%rbp), %rdi
movq %rax, -0x120(%rbp)
callq 0x4c10
movq %rax, -0x128(%rbp)
movq -0x120(%rbp), %rsi
movq -0x128(%rbp), %rdx
leaq -0xc0(%rbp), %rdi
callq 0x4f30
jmp 0x273b
leaq -0x118(%rbp), %rdi
callq 0x4a80
jmp 0x2777
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
jmp 0x295c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0x118(%rbp), %rdi
callq 0x4a80
jmp 0x295c
jmp 0x2779
leaq -0xd0(%rbp), %rdi
callq 0x4f70
jmp 0x2664
leaq -0xc0(%rbp), %rdi
callq 0x4fa0
testb $0x1, %al
jne 0x279c
jmp 0x27ab
movl $0x6, -0x12c(%rbp)
jmp 0x2932
leaq -0x28(%rbp), %rdi
movq %rdi, -0x1e8(%rbp)
callq 0x2bd0
movq -0x1e8(%rbp), %rdi
movq %rax, -0x140(%rbp)
callq 0x2c00
movq %rax, -0x148(%rbp)
leaq -0xc0(%rbp), %rax
movq %rax, -0x150(%rbp)
movq -0x140(%rbp), %rdi
movq -0x148(%rbp), %rsi
movq -0x150(%rbp), %rdx
callq 0x2b70
movq %rax, -0x1e0(%rbp)
jmp 0x2806
movq -0x1e0(%rbp), %rax
movq %rax, -0x138(%rbp)
leaq -0x28(%rbp), %rdi
callq 0x2c70
movq %rax, -0x158(%rbp)
leaq -0x138(%rbp), %rdi
leaq -0x158(%rbp), %rsi
callq 0x2c30
testb $0x1, %al
jne 0x2840
jmp 0x28de
leaq -0x160(%rbp), %rdi
callq 0x4ac0
jmp 0x284e
leaq -0x28(%rbp), %rdi
leaq -0x160(%rbp), %rsi
leaq -0xc0(%rbp), %rdx
callq 0x2ca0
jmp 0x2867
leaq -0x160(%rbp), %rdi
callq 0x4b50
movq -0x50(%rbp), %rsi
leaq -0x28(%rbp), %rdi
movq %rdi, -0x1f8(%rbp)
callq 0x2b50
movq %rax, %rdi
callq 0x4c60
movq -0x1f8(%rbp), %rdi
movq %rax, -0x1f0(%rbp)
callq 0x2d20
movq %rax, %rdi
callq 0x4ff0
movq -0x1f0(%rbp), %rdi
movq %rax, %rsi
movsbl -0x81(%rbp), %edx
callq 0x4fc0
jmp 0x28c2
jmp 0x2928
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x38(%rbp)
movl %eax, -0x3c(%rbp)
leaq -0x160(%rbp), %rdi
callq 0x4b50
jmp 0x295c
movq -0x50(%rbp), %rsi
leaq -0x28(%rbp), %rdi
callq 0x2b50
movq %rax, %rdi
callq 0x4c60
movq %rax, -0x200(%rbp)
leaq -0x138(%rbp), %rdi
callq 0x2d60
movq %rax, %rdi
callq 0x4ff0
movq -0x200(%rbp), %rdi
movq %rax, %rsi
movsbl -0x81(%rbp), %edx
callq 0x4fc0
jmp 0x2926
jmp 0x2928
movl $0x0, -0x12c(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0x4a80
movl -0x12c(%rbp), %eax
testl %eax, %eax
je 0x294c
jmp 0x294a
jmp 0x294e
jmp 0x294e
leaq -0x78(%rbp), %rdi
callq 0x5020
jmp 0x25f3
leaq -0xc0(%rbp), %rdi
callq 0x4a80
jmp 0x2a14
jmp 0x296f
movq -0x50(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x50(%rbp)
jmp 0x24c7
leaq -0x28(%rbp), %rax
movq %rax, -0x168(%rbp)
movq -0x168(%rbp), %rdi
callq 0x2d80
movq %rax, -0x170(%rbp)
movq -0x168(%rbp), %rdi
callq 0x2c70
movq %rax, -0x178(%rbp)
leaq -0x170(%rbp), %rdi
leaq -0x178(%rbp), %rsi
callq 0x2db0
testb $0x1, %al
jne 0x29ca
jmp 0x2a02
leaq -0x170(%rbp), %rdi
callq 0x2df0
movq -0x188(%rbp), %rdi
movq %rax, -0x180(%rbp)
movq -0x180(%rbp), %rsi
callq 0x5050
jmp 0x29f2
jmp 0x29f4
leaq -0x170(%rbp), %rdi
callq 0x2e10
jmp 0x29b1
leaq -0x28(%rbp), %rdi
callq 0x2e30
addq $0x200, %rsp            # imm = 0x200
popq %rbp
retq
leaq -0x28(%rbp), %rdi
callq 0x2e30
movq -0x190(%rbp), %rdi
callq 0x50d0
movq -0x38(%rbp), %rdi
callq 0x2240
nopw %cs:(%rax,%rax)