// File: /workspace/github_cpp_makefile_star2_O2/phillip-h[P]fractal-gen/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 error = 0;
  unsigned i;
  size_t numpresent = 0; /*number of symbols with non-zero frequency*/
  BPMNode* leaves; /*the symbols, only those with > 0 frequency*/

  if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/
  if((1u << maxbitlen) < numcodes) return 80; /*error: represent all symbols*/

  leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves));
  if(!leaves) return 83; /*alloc fail*/

  for(i = 0; i != numcodes; ++i)
  {
    if(frequencies[i] > 0)
    {
      leaves[numpresent].weight = (int)frequencies[i];
      leaves[numpresent].index = i;
      ++numpresent;
    }
  }

  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. Some 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)
  {
    lengths[leaves[0].index] = 1;
    lengths[leaves[0].index == 0 ? 1 : 0] = 1;
  }
  else
  {
    BPMLists lists;
    BPMNode* node;

    bpmnode_sort(leaves, numpresent);

    lists.listsize = maxbitlen;
    lists.memsize = 2 * maxbitlen * (maxbitlen + 1);
    lists.nextfree = 0;
    lists.numfree = lists.memsize;
    lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory));
    lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*));
    lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*));
    lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*));
    if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/

    if(!error)
    {
      for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i];

      bpmnode_create(&lists, leaves[0].weight, 1, 0);
      bpmnode_create(&lists, leaves[1].weight, 2, 0);

      for(i = 0; i != lists.listsize; ++i)
      {
        lists.chains0[i] = &lists.memory[0];
        lists.chains1[i] = &lists.memory[1];
      }

      /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/
      for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i);

      for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail)
      {
        for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index];
      }
    }

    lodepng_free(lists.memory);
    lodepng_free(lists.freelist);
    lodepng_free(lists.chains0);
    lodepng_free(lists.chains1);
  }

  lodepng_free(leaves);
  return error;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
