// File: karel-brinda[P]ococo/ext/htslib/cram/cram_codecs.c
// Function: cram_huffman_encode_init
cram_codec *cram_huffman_encode_init(cram_stats *st,
				     enum cram_external_type option,
				     void *dat,
				     int version) {
    int *vals = NULL, *freqs = NULL, vals_alloc = 0, *lens, code, len;
    int nvals, i, ntot = 0, max_val = 0, min_val = INT_MAX, k;
    cram_codec *c;
    cram_huffman_code *codes;

    c = malloc(sizeof(*c));
    if (!c)
	return NULL;
    c->codec = E_HUFFMAN;

    /* Count number of unique symbols */
    for (nvals = i = 0; i < MAX_STAT_VAL; i++) {
	if (!st->freqs[i])
	    continue;
	if (nvals >= vals_alloc) {
	    vals_alloc = vals_alloc ? vals_alloc*2 : 1024;
	    vals  = realloc(vals,  vals_alloc * sizeof(int));
	    freqs = realloc(freqs, vals_alloc * sizeof(int));
	    if (!vals || !freqs) {
		if (vals)  free(vals);
		if (freqs) free(freqs);
		free(c);
		return NULL;
	    }
	}
	vals[nvals] = i;
	freqs[nvals] = st->freqs[i];
	assert(st->freqs[i] > 0);
	ntot += freqs[nvals];
	if (max_val < i) max_val = i;
	if (min_val > i) min_val = i;
	nvals++;
    }
    if (st->h) {
	khint_t k;

	for (k = kh_begin(st->h); k != kh_end(st->h); k++) {
	    if (!kh_exist(st->h, k))
		continue;
	    if (nvals >= vals_alloc) {
		vals_alloc = vals_alloc ? vals_alloc*2 : 1024;
		vals  = realloc(vals,  vals_alloc * sizeof(int));
		freqs = realloc(freqs, vals_alloc * sizeof(int));
		if (!vals || !freqs)
		    return NULL;
	    }
	    vals[nvals]= kh_key(st->h, k);
	    freqs[nvals] = kh_val(st->h, k);
	    assert(freqs[nvals] > 0);
	    ntot += freqs[nvals];
	    if (max_val < i) max_val = i;
	    if (min_val > i) min_val = i;
	    nvals++;
	}
    }

    assert(nvals > 0);

    freqs = realloc(freqs, 2*nvals*sizeof(*freqs));
    lens = calloc(2*nvals, sizeof(*lens));
    if (!lens || !freqs)
	return NULL;

    /* Inefficient, use pointers to form chain so we can insert and maintain
     * a sorted list? This is currently O(nvals^2) complexity.
     */
    for (;;) {
	int low1 = INT_MAX, low2 = INT_MAX;
	int ind1 = 0, ind2 = 0;
	for (i = 0; i < nvals; i++) {
	    if (freqs[i] < 0)
		continue;
	    if (low1 > freqs[i]) 
		low2 = low1, ind2 = ind1, low1 = freqs[i], ind1 = i;
	    else if (low2 > freqs[i])
		low2 = freqs[i], ind2 = i;
	}
	if (low2 == INT_MAX)
	    break;

	freqs[nvals] = low1 + low2;
	lens[ind1] = nvals;
	lens[ind2] = nvals;
	freqs[ind1] *= -1;
	freqs[ind2] *= -1;
	nvals++;
    }
    nvals = nvals/2+1;

    /* Assign lengths */
    for (i = 0; i < nvals; i++) {
	int code_len = 0;
	for (k = lens[i]; k; k = lens[k])
	    code_len++;
	lens[i] = code_len;
	freqs[i] *= -1;
	//fprintf(stderr, "%d / %d => %d\n", vals[i], freqs[i], lens[i]);
    }


    /* Sort, need in a struct */
    if (!(codes = malloc(nvals * sizeof(*codes))))
	return NULL;
    for (i = 0; i < nvals; i++) {
	codes[i].symbol = vals[i];
	codes[i].len = lens[i];
    }
    qsort(codes, nvals, sizeof(*codes), code_sort);

    /*
     * Generate canonical codes from lengths.
     * Sort by length.
     * Start with 0.
     * Every new code of same length is +1.
     * Every new code of new length is +1 then <<1 per extra length.
     *
     * /\
     * a/\
     * /\/\
     * bcd/\
     *    ef
     * 
     * a 1  0
     * b 3  4 (0+1)<<2
     * c 3  5
     * d 3  6
     * e 4  14  (6+1)<<1
     * f 5  15     
     */
    code = 0; len = codes[0].len;
    for (i = 0; i < nvals; i++) {
	while (len != codes[i].len) {
	    code<<=1;
	    len++;
	}
	codes[i].code = code++;

	if (codes[i].symbol >= -1 && codes[i].symbol < MAX_HUFF)
	    c->e_huffman.val2code[codes[i].symbol+1] = i;

	//fprintf(stderr, "sym %d, code %d, len %d\n",
	//	codes[i].symbol, codes[i].code, codes[i].len);
    }

    free(lens);
    free(vals);
    free(freqs);

    c->e_huffman.codes = codes;
    c->e_huffman.nvals = nvals;

    c->free = cram_huffman_encode_free;
    if (option == E_BYTE || option == E_BYTE_ARRAY) {
	if (c->e_huffman.codes[0].len == 0)
	    c->encode = cram_huffman_encode_char0;
	else
	    c->encode = cram_huffman_encode_char;
    } else {
	if (c->e_huffman.codes[0].len == 0)
	    c->encode = cram_huffman_encode_int0;
	else
	    c->encode = cram_huffman_encode_int;
    }
    c->store = cram_huffman_encode_store;

    return c;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movq %rdx, -0x20(%rbp)
movl %ecx, -0x24(%rbp)
movq $0x0, -0x30(%rbp)
movq $0x0, -0x38(%rbp)
movl $0x0, -0x3c(%rbp)
movl $0x0, -0x5c(%rbp)
movl $0x0, -0x60(%rbp)
movl $0x7fffffff, -0x64(%rbp) # imm = 0x7FFFFFFF
movl $0x240, %edi            # imm = 0x240
callq 0x47a0
movq %rax, -0x70(%rbp)
cmpq $0x0, -0x70(%rbp)
jne 0x724d7
movq $0x0, -0x8(%rbp)
jmp 0x72c2b
movq -0x70(%rbp), %rax
movl $0x3, (%rax)
movl $0x0, -0x58(%rbp)
movl $0x0, -0x54(%rbp)
cmpl $0x400, -0x58(%rbp)     # imm = 0x400
jge 0x7264b
movq -0x10(%rbp), %rax
movslq -0x58(%rbp), %rcx
cmpl $0x0, (%rax,%rcx,4)
jne 0x7250f
jmp 0x7263d
movl -0x54(%rbp), %eax
cmpl -0x3c(%rbp), %eax
jl 0x725b4
cmpl $0x0, -0x3c(%rbp)
je 0x7252e
movl -0x3c(%rbp), %eax
shll %eax
movl %eax, -0x94(%rbp)
jmp 0x7253b
movl $0x400, %eax            # imm = 0x400
movl %eax, -0x94(%rbp)
jmp 0x7253b
movl -0x94(%rbp), %eax
movl %eax, -0x3c(%rbp)
movq -0x30(%rbp), %rdi
movslq -0x3c(%rbp), %rsi
shlq $0x2, %rsi
callq 0x4990
movq %rax, -0x30(%rbp)
movq -0x38(%rbp), %rdi
movslq -0x3c(%rbp), %rsi
shlq $0x2, %rsi
callq 0x4990
movq %rax, -0x38(%rbp)
cmpq $0x0, -0x30(%rbp)
je 0x7257c
cmpq $0x0, -0x38(%rbp)
jne 0x725b2
cmpq $0x0, -0x30(%rbp)
je 0x7258c
movq -0x30(%rbp), %rdi
callq 0x46a0
cmpq $0x0, -0x38(%rbp)
je 0x7259c
movq -0x38(%rbp), %rdi
callq 0x46a0
movq -0x70(%rbp), %rdi
callq 0x46a0
movq $0x0, -0x8(%rbp)
jmp 0x72c2b
jmp 0x725b4
movl -0x58(%rbp), %edx
movq -0x30(%rbp), %rax
movslq -0x54(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movq -0x10(%rbp), %rax
movslq -0x58(%rbp), %rcx
movl (%rax,%rcx,4), %edx
movq -0x38(%rbp), %rax
movslq -0x54(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movq -0x10(%rbp), %rax
movslq -0x58(%rbp), %rcx
cmpl $0x0, (%rax,%rcx,4)
jle 0x725e8
jmp 0x72607
leaq 0xc614(%rip), %rdi      # 0x7ec03
leaq 0xc495(%rip), %rsi      # 0x7ea8b
movl $0x4bd, %edx            # imm = 0x4BD
leaq 0xc612(%rip), %rcx      # 0x7ec14
callq 0x4360
movq -0x38(%rbp), %rax
movslq -0x54(%rbp), %rcx
movl (%rax,%rcx,4), %eax
addl -0x5c(%rbp), %eax
movl %eax, -0x5c(%rbp)
movl -0x60(%rbp), %eax
cmpl -0x58(%rbp), %eax
jge 0x72626
movl -0x58(%rbp), %eax
movl %eax, -0x60(%rbp)
movl -0x64(%rbp), %eax
cmpl -0x58(%rbp), %eax
jle 0x72634
movl -0x58(%rbp), %eax
movl %eax, -0x64(%rbp)
movl -0x54(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x54(%rbp)
movl -0x58(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x58(%rbp)
jmp 0x724ef
movq -0x10(%rbp), %rax
cmpq $0x0, 0x1000(%rax)
je 0x727d8
movl $0x0, -0x7c(%rbp)
movl -0x7c(%rbp), %eax
movq -0x10(%rbp), %rcx
movq 0x1000(%rcx), %rcx
cmpl (%rcx), %eax
je 0x727d6
movq -0x10(%rbp), %rax
movq 0x1000(%rax), %rax
movq 0x10(%rax), %rax
movl -0x7c(%rbp), %ecx
shrl $0x4, %ecx
movl %ecx, %ecx
movl (%rax,%rcx,4), %eax
movl -0x7c(%rbp), %ecx
andl $0xf, %ecx
shll %ecx
shrl %cl, %eax
andl $0x3, %eax
cmpl $0x0, %eax
je 0x726ab
jmp 0x727c8
movl -0x54(%rbp), %eax
cmpl -0x3c(%rbp), %eax
jl 0x72723
cmpl $0x0, -0x3c(%rbp)
je 0x726c6
movl -0x3c(%rbp), %eax
shll %eax
movl %eax, -0x98(%rbp)
jmp 0x726d3
movl $0x400, %eax            # imm = 0x400
movl %eax, -0x98(%rbp)
jmp 0x726d3
movl -0x98(%rbp), %eax
movl %eax, -0x3c(%rbp)
movq -0x30(%rbp), %rdi
movslq -0x3c(%rbp), %rsi
shlq $0x2, %rsi
callq 0x4990
movq %rax, -0x30(%rbp)
movq -0x38(%rbp), %rdi
movslq -0x3c(%rbp), %rsi
shlq $0x2, %rsi
callq 0x4990
movq %rax, -0x38(%rbp)
cmpq $0x0, -0x30(%rbp)
je 0x72714
cmpq $0x0, -0x38(%rbp)
jne 0x72721
movq $0x0, -0x8(%rbp)
jmp 0x72c2b
jmp 0x72723
movq -0x10(%rbp), %rax
movq 0x1000(%rax), %rax
movq 0x18(%rax), %rax
movl -0x7c(%rbp), %ecx
movl (%rax,%rcx,4), %edx
movq -0x30(%rbp), %rax
movslq -0x54(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movq -0x10(%rbp), %rax
movq 0x1000(%rax), %rax
movq 0x20(%rax), %rax
movl -0x7c(%rbp), %ecx
movl (%rax,%rcx,4), %edx
movq -0x38(%rbp), %rax
movslq -0x54(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movq -0x38(%rbp), %rax
movslq -0x54(%rbp), %rcx
cmpl $0x0, (%rax,%rcx,4)
jle 0x72773
jmp 0x72792
leaq 0xc4f3(%rip), %rdi      # 0x7ec6d
leaq 0xc30a(%rip), %rsi      # 0x7ea8b
movl $0x4d2, %edx            # imm = 0x4D2
leaq 0xc487(%rip), %rcx      # 0x7ec14
callq 0x4360
movq -0x38(%rbp), %rax
movslq -0x54(%rbp), %rcx
movl (%rax,%rcx,4), %eax
addl -0x5c(%rbp), %eax
movl %eax, -0x5c(%rbp)
movl -0x60(%rbp), %eax
cmpl -0x58(%rbp), %eax
jge 0x727b1
movl -0x58(%rbp), %eax
movl %eax, -0x60(%rbp)
movl -0x64(%rbp), %eax
cmpl -0x58(%rbp), %eax
jle 0x727bf
movl -0x58(%rbp), %eax
movl %eax, -0x64(%rbp)
movl -0x54(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x54(%rbp)
movl -0x7c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x7c(%rbp)
jmp 0x72664
jmp 0x727d8
cmpl $0x0, -0x54(%rbp)
jle 0x727e0
jmp 0x727ff
leaq 0xc497(%rip), %rdi      # 0x7ec7e
leaq 0xc29d(%rip), %rsi      # 0x7ea8b
movl $0x4da, %edx            # imm = 0x4DA
leaq 0xc41a(%rip), %rcx      # 0x7ec14
callq 0x4360
movq -0x38(%rbp), %rdi
movl -0x54(%rbp), %eax
shll %eax
movslq %eax, %rsi
shlq $0x2, %rsi
callq 0x4990
movq %rax, -0x38(%rbp)
movl -0x54(%rbp), %eax
shll %eax
movslq %eax, %rdi
movl $0x4, %esi
callq 0x4370
movq %rax, -0x48(%rbp)
cmpq $0x0, -0x48(%rbp)
je 0x7283c
cmpq $0x0, -0x38(%rbp)
jne 0x72849
movq $0x0, -0x8(%rbp)
jmp 0x72c2b
jmp 0x7284b
movl $0x7fffffff, -0x80(%rbp) # imm = 0x7FFFFFFF
movl $0x7fffffff, -0x84(%rbp) # imm = 0x7FFFFFFF
movl $0x0, -0x88(%rbp)
movl $0x0, -0x8c(%rbp)
movl $0x0, -0x58(%rbp)
movl -0x58(%rbp), %eax
cmpl -0x54(%rbp), %eax
jge 0x72910
movq -0x38(%rbp), %rax
movslq -0x58(%rbp), %rcx
cmpl $0x0, (%rax,%rcx,4)
jge 0x72893
jmp 0x72902
movl -0x80(%rbp), %eax
movq -0x38(%rbp), %rcx
movslq -0x58(%rbp), %rdx
cmpl (%rcx,%rdx,4), %eax
jle 0x728d1
movl -0x80(%rbp), %eax
movl %eax, -0x84(%rbp)
movl -0x88(%rbp), %eax
movl %eax, -0x8c(%rbp)
movq -0x38(%rbp), %rax
movslq -0x58(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x80(%rbp)
movl -0x58(%rbp), %eax
movl %eax, -0x88(%rbp)
jmp 0x72900
movl -0x84(%rbp), %eax
movq -0x38(%rbp), %rcx
movslq -0x58(%rbp), %rdx
cmpl (%rcx,%rdx,4), %eax
jle 0x728fe
movq -0x38(%rbp), %rax
movslq -0x58(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x84(%rbp)
movl -0x58(%rbp), %eax
movl %eax, -0x8c(%rbp)
jmp 0x72900
jmp 0x72902
movl -0x58(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x58(%rbp)
jmp 0x72877
cmpl $0x7fffffff, -0x84(%rbp) # imm = 0x7FFFFFFF
jne 0x7291e
jmp 0x72986
movl -0x80(%rbp), %edx
addl -0x84(%rbp), %edx
movq -0x38(%rbp), %rax
movslq -0x54(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movl -0x54(%rbp), %edx
movq -0x48(%rbp), %rax
movslq -0x88(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movl -0x54(%rbp), %edx
movq -0x48(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movq -0x38(%rbp), %rax
movslq -0x88(%rbp), %rcx
imull $-0x1, (%rax,%rcx,4), %edx
movl %edx, (%rax,%rcx,4)
movq -0x38(%rbp), %rax
movslq -0x8c(%rbp), %rcx
imull $-0x1, (%rax,%rcx,4), %edx
movl %edx, (%rax,%rcx,4)
movl -0x54(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x54(%rbp)
jmp 0x7284b
movl -0x54(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
addl $0x1, %eax
movl %eax, -0x54(%rbp)
movl $0x0, -0x58(%rbp)
movl -0x58(%rbp), %eax
cmpl -0x54(%rbp), %eax
jge 0x72a0e
movl $0x0, -0x90(%rbp)
movq -0x48(%rbp), %rax
movslq -0x58(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x68(%rbp)
cmpl $0x0, -0x68(%rbp)
je 0x729e3
movl -0x90(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x90(%rbp)
movq -0x48(%rbp), %rax
movslq -0x68(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, -0x68(%rbp)
jmp 0x729be
movl -0x90(%rbp), %edx
movq -0x48(%rbp), %rax
movslq -0x58(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movq -0x38(%rbp), %rax
movslq -0x58(%rbp), %rcx
imull $-0x1, (%rax,%rcx,4), %edx
movl %edx, (%rax,%rcx,4)
movl -0x58(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x58(%rbp)
jmp 0x7299e
movslq -0x54(%rbp), %rdi
shlq $0x4, %rdi
callq 0x47a0
movq %rax, -0x78(%rbp)
cmpq $0x0, %rax
jne 0x72a32
movq $0x0, -0x8(%rbp)
jmp 0x72c2b
movl $0x0, -0x58(%rbp)
movl -0x58(%rbp), %eax
cmpl -0x54(%rbp), %eax
jge 0x72a85
movq -0x30(%rbp), %rax
movslq -0x58(%rbp), %rcx
movl (%rax,%rcx,4), %ecx
movq -0x78(%rbp), %rax
movslq -0x58(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rax
movl %ecx, (%rax)
movq -0x48(%rbp), %rax
movslq -0x58(%rbp), %rcx
movl (%rax,%rcx,4), %ecx
movq -0x78(%rbp), %rax
movslq -0x58(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rax
movl %ecx, 0xc(%rax)
movl -0x58(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x58(%rbp)
jmp 0x72a39
movq -0x78(%rbp), %rdi
movslq -0x54(%rbp), %rsi
movl $0x10, %edx
leaq -0x1739(%rip), %rcx     # 0x71360
callq 0x4b00
movl $0x0, -0x4c(%rbp)
movq -0x78(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, -0x50(%rbp)
movl $0x0, -0x58(%rbp)
movl -0x58(%rbp), %eax
cmpl -0x54(%rbp), %eax
jge 0x72b68
jmp 0x72ac4
movl -0x50(%rbp), %eax
movq -0x78(%rbp), %rcx
movslq -0x58(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rcx
cmpl 0xc(%rcx), %eax
je 0x72aee
movl -0x4c(%rbp), %eax
shll %eax
movl %eax, -0x4c(%rbp)
movl -0x50(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x50(%rbp)
jmp 0x72ac4
movl -0x4c(%rbp), %ecx
movl %ecx, %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
movq -0x78(%rbp), %rax
movslq -0x58(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rax
movl %ecx, 0x8(%rax)
movq -0x78(%rbp), %rax
movslq -0x58(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
cmpl $-0x1, (%rax)
jl 0x72b58
movq -0x78(%rbp), %rax
movslq -0x58(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
cmpl $0x80, (%rax)
jge 0x72b58
movl -0x58(%rbp), %edx
movq -0x70(%rbp), %rax
movq -0x78(%rbp), %rcx
movslq -0x58(%rbp), %rsi
shlq $0x4, %rsi
addq %rsi, %rcx
movl (%rcx), %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
movl %edx, 0x3c(%rax,%rcx,4)
jmp 0x72b5a
movl -0x58(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x58(%rbp)
jmp 0x72ab6
movq -0x48(%rbp), %rdi
callq 0x46a0
movq -0x30(%rbp), %rdi
callq 0x46a0
movq -0x38(%rbp), %rdi
callq 0x46a0
movq -0x78(%rbp), %rcx
movq -0x70(%rbp), %rax
movq %rcx, 0x30(%rax)
movl -0x54(%rbp), %ecx
movq -0x70(%rbp), %rax
movl %ecx, 0x38(%rax)
movq -0x70(%rbp), %rax
leaq -0x1464(%rip), %rcx     # 0x71740
movq %rcx, 0x10(%rax)
cmpl $0x3, -0x14(%rbp)
je 0x72bb4
cmpl $0x4, -0x14(%rbp)
jne 0x72be4
movq -0x70(%rbp), %rax
movq 0x30(%rax), %rax
cmpl $0x0, 0xc(%rax)
jne 0x72bd3
movq -0x70(%rbp), %rax
leaq -0x180d(%rip), %rcx     # 0x713c0
movq %rcx, 0x20(%rax)
jmp 0x72be2
movq -0x70(%rbp), %rax
leaq -0x17fe(%rip), %rcx     # 0x713e0
movq %rcx, 0x20(%rax)
jmp 0x72c14
movq -0x70(%rbp), %rax
movq 0x30(%rax), %rax
cmpl $0x0, 0xc(%rax)
jne 0x72c03
movq -0x70(%rbp), %rax
leaq -0x167d(%rip), %rcx     # 0x71580
movq %rcx, 0x20(%rax)
jmp 0x72c12
movq -0x70(%rbp), %rax
leaq -0x166e(%rip), %rcx     # 0x715a0
movq %rcx, 0x20(%rax)
jmp 0x72c14
movq -0x70(%rbp), %rax
leaq -0x149f(%rip), %rcx     # 0x71780
movq %rcx, 0x28(%rax)
movq -0x70(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0xa0, %rsp
popq %rbp
retq
nopl (%rax,%rax)