// File: attractivechaos[P]udb2/stb/./stb.h
// Function: stb_dupe_finish
void stb_dupe_finish(stb_dupe *sd)
{
   int i,j,k;
   assert(sd->dupes == NULL);
   for (i=0; i < sd->hash_size; ++i) {
      void ** list = sd->hash_table[i];
      if (list != NULL) {                                          
         int n = stb_arr_len(list);
         // @TODO: measure to find good numbers instead of just making them up!
         int thresh = (sd->ineq ? 200 : 20);
         // if n is large enough to be worth it, and n is smaller than
         // before (so we can guarantee we'll use a smaller hash table);
         // and there are enough hash bits left, assuming full 32-bit hash
         if (n > thresh && n < (sd->population >> 3) && sd->hash_shift + sd->size_log2*2 < 32) {

            // recursively process this row using stb_dupe, O(N log log N)

            stb_dupe *d = stb_dupe_create(sd->hash, sd->eq, n, sd->ineq);
            d->hash_shift = stb_randLCG_explicit(sd->hash_shift);
            for (j=0; j < n; ++j)
               stb_dupe_add(d, list[j]);
            stb_arr_free(sd->hash_table[i]);
            stb_dupe_finish(d);
            for (j=0; j < stb_arr_len(d->dupes); ++j) {
               stb_arr_push(sd->dupes, d->dupes[j]);
               d->dupes[j] = NULL; // take over ownership
            }
            stb_dupe_free(d);

         } else if (sd->ineq) {

            // process this row using qsort(), O(N log N)
            stb__compare = sd->ineq;
            qsort(list, n, sizeof(list[0]), stb__dupe_compare);

            // find equal subsequences of the list
            for (j=0; j < n-1; ) {
               // find a subsequence from j..k
               for (k=j; k < n; ++k)
                  // only use ineq so eq can be left undefined
                  if (sd->ineq(list[j], list[k]))
                     break;
               // k is the first one not in the subsequence
               if (k-j > 1) {
                  void **mylist = NULL;
                  stb_arr_setlen(mylist, k-j);
                  memcpy(mylist, list+j, sizeof(list[j]) * (k-j));
                  stb_arr_push(sd->dupes, mylist);
               }
               j = k;
            }
            stb_arr_free(sd->hash_table[i]);
         } else {

            // process this row using eq(), O(N^2)
            for (j=0; j < n; ++j) {
               if (list[j] != NULL) {
                  void **output  = NULL;
                  for (k=j+1; k < n; ++k) {
                     if (sd->eq(list[j], list[k])) {
                        if (output == NULL)
                           stb_arr_push(output, list[j]);
                        stb_arr_push(output, list[k]);
                        list[k] = NULL;
                     }
                  }
                  list[j] = NULL;
                  if (output)
                     stb_arr_push(sd->dupes, output);
               }
            }
            stb_arr_free(sd->hash_table[i]);
         }
      }
   }
   free(sd->hash_table);
   sd->hash_table = NULL;
}

