// File: /workspace/github_cpp_makefile_star2_O1/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, %eax       # imm = 0xFFFFFFFF
movq %rcx, -0x50(%rbp)
testl %ecx, %ecx
je 0x2c4a
testl %esi, %esi
je 0x2c4a
movq %rdi, %rbx
testq %rdi, %rdi
je 0x2c4a
movq %rdx, %r15
testq %rdx, %rdx
je 0x2c4a
movq %r9, %r14
movq %rsi, -0x48(%rbp)
movq %r8, -0x100(%rbp)
movq -0x50(%rbp), %rax
leal 0x1(%rax), %r13d
leaq -0x80(%rbp), %rdx
movl $0x0, (%rdx)
leaq -0x288(%rbp), %rdi
leaq -0xa0(%rbp), %rcx
movq %r13, %rsi
callq 0x2fae
movq -0x48(%rbp), %rax
leal 0x1(%rax), %r12d
leaq -0xb8(%rbp), %rdi
leaq -0x288(%rbp), %rdx
leaq -0xf0(%rbp), %rcx
movq %r12, %rsi
callq 0x3036
movq -0x288(%rbp), %rdi
testq %rdi, %rdi
je 0x269b
movq -0x278(%rbp), %rsi
subq %rdi, %rsi
callq 0x2130
leaq -0x80(%rbp), %rdx
movb $0x0, (%rdx)
leaq -0x288(%rbp), %rdi
leaq -0xa0(%rbp), %rcx
movq %r13, %rsi
callq 0x30d8
leaq -0xd0(%rbp), %rdi
leaq -0x288(%rbp), %rdx
leaq -0xf0(%rbp), %rcx
movq %r12, %rsi
callq 0x3138
movq -0x288(%rbp), %rdi
testq %rdi, %rdi
je 0x26f0
movq -0x278(%rbp), %rsi
subq %rdi, %rsi
callq 0x2130
cmpl $0x1, %r12d
movq -0x48(%rbp), %rcx
adcl $0x1, %ecx
movq -0xb8(%rbp), %rax
addq %rcx, %rcx
leaq (%rcx,%rcx,2), %rcx
xorl %edx, %edx
movq (%rax), %rsi
movl %edx, (%rsi)
addq $0x18, %rax
addq $-0x6, %rdx
movq %rcx, %rsi
addq %rdx, %rsi
jne 0x270b
movq -0xb8(%rbp), %rax
cmpl $0x1, %r13d
movq -0x50(%rbp), %rcx
adcl $0x1, %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 0x273e
movq %r14, -0xf8(%rbp)
movq -0x48(%rbp), %rax
testl %eax, %eax
je 0x2898
cmpl $0x3, %r13d
movl $0x2, %ecx
cmovbl %ecx, %r13d
cmpl $0x3, %r12d
cmovael %r12d, %ecx
movq %rcx, -0x38(%rbp)
movl %eax, %ecx
decq %r13
xorl %r14d, %r14d
movl $0x1, %edx
cmpl $0x0, -0x50(%rbp)
je 0x2889
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, %r11d
cmpb (%r15,%r8), %r9b
je 0x27c1
movl $0xfffffffe, %r11d      # imm = 0xFFFFFFFE
movq -0xb8(%rbp), %r9
movq (%r9,%rsi,8), %r12
movl 0x4(%r12,%r8,4), %r10d
addl $-0x6, %r10d
movq (%r9,%rdi), %rax
movl (%rax,%r8,4), %r9d
addl (%r12,%r8,4), %r11d
movl %r11d, 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), %r12
leaq (%rdx,%rdx,2), %r11
cmpl 0x4(%r12,%r8,4), %r10d
jle 0x282b
movl %r10d, 0x4(%r12,%r8,4)
movq -0xd0(%rbp), %rax
movq (%rax,%r11,8), %rax
movb $0x2, 0x1(%rax,%r8)
addl $-0x6, %r9d
movq -0xb8(%rbp), %rax
movq (%rax,%r11,8), %r10
cmpl 0x4(%r10,%r8,4), %r9d
jle 0x2857
movl %r9d, 0x4(%r10,%r8,4)
movq -0xd0(%rbp), %rax
movq (%rax,%r11,8), %rax
movb $0x3, 0x1(%rax,%r8)
cmpq %rcx, %rdx
jne 0x287d
movq -0xb8(%rbp), %rax
leaq (%rcx,%rcx,2), %r9
movq (%rax,%r9,8), %rax
movl 0x4(%rax,%r8,4), %r9d
movslq %r14d, %r10
cmpl (%rax,%r10,4), %r9d
jle 0x287d
leal 0x1(%r8), %r14d
incq %r8
cmpq %r8, %r13
jne 0x27aa
incq %rdx
cmpq -0x38(%rbp), %rdx
jne 0x2789
jmp 0x289b
xorl %r14d, %r14d
leaq -0x288(%rbp), %rdi
callq 0x20c0
leaq -0x70(%rbp), %rax
movq %rax, -0x10(%rax)
leaq 0x1827(%rip), %rdx      # 0x40dd
leaq -0x80(%rbp), %rdi
movq %rdx, %rsi
callq 0x2546
movq -0x48(%rbp), %r12
leaq -0x90(%rbp), %rax
movq %rax, -0x10(%rax)
leaq 0x1805(%rip), %rdx      # 0x40dd
leaq -0xa0(%rbp), %rdi
movq %rdx, %rsi
callq 0x2546
testl %r14d, %r14d
setle %al
testl %r12d, %r12d
setle %cl
orb %al, %cl
jne 0x2a35
movl $0x0, -0x2c(%rbp)
xorl %esi, %esi
movl $0x0, -0x30(%rbp)
movl $0x0, -0x3c(%rbp)
movq $0x0, -0x58(%rbp)
movl %r12d, %r13d
movl %r13d, %r13d
movq -0xd0(%rbp), %rax
leaq (,%r13,2), %rcx
addq %r13, %rcx
movl %r14d, %edx
movq (%rax,%rcx,8), %rax
movzbl (%rax,%rdx), %r12d
movl $0x1, -0x38(%rbp)
subl $0x1, -0x2c(%rbp)
jae 0x2951
movl %r12d, -0x30(%rbp)
jmp 0x29a3
movl -0x30(%rbp), %ecx
cmpl %r12d, %ecx
jne 0x2960
incl %esi
movl %esi, -0x38(%rbp)
jmp 0x29a3
movl %esi, -0x5c(%rbp)
movb $0x58, %al
cmpl $0x3, %ecx
ja 0x2976
movl %ecx, %eax
leaq 0x179c(%rip), %rcx      # 0x410f
movb (%rax,%rcx), %al
movb %al, -0xf0(%rbp)
movl $0x1, %edx
leaq -0x278(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x2140
movl -0x5c(%rbp), %esi
movq %rax, %rdi
callq 0x20b0
movl %r12d, -0x30(%rbp)
cmpl $0x1, %r12d
movq -0x58(%rbp), %rax
sbbl $-0x1, %eax
movq %rax, -0x58(%rbp)
cmpq $0x0, 0x10(%rbp)
je 0x29ee
cmpl $0x3, %r12d
je 0x29cb
testl %r12d, %r12d
jne 0x29cf
movb -0x1(%rbx,%r13), %al
jmp 0x29df
movb $0x2d, %al
jmp 0x29df
movl $0x2b, %eax
cmpl $0x2, %r12d
je 0x29df
movl $0x78, %eax
movsbl %al, %esi
leaq -0xa0(%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, %r14d
testl %r14d, %r14d
movl -0x38(%rbp), %edx
jle 0x2a23
movb %cl, %al
subl %eax, %r13d
movl %edx, %esi
testl %r13d, %r13d
jg 0x291d
movl %edx, %eax
movq %rax, -0x38(%rbp)
negl -0x2c(%rbp)
movq -0x48(%rbp), %r12
movl -0x30(%rbp), %ecx
jmp 0x2a55
movq $0x0, -0x58(%rbp)
movl $0x0, -0x2c(%rbp)
movl $0x0, -0x3c(%rbp)
xorl %ecx, %ecx
movq $0x0, -0x38(%rbp)
leaq -0x278(%rbp), %rdi
movb $0x58, %al
cmpl $0x3, %ecx
movq -0xf8(%rbp), %r13
ja 0x2a76
movl %ecx, %eax
leaq 0x169c(%rip), %rcx      # 0x410f
movb (%rax,%rcx), %al
leaq -0xf0(%rbp), %rsi
movb %al, (%rsi)
movl $0x1, %edx
callq 0x2140
movq %rax, %rdi
movq -0x38(%rbp), %rsi
callq 0x20b0
leaq -0x270(%rbp), %rsi
leaq -0xf0(%rbp), %rdi
callq 0x2190
leaq -0x80(%rbp), %rdi
leaq -0xf0(%rbp), %r14
movq %r14, %rsi
callq 0x2150
movq (%r14), %rdi
leaq -0xe0(%rbp), %rax
cmpq %rax, %rdi
je 0x2ad9
movq -0xe0(%rbp), %rsi
incq %rsi
callq 0x2130
movq -0x80(%rbp), %rax
movq -0x78(%rbp), %rcx
testq %rcx, %rcx
setne %dl
addq %rax, %rcx
decq %rcx
cmpq %rax, %rcx
seta %sil
andb %dl, %sil
cmpb $0x1, %sil
jne 0x2b1b
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 0x2b00
movq -0xa0(%rbp), %rax
movq -0x98(%rbp), %rcx
testq %rcx, %rcx
setne %dl
addq %rax, %rcx
decq %rcx
cmpq %rax, %rcx
seta %sil
andb %dl, %sil
cmpb $0x1, %sil
movq -0x100(%rbp), %rdi
jne 0x2b6a
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 0x2b4f
testq %rdi, %rdi
je 0x2b7a
leaq -0x80(%rbp), %rsi
callq 0x2090
jmp 0x2bae
movq 0x3447(%rip), %rax      # 0x5fc8
movq (%rax), %rdi
leaq -0x80(%rbp), %r9
movq %rbx, %rsi
movl %r12d, %edx
movq %r15, %rcx
movq -0x50(%rbp), %r8
leaq -0xd0(%rbp), %rax
pushq %rax
leaq -0xb8(%rbp), %rax
pushq %rax
callq 0x2d4d
addq $0x10, %rsp
testq %r13, %r13
je 0x2bbd
movl -0x2c(%rbp), %eax
subl -0x3c(%rbp), %eax
movl %eax, (%r13)
cmpq $0x0, 0x10(%rbp)
je 0x2bd4
leaq -0xa0(%rbp), %rsi
movq 0x10(%rbp), %rdi
callq 0x2090
movq -0xa0(%rbp), %rdi
leaq -0x90(%rbp), %rax
cmpq %rax, %rdi
je 0x2bf6
movq -0x90(%rbp), %rsi
incq %rsi
callq 0x2130
movq -0x80(%rbp), %rdi
leaq -0x70(%rbp), %rax
cmpq %rax, %rdi
je 0x2c0f
movq -0x70(%rbp), %rsi
incq %rsi
callq 0x2130
movq 0x33ba(%rip), %rsi      # 0x5fd0
leaq -0x288(%rbp), %rdi
callq 0x20e0
leaq -0x208(%rbp), %rdi
callq 0x2050
leaq -0xd0(%rbp), %rdi
callq 0x31da
leaq -0xb8(%rbp), %rdi
callq 0x3236
movq -0x58(%rbp), %rax
addq $0x268, %rsp            # imm = 0x268
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2cd0
movq %rax, %rbx
jmp 0x2cf5
movq %rax, %rbx
jmp 0x2d0e
movq %rax, %rbx
jmp 0x2d2d
movq %rax, %rbx
movq -0x288(%rbp), %rdi
testq %rdi, %rdi
je 0x2d39
movq -0x278(%rbp), %rsi
subq %rdi, %rsi
callq 0x2130
jmp 0x2d39
movq %rax, %rbx
jmp 0x2d39
movq %rax, %rbx
movq -0x288(%rbp), %rdi
testq %rdi, %rdi
je 0x2d45
movq -0x278(%rbp), %rsi
subq %rdi, %rsi
callq 0x2130
jmp 0x2d45
movq %rax, %rbx
jmp 0x2d45
jmp 0x2cd0
movq %rax, %rbx
movq -0xa0(%rbp), %rdi
leaq -0x90(%rbp), %rax
cmpq %rax, %rdi
je 0x2cf5
movq -0x90(%rbp), %rsi
incq %rsi
callq 0x2130
movq -0x80(%rbp), %rdi
leaq -0x70(%rbp), %rax
cmpq %rax, %rdi
je 0x2d0e
movq -0x70(%rbp), %rsi
incq %rsi
callq 0x2130
movq 0x32bb(%rip), %rsi      # 0x5fd0
leaq -0x288(%rbp), %rdi
callq 0x20e0
leaq -0x208(%rbp), %rdi
callq 0x2050
leaq -0xd0(%rbp), %rdi
callq 0x31da
leaq -0xb8(%rbp), %rdi
callq 0x3236
movq %rbx, %rdi
callq 0x21c0