// File: /workspace/github_cpp_makefile_star2_O2/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 0x9938
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rdx, %r13
movq %rdi, %rbx
xorl %r12d, %r12d
xorl %edi, %edi
xorl %eax, %eax
movl %eax, %eax
cmpq %r13, %rax
je 0x98ff
movl (%rsi,%rax,4), %edx
addq %rdx, %rdi
cmpq $0x1, %rdx
sbbq $-0x1, %r12
incl %eax
jmp 0x98e6
xorl %eax, %eax
movl %eax, %eax
cmpq %r13, %rax
je 0x9910
andl $0x0, (%rbx,%rax,4)
incl %eax
jmp 0x9901
testq %r12, %r12
je 0x993c
cmpq $0x1, %r12
jne 0x994e
xorl %eax, %eax
xorl %ecx, %ecx
movl %ecx, %ecx
cmpq %r13, %rcx
je 0x9bbe
cmpl $0x0, (%rsi,%rcx,4)
jne 0x9bac
incl %ecx
jmp 0x991f
pushq $0x50
popq %rax
retq
movabsq $0x100000001, %rax      # imm = 0x100000001
movq %rax, (%rbx)
jmp 0x9ba8
movq %rdi, -0x50(%rbp)
movl %ecx, -0x34(%rbp)
movq %rsi, -0x58(%rbp)
movq %r12, %r14
shlq $0x6, %r14
movq %r14, %rdi
callq 0x32b0
movq %rax, %r15
movq %r14, %rdi
callq 0x32b0
movq %rax, %r14
testq %r15, %r15
setne %al
testq %r14, %r14
setne %cl
testb %cl, %al
je 0x9b22
movq %rbx, -0x70(%rbp)
leaq (%r12,%r12), %rbx
movq %r15, %rdi
movq %rbx, %rsi
callq 0x9bcd
movq %r14, %rdi
movq %rbx, -0x68(%rbp)
movq %rbx, %rsi
callq 0x9bcd
movq %r15, %rdi
movq -0x58(%rbp), %rsi
movq %r13, -0x78(%rbp)
movl %r13d, %edx
movq -0x50(%rbp), %rcx
callq 0x9bea
leaq 0x2ad(%rip), %rcx       # 0x9c77
pushq $0x20
popq %rdx
movq %r15, %rdi
movq %r12, %rsi
callq 0x3440
pushq $0x1
popq %rcx
xorl %eax, %eax
movq %r12, -0x48(%rbp)
movq %r12, %r13
movl -0x34(%rbp), %ebx
movq %r13, -0x60(%rbp)
movq %r15, -0x30(%rbp)
cmpl %ebx, %ecx
ja 0x9b3a
movl %ecx, -0x38(%rbp)
movl %eax, %r15d
movq %r14, %rdi
movq %r15, %rsi
callq 0x9c9c
movq %r14, -0x40(%rbp)
movq %r14, %rdi
movq %r15, %rsi
callq 0x9bcd
xorl %r13d, %r13d
xorl %r14d, %r14d
movl %r14d, %ebx
orl $0x1, %ebx
cmpl -0x60(%rbp), %ebx
jae 0x9aca
movq %r13, %rax
shlq $0x5, %rax
movq -0x40(%rbp), %rcx
leaq (%rcx,%rax), %r15
movl %r14d, %r12d
shlq $0x5, %r12
movq -0x30(%rbp), %rdx
movss 0x18(%rdx,%r12), %xmm0
movss %xmm0, 0x18(%rcx,%rax)
movq 0x8(%rdx,%r12), %rsi
movq %r15, %rdi
callq 0x10cd6
testl %eax, %eax
je 0x9a86
addq -0x30(%rbp), %r12
movq 0x8(%r12), %rax
xorl %ecx, %ecx
cmpq %rcx, %rax
je 0x9a86
movq (%r12), %rdx
movl (%rdx,%rcx,4), %edx
movq (%r15), %rsi
movl %edx, (%rsi,%rcx,4)
incq %rcx
jmp 0x9a6f
incq %r13
movl %ebx, %ebx
shlq $0x5, %rbx
addq -0x30(%rbp), %rbx
xorl %r12d, %r12d
cmpq 0x8(%rbx), %r12
je 0x9ab0
movq (%rbx), %rax
movl (%rax,%r12,4), %esi
movq %r15, %rdi
callq 0x10ca3
incq %r12
jmp 0x9a96
movss 0x18(%rbx), %xmm0
addss 0x18(%r15), %xmm0
movss %xmm0, 0x18(%r15)
addl $0x2, %r14d
jmp 0x9a1d
movl -0x34(%rbp), %ebx
cmpl %ebx, -0x38(%rbp)
jae 0x9af7
movq %r13, %rdi
shlq $0x5, %rdi
movq -0x40(%rbp), %r15
addq %r15, %rdi
movq -0x58(%rbp), %rsi
movq -0x78(%rbp), %rdx
movq -0x50(%rbp), %rcx
callq 0x9bea
addq -0x48(%rbp), %r13
jmp 0x9afb
movq -0x40(%rbp), %r15
movq %r15, %rdi
movq %r13, %rsi
pushq $0x20
popq %rdx
leaq 0x16c(%rip), %rcx       # 0x9c77
callq 0x3440
movl -0x38(%rbp), %ecx
incl %ecx
movq -0x30(%rbp), %r14
movq -0x60(%rbp), %rax
jmp 0x99e7
movq %r15, %rdi
callq 0x3250
movq %r14, %rdi
callq 0x3250
pushq $0x53
popq %rax
jmp 0x9bbe
xorl %ecx, %ecx
movq -0x70(%rbp), %r8
movq -0x48(%rbp), %r9
leal 0x1(%rcx), %eax
cmpq %rax, %r9
jbe 0x9b7a
movl %ecx, %edx
shlq $0x5, %rdx
movq -0x30(%rbp), %rsi
leaq (%rsi,%rdx), %rcx
movq 0x8(%rsi,%rdx), %rdx
xorl %esi, %esi
movl %esi, %esi
cmpq %rsi, %rdx
jbe 0x9b76
movq (%rcx), %rdi
movl (%rdi,%rsi,4), %edi
incl (%r8,%rdi,4)
incl %esi
jmp 0x9b61
movl %eax, %ecx
jmp 0x9b44
movq -0x30(%rbp), %r15
movq %r15, %rdi
movq -0x68(%rbp), %rbx
movq %rbx, %rsi
callq 0x9c9c
movq %r15, %rdi
callq 0x3250
movq %r14, %rdi
movq %rbx, %rsi
callq 0x9c9c
movq %r14, %rdi
callq 0x3250
xorl %eax, %eax
jmp 0x9bbe
pushq $0x1
popq %rdx
movl %edx, (%rbx,%rcx,4)
xorl %esi, %esi
testq %rcx, %rcx
sete %sil
movl %edx, (%rbx,%rsi,4)
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq