// File: /workspace/github_cpp_makefile_star2_O1/logicx24[P]RayTracer/lodepng.cpp
// Function: lodepng_huffman_code_lengths(unsigned int*, unsigned int const*, unsigned long, unsigned int)
unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies,
                                      size_t numcodes, unsigned maxbitlen)
{
  unsigned i, j;
  size_t sum = 0, numpresent = 0;
  unsigned error = 0;
  Coin* coins; /*the coins of the currently calculated row*/
  Coin* prev_row; /*the previous row of coins*/
  size_t numcoins;
  size_t coinmem;

  if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/

  for(i = 0; i != numcodes; ++i)
  {
    if(frequencies[i] > 0)
    {
      ++numpresent;
      sum += frequencies[i];
    }
  }

  for(i = 0; i != numcodes; ++i) lengths[i] = 0;

  /*ensure at least two present symbols. There should be at least one symbol
  according to RFC 1951 section 3.2.7. To decoders incorrectly require two. To
  make these work as well ensure there are at least two symbols. The
  Package-Merge code below also doesn't work correctly if there's only one
  symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/
  if(numpresent == 0)
  {
    lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/
  }
  else if(numpresent == 1)
  {
    for(i = 0; i != numcodes; ++i)
    {
      if(frequencies[i])
      {
        lengths[i] = 1;
        lengths[i == 0 ? 1 : 0] = 1;
        break;
      }
    }
  }
  else
  {
    /*Package-Merge algorithm represented by coin collector's problem
    For every symbol, maxbitlen coins will be created*/

    coinmem = numpresent * 2; /*max amount of coins needed with the current algo*/
    coins = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem);
    prev_row = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem);
    if(!coins || !prev_row)
    {
      lodepng_free(coins);
      lodepng_free(prev_row);
      return 83; /*alloc fail*/
    }
    init_coins(coins, coinmem);
    init_coins(prev_row, coinmem);

    /*first row, lowest denominator*/
    error = append_symbol_coins(coins, frequencies, numcodes, sum);
    numcoins = numpresent;
    qsort(coins, numcoins, sizeof(Coin), coin_compare);
    if(!error)
    {
      unsigned numprev = 0;
      for(j = 1; j <= maxbitlen && !error; ++j) /*each of the remaining rows*/
      {
        unsigned tempnum;
        Coin* tempcoins;
        /*swap prev_row and coins, and their amounts*/
        tempcoins = prev_row; prev_row = coins; coins = tempcoins;
        tempnum = numprev; numprev = numcoins; numcoins = tempnum;

        cleanup_coins(coins, numcoins);
        init_coins(coins, numcoins);

        numcoins = 0;

        /*fill in the merged coins of the previous row*/
        for(i = 0; i + 1 < numprev; i += 2)
        {
          /*merge prev_row[i] and prev_row[i + 1] into new coin*/
          Coin* coin = &coins[numcoins++];
          coin_copy(coin, &prev_row[i]);
          add_coins(coin, &prev_row[i + 1]);
        }
        /*fill in all the original symbols again*/
        if(j < maxbitlen)
        {
          error = append_symbol_coins(coins + numcoins, frequencies, numcodes, sum);
          numcoins += numpresent;
        }
        qsort(coins, numcoins, sizeof(Coin), coin_compare);
      }
    }

    if(!error)
    {
      /*calculate the lengths of each symbol, as the amount of times a coin of each symbol is used*/
      for(i = 0; i + 1 < numpresent; ++i)
      {
        Coin* coin = &coins[i];
        for(j = 0; j < coin->symbols.size; ++j) ++lengths[coin->symbols.data[j]];
      }
    }

    cleanup_coins(coins, coinmem);
    lodepng_free(coins);
    cleanup_coins(prev_row, coinmem);
    lodepng_free(prev_row);
  }

  return error;
}