// Assembly:
subq $0x118, %rsp            # imm = 0x118
movq %rdi, 0x110(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
jne 0x15160
jmp 0x1517f
leaq 0xaa46(%rip), %rdi      # 0x1fbad
leaq 0xa21b(%rip), %rsi      # 0x1f389
movl $0x20e8, %edx           # imm = 0x20E8
leaq 0xaa45(%rip), %rcx      # 0x1fbbf
callq 0x2140
movl $0x0, 0x10c(%rsp)
movl 0x10c(%rsp), %eax
movq 0x110(%rsp), %rcx
cmpl 0x8(%rcx), %eax
jge 0x15c1f
movq 0x110(%rsp), %rax
movq (%rax), %rax
movslq 0x10c(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0xf8(%rsp)
cmpq $0x0, 0xf8(%rsp)
je 0x15c07
cmpq $0x0, 0xf8(%rsp)
je 0x151ef
movq 0xf8(%rsp), %rax
movl -0x10(%rax), %eax
movl %eax, 0xd4(%rsp)
jmp 0x151fa
xorl %eax, %eax
movl %eax, 0xd4(%rsp)
jmp 0x151fa
movl 0xd4(%rsp), %eax
movl %eax, 0xf4(%rsp)
movq 0x110(%rsp), %rax
movq 0x28(%rax), %rdx
movl $0x14, %eax
movl $0xc8, %ecx
cmpq $0x0, %rdx
cmovnel %ecx, %eax
movl %eax, 0xf0(%rsp)
movl 0xf4(%rsp), %eax
cmpl 0xf0(%rsp), %eax
jle 0x15534
movl 0xf4(%rsp), %eax
movq 0x110(%rsp), %rcx
movl 0x10(%rcx), %ecx
sarl $0x3, %ecx
cmpl %ecx, %eax
jge 0x15534
movq 0x110(%rsp), %rax
movl 0x14(%rax), %eax
movq 0x110(%rsp), %rcx
movl 0xc(%rcx), %ecx
shll %ecx
addl %ecx, %eax
cmpl $0x20, %eax
jge 0x15534
movq 0x110(%rsp), %rax
movq 0x18(%rax), %rdi
movq 0x110(%rsp), %rax
movq 0x20(%rax), %rsi
movl 0xf4(%rsp), %edx
movq 0x110(%rsp), %rax
movq 0x28(%rax), %rcx
callq 0x14df0
movq %rax, 0xe8(%rsp)
movq 0x110(%rsp), %rax
movslq 0x14(%rax), %rdi
callq 0x14740
movl %eax, %ecx
movq 0xe8(%rsp), %rax
movl %ecx, 0x14(%rax)
movl $0x0, 0x108(%rsp)
movl 0x108(%rsp), %eax
cmpl 0xf4(%rsp), %eax
jge 0x15325
movq 0xe8(%rsp), %rdi
movq 0xf8(%rsp), %rax
movslq 0x108(%rsp), %rcx
movq (%rax,%rcx,8), %rsi
callq 0x14f10
movl 0x108(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x108(%rsp)
jmp 0x152e1
movq 0x110(%rsp), %rax
movq (%rax), %rdi
movslq 0x10c(%rsp), %rax
shlq $0x3, %rax
addq %rax, %rdi
callq 0x7d20
movq 0xe8(%rsp), %rdi
callq 0x15140
movl $0x0, 0x108(%rsp)
movl 0x108(%rsp), %eax
movl %eax, 0xd0(%rsp)
movq 0xe8(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x15391
movq 0xe8(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %eax
movl %eax, 0xcc(%rsp)
jmp 0x1539c
xorl %eax, %eax
movl %eax, 0xcc(%rsp)
jmp 0x1539c
movl 0xd0(%rsp), %eax
movl 0xcc(%rsp), %ecx
cmpl %ecx, %eax
jge 0x15522
movq 0xe8(%rsp), %rax
movq 0x30(%rax), %rax
movslq 0x108(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0xc0(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x153f9
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %eax
movl %eax, 0xbc(%rsp)
jmp 0x15404
xorl %eax, %eax
movl %eax, 0xbc(%rsp)
jmp 0x15404
movl 0xbc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xb8(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x1543c
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0xc(%rax), %eax
movl %eax, 0xb4(%rsp)
jmp 0x15447
xorl %eax, %eax
movl %eax, 0xb4(%rsp)
jmp 0x15447
movl 0xb8(%rsp), %eax
movl 0xb4(%rsp), %ecx
cmpl %ecx, %eax
jle 0x15476
movq 0x110(%rsp), %rdi
addq $0x30, %rdi
movl $0x8, %esi
movl $0x1, %edx
callq 0x8030
jmp 0x1548b
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %ecx
addl $0x1, %ecx
movl %ecx, -0x10(%rax)
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movq %rax, 0xa8(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x154c6
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %eax
movl %eax, 0xa4(%rsp)
jmp 0x154d1
xorl %eax, %eax
movl %eax, 0xa4(%rsp)
jmp 0x154d1
movq 0xa8(%rsp), %rax
movq 0xc0(%rsp), %rdx
movl 0xa4(%rsp), %ecx
movslq %ecx, %rcx
movq %rdx, -0x8(%rax,%rcx,8)
movq 0xe8(%rsp), %rax
movq 0x30(%rax), %rax
movslq 0x108(%rsp), %rcx
movq $0x0, (%rax,%rcx,8)
movl 0x108(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x108(%rsp)
jmp 0x1535c
movq 0xe8(%rsp), %rdi
callq 0x15090
jmp 0x15c05
movq 0x110(%rsp), %rax
cmpq $0x0, 0x28(%rax)
je 0x157e7
movq 0x110(%rsp), %rax
movq 0x28(%rax), %rax
movq %rax, 0x169e6(%rip)     # 0x2bf40
movq 0xf8(%rsp), %rdi
movslq 0xf4(%rsp), %rsi
movl $0x8, %edx
leaq 0x6da(%rip), %rcx       # 0x15c50
callq 0x20a0
movl $0x0, 0x108(%rsp)
movl 0x108(%rsp), %eax
movl 0xf4(%rsp), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jge 0x157c3
movl 0x108(%rsp), %eax
movl %eax, 0x104(%rsp)
movl 0x104(%rsp), %eax
cmpl 0xf4(%rsp), %eax
jge 0x1560f
movq 0x110(%rsp), %rax
movq 0x28(%rax), %rax
movq 0xf8(%rsp), %rcx
movslq 0x108(%rsp), %rdx
movq (%rcx,%rdx,8), %rdi
movq 0xf8(%rsp), %rcx
movslq 0x104(%rsp), %rdx
movq (%rcx,%rdx,8), %rsi
callq *%rax
cmpl $0x0, %eax
je 0x155fa
jmp 0x1560f
jmp 0x155fc
movl 0x104(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x104(%rsp)
jmp 0x155ad
movl 0x104(%rsp), %eax
subl 0x108(%rsp), %eax
cmpl $0x1, %eax
jle 0x157b0
movq $0x0, 0xe0(%rsp)
movl 0x104(%rsp), %edx
subl 0x108(%rsp), %edx
leaq 0xe0(%rsp), %rdi
movl $0x8, %esi
callq 0x7fb0
movq 0xe0(%rsp), %rdi
movq 0xf8(%rsp), %rsi
movslq 0x108(%rsp), %rax
shlq $0x3, %rax
addq %rax, %rsi
movl 0x104(%rsp), %eax
subl 0x108(%rsp), %eax
movslq %eax, %rdx
shlq $0x3, %rdx
callq 0x2230
movq 0xe0(%rsp), %rax
movq %rax, 0x98(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x156c2
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %eax
movl %eax, 0x94(%rsp)
jmp 0x156cd
xorl %eax, %eax
movl %eax, 0x94(%rsp)
jmp 0x156cd
movl 0x94(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x90(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x15705
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0xc(%rax), %eax
movl %eax, 0x8c(%rsp)
jmp 0x15710
xorl %eax, %eax
movl %eax, 0x8c(%rsp)
jmp 0x15710
movl 0x90(%rsp), %eax
movl 0x8c(%rsp), %ecx
cmpl %ecx, %eax
jle 0x1573f
movq 0x110(%rsp), %rdi
addq $0x30, %rdi
movl $0x8, %esi
movl $0x1, %edx
callq 0x8030
jmp 0x15754
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %ecx
addl $0x1, %ecx
movl %ecx, -0x10(%rax)
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movq %rax, 0x80(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x1578c
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %eax
movl %eax, 0x7c(%rsp)
jmp 0x15794
xorl %eax, %eax
movl %eax, 0x7c(%rsp)
jmp 0x15794
movq 0x80(%rsp), %rax
movq 0x98(%rsp), %rdx
movl 0x7c(%rsp), %ecx
movslq %ecx, %rcx
movq %rdx, -0x8(%rax,%rcx,8)
movl 0x104(%rsp), %eax
movl %eax, 0x108(%rsp)
jmp 0x15586
movq 0x110(%rsp), %rax
movq (%rax), %rdi
movslq 0x10c(%rsp), %rax
shlq $0x3, %rax
addq %rax, %rdi
callq 0x7d20
jmp 0x15c03
movl $0x0, 0x108(%rsp)
movl 0x108(%rsp), %eax
cmpl 0xf4(%rsp), %eax
jge 0x15be4
movq 0xf8(%rsp), %rax
movslq 0x108(%rsp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0x15bcc
movq $0x0, 0xd8(%rsp)
movl 0x108(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x104(%rsp)
movl 0x104(%rsp), %eax
cmpl 0xf4(%rsp), %eax
jge 0x15aa2
movq 0x110(%rsp), %rax
movq 0x20(%rax), %rax
movq 0xf8(%rsp), %rcx
movslq 0x108(%rsp), %rdx
movq (%rcx,%rdx,8), %rdi
movq 0xf8(%rsp), %rcx
movslq 0x104(%rsp), %rdx
movq (%rcx,%rdx,8), %rsi
callq *%rax
cmpl $0x0, %eax
je 0x15a8a
cmpq $0x0, 0xd8(%rsp)
jne 0x15989
movq 0xf8(%rsp), %rax
movslq 0x108(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x70(%rsp)
cmpq $0x0, 0xd8(%rsp)
je 0x158d5
movq 0xd8(%rsp), %rax
movl -0x10(%rax), %eax
movl %eax, 0x6c(%rsp)
jmp 0x158dd
xorl %eax, %eax
movl %eax, 0x6c(%rsp)
jmp 0x158dd
movl 0x6c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x68(%rsp)
cmpq $0x0, 0xd8(%rsp)
je 0x15904
movq 0xd8(%rsp), %rax
movl -0xc(%rax), %eax
movl %eax, 0x64(%rsp)
jmp 0x1590c
xorl %eax, %eax
movl %eax, 0x64(%rsp)
jmp 0x1590c
movl 0x68(%rsp), %eax
movl 0x64(%rsp), %ecx
cmpl %ecx, %eax
jle 0x15931
leaq 0xd8(%rsp), %rdi
movl $0x8, %esi
movl $0x1, %edx
callq 0x8030
jmp 0x15942
movq 0xd8(%rsp), %rax
movl -0x10(%rax), %ecx
addl $0x1, %ecx
movl %ecx, -0x10(%rax)
movq 0xd8(%rsp), %rax
movq %rax, 0x58(%rsp)
cmpq $0x0, 0xd8(%rsp)
je 0x1596b
movq 0xd8(%rsp), %rax
movl -0x10(%rax), %eax
movl %eax, 0x54(%rsp)
jmp 0x15973
xorl %eax, %eax
movl %eax, 0x54(%rsp)
jmp 0x15973
movq 0x58(%rsp), %rax
movq 0x70(%rsp), %rdx
movl 0x54(%rsp), %ecx
movslq %ecx, %rcx
movq %rdx, -0x8(%rax,%rcx,8)
movq 0xf8(%rsp), %rax
movslq 0x104(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x48(%rsp)
cmpq $0x0, 0xd8(%rsp)
je 0x159be
movq 0xd8(%rsp), %rax
movl -0x10(%rax), %eax
movl %eax, 0x44(%rsp)
jmp 0x159c6
xorl %eax, %eax
movl %eax, 0x44(%rsp)
jmp 0x159c6
movl 0x44(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x40(%rsp)
cmpq $0x0, 0xd8(%rsp)
je 0x159ed
movq 0xd8(%rsp), %rax
movl -0xc(%rax), %eax
movl %eax, 0x3c(%rsp)
jmp 0x159f5
xorl %eax, %eax
movl %eax, 0x3c(%rsp)
jmp 0x159f5
movl 0x40(%rsp), %eax
movl 0x3c(%rsp), %ecx
cmpl %ecx, %eax
jle 0x15a1a
leaq 0xd8(%rsp), %rdi
movl $0x8, %esi
movl $0x1, %edx
callq 0x8030
jmp 0x15a2b
movq 0xd8(%rsp), %rax
movl -0x10(%rax), %ecx
addl $0x1, %ecx
movl %ecx, -0x10(%rax)
movq 0xd8(%rsp), %rax
movq %rax, 0x30(%rsp)
cmpq $0x0, 0xd8(%rsp)
je 0x15a54
movq 0xd8(%rsp), %rax
movl -0x10(%rax), %eax
movl %eax, 0x2c(%rsp)
jmp 0x15a5c
xorl %eax, %eax
movl %eax, 0x2c(%rsp)
jmp 0x15a5c
movq 0x30(%rsp), %rax
movq 0x48(%rsp), %rdx
movl 0x2c(%rsp), %ecx
movslq %ecx, %rcx
movq %rdx, -0x8(%rax,%rcx,8)
movq 0xf8(%rsp), %rax
movslq 0x104(%rsp), %rcx
movq $0x0, (%rax,%rcx,8)
jmp 0x15a8c
movl 0x104(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x104(%rsp)
jmp 0x1583e
movq 0xf8(%rsp), %rax
movslq 0x108(%rsp), %rcx
movq $0x0, (%rax,%rcx,8)
cmpq $0x0, 0xd8(%rsp)
je 0x15bca
movq 0xd8(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x15afa
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %eax
movl %eax, 0x1c(%rsp)
jmp 0x15b02
xorl %eax, %eax
movl %eax, 0x1c(%rsp)
jmp 0x15b02
movl 0x1c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x18(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x15b31
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0xc(%rax), %eax
movl %eax, 0x14(%rsp)
jmp 0x15b39
xorl %eax, %eax
movl %eax, 0x14(%rsp)
jmp 0x15b39
movl 0x18(%rsp), %eax
movl 0x14(%rsp), %ecx
cmpl %ecx, %eax
jle 0x15b62
movq 0x110(%rsp), %rdi
addq $0x30, %rdi
movl $0x8, %esi
movl $0x1, %edx
callq 0x8030
jmp 0x15b77
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %ecx
addl $0x1, %ecx
movl %ecx, -0x10(%rax)
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movq %rax, 0x8(%rsp)
movq 0x110(%rsp), %rax
cmpq $0x0, 0x30(%rax)
je 0x15bac
movq 0x110(%rsp), %rax
movq 0x30(%rax), %rax
movl -0x10(%rax), %eax
movl %eax, 0x4(%rsp)
jmp 0x15bb4
xorl %eax, %eax
movl %eax, 0x4(%rsp)
jmp 0x15bb4
movq 0x8(%rsp), %rax
movq 0x20(%rsp), %rdx
movl 0x4(%rsp), %ecx
movslq %ecx, %rcx
movq %rdx, -0x8(%rax,%rcx,8)
jmp 0x15bcc
jmp 0x15bce
movl 0x108(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x108(%rsp)
jmp 0x157f2
movq 0x110(%rsp), %rax
movq (%rax), %rdi
movslq 0x10c(%rsp), %rax
shlq $0x3, %rax
addq %rax, %rdi
callq 0x7d20
jmp 0x15c05
jmp 0x15c07
jmp 0x15c09
movl 0x10c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x10c(%rsp)
jmp 0x1518a
movq 0x110(%rsp), %rax
movq (%rax), %rdi
callq 0x23c0
movq 0x110(%rsp), %rax
movq $0x0, (%rax)
addq $0x118, %rsp            # imm = 0x118
retq
nopw %cs:(%rax,%rax)