// File: /workspace/github_cpp_makefile_star2_O3/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 0xa9a7
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 0xa951
xorl %eax, %eax
movl $0x0, (%r14,%rax,4)
incq %rax
movl %eax, %ecx
cmpq %rdx, %rcx
jne 0xa96b
testq %r15, %r15
je 0xa9ad
cmpq $0x1, %r15
jne 0xa9bf
movl $0x1, %eax
xorl %ecx, %ecx
cmpl $0x0, (%rsi,%rcx,4)
jne 0xac5c
movl %eax, %ecx
incl %eax
cmpq %rdx, %rcx
jne 0xa98f
jmp 0xad4b
movl $0x50, %eax
retq
movabsq $0x100000001, %rax      # imm = 0x100000001
movq %rax, (%r14)
jmp 0xad4b
movq %rdi, -0x60(%rbp)
movq %rsi, -0x68(%rbp)
movq %rdx, -0x70(%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 0xac75
movq %r15, -0x48(%rbp)
addq %r15, %r15
movq %r15, -0x38(%rbp)
movq -0x70(%rbp), %rdx
movq -0x68(%rbp), %rsi
je 0xaa4a
xorps %xmm0, %xmm0
movq %rbx, %rdi
movq -0x38(%rbp), %rcx
movups %xmm0, (%rdi)
movq $0x0, 0x10(%rdi)
addq $0x20, %rdi
decq %rcx
jne 0xaa18
xorps %xmm0, %xmm0
movq %rax, %rdi
movq -0x38(%rbp), %rcx
movups %xmm0, (%rdi)
movq $0x0, 0x10(%rdi)
addq $0x20, %rdi
decq %rcx
jne 0xaa36
movq %rax, %r13
movq %r14, -0x78(%rbp)
movq %rbx, %rdi
movq -0x60(%rbp), %rcx
callq 0xad5c
leaq 0x3ab(%rip), %rcx       # 0xae0f
movl $0x20, %edx
movq %rbx, %rdi
movq %rbx, %r15
movq -0x48(%rbp), %rbx
movq %rbx, %rsi
callq 0x34b0
testl %r12d, %r12d
je 0xac92
movl $0x1, -0x2c(%rbp)
xorl %r14d, %r14d
xorps %xmm0, %xmm0
movq %rbx, -0x40(%rbp)
movq %r15, %rbx
movq %r13, %r10
movl %r12d, -0x54(%rbp)
movq %r10, %r13
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
andq %rax, %r14
je 0xaaf7
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 0xaab5
xorl %eax, %eax
movq %r15, %rbx
movups %xmm0, (%r13,%rax)
movq $0x0, 0x10(%r13,%rax)
addq $0x20, %rax
cmpq %rax, %r14
jne 0xaadf
movq %r13, -0x50(%rbp)
cmpl $0x2, -0x40(%rbp)
jb 0xabea
xorl %r13d, %r13d
xorl %r12d, %r12d
movq %rbx, -0x80(%rbp)
movq %r12, -0x88(%rbp)
shlq $0x5, %r12
movq -0x50(%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 0x13f07
testl %eax, %eax
je 0xab6a
addq %rbx, %r15
movq 0x8(%r15), %rax
testq %rax, %rax
je 0xab6a
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 0xab5c
movl %r13d, %eax
orl $0x1, %eax
movl %eax, %eax
shlq $0x5, %rax
leaq (%rbx,%rax), %r15
cmpq $0x0, 0x8(%rbx,%rax)
je 0xabb3
xorl %r12d, %r12d
movq (%r15), %rax
movl (%rax,%r12,4), %ebx
movq 0x8(%r14), %rsi
incq %rsi
movq %r14, %rdi
callq 0x13f07
testl %eax, %eax
je 0xabaa
movq (%r14), %rax
movq 0x8(%r14), %rcx
movl %ebx, -0x4(%rax,%rcx,4)
incq %r12
cmpq 0x8(%r15), %r12
jne 0xab85
movq -0x88(%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 -0x80(%rbp), %rbx
jb 0xab0f
jmp 0xabed
xorl %r12d, %r12d
movl -0x54(%rbp), %eax
movl %eax, %r13d
cmpl %eax, -0x2c(%rbp)
jae 0xac1d
movq %r12, %rdi
shlq $0x5, %rdi
movq -0x50(%rbp), %r15
addq %r15, %rdi
movq -0x68(%rbp), %rsi
movq -0x70(%rbp), %rdx
movq -0x60(%rbp), %rcx
callq 0xad5c
addq -0x48(%rbp), %r12
jmp 0xac21
movq -0x50(%rbp), %r15
movl $0x20, %edx
movq %r15, %rdi
movq %r12, %rsi
leaq 0x1dc(%rip), %rcx       # 0xae0f
callq 0x34b0
movl -0x2c(%rbp), %eax
incl %eax
movq %rbx, %r10
movq -0x40(%rbp), %r14
movq %r12, -0x40(%rbp)
movq %r15, %rbx
movl %eax, -0x2c(%rbp)
cmpl %r13d, %eax
xorps %xmm0, %xmm0
jbe 0xaa9f
jmp 0xac95
movl $0x1, %edx
movl %edx, (%r14,%rcx,4)
xorl %ecx, %ecx
cmpl %edx, %eax
sete %cl
movl %edx, (%r14,%rcx,4)
jmp 0xad4b
movq %rbx, %rdi
movq %rax, %rbx
callq 0x3280
movq %rbx, %rdi
callq 0x3280
movl $0x53, %eax
jmp 0xad4d
movq %r13, %r10
movq -0x48(%rbp), %r9
cmpq $0x2, %r9
movq -0x78(%rbp), %r8
movq -0x38(%rbp), %r14
jb 0xace1
xorl %eax, %eax
movl $0x1, %ecx
movl %eax, %edx
movl %ecx, %eax
shlq $0x5, %rdx
movq 0x8(%r15,%rdx), %rcx
testq %rcx, %rcx
je 0xacd9
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 0xacc8
leal 0x1(%rax), %ecx
cmpq %rcx, %r9
ja 0xacae
movq %r10, %r12
testq %r14, %r14
je 0xad3b
movq %r15, %rbx
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rbx)
movq (%rbx), %rdi
callq 0x3280
movq $0x0, (%rbx)
addq $0x20, %rbx
decq %r14
jne 0xacec
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 0xad1a
jmp 0xad43
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