// Assembly:
testq %rdx, %rdx
je 0xad93
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movl %ecx, %r12d
movq %rdi, %r14
xorl %eax, %eax
xorl %edi, %edi
xorl %r15d, %r15d
movl (%rsi,%rax,4), %ecx
addq %rcx, %rdi
cmpq $0x1, %rcx
sbbq $-0x1, %r15
incq %rax
movl %eax, %ecx
cmpq %rdx, %rcx
jne 0xad3d
xorl %eax, %eax
movl $0x0, (%r14,%rax,4)
incq %rax
movl %eax, %ecx
cmpq %rdx, %rcx
jne 0xad57
testq %r15, %r15
je 0xad99
cmpq $0x1, %r15
jne 0xadab
movl $0x1, %eax
xorl %ecx, %ecx
cmpl $0x0, (%rsi,%rcx,4)
jne 0xb04b
movl %eax, %ecx
incl %eax
cmpq %rdx, %rcx
jne 0xad7b
jmp 0xb13b
movl $0x50, %eax
retq
movabsq $0x100000001, %rax      # imm = 0x100000001
movq %rax, (%r14)
jmp 0xb13b
movq %rdi, -0x68(%rbp)
movq %rsi, -0x70(%rbp)
movq %rdx, -0x78(%rbp)
movq %r15, %rbx
shlq $0x6, %rbx
movq %rbx, %rdi
callq 0x32e0
movq %rbx, %rdi
movq %rax, %rbx
callq 0x32e0
testq %rbx, %rbx
setne %dl
testq %rax, %rax
setne %cl
testb %cl, %dl
je 0xb064
movq %r15, -0x50(%rbp)
addq %r15, %r15
movq %r15, -0x38(%rbp)
movq -0x78(%rbp), %rdx
movq -0x70(%rbp), %rsi
je 0xae36
xorps %xmm0, %xmm0
movq %rbx, %rdi
movq -0x38(%rbp), %rcx
movups %xmm0, (%rdi)
movq $0x0, 0x10(%rdi)
addq $0x20, %rdi
decq %rcx
jne 0xae04
xorps %xmm0, %xmm0
movq %rax, %rdi
movq -0x38(%rbp), %rcx
movups %xmm0, (%rdi)
movq $0x0, 0x10(%rdi)
addq $0x20, %rdi
decq %rcx
jne 0xae22
movq %rax, -0x48(%rbp)
movq %r14, -0x80(%rbp)
movq %rbx, %rdi
movq -0x68(%rbp), %rcx
callq 0xb14c
leaq 0x3ae(%rip), %rcx       # 0xb1ff
movl $0x20, %edx
movq %rbx, %rdi
movq %rbx, %r15
movq -0x50(%rbp), %rbx
movq %rbx, %rsi
callq 0x34b0
testl %r12d, %r12d
je 0xb081
movl $0x1, %r13d
xorl %r14d, %r14d
xorps %xmm0, %xmm0
movq %rbx, -0x40(%rbp)
movq %r15, %rbx
movq -0x48(%rbp), %r10
movl %r12d, -0x2c(%rbp)
movl %r13d, -0x5c(%rbp)
movq %r10, %r13
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
andq %rax, %r14
je 0xaee8
movq %rbx, %r15
shlq $0x5, %r14
xorl %ebx, %ebx
movups %xmm0, 0x8(%r13,%rbx)
movq (%r13,%rbx), %rdi
callq 0x3280
xorps %xmm0, %xmm0
movq $0x0, (%r13,%rbx)
addq $0x20, %rbx
cmpq %rbx, %r14
jne 0xaea6
xorl %eax, %eax
movq %r15, %rbx
movups %xmm0, (%r13,%rax)
movq $0x0, 0x10(%r13,%rax)
addq $0x20, %rax
cmpq %rax, %r14
jne 0xaed0
movq %r13, -0x58(%rbp)
cmpl $0x2, -0x40(%rbp)
jb 0xafdb
xorl %r13d, %r13d
xorl %r12d, %r12d
movq %rbx, -0x88(%rbp)
movq %r12, -0x48(%rbp)
shlq $0x5, %r12
movq -0x58(%rbp), %rcx
leaq (%rcx,%r12), %r14
movl %r13d, %r15d
shlq $0x5, %r15
movss 0x18(%rbx,%r15), %xmm0
movss %xmm0, 0x18(%rcx,%r12)
movq 0x8(%rbx,%r15), %rsi
movq %r14, %rdi
callq 0x13dd8
testl %eax, %eax
je 0xaf5b
addq %rbx, %r15
movq 0x8(%r15), %rax
testq %rax, %rax
je 0xaf5b
movq (%r15), %rcx
movq (%r14), %rdx
xorl %esi, %esi
movl (%rcx,%rsi,4), %edi
movl %edi, (%rdx,%rsi,4)
incq %rsi
cmpq %rsi, %rax
jne 0xaf4d
movl %r13d, %eax
orl $0x1, %eax
movl %eax, %eax
shlq $0x5, %rax
leaq (%rbx,%rax), %r15
cmpq $0x0, 0x8(%rbx,%rax)
je 0xafa4
xorl %r12d, %r12d
movq (%r15), %rax
movl (%rax,%r12,4), %ebx
movq 0x8(%r14), %rsi
incq %rsi
movq %r14, %rdi
callq 0x13dd8
testl %eax, %eax
je 0xaf9b
movq (%r14), %rax
movq 0x8(%r14), %rcx
movl %ebx, -0x4(%rax,%rcx,4)
incq %r12
cmpq 0x8(%r15), %r12
jne 0xaf76
movq -0x48(%rbp), %r12
incq %r12
movss 0x18(%r15), %xmm0
addss 0x18(%r14), %xmm0
movss %xmm0, 0x18(%r14)
leal 0x2(%r13), %eax
addl $0x3, %r13d
cmpl -0x40(%rbp), %r13d
movl %eax, %r13d
movq -0x88(%rbp), %rbx
jb 0xaf03
jmp 0xafde
xorl %r12d, %r12d
movl -0x5c(%rbp), %r13d
cmpl -0x2c(%rbp), %r13d
jae 0xb00d
movq %r12, %rdi
shlq $0x5, %rdi
movq -0x58(%rbp), %r15
addq %r15, %rdi
movq -0x70(%rbp), %rsi
movq -0x78(%rbp), %rdx
movq -0x68(%rbp), %rcx
callq 0xb14c
addq -0x50(%rbp), %r12
jmp 0xb011
movq -0x58(%rbp), %r15
movl $0x20, %edx
movq %r15, %rdi
movq %r12, %rsi
leaq 0x1dc(%rip), %rcx       # 0xb1ff
callq 0x34b0
incl %r13d
movq %rbx, %r10
movq -0x40(%rbp), %r14
movq %r12, -0x40(%rbp)
movq %r15, %rbx
movl -0x2c(%rbp), %r12d
cmpl %r12d, %r13d
xorps %xmm0, %xmm0
jbe 0xae8c
jmp 0xb085
movl $0x1, %edx
movl %edx, (%r14,%rcx,4)
xorl %ecx, %ecx
cmpl %edx, %eax
sete %cl
movl %edx, (%r14,%rcx,4)
jmp 0xb13b
movq %rbx, %rdi
movq %rax, %rbx
callq 0x3280
movq %rbx, %rdi
callq 0x3280
movl $0x53, %eax
jmp 0xb13d
movq -0x48(%rbp), %r10
movq -0x50(%rbp), %r9
cmpq $0x2, %r9
movq -0x80(%rbp), %r8
movq -0x38(%rbp), %r14
jb 0xb0d1
xorl %eax, %eax
movl $0x1, %ecx
movl %eax, %edx
movl %ecx, %eax
shlq $0x5, %rdx
movq 0x8(%r15,%rdx), %rcx
testq %rcx, %rcx
je 0xb0c9
addq %r15, %rdx
movq (%rdx), %rdx
xorl %esi, %esi
movl (%rdx,%rsi,4), %edi
incl (%r8,%rdi,4)
incq %rsi
movl %esi, %edi
cmpq %rdi, %rcx
ja 0xb0b8
leal 0x1(%rax), %ecx
cmpq %rcx, %r9
ja 0xb09e
movq %r10, %r12
testq %r14, %r14
je 0xb12b
movq %r15, %rbx
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rbx)
movq (%rbx), %rdi
callq 0x3280
movq $0x0, (%rbx)
addq $0x20, %rbx
decq %r14
jne 0xb0dc
movq %r15, %rdi
callq 0x3280
movq %r12, %rbx
movq -0x38(%rbp), %r14
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rbx)
movq (%rbx), %rdi
callq 0x3280
movq $0x0, (%rbx)
addq $0x20, %rbx
decq %r14
jne 0xb10a
jmp 0xb133
movq %r15, %rdi
callq 0x3280
movq %r12, %rdi
callq 0x3280
xorl %eax, %eax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq