// File: 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
movq %rsp, %rbp
subq $0x4f0, %rsp            # imm = 0x4F0
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movl %edx, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
cmpq $0x0, -0x10(%rbp)
je 0x24495
cmpl $0x0, -0x14(%rbp)
jne 0x244a2
movq $0x0, -0x8(%rbp)
jmp 0x249a0
movl -0x14(%rbp), %eax
movq %rax, -0x4a8(%rbp)
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
movq %rdi, -0x4b0(%rbp)
callq 0x3030
movq %rax, %rcx
movq -0x4a8(%rbp), %rax
movq %rcx, -0x4a0(%rbp)
cmpq $0x0, %rax
je 0x24544
movq -0x4a0(%rbp), %rax
movq -0x4a8(%rbp), %rdx
shlq $0x3, %rdx
movq %rax, %rcx
addq %rdx, %rcx
movq %rcx, -0x4c0(%rbp)
movq %rax, -0x4b8(%rbp)
movq -0x4b8(%rbp), %rdi
movq %rdi, -0x4c8(%rbp)
callq 0xe530
jmp 0x24526
movq -0x4c0(%rbp), %rcx
movq -0x4c8(%rbp), %rax
addq $0x8, %rax
cmpq %rcx, %rax
movq %rax, -0x4b8(%rbp)
jne 0x24511
movq -0x4a0(%rbp), %rax
movq %rax, -0x28(%rbp)
movl -0x14(%rbp), %eax
movl %eax, %edi
shlq $0x2, %rdi
callq 0x3030
movq %rax, -0x40(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x14dd0
movl $0x1, -0x5c(%rbp)
leaq -0x1c(%rbp), %rdi
leaq -0x5c(%rbp), %rsi
callq 0x6360
movq %rax, -0x4d0(%rbp)
jmp 0x24587
movq -0x4d0(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x1c(%rbp)
movl $0x0, -0x464(%rbp)
cmpl $0x100, -0x464(%rbp)    # imm = 0x100
jae 0x24609
movl -0x464(%rbp), %eax
movl $0x0, -0x460(%rbp,%rax,4)
movl -0x464(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x464(%rbp)
jmp 0x2459d
movq -0x4b0(%rbp), %rsi
movq -0x4a0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x3590
jmp 0x249ad
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x14ec0
jmp 0x249ad
movl $0x0, -0x468(%rbp)
movl -0x468(%rbp), %eax
cmpl -0x14(%rbp), %eax
jae 0x2464e
movq -0x10(%rbp), %rax
movl -0x468(%rbp), %ecx
movzbl (%rax,%rcx), %eax
movl -0x460(%rbp,%rax,4), %ecx
addl $0x1, %ecx
movl %ecx, -0x460(%rbp,%rax,4)
movl -0x468(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x468(%rbp)
jmp 0x24613
movl -0x18(%rbp), %eax
movl %eax, -0x46c(%rbp)
movl $0x1, -0x470(%rbp)
cmpl $0x100, -0x470(%rbp)    # imm = 0x100
jae 0x246bc
movl -0x46c(%rbp), %eax
movl %eax, -0x474(%rbp)
movl -0x470(%rbp), %eax
cmpl $0x0, -0x460(%rbp,%rax,4)
jbe 0x24698
movl -0x46c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x46c(%rbp)
movl -0x474(%rbp), %ecx
movl -0x470(%rbp), %eax
movl %ecx, -0x460(%rbp,%rax,4)
movl -0x470(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x470(%rbp)
jmp 0x24661
callq 0x19410
xorl %edx, %edx
divl -0x46c(%rbp)
movl %eax, -0x478(%rbp)
movl $0x1, -0x47c(%rbp)
movl $0x1, -0x480(%rbp)
cmpl $0x1, -0x46c(%rbp)
jbe 0x24729
jmp 0x246ee
movl -0x480(%rbp), %eax
imull -0x46c(%rbp), %eax
cmpl -0x478(%rbp), %eax
ja 0x24727
movl -0x47c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x47c(%rbp)
movl -0x46c(%rbp), %eax
imull -0x480(%rbp), %eax
movl %eax, -0x480(%rbp)
jmp 0x246ee
jmp 0x24729
movl $0x0, -0x484(%rbp)
movl $0x0, -0x488(%rbp)
movl $0x0, -0x48c(%rbp)
movl -0x48c(%rbp), %eax
cmpl -0x47c(%rbp), %eax
jae 0x247d9
movl -0x46c(%rbp), %eax
imull -0x488(%rbp), %eax
movl %eax, -0x488(%rbp)
movq -0x10(%rbp), %rax
movl -0x48c(%rbp), %ecx
movzbl (%rax,%rcx), %eax
cmpl $0x0, %eax
jne 0x247a2
movl -0x484(%rbp), %eax
addl -0x488(%rbp), %eax
movl %eax, -0x488(%rbp)
movl -0x484(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x484(%rbp)
jmp 0x247c3
movq -0x10(%rbp), %rax
movl -0x48c(%rbp), %ecx
movzbl (%rax,%rcx), %eax
movl -0x460(%rbp,%rax,4), %eax
addl -0x488(%rbp), %eax
movl %eax, -0x488(%rbp)
jmp 0x247c5
movl -0x48c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x48c(%rbp)
jmp 0x24747
movl $0x0, -0x490(%rbp)
movl -0x490(%rbp), %eax
movl -0x14(%rbp), %ecx
subl -0x47c(%rbp), %ecx
cmpl %ecx, %eax
jae 0x248b9
movl -0x490(%rbp), %edx
movq -0x28(%rbp), %rax
movl -0x490(%rbp), %ecx
movl %edx, (%rax,%rcx,8)
movl -0x488(%rbp), %edx
movq -0x28(%rbp), %rax
movl -0x490(%rbp), %ecx
movl %edx, 0x4(%rax,%rcx,8)
movl -0x488(%rbp), %eax
xorl %edx, %edx
divl -0x480(%rbp)
imull -0x46c(%rbp), %edx
movl %edx, -0x488(%rbp)
movq -0x10(%rbp), %rax
movl -0x490(%rbp), %ecx
addl -0x47c(%rbp), %ecx
movl %ecx, %ecx
movzbl (%rax,%rcx), %eax
cmpl $0x0, %eax
jne 0x2487a
movl -0x484(%rbp), %eax
addl -0x488(%rbp), %eax
movl %eax, -0x488(%rbp)
movl -0x484(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x484(%rbp)
jmp 0x248a3
movq -0x10(%rbp), %rax
movl -0x490(%rbp), %ecx
addl -0x47c(%rbp), %ecx
movl %ecx, %ecx
movzbl (%rax,%rcx), %eax
movl -0x460(%rbp,%rax,4), %eax
addl -0x488(%rbp), %eax
movl %eax, -0x488(%rbp)
jmp 0x248a5
movl -0x490(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x490(%rbp)
jmp 0x247e3
movl -0x14(%rbp), %eax
subl -0x47c(%rbp), %eax
movl %eax, -0x494(%rbp)
movl -0x494(%rbp), %eax
cmpl -0x14(%rbp), %eax
jae 0x24926
movl -0x494(%rbp), %edx
movq -0x28(%rbp), %rax
movl -0x494(%rbp), %ecx
movl %edx, (%rax,%rcx,8)
movl -0x488(%rbp), %edx
movq -0x28(%rbp), %rax
movl -0x494(%rbp), %ecx
movl %edx, 0x4(%rax,%rcx,8)
movl -0x488(%rbp), %eax
xorl %edx, %edx
divl -0x480(%rbp)
imull -0x46c(%rbp), %edx
movl %edx, -0x488(%rbp)
movl -0x494(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x494(%rbp)
jmp 0x248c8
movq -0x28(%rbp), %rdi
movq -0x40(%rbp), %rsi
movl -0x14(%rbp), %ecx
movl -0x1c(%rbp), %r8d
movl -0x47c(%rbp), %r9d
leaq -0x58(%rbp), %rdx
callq 0x23b40
movl %eax, -0x4d4(%rbp)
jmp 0x2494d
movl -0x4d4(%rbp), %eax
movl %eax, -0x498(%rbp)
movq -0x28(%rbp), %rdi
movq -0x40(%rbp), %rsi
movl -0x14(%rbp), %ecx
movl -0x1c(%rbp), %r8d
movl -0x498(%rbp), %r9d
movl -0x47c(%rbp), %edx
movq %rsp, %rax
movl %edx, (%rax)
leaq -0x58(%rbp), %rdx
callq 0x23c40
movq %rax, -0x4e0(%rbp)
jmp 0x2498c
movq -0x4e0(%rbp), %rax
movq %rax, -0x8(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x14ec0
movq -0x8(%rbp), %rax
addq $0x4f0, %rsp            # imm = 0x4F0
popq %rbp
retq
movq -0x30(%rbp), %rdi
callq 0x3530
nopw %cs:(%rax,%rax)