// File: /workspace/github_cpp_makefile_star2_O2/adamnovak[P]rlcsa/rlcsa.cpp
// Function: CSA::RLCSA::buildRLCSA(unsigned char*, unsigned int*, unsigned int, unsigned int, unsigned int, CSA::Sampler*, bool, bool)
void
RLCSA::buildRLCSA(uchar* data, usint* ranks, usint bytes, usint block_size, usint threads, Sampler* sampler, bool multiple_sequences, bool delete_data)
{
  threads = std::max(threads, (usint)1);
  #ifdef MULTITHREAD_SUPPORT
  omp_set_num_threads(threads);
  #endif


  // Do we store SA samples?
  bool sample_sa = true;
  if(this->sample_rate == 0)
  {
    sample_sa = false; this->sample_rate = 1;
  }


  // Determine the number of sequences and mark their end points.
  DeltaEncoder endings(RLCSA::ENDPOINT_BLOCK_SIZE);
  if(multiple_sequences)
  {
    this->number_of_sequences = 0;
    usint marker = 0;
    usint padding = 0, chars_encountered = 0;

    for(usint i = 0; i < bytes; i++)
    {
      if(data[i] == 0)
      {
        if(i == marker) { break; }  // Empty sequence.
        this->number_of_sequences++;
        marker = i + 1;
        usint pos = chars_encountered + padding - 1;
        endings.setBit(pos);
        padding = ((pos + this->sample_rate) / this->sample_rate) * this->sample_rate - chars_encountered;
      }
      else { chars_encountered++; }
    }

    if(this->number_of_sequences == 0 || marker != bytes)
    {
      std::cerr << "RLCSA: Collection must consist of 0-terminated nonempty sequences!" << std::endl;
      if(delete_data) { delete[] data; }
      return;
    }
    this->end_points = new DeltaVector(endings, chars_encountered + padding);
  }
  else
  {
    this->number_of_sequences = 1;
    DeltaEncoder endings(RLCSA::ENDPOINT_BLOCK_SIZE, RLCSA::ENDPOINT_BLOCK_SIZE);
    endings.setBit(bytes - 1);
    this->end_points = new DeltaVector(endings, bytes);
  }


  // Build character tables etc.
  usint distribution[CHARS];
  for(usint c = 0; c < CHARS; c++) { distribution[c] = 0; }
  for(usint i = 0; i < bytes; i++) { distribution[(usint)data[i]]++; }
  if(multiple_sequences) { distribution[0] = 0; } // \0 is an end marker
  this->alphabet = new Alphabet(distribution); this->data_size = this->alphabet->getDataSize();


  // Build suffix array.
  short_pair* sa = 0;
  if(multiple_sequences)
  {
    if(ranks == 0) { sa = simpleSuffixSort(data, bytes, this->number_of_sequences, threads); }
    else           { sa = simpleSuffixSort(ranks, bytes, threads); }
  }
  else
  {
    bytes++;
    sa = new short_pair[bytes];
    #pragma omp parallel for schedule(static)
    for(usint i = 0; i < bytes - 1; i++) { sa[i].second = data[i] + 1; }
    sa[bytes - 1].second = 0;
    simpleSuffixSort(sa, bytes, threads);
  }
  if(delete_data) { delete[] data; }


  // Sample SA.
  if(sample_sa)
  {
    if(sampler != 0) { this->sa_samples = new SASamples(sa, sampler, threads); }
    else             { this->sa_samples = new SASamples(sa, this->end_points, this->data_size, this->sample_rate, threads); }
    this->support_locate = this->sa_samples->supportsLocate();
    this->support_display = this->sa_samples->supportsDisplay();
  }


  // Build Psi.
  #pragma omp parallel for schedule(static)
  for(usint i = 0; i < bytes; i++) { sa[i].first = sa[(sa[i].first + 1) % bytes].second; }


  // Build RLCSA.
  #pragma omp parallel for schedule(dynamic, 1)
  for(usint c = 0; c < CHARS; c++)
  {
    if(!(this->alphabet->hasChar(c))) { this->array[c] = 0; continue; }

    short_pair* curr = sa + this->alphabet->cumulative(c) + this->number_of_sequences;
    short_pair* limit = curr + this->alphabet->countOf(c);
    PsiVector::Encoder encoder(block_size);
    pair_type run((*curr).first, 1); ++curr;

    for(; curr < limit; ++curr)
    {
      if((*curr).first == run.first + run.second) { run.second++; }
      else
      {
        encoder.addRun(run.first, run.second);
        run = pair_type((*curr).first, 1);
      }
    }
    encoder.addRun(run.first, run.second);
    encoder.flush();

    this->array[c] = new PsiVector(encoder, this->data_size + this->number_of_sequences);
  }
  delete[] sa;


  this->ok = true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x538, %rsp            # imm = 0x538
movl %r9d, %ebx
movl %r8d, 0x1c(%rsp)
movl %ecx, %r14d
movq %rdx, %r13
movq %rsi, %r12
cmpl $0x1, %r9d
adcl $0x0, %ebx
movq %rdi, 0x8(%rsp)
movl 0x81c(%rdi), %eax
movl %eax, 0x18(%rsp)
testl %eax, %eax
jne 0x50b1
movq 0x8(%rsp), %rax
movl $0x1, 0x81c(%rax)
leaq 0x48(%rsp), %rdi
pushq $0x10
popq %rsi
movl $0x100000, %edx         # imm = 0x100000
callq 0xfbb6
movl %r14d, %ebp
cmpb $0x0, 0x578(%rsp)
je 0x51b7
movq %r14, 0x20(%rsp)
movl %ebx, %edx
movq %r13, 0x40(%rsp)
movq 0x8(%rsp), %rax
andl $0x0, 0x820(%rax)
movq %rbp, %r8
negq %r8
xorl %esi, %esi
leaq 0x48(%rsp), %rdi
xorl %r14d, %r14d
xorl %ebx, %ebx
leaq (%r8,%rsi), %rax
leaq (%r12,%rsi), %rcx
xorl %r15d, %r15d
movq %rbx, 0x28(%rsp)
movl %ebx, %r13d
movl %edx, %ebx
movq %rax, %rdx
addq %r15, %rdx
je 0x5222
cmpb $0x0, (%rcx,%r15)
je 0x512e
incl %r13d
incq %r15
jmp 0x5113
movl %ebx, 0x14(%rsp)
movl %esi, %eax
movq %rsi, %rcx
subq %rax, %rcx
movq 0x8(%rsp), %rdx
movl 0x820(%rdx), %eax
addq %r15, %rcx
je 0x55b3
movq %r8, 0x30(%rsp)
movq %rsi, 0x38(%rsp)
incl %eax
movl %eax, 0x820(%rdx)
movq 0x28(%rsp), %rbx
addl %ebx, %r14d
leal (%r15,%r14), %esi
decl %esi
callq 0xfbc4
movl %ebx, %ebx
addq %r15, %rbx
movq 0x38(%rsp), %rsi
addq %r15, %rsi
incq %rsi
movq 0x8(%rsp), %rax
movl 0x81c(%rax), %ecx
addl %ecx, %r14d
addl %r15d, %r14d
decl %r14d
movl %r14d, %eax
xorl %edx, %edx
divl %ecx
addl %r13d, %edx
subl %edx, %r14d
movl 0x14(%rsp), %edx
movq 0x30(%rsp), %r8
leaq 0x48(%rsp), %rdi
jmp 0x50fe
movq 0x8(%rsp), %rax
movl $0x1, 0x820(%rax)
leaq 0x130(%rsp), %rdi
pushq $0x10
popq %rdx
movl %edx, %esi
callq 0xfbb6
leal -0x1(%r14), %esi
leaq 0x130(%rsp), %rdi
callq 0xfbc4
pushq $0x48
popq %rdi
callq 0x3220
movq %rax, %r15
leaq 0x130(%rsp), %rsi
movq %rax, %rdi
movl %r14d, %edx
callq 0xf8c0
movq 0x8(%rsp), %rax
movq %r15, 0x828(%rax)
leaq 0x130(%rsp), %rdi
callq 0xfbbe
jmp 0x527b
movq 0x8(%rsp), %rax
movl 0x820(%rax), %eax
testl %eax, %eax
movq 0x40(%rsp), %r13
je 0x5369
cmpl 0x20(%rsp), %esi
jne 0x5369
pushq $0x48
popq %rdi
callq 0x3220
movq 0x28(%rsp), %rcx
addl %r14d, %ecx
addl %ecx, %r15d
leaq 0x48(%rsp), %rsi
movq %rax, %r14
movq %rax, %rdi
movl %r15d, %edx
callq 0xf8c0
movq 0x8(%rsp), %rax
movq %r14, 0x828(%rax)
movq 0x20(%rsp), %r14
xorl %eax, %eax
cmpq $0x100, %rax            # imm = 0x100
je 0x5292
andl $0x0, 0x130(%rsp,%rax,4)
incq %rax
jmp 0x527d
xorl %eax, %eax
cmpq %rax, %rbp
je 0x52aa
movzbl (%r12,%rax), %ecx
incl 0x130(%rsp,%rcx,4)
incq %rax
jmp 0x5294
cmpb $0x0, 0x578(%rsp)
je 0x52bc
andl $0x0, 0x130(%rsp)
movl $0x1010, %edi           # imm = 0x1010
callq 0x3220
movq %rax, %r15
leaq 0x130(%rsp), %rsi
movq %rax, %rdi
callq 0xb32c
movq 0x8(%rsp), %rcx
movq %r15, 0x808(%rcx)
movl 0x800(%r15), %eax
movl %eax, 0x4(%rcx)
cmpb $0x0, 0x578(%rsp)
je 0x5314
testq %r13, %r13
je 0x53a9
movq %r13, %rdi
movl %r14d, %esi
movl %ebx, %edx
callq 0x11314
jmp 0x53c1
incl %r14d
leaq (,%r14,8), %r15
movq %r15, %rdi
callq 0x3030
movq %rax, %r13
testl %r14d, %r14d
je 0x533c
movq %r13, %rdi
xorl %esi, %esi
movq %r15, %rdx
callq 0x3130
xorl %eax, %eax
cmpq %rax, %rbp
je 0x5354
movzbl (%r12,%rax), %ecx
incl %ecx
movl %ecx, 0x4(%r13,%rax,8)
incq %rax
jmp 0x533e
andl $0x0, 0x4(%r13,%rbp,8)
movq %r13, %rdi
movl %r14d, %esi
movl %ebx, %edx
callq 0x11439
jmp 0x53c4
movq 0x17c80(%rip), %rdi     # 0x1cff0
leaq 0xe29e(%rip), %rsi      # 0x13615
callq 0x3200
movq %rax, %rdi
callq 0x3100
testq %r12, %r12
sete %al
movb 0x580(%rsp), %cl
xorb $0x1, %cl
orb %al, %cl
jne 0x5597
movq %r12, %rdi
callq 0x32b0
jmp 0x5597
movq 0x8(%rsp), %rax
movl 0x820(%rax), %edx
movq %r12, %rdi
movl %r14d, %esi
movl %ebx, %ecx
callq 0x114fb
movq %rax, %r13
testq %r12, %r12
sete %al
movb 0x580(%rsp), %cl
xorb $0x1, %cl
orb %al, %cl
jne 0x53e0
movq %r12, %rdi
callq 0x32b0
cmpl $0x0, 0x18(%rsp)
movq 0x8(%rsp), %r12
je 0x5479
cmpq $0x0, 0x570(%rsp)
je 0x5422
pushq $0x30
popq %rdi
callq 0x3220
movq %rax, %r15
movq %rax, %rdi
movq %r13, %rsi
movq 0x570(%rsp), %rdx
movl %ebx, %ecx
callq 0xa198
movq 0x8(%rsp), %r12
jmp 0x5455
pushq $0x30
popq %rdi
callq 0x3220
movq %rax, %r15
movq 0x8(%rsp), %r12
movq 0x828(%r12), %rdx
movl 0x4(%r12), %ecx
movl 0x81c(%r12), %r8d
movq %rax, %rdi
movq %r13, %rsi
movl %ebx, %r9d
callq 0x9f7e
movq %r15, 0x810(%r12)
cmpq $0x0, 0x18(%r15)
setne 0x818(%r12)
cmpq $0x0, 0x28(%r15)
setne 0x819(%r12)
movl %r14d, %ecx
xorl %esi, %esi
cmpq %rsi, %rcx
je 0x549e
movl (%r13,%rsi,8), %eax
incl %eax
xorl %edx, %edx
divl %r14d
movl 0x4(%r13,%rdx,8), %eax
movl %eax, (%r13,%rsi,8)
incq %rsi
jmp 0x547e
xorl %ebp, %ebp
leaq 0xb8(%rsp), %r14
cmpq $0x100, %rbp            # imm = 0x100
je 0x5585
movq 0x808(%r12), %rax
movq (%rax,%rbp,8), %rbx
movq %rbx, %r15
shrq $0x20, %r15
cmpl %r15d, %ebx
jbe 0x54d8
andq $0x0, 0x8(%r12,%rbp,8)
jmp 0x557d
movl 0x820(%r12), %r12d
movq %r14, %rdi
movl 0x1c(%rsp), %esi
movl $0x100000, %edx         # imm = 0x100000
callq 0x10178
movl %ebx, %eax
leaq (,%rax,8), %rax
addq %r13, %rax
leaq (%rax,%r12,8), %r12
subl %ebx, %r15d
incl %r15d
leaq (%r12,%r15,8), %r15
movl (%r12), %esi
addq $0x8, %r12
pushq $0x1
popq %rax
movl %eax, %edx
cmpq %r15, %r12
jae 0x5539
leal (%rsi,%rdx), %eax
cmpl (%r12), %eax
jne 0x552f
incl %edx
addq $0x8, %r12
jmp 0x5519
movq %r14, %rdi
callq 0x10294
jmp 0x550c
movq %r14, %rdi
callq 0x10294
movq %r14, %rdi
callq 0x102cc
pushq $0x48
popq %rdi
callq 0x3220
movq %rax, %r12
movq 0x8(%rsp), %rbx
movl 0x820(%rbx), %edx
addl 0x4(%rbx), %edx
movq %rax, %rdi
movq %r14, %rsi
callq 0xfcec
movq %r12, 0x8(%rbx,%rbp,8)
movq %r14, %rdi
callq 0x1018e
movq %rbx, %r12
incq %rbp
jmp 0x54a8
testq %r13, %r13
je 0x5592
movq %r13, %rdi
callq 0x32b0
movb $0x1, (%r12)
leaq 0x48(%rsp), %rdi
callq 0xfbbe
addq $0x538, %rsp            # imm = 0x538
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl 0x14(%rsp), %ebx
jmp 0x522d
jmp 0x55c9
movq %rax, %rbx
pushq $0x48
popq %rsi
movq %r14, %rdi
jmp 0x55f0
movq %rax, %rbx
pushq $0x30
popq %rsi
jmp 0x55ed
jmp 0x5611
movq %rax, %rbx
pushq $0x48
popq %rsi
movq %r15, %rdi
callq 0x3230
jmp 0x55fe
jmp 0x5611
movq %rax, %rbx
movl $0x1010, %esi           # imm = 0x1010
movq %r15, %rdi
callq 0x3230
jmp 0x5636
jmp 0x5611
jmp 0x5611
movq %rax, %rbx
leaq 0x130(%rsp), %rdi
callq 0xfbbe
jmp 0x5636
jmp 0x5611
jmp 0x5626
movq %rax, %rbx
jmp 0x5636
movq %rax, %rbx
pushq $0x48
popq %rsi
movq %r12, %rdi
callq 0x3230
jmp 0x5629
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
callq 0x1018e
leaq 0x48(%rsp), %rdi
callq 0xfbbe
movq %rbx, %rdi
callq 0x3410