pushq $0x1
popq %r15
shlxl %ecx, %r15d, %eax
leaq -0x1(%rdx), %r8
movq %rcx, (%rsp)
movl %eax, %eax
cmpq %rax, %r8
jae 0x3d83
movq %rdi, 0x10(%rsp)
imulq $0x18, %rdx, %rdi
movq %rdx, %r13
movq %rsi, %rbx
callq 0x21c0
testq %rax, %rax
je 0x3db7
movq 0x10(%rsp), %rsi
movq %rax, %rdi
xorl %eax, %eax
xorl %r12d, %r12d
movl %eax, %ecx
cmpq %r13, %rcx
je 0x3d87
movl (%rbx,%rcx,4), %ecx
testl %ecx, %ecx
je 0x3d7f
imulq $0x18, %r12, %rdx
incq %r12
movl %ecx, (%rdi,%rdx)
movl %eax, 0x4(%rdi,%rdx)
incl %eax
jmp 0x3d63
pushq $0x50
jmp 0x3db9
xorl %eax, %eax
movl %eax, %eax
cmpq %r13, %rax
je 0x3d98
andl $0x0, (%rsi,%rax,4)
incl %eax
jmp 0x3d89
cmpq $0x1, %r12
je 0x3dbf
testq %r12, %r12
jne 0x3dd9
movabsq $0x100000001, %rax      # imm = 0x100000001
xorl %ebp, %ebp
movq %rax, (%rsi)
jmp 0x408b
pushq $0x53
popq %rbp
jmp 0x4090
movl 0x4(%rdi), %eax
xorl %ecx, %ecx
testq %rax, %rax
movl %r15d, (%rsi,%rax,4)
sete %cl
xorl %ebp, %ebp
movl %r15d, (%rsi,%rcx,4)
jmp 0x408b
movq %rdi, 0x8(%rsp)
imulq $0x18, %r12, %rdi
movq %rdi, 0x20(%rsp)
callq 0x21c0
movq %rax, 0x18(%rsp)
pushq $0x1
popq %rcx
xorl %eax, %eax
cmpq %r12, %rcx
jae 0x3eb4
movq %rax, 0x28(%rsp)
testb $0x1, %al
movq 0x18(%rsp), %rax
movq 0x8(%rsp), %rbx
leaq (%rcx,%rcx), %rdx
movq %rax, %rsi
cmoveq %rbx, %rsi
cmoveq %rax, %rbx
imulq $0x30, %rcx, %r8
xorl %r10d, %r10d
cmpq %r12, %r10
jae 0x3ea4
leaq (%r10,%rcx), %r14
leaq (%r10,%rdx), %r13
movq %r12, %r15
movq %rbx, %rdi
movq %r10, %r9
cmpq %r12, %r14
cmovaeq %r12, %r14
cmpq %r12, %r13
cmovbq %r13, %r15
movq %r14, %rax
cmpq %r15, %r9
jae 0x3e9c
cmpq %r14, %r10
jae 0x3e6e
cmpq %r15, %rax
jae 0x3e76
imulq $0x18, %r10, %r11
imulq $0x18, %rax, %rbp
movl (%rsi,%r11), %r11d
cmpl (%rsi,%rbp), %r11d
jle 0x3e76
movq %rax, %r11
incq %rax
jmp 0x3e7c
movq %r10, %r11
incq %r10
imulq $0x18, %r11, %r11
incq %r9
movq 0x10(%rsi,%r11), %rbp
movq %rbp, 0x10(%rdi)
vmovups (%rsi,%r11), %xmm0
vmovups %xmm0, (%rdi)
addq $0x18, %rdi
jmp 0x3e4d
addq %r8, %rbx
movq %r13, %r10
jmp 0x3e26
movq 0x28(%rsp), %rax
movq %rdx, %rcx
incq %rax
jmp 0x3df6
testb $0x1, %al
je 0x3ecc
movq 0x8(%rsp), %rdi
movq 0x18(%rsp), %rsi
movq 0x20(%rsp), %rdx
callq 0x20d0
movq 0x18(%rsp), %rdi
callq 0x2180
movq (%rsp), %r14
leal 0x1(%r14), %r15d
movl %r14d, 0x50(%rsp)
imull %r14d, %r15d
addl %r15d, %r15d
movl %r15d, 0x30(%rsp)
andl $0x0, 0x44(%rsp)
imulq $0x18, %r15, %rdi
movl %r15d, 0x40(%rsp)
callq 0x21c0
leaq (,%r15,8), %rdi
movq %rax, %r13
movq %rax, 0x38(%rsp)
callq 0x21c0
movl %r14d, %r14d
shlq $0x3, %r14
movq %rax, %rbx
movq %rax, 0x48(%rsp)
movq %r14, %rdi
callq 0x21c0
movq %r14, %rdi
movq %rax, %rbp
movq %rax, 0x58(%rsp)
callq 0x21c0
testq %r13, %r13
movq %rax, %r14
movq %rax, 0x60(%rsp)
movq %rbp, %rsi
setne %al
testq %rbx, %rbx
setne %cl
testq %rbp, %rbp
setne %dl
andb %cl, %dl
andb %al, %dl
testq %r14, %r14
setne %al
xorl %ecx, %ecx
pushq $0x53
popq %rbp
testb %al, %dl
cmovnel %ecx, %ebp
je 0x3f8a
movq 0x8(%rsp), %rcx
xorl %eax, %eax
cmpq %rax, %r15
je 0x3f92
movq %r13, (%rbx,%rax,8)
incq %rax
addq $0x18, %r13
jmp 0x3f78
movq %rsi, %r15
jmp 0x4066
movl (%rcx), %esi
movq %rcx, %rbx
xorl %r13d, %r13d
leaq 0x30(%rsp), %r15
pushq $0x1
popq %rdx
movq %r15, %rdi
xorl %ecx, %ecx
callq 0x40a1
movl 0x18(%rbx), %esi
pushq $0x2
popq %rbx
movq %r15, %rdi
movl %ebx, %edx
xorl %ecx, %ecx
callq 0x40a1
movq 0x8(%r15), %rcx
movl 0x20(%r15), %eax
movq 0x28(%r15), %rdx
movq 0x30(%r15), %rdi
movq 0x10(%rsp), %r8
leaq 0x18(%rcx), %rsi
cmpq %r13, %rax
je 0x3fe9
movq %rcx, (%rdx,%r13,8)
movq %rsi, (%rdi,%r13,8)
incq %r13
jmp 0x3fd7
movq (%rsp), %rax
leaq -0x2(%r12,%r12), %r15
leaq 0x30(%rsp), %r13
decl %eax
movq %rax, (%rsp)
movq 0x8(%rsp), %rsi
movl %ebx, %eax
cmpq %rax, %r15
je 0x4024
movq (%rsp), %rcx
movq %r13, %rdi
movq %r12, %rdx
movl %ebx, %r8d
callq 0x4179
movq 0x10(%rsp), %r8
incl %ebx
jmp 0x3ffd
movq 0x60(%rsp), %r14
movl (%rsp), %eax
leaq (%r14,%rax,8), %rax
movq (%rax), %rax
testq %rax, %rax
je 0x4057
xorl %ecx, %ecx
cmpl 0x4(%rax), %ecx
je 0x4051
movl %ecx, %edx
imulq $0x18, %rdx, %rdx
incl %ecx
movl 0x4(%rsi,%rdx), %edx
incl (%r8,%rdx,4)
jmp 0x403a
addq $0x8, %rax
jmp 0x4030
movq 0x38(%rsp), %r13
movq 0x48(%rsp), %rbx
movq 0x58(%rsp), %r15
movq %r13, %rdi
callq 0x2180
movq %rbx, %rdi
callq 0x2180
movq %r15, %rdi
callq 0x2180
movq %r14, %rdi
callq 0x2180
movq 0x8(%rsp), %rdi
callq 0x2180
movl %ebp, %eax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq