// File: /workspace/github_cpp_makefile_star2_O2/adamnovak[P]rlcsa/misc/utils.cpp
// Function: CSA::simpleSuffixSort(unsigned char const*, unsigned int, unsigned int, unsigned int)
short_pair*
simpleSuffixSort(const uchar* sequence, uint n, uint sequences, uint threads)
{
  if(sequence == 0 || n == 0) { return 0; }

  short_pair* pairs = new short_pair[n];  // In sorted order.
  uint* keys = new uint[n];               // In text order.
  std::vector<ss_range> unsorted;
  threads = std::max(threads, (uint)1);
  #ifdef MULTITHREAD_SUPPORT
  omp_set_num_threads(threads);
  #endif

  // Remap alphabet.
  uint alphabet[CHARS];
  for(uint c = 0; c < CHARS; c++) { alphabet[c] = 0; }
  for(uint i = 0; i < n; i++) { alphabet[sequence[i]]++; }
  uint alphabet_size = sequences;
  for(uint c = 1; c < CHARS; c++)
  {
    uint temp = alphabet_size;
    if(alphabet[c] > 0) { alphabet_size++; }
    alphabet[c] = temp;
  }

  // Determine pack factor.
  uint limit = std::numeric_limits<uint>::max() / alphabet_size;
  uint h = 1, pack_multiplier = 1;
  if(alphabet_size > 1)
  {
    while(pack_multiplier * alphabet_size <= limit) { h++; pack_multiplier *= alphabet_size; }
  }

  // Initialize pairs.
  uint zeros = 0, value = 0;
  for(uint i = 0; i < h; i++)
  {
    value *= alphabet_size;
    if(sequence[i] == 0) { value += zeros; zeros++; }
    else { value += alphabet[sequence[i]]; }
  }
  for(uint i = 0; i < n - h; i++)
  {
    pairs[i].first = i; pairs[i].second = value;
    value = (value % pack_multiplier) * alphabet_size;
    if(sequence[i + h] == 0) { value += zeros; zeros++; }
    else { value += alphabet[sequence[i + h]]; }
  }
  for(uint i = n - h; i < n; i++)
  {
    pairs[i].first = i; pairs[i].second = value;
    value = (value % pack_multiplier) * alphabet_size;
  }

  // Initialize pairs.
/*  uint zeros = 0;
  for(uint i = 0; i < n; i++)
  {
    pairs[i].first = i;
    pairs[i].second = (sequence[i] == '\0' ? zeros++ : sequence[i] + sequences);
  }
  uint h = 1;
  if(length(CHARS + sequences - 1) <= sizeof(uint) * CHAR_BIT / 2)
  {
    for(uint i = 0; i < n - 1; i++)
    {
      pairs[i].second = (CHARS + sequences) * pairs[i].second + pairs[i + 1].second;
    }
    pairs[n - 1].second *= CHARS + sequences;
    h = 2;
  }*/

  uint total = initialSort(pairs, keys, unsorted, n, threads, h);
  return prefixDoubling(pairs, keys, unsorted, n, threads, total, h);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x438, %rsp            # imm = 0x438
movl %edx, %r15d
testq %rdi, %rdi
sete %al
testl %esi, %esi
sete %dl
orb %al, %dl
je 0x11525
xorl %ebx, %ebx
jmp 0x116be
movq %rdi, %r13
movl %ecx, 0xc(%rsp)
movl %esi, 0x8(%rsp)
movl %esi, %ebp
leaq (,%rbp,8), %r12
movq %r12, %rdi
callq 0x3030
movq %rax, %rbx
xorl %r14d, %r14d
movq %rax, %rdi
xorl %esi, %esi
movq %r12, %rdx
callq 0x3130
leaq (,%rbp,4), %rdi
callq 0x3030
movq %rax, %r11
xorps %xmm0, %xmm0
movaps %xmm0, 0x10(%rsp)
andq $0x0, 0x20(%rsp)
cmpq $0x100, %r14            # imm = 0x100
je 0x11587
andl $0x0, 0x30(%rsp,%r14,4)
incq %r14
jmp 0x11573
xorl %eax, %eax
movl 0xc(%rsp), %r14d
movl 0x8(%rsp), %ecx
cmpq %rax, %rbp
je 0x115a6
movzbl (%r13,%rax), %edx
incl 0x30(%rsp,%rdx,4)
incq %rax
jmp 0x11592
pushq $0x1
popq %rax
cmpq $0x100, %rax            # imm = 0x100
je 0x115c4
cmpl $0x1, 0x30(%rsp,%rax,4)
movl %r15d, 0x30(%rsp,%rax,4)
sbbl $-0x1, %r15d
incq %rax
jmp 0x115a9
cmpl $0x1, %r14d
adcl $0x0, %r14d
cmpl $0x2, %r15d
jb 0x115e9
pushq $0x1
popq %rdi
xorl %esi, %esi
movl %edi, %r10d
imull %r15d, %edi
incl %esi
movl %r15d, %eax
mull %edi
jno 0x115d7
jmp 0x115ef
pushq $0x1
popq %rsi
movl %esi, %r10d
movl %esi, %r12d
xorl %edx, %edx
xorl %esi, %esi
xorl %eax, %eax
cmpq %rdx, %r12
je 0x11621
movzbl (%r13,%rdx), %r8d
testq %r8, %r8
je 0x11611
movl %esi, %edi
movl 0x30(%rsp,%r8,4), %esi
jmp 0x11614
leal 0x1(%rsi), %edi
imull %r15d, %eax
addl %esi, %eax
incq %rdx
movl %edi, %esi
jmp 0x115f8
movl %ecx, %edi
subl %r12d, %edi
xorl %r8d, %r8d
cmpq %r8, %rdi
je 0x1167b
movl %r8d, (%rbx,%r8,8)
movl %eax, 0x4(%rbx,%r8,8)
xorl %edx, %edx
divl %r10d
leal (%r12,%r8), %eax
movzbl (%r13,%rax), %r9d
movl %edx, %eax
testq %r9, %r9
je 0x11656
movl %esi, %edx
movl 0x30(%rsp,%r9,4), %esi
jmp 0x11659
leal 0x1(%rsi), %edx
imull %r15d, %eax
addl %esi, %eax
incq %r8
movl %edx, %esi
jmp 0x11629
movl %edi, (%rbx,%rdi,8)
movl %eax, 0x4(%rbx,%rdi,8)
xorl %edx, %edx
divl %r10d
movl %edx, %eax
imull %r15d, %eax
incq %rdi
cmpq %rbp, %rdi
jb 0x11666
leaq 0x10(%rsp), %rdx
movq %rbx, %rdi
movq %r11, %rsi
movl %r14d, %r8d
movl %ecx, %ebp
movq %r11, %r15
callq 0x1104a
movl %r12d, (%rsp)
leaq 0x10(%rsp), %rdx
movq %rbx, %rdi
movq %r15, %rsi
movl %ebp, %ecx
movl %r14d, %r8d
movl %eax, %r9d
callq 0x110b2
leaq 0x10(%rsp), %rdi
callq 0xb30c
movq %rbx, %rax
addq $0x438, %rsp            # imm = 0x438
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
leaq 0x10(%rsp), %rdi
callq 0xb30c
movq %rbx, %rdi
callq 0x3410