// File: /workspace/github_cpp_makefile_star2_O3/isovic[P]cigargen/cigargen.cc
// Function: GenerateCigar(char*, unsigned int, char*, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, unsigned int*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*)
int32_t GenerateCigar(char *query, uint32_t query_length, char *reference, uint32_t reference_length, std::string *ret_cigar, uint32_t *ret_alignment_length, std::string *ret_alignment) {
  if (query == NULL || reference == NULL || query_length == 0 || reference_length == 0)
    return -1;

  // Preallocate the memory for the DP matrix and traceback, and initialize all values to 0.
  std::vector<std::vector<int32_t> > dp_matrix((query_length + 1), std::vector<int32_t>((reference_length + 1), 0));
  std::vector<std::vector<uint8_t> > dp_traceback((query_length + 1), std::vector<uint8_t>((reference_length + 1), 0));
  // Temporary variables for storing the options for the current step. (Could have been done differently, but increases readability.)
  int32_t up=0, left=0, diagonal=0;

  // Initialize the first row and column according to Needleman-Wunsch.
  for (uint32_t i=0; i<=query_length; i++)
    dp_matrix[i][0] = i * PENALTY_INSERTION;
  for (uint32_t i=0; i<=reference_length; i++)
    dp_matrix[0][i] = i * PENALTY_DELETION;

  int32_t max_score_index = 0;

  for (uint32_t i=1; i<=query_length; i++) {
    for (uint32_t j=1; j<=reference_length; j++) {
      // Calculate the options for the current value of the DP matrix.
      up = dp_matrix[i-1][j] + PENALTY_INSERTION;
      left = dp_matrix[i][j-1] + PENALTY_DELETION;
      diagonal = dp_matrix[i-1][j-1] + ((query[i-1] == reference[j-1]) ? PENALTY_MATCH : PENALTY_MISMATCH);

      // Find the maximum of the three values.
      dp_matrix[i][j] = diagonal;
      dp_traceback[i][j] = ((query[i-1] == reference[j-1])?0:1);
      if (up > dp_matrix[i][j]) {
        dp_matrix[i][j] = up;
        dp_traceback[i][j] = 2;
      }
      if (left > dp_matrix[i][j]) {
        dp_matrix[i][j] = left;
        dp_traceback[i][j] = 3;
      }

      // If this is the last row of the matrix, we need to look up for the maximum score. This will be our starting point for the
      // CIGAR traceback calculation.
      if (i == query_length && dp_matrix[query_length][j] > dp_matrix[query_length][max_score_index])
        max_score_index = j;
    }
  }

  // Initialize the traceback column to the index of the highest score, and the traceback row to the last row of the matrix.
  int32_t current_traceback_row = query_length, current_traceback_column = max_score_index;

  std::stringstream cigar_stream;
  std::string cigar = "";
  std::string alignment = "";
  uint32_t edit_distance = 0;

  // Traceback: Find the CIGAR string.
  uint32_t iterations=0, num_insertions=0, type=0, last_type=0, num_same_types=0;
  while (current_traceback_column > 0 && current_traceback_row > 0) {
    type = dp_traceback[current_traceback_row][current_traceback_column];

    // Count the number of same transitions in the DP matrix (whether if it was to the left, right or up.)
    if (iterations == 0) {
      // If this is the first traceback step, initialize the last type for counting.
      last_type = type;
      num_same_types = 1;
    }
    else {
      if (type == last_type) {
        // If types of transition are the same, just count them.
        num_same_types += 1;
      }
      else {
        // If the type has changed, stream the CIGAR count, and reset the type to the current one.
        cigar_stream << TypeToSymbol(last_type) << num_same_types;
        last_type = type;
        num_same_types = 1;
      }
    }

    if (type != TYPE_MATCH)
      edit_distance += 1;

    // Accumulate the characters for the alignment, but only if this was asked for (that's why there is
    // the NULL testing). We insert a special character '+' in this implementation, which represents that
    // there was an insertion on the reference (one character was removed from the query).
    // Character '-' represents the deletion in the reference (or an insertion on the query).
    if (ret_alignment != NULL)
        alignment +=  ((type == TYPE_DELETION) ? '-' :
                      ((type == TYPE_MATCH) ? query[current_traceback_row - 1] :
                      ((type == TYPE_INSERTION) ? '+' :
                      'x')));

    if (type == TYPE_INSERTION)
      num_insertions += 1;

    // Row changes in all cases except when a deletion occurs (type == 3).
    current_traceback_row -= (type != TYPE_DELETION) ? 1 : 0;
    // Column changes in all cases except when an insertion occurs (type == 2).
    current_traceback_column -= (type != TYPE_INSERTION) ? 1 : 0;

    // Count the traceback length.
    iterations += 1;
  }

  // Stream the remaining count to the CIGAR stream.
  cigar_stream << TypeToSymbol(last_type) << num_same_types;
  cigar = cigar_stream.str();
  std::reverse(cigar.begin(), cigar.end());
  std::reverse(alignment.begin(), alignment.end());

  if (ret_cigar != NULL)
    *ret_cigar = cigar;
  else
    Verbose(stdout, query, query_length, reference, reference_length, cigar, dp_matrix, dp_traceback);

  // Return the final alignment length. We need to subtract the number of insertions on the reference because the final
  // alignment should be shorter than the traceback for this amount.
  if (ret_alignment_length != NULL)
    *ret_alignment_length = (iterations - num_insertions);

  // Return the final alignment if required. The alignment.size() value is larger than ret_alignment_length, because
  // query deletions have not been completely removed, but changed with a special character.
  if (ret_alignment != NULL)
    *ret_alignment = alignment;

  return edit_distance;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x268, %rsp            # imm = 0x268
movl $0xffffffff, %r14d      # imm = 0xFFFFFFFF
testl %ecx, %ecx
je 0x2c3f
testl %esi, %esi
je 0x2c3f
movq %rdi, %rbx
testq %rdi, %rdi
je 0x2c3f
movq %rdx, %r15
testq %rdx, %rdx
je 0x2c3f
movq %r9, %r13
movq %rsi, -0x50(%rbp)
movq %r8, -0x108(%rbp)
movq %rcx, -0xf8(%rbp)
leal 0x1(%rcx), %r14d
leaq -0x78(%rbp), %rdx
movl $0x0, (%rdx)
leaq -0x290(%rbp), %rdi
leaq -0x98(%rbp), %rcx
movq %r14, %rsi
callq 0x2faa
movq -0x50(%rbp), %rax
leal 0x1(%rax), %r12d
leaq -0xb8(%rbp), %rdi
leaq -0x290(%rbp), %rdx
leaq -0xf0(%rbp), %rcx
movq %r12, %rsi
callq 0x3032
movq -0x290(%rbp), %rdi
testq %rdi, %rdi
je 0x269f
movq -0x280(%rbp), %rsi
subq %rdi, %rsi
callq 0x2130
leaq -0x78(%rbp), %rdx
movb $0x0, (%rdx)
leaq -0x290(%rbp), %rdi
leaq -0x98(%rbp), %rcx
movq %r14, %rsi
callq 0x30d4
leaq -0xd0(%rbp), %rdi
leaq -0x290(%rbp), %rdx
leaq -0xf0(%rbp), %rcx
movq %r12, %rsi
callq 0x3134
movq -0x290(%rbp), %rdi
testq %rdi, %rdi
je 0x26f4
movq -0x280(%rbp), %rsi
subq %rdi, %rsi
callq 0x2130
movq -0xb8(%rbp), %rax
cmpl $0x2, %r12d
movl $0x1, %ecx
cmovael %r12d, %ecx
shlq $0x3, %rcx
leaq (%rcx,%rcx,2), %rcx
xorl %edx, %edx
xorl %esi, %esi
movq (%rax,%rsi), %rdi
movl %edx, (%rdi)
addq $0x18, %rsi
addl $-0x6, %edx
cmpq %rsi, %rcx
jne 0x2714
movq %r13, -0x100(%rbp)
cmpl $0x2, %r14d
movl $0x1, %ecx
cmovael %r14d, %ecx
movq (%rax), %rax
addq %rcx, %rcx
leaq (%rcx,%rcx,2), %rcx
xorl %edx, %edx
movl %edx, (%rax)
addq $0x4, %rax
addq $-0x6, %rdx
movq %rcx, %rsi
addq %rdx, %rsi
jne 0x2746
cmpl $0x3, %r14d
movl $0x2, %eax
cmovbl %eax, %r14d
cmpl $0x3, %r12d
cmovael %r12d, %eax
movq %rax, -0x38(%rbp)
movl -0x50(%rbp), %ecx
decq %r14
xorl %r13d, %r13d
movl $0x1, %edx
leaq -0x1(%rdx), %rsi
leaq (%rsi,%rsi,2), %rsi
leaq (,%rdx,8), %rdi
leaq (%rdi,%rdi,2), %rdi
xorl %r8d, %r8d
movb -0x1(%rbx,%rdx), %r9b
movl $0x5, %r10d
cmpb (%r15,%r8), %r9b
je 0x27ad
movl $0xfffffffe, %r10d      # imm = 0xFFFFFFFE
movq -0xb8(%rbp), %r9
movq (%r9,%rsi,8), %r12
movl 0x4(%r12,%r8,4), %r11d
addl $-0x6, %r11d
movq (%r9,%rdi), %rax
movl (%rax,%r8,4), %r9d
addl (%r12,%r8,4), %r10d
movl %r10d, 0x4(%rax,%r8,4)
movb -0x1(%rbx,%rdx), %al
cmpb (%r15,%r8), %al
movq -0xd0(%rbp), %rax
movq (%rax,%rdi), %rax
setne 0x1(%rax,%r8)
movq -0xb8(%rbp), %rax
movq (%rax,%rdi), %r10
movl 0x4(%r10,%r8,4), %r12d
cmpl %r12d, %r11d
jle 0x2826
movl %r11d, 0x4(%r10,%r8,4)
movq -0xd0(%rbp), %rax
movq (%rax,%rdi), %rax
movb $0x2, 0x1(%rax,%r8)
movq -0xb8(%rbp), %rax
movq (%rax,%rdi), %r10
movl 0x4(%r10,%r8,4), %r12d
addl $-0x6, %r9d
cmpl %r12d, %r9d
jle 0x2849
movl %r9d, 0x4(%r10,%r8,4)
movq -0xd0(%rbp), %rax
leaq (%rdx,%rdx,2), %r9
movq (%rax,%r9,8), %rax
movb $0x3, 0x1(%rax,%r8)
cmpq %rcx, %rdx
jne 0x286f
movq -0xb8(%rbp), %rax
leaq (%rcx,%rcx,2), %r9
movq (%rax,%r9,8), %rax
movl 0x4(%rax,%r8,4), %r9d
movslq %r13d, %r10
cmpl (%rax,%r10,4), %r9d
jle 0x286f
leal 0x1(%r8), %r13d
incq %r8
cmpq %r8, %r14
jne 0x2796
incq %rdx
cmpq -0x38(%rbp), %rdx
jne 0x277f
leaq -0x290(%rbp), %rdi
callq 0x20c0
leaq -0x68(%rbp), %r12
movq %r12, -0x10(%r12)
leaq 0x1839(%rip), %rdx      # 0x40dd
leaq -0x78(%rbp), %rdi
movq %rdx, %rsi
callq 0x2546
leaq -0x88(%rbp), %rax
movq %rax, -0x10(%rax)
leaq 0x181b(%rip), %rdx      # 0x40dd
leaq -0x98(%rbp), %rdi
movq %rdx, %rsi
callq 0x2546
testl %r13d, %r13d
setle %al
movq -0x50(%rbp), %r14
testl %r14d, %r14d
setle %cl
leaq -0x280(%rbp), %rdx
movq %rdx, -0xa0(%rbp)
orb %al, %cl
jne 0x2a32
movl $0x0, -0x44(%rbp)
xorl %esi, %esi
movl $0x0, -0x2c(%rbp)
movl $0x0, -0x3c(%rbp)
movl $0x0, -0x40(%rbp)
movl %r14d, %r14d
movq -0xd0(%rbp), %rax
leaq (%r14,%r14,2), %rcx
movl %r13d, %edx
movq (%rax,%rcx,8), %rax
movzbl (%rax,%rdx), %r12d
movl $0x1, -0x38(%rbp)
subl $0x1, -0x44(%rbp)
jae 0x2942
movl %r12d, -0x2c(%rbp)
jmp 0x2994
movl -0x2c(%rbp), %ecx
cmpl %r12d, %ecx
jne 0x2951
incl %esi
movl %esi, -0x38(%rbp)
jmp 0x2994
movl %esi, -0x54(%rbp)
movb $0x58, %al
cmpl $0x3, %ecx
ja 0x2967
movl %ecx, %eax
leaq 0x17ab(%rip), %rcx      # 0x410f
movb (%rax,%rcx), %al
movb %al, -0xf0(%rbp)
movl $0x1, %edx
leaq -0x280(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x2140
movl -0x54(%rbp), %esi
movq %rax, %rdi
callq 0x20b0
movl %r12d, -0x2c(%rbp)
cmpl $0x1, %r12d
sbbl $-0x1, -0x40(%rbp)
cmpq $0x0, 0x10(%rbp)
je 0x29d8
cmpl $0x3, %r12d
je 0x29b5
testl %r12d, %r12d
jne 0x29b9
movb -0x1(%rbx,%r14), %al
jmp 0x29c9
movb $0x2d, %al
jmp 0x29c9
movl $0x2b, %eax
cmpl $0x2, %r12d
je 0x29c9
movl $0x78, %eax
movsbl %al, %esi
leaq -0x98(%rbp), %rdi
callq 0x2110
xorl %eax, %eax
xorl %edx, %edx
cmpl $0x2, %r12d
sete %al
setne %dl
addl %eax, -0x3c(%rbp)
xorl %eax, %eax
cmpl $0x3, %r12d
setne %cl
subl %edx, %r13d
movl -0x38(%rbp), %edx
je 0x2a07
movb %cl, %al
movl %edx, %esi
subl %eax, %r14d
jne 0x2915
movl %edx, %eax
movq %rax, -0x38(%rbp)
leaq -0x280(%rbp), %rax
movq %rax, -0xa0(%rbp)
movl -0x44(%rbp), %r13d
negl %r13d
movb $0x58, %al
movl -0x2c(%rbp), %ecx
cmpl $0x3, %ecx
leaq -0x68(%rbp), %r12
jbe 0x2a4d
jmp 0x2a59
movq $0x0, -0x38(%rbp)
xorl %ecx, %ecx
movl $0x0, -0x3c(%rbp)
xorl %r13d, %r13d
movl $0x0, -0x40(%rbp)
movl %ecx, %eax
leaq 0x16b9(%rip), %rcx      # 0x410f
movb (%rax,%rcx), %al
leaq -0xf0(%rbp), %rsi
movb %al, (%rsi)
movl $0x1, %edx
movq -0xa0(%rbp), %rdi
callq 0x2140
movq %rax, %rdi
movq -0x38(%rbp), %rsi
callq 0x20b0
movq %r12, %r14
leaq -0x278(%rbp), %rsi
leaq -0xf0(%rbp), %rdi
callq 0x2190
leaq -0x78(%rbp), %rdi
leaq -0xf0(%rbp), %r12
movq %r12, %rsi
callq 0x2150
movq (%r12), %rdi
leaq -0xe0(%rbp), %rax
cmpq %rax, %rdi
je 0x2ac7
movq -0xe0(%rbp), %rsi
incq %rsi
callq 0x2130
movq -0x78(%rbp), %rax
movq -0x70(%rbp), %rcx
testq %rcx, %rcx
setne %dl
addq %rax, %rcx
decq %rcx
cmpq %rax, %rcx
seta %sil
andb %dl, %sil
cmpb $0x1, %sil
jne 0x2b09
incq %rax
movb -0x1(%rax), %dl
movb (%rcx), %sil
movb %sil, -0x1(%rax)
movb %dl, (%rcx)
decq %rcx
leaq 0x1(%rax), %rdx
cmpq %rcx, %rax
movq %rdx, %rax
jb 0x2aee
movq -0x98(%rbp), %rax
movq -0x90(%rbp), %rcx
testq %rcx, %rcx
setne %dl
addq %rax, %rcx
decq %rcx
cmpq %rax, %rcx
seta %sil
andb %dl, %sil
cmpb $0x1, %sil
movq -0x108(%rbp), %rdi
movq %r14, %r12
jne 0x2b5b
incq %rax
movb -0x1(%rax), %dl
movb (%rcx), %sil
movb %sil, -0x1(%rax)
movb %dl, (%rcx)
decq %rcx
leaq 0x1(%rax), %rdx
cmpq %rcx, %rax
movq %rdx, %rax
jb 0x2b40
testq %rdi, %rdi
movq -0x100(%rbp), %r14
je 0x2b72
leaq -0x78(%rbp), %rsi
callq 0x2090
jmp 0x2baa
movq 0x344f(%rip), %rax      # 0x5fc8
movq (%rax), %rdi
leaq -0x78(%rbp), %r9
movq %rbx, %rsi
movq -0x50(%rbp), %rdx
movq %r15, %rcx
movq -0xf8(%rbp), %r8
leaq -0xd0(%rbp), %rax
pushq %rax
leaq -0xb8(%rbp), %rax
pushq %rax
callq 0x2d45
addq $0x10, %rsp
testq %r14, %r14
je 0x2bb6
subl -0x3c(%rbp), %r13d
movl %r13d, (%r14)
cmpq $0x0, 0x10(%rbp)
je 0x2bcd
leaq -0x98(%rbp), %rsi
movq 0x10(%rbp), %rdi
callq 0x2090
movq -0x98(%rbp), %rdi
leaq -0x88(%rbp), %rax
cmpq %rax, %rdi
je 0x2bef
movq -0x88(%rbp), %rsi
incq %rsi
callq 0x2130
movq -0x78(%rbp), %rdi
cmpq %r12, %rdi
movl -0x40(%rbp), %r14d
je 0x2c08
movq -0x68(%rbp), %rsi
incq %rsi
callq 0x2130
movq 0x33c1(%rip), %rsi      # 0x5fd0
leaq -0x290(%rbp), %rdi
callq 0x20e0
leaq -0x210(%rbp), %rdi
callq 0x2050
leaq -0xd0(%rbp), %rdi
callq 0x31d6
leaq -0xb8(%rbp), %rdi
callq 0x3238
movl %r14d, %eax
addq $0x268, %rsp            # imm = 0x268
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2cc8
movq %rax, %rbx
jmp 0x2ced
movq %rax, %rbx
jmp 0x2d06
movq %rax, %rbx
jmp 0x2d25
movq %rax, %rbx
movq -0x290(%rbp), %rdi
testq %rdi, %rdi
je 0x2d31
movq -0x280(%rbp), %rsi
subq %rdi, %rsi
callq 0x2130
jmp 0x2d31
movq %rax, %rbx
jmp 0x2d31
movq %rax, %rbx
movq -0x290(%rbp), %rdi
testq %rdi, %rdi
je 0x2d3d
movq -0x280(%rbp), %rsi
subq %rdi, %rsi
callq 0x2130
jmp 0x2d3d
movq %rax, %rbx
jmp 0x2d3d
jmp 0x2cc8
movq %rax, %rbx
movq -0x98(%rbp), %rdi
leaq -0x88(%rbp), %rax
cmpq %rax, %rdi
je 0x2ced
movq -0x88(%rbp), %rsi
incq %rsi
callq 0x2130
movq -0x78(%rbp), %rdi
leaq -0x68(%rbp), %rax
cmpq %rax, %rdi
je 0x2d06
movq -0x68(%rbp), %rsi
incq %rsi
callq 0x2130
movq 0x32c3(%rip), %rsi      # 0x5fd0
leaq -0x290(%rbp), %rdi
callq 0x20e0
leaq -0x210(%rbp), %rdi
callq 0x2050
leaq -0xd0(%rbp), %rdi
callq 0x31d6
leaq -0xb8(%rbp), %rdi
callq 0x3238
movq %rbx, %rdi
callq 0x21c0