// File: drummyfish[P]flowchart/src/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*/
  unsigned numcoins;
  unsigned 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;

  /*there are no symbols at all, in that case add one symbol of value 0 to the tree (see RFC 1951 section 3.2.7) */
  if(numpresent == 0)
  {
    lengths[0] = 1;
  }
  /*the package merge algorithm gives wrong results if there's only one symbol
  (theoretically 0 bits would then suffice, but we need a proper symbol for zlib)*/
  else if(numpresent == 1)
  {
    for(i = 0; i < numcodes; i++) if(frequencies[i]) lengths[i] = 1;
  }
  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*)mymalloc(sizeof(Coin) * coinmem);
    prev_row = (Coin*)mymalloc(sizeof(Coin) * coinmem);
    if(!coins || !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;
    sort_coins(coins, numcoins);
    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;
        }
        sort_coins(coins, numcoins);
      }
    }

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

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

  return error;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x90, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movl %ecx, -0x24(%rbp)
movq $0x0, -0x38(%rbp)
movq $0x0, -0x40(%rbp)
movl $0x0, -0x44(%rbp)
cmpq $0x0, -0x20(%rbp)
jne 0x3914
movl $0x50, -0x4(%rbp)
jmp 0x3c75
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
cmpq -0x20(%rbp), %rax
jae 0x395c
movq -0x18(%rbp), %rax
movl -0x28(%rbp), %ecx
cmpl $0x0, (%rax,%rcx,4)
jbe 0x394f
movq -0x40(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x40(%rbp)
movq -0x18(%rbp), %rax
movl -0x28(%rbp), %ecx
movl (%rax,%rcx,4), %eax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
jmp 0x3951
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x391b
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
cmpq -0x20(%rbp), %rax
jae 0x3985
movq -0x10(%rbp), %rax
movl -0x28(%rbp), %ecx
movl $0x0, (%rax,%rcx,4)
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x3963
cmpq $0x0, -0x40(%rbp)
jne 0x399b
movq -0x10(%rbp), %rax
movl $0x1, (%rax)
jmp 0x3c6f
cmpq $0x1, -0x40(%rbp)
jne 0x39df
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
cmpq -0x20(%rbp), %rax
jae 0x39da
movq -0x18(%rbp), %rax
movl -0x28(%rbp), %ecx
cmpl $0x0, (%rax,%rcx,4)
je 0x39cd
movq -0x10(%rbp), %rax
movl -0x28(%rbp), %ecx
movl $0x1, (%rax,%rcx,4)
jmp 0x39cf
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x39a9
jmp 0x3c6d
movq -0x40(%rbp), %rax
shlq %rax
movl %eax, -0x60(%rbp)
movl -0x60(%rbp), %eax
movl %eax, %edi
shlq $0x5, %rdi
callq 0x3840
movq %rax, -0x50(%rbp)
movl -0x60(%rbp), %eax
movl %eax, %edi
shlq $0x5, %rdi
callq 0x3840
movq %rax, -0x58(%rbp)
cmpq $0x0, -0x50(%rbp)
je 0x3a1b
cmpq $0x0, -0x58(%rbp)
jne 0x3a27
movl $0x53, -0x4(%rbp)
jmp 0x3c75
movq -0x50(%rbp), %rdi
movl -0x60(%rbp), %eax
movl %eax, %esi
callq 0x3c90
movq -0x58(%rbp), %rdi
movl -0x60(%rbp), %eax
movl %eax, %esi
callq 0x3c90
movq -0x50(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rax
movl %eax, %edx
movq -0x38(%rbp), %rcx
callq 0x3ce0
movl %eax, -0x44(%rbp)
movq -0x40(%rbp), %rax
movl %eax, -0x5c(%rbp)
movq -0x50(%rbp), %rdi
movl -0x5c(%rbp), %eax
movl %eax, %esi
callq 0x3dd0
cmpl $0x0, -0x44(%rbp)
jne 0x3bc8
movl $0x0, -0x64(%rbp)
movl $0x1, -0x2c(%rbp)
movl -0x2c(%rbp), %ecx
xorl %eax, %eax
cmpl -0x24(%rbp), %ecx
movb %al, -0x81(%rbp)
ja 0x3aa9
cmpl $0x0, -0x44(%rbp)
setne %al
xorb $-0x1, %al
movb %al, -0x81(%rbp)
movb -0x81(%rbp), %al
testb $0x1, %al
jne 0x3ab8
jmp 0x3bc6
movq -0x58(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0x50(%rbp)
movl -0x64(%rbp), %eax
movl %eax, -0x68(%rbp)
movl -0x5c(%rbp), %eax
movl %eax, -0x64(%rbp)
movl -0x68(%rbp), %eax
movl %eax, -0x5c(%rbp)
movq -0x50(%rbp), %rdi
movl -0x5c(%rbp), %eax
movl %eax, %esi
callq 0x3f50
movq -0x50(%rbp), %rdi
movl -0x5c(%rbp), %eax
movl %eax, %esi
callq 0x3c90
movl $0x0, -0x5c(%rbp)
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
addl $0x1, %eax
cmpl -0x64(%rbp), %eax
jae 0x3b71
movq -0x50(%rbp), %rax
movl -0x5c(%rbp), %ecx
movl %ecx, %edx
addl $0x1, %edx
movl %edx, -0x5c(%rbp)
movl %ecx, %ecx
shlq $0x5, %rcx
addq %rcx, %rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rdi
movq -0x58(%rbp), %rsi
movl -0x28(%rbp), %eax
shlq $0x5, %rax
addq %rax, %rsi
callq 0x3fa0
movq -0x78(%rbp), %rdi
movq -0x58(%rbp), %rsi
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, %eax
shlq $0x5, %rax
addq %rax, %rsi
callq 0x3fe0
movl -0x28(%rbp), %eax
addl $0x2, %eax
movl %eax, -0x28(%rbp)
jmp 0x3b0c
movl -0x2c(%rbp), %eax
cmpl -0x24(%rbp), %eax
jae 0x3baa
movq -0x50(%rbp), %rdi
movl -0x5c(%rbp), %eax
shlq $0x5, %rax
addq %rax, %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rax
movl %eax, %edx
movq -0x38(%rbp), %rcx
callq 0x3ce0
movl %eax, -0x44(%rbp)
movq -0x40(%rbp), %rcx
movl -0x5c(%rbp), %eax
addq %rcx, %rax
movl %eax, -0x5c(%rbp)
movq -0x50(%rbp), %rdi
movl -0x5c(%rbp), %eax
movl %eax, %esi
callq 0x3dd0
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x3a8a
jmp 0x3bc8
cmpl $0x0, -0x44(%rbp)
jne 0x3c3f
movl $0x0, -0x28(%rbp)
movl -0x28(%rbp), %eax
movq -0x40(%rbp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
jae 0x3c3d
movq -0x50(%rbp), %rax
movl -0x28(%rbp), %ecx
shlq $0x5, %rcx
addq %rcx, %rax
movq %rax, -0x80(%rbp)
movl $0x0, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
movq -0x80(%rbp), %rcx
cmpq 0x8(%rcx), %rax
jae 0x3c30
movq -0x10(%rbp), %rax
movq -0x80(%rbp), %rcx
movq (%rcx), %rcx
movl -0x2c(%rbp), %edx
movl (%rcx,%rdx,4), %ecx
movl (%rax,%rcx,4), %edx
addl $0x1, %edx
movl %edx, (%rax,%rcx,4)
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x3bfe
jmp 0x3c32
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x3bd5
jmp 0x3c3f
movq -0x50(%rbp), %rdi
movl -0x60(%rbp), %eax
movl %eax, %esi
callq 0x3f50
movq -0x50(%rbp), %rdi
callq 0x4050
movq -0x58(%rbp), %rdi
movl -0x60(%rbp), %eax
movl %eax, %esi
callq 0x3f50
movq -0x58(%rbp), %rdi
callq 0x4050
jmp 0x3c6f
movl -0x44(%rbp), %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x90, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)