// File: cloudinary[P]fuif/encoding/../maniac/symbol_enc.h
// Function: int estimate_writer<15, FinalCompoundSymbolBitCoder<SimpleBitChance, RacOutput24<BlobIO>, 15>>(FinalCompoundSymbolBitCoder<SimpleBitChance, RacOutput24<BlobIO>, 15>&, int, int, int)
int estimate_writer(SymbolCoder& coder, int min, int max, int value) {
    assert(min<=max);
    assert(value>=min);
    assert(value<=max);

    uint64_t total=0;

    // avoid doing anything if the value is already known
    if (min == max) return total;

    if (value == 0) { // value is zero
        coder.estimate(true, BIT_ZERO,0,total);
        return total;
    }

    assert(min <= 0 && max >= 0); // should always be the case, because guess should always be in valid range

    coder.estimate(false,BIT_ZERO,0,total);
    int sign = (value > 0 ? 1 : 0);
    if (max > 0 && min < 0) {
        // only output sign bit if value can be both pos and neg
        coder.estimate(sign,BIT_SIGN,0,total);
    }
    if (sign) min = 1;
    if (!sign) max = -1;
    const int a = abs(value);
    const int e = maniac::util::ilog2(a);
    int amin = sign ? abs(min) : abs(max);
    int amax = sign ? abs(max) : abs(min);

    int emax = maniac::util::ilog2(amax);
    int i = maniac::util::ilog2(amin);

    while (i < emax) {
        // if exponent >i is impossible, we are done
        if ((1 << (i+1)) > amax) break;
        // if exponent i is possible, output the exponent bit
        coder.estimate(i==e, BIT_EXP, i,total);
        if (i==e) break;
        i++;
    }

    int have = (1 << e);
    int left = have-1;
    for (int pos = e; pos>0;) {
        int bit = 1;
        left ^= (1 << (--pos));
        int minabs1 = have | (1<<pos);
        if (minabs1 > amax) { // 1-bit is impossible
            bit = 0;
        } else {
            bit = (a >> pos) & 1;
            coder.estimate(bit, BIT_MANT, pos,total);
        }
        have |= (bit << pos);
    }
//    printf("Total to write %i in %i..%i: %lu\n",value,min,max,total);
    return total;
}

// Assembly:
subq $0x68, %rsp
movq %rdi, 0x58(%rsp)
movl %esi, 0x54(%rsp)
movl %edx, 0x50(%rsp)
movl %ecx, 0x4c(%rsp)
movq $0x0, 0x40(%rsp)
movl 0x54(%rsp), %eax
cmpl 0x50(%rsp), %eax
jne 0x35646
movq 0x40(%rsp), %rax
movl %eax, 0x64(%rsp)
jmp 0x358b4
cmpl $0x0, 0x4c(%rsp)
jne 0x35673
movq 0x58(%rsp), %rdi
movl $0x1, %esi
xorl %ecx, %ecx
leaq 0x40(%rsp), %r8
movl %ecx, %edx
callq 0x358c0
movq 0x40(%rsp), %rax
movl %eax, 0x64(%rsp)
jmp 0x358b4
movq 0x58(%rsp), %rdi
xorl %ecx, %ecx
leaq 0x40(%rsp), %r8
movl %ecx, %esi
movl %ecx, %edx
callq 0x358c0
movl 0x4c(%rsp), %edx
xorl %eax, %eax
movl $0x1, %ecx
cmpl $0x0, %edx
cmovgl %ecx, %eax
movl %eax, 0x3c(%rsp)
cmpl $0x0, 0x50(%rsp)
jle 0x356cf
cmpl $0x0, 0x54(%rsp)
jge 0x356cf
movq 0x58(%rsp), %rdi
cmpl $0x0, 0x3c(%rsp)
setne %al
movzbl %al, %esi
andl $0x1, %esi
movl $0x1, %edx
xorl %ecx, %ecx
leaq 0x40(%rsp), %r8
callq 0x358c0
cmpl $0x0, 0x3c(%rsp)
je 0x356de
movl $0x1, 0x54(%rsp)
cmpl $0x0, 0x3c(%rsp)
jne 0x356ed
movl $0xffffffff, 0x50(%rsp) # imm = 0xFFFFFFFF
movl 0x4c(%rsp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
movl %eax, 0x38(%rsp)
movl 0x38(%rsp), %edi
callq 0x1ebd0
movl %eax, 0x34(%rsp)
cmpl $0x0, 0x3c(%rsp)
je 0x35721
movl 0x54(%rsp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
movl %eax, 0xc(%rsp)
jmp 0x35730
movl 0x50(%rsp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
movl %eax, 0xc(%rsp)
movl 0xc(%rsp), %eax
movl %eax, 0x30(%rsp)
cmpl $0x0, 0x3c(%rsp)
je 0x35750
movl 0x50(%rsp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
movl %eax, 0x8(%rsp)
jmp 0x3575f
movl 0x54(%rsp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
movl %eax, 0x8(%rsp)
movl 0x8(%rsp), %eax
movl %eax, 0x2c(%rsp)
movl 0x2c(%rsp), %edi
callq 0x1ebd0
movl %eax, 0x28(%rsp)
movl 0x30(%rsp), %edi
callq 0x1ebd0
movl %eax, 0x24(%rsp)
movl 0x24(%rsp), %eax
cmpl 0x28(%rsp), %eax
jge 0x357e3
movl 0x24(%rsp), %ecx
addl $0x1, %ecx
movl $0x1, %eax
shll %cl, %eax
cmpl 0x2c(%rsp), %eax
jle 0x357a1
jmp 0x357e3
movq 0x58(%rsp), %rdi
movl 0x24(%rsp), %eax
cmpl 0x34(%rsp), %eax
sete %al
movl 0x24(%rsp), %ecx
movzbl %al, %esi
andl $0x1, %esi
movl $0x2, %edx
leaq 0x40(%rsp), %r8
callq 0x358c0
movl 0x24(%rsp), %eax
cmpl 0x34(%rsp), %eax
jne 0x357d6
jmp 0x357e3
movl 0x24(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x24(%rsp)
jmp 0x35781
movl 0x34(%rsp), %ecx
movl $0x1, %eax
shll %cl, %eax
movl %eax, 0x20(%rsp)
movl 0x20(%rsp), %eax
subl $0x1, %eax
movl %eax, 0x1c(%rsp)
movl 0x34(%rsp), %eax
movl %eax, 0x18(%rsp)
cmpl $0x0, 0x18(%rsp)
jle 0x358ab
movl $0x1, 0x14(%rsp)
movl 0x18(%rsp), %ecx
addl $-0x1, %ecx
movl %ecx, 0x18(%rsp)
movl $0x1, %eax
shll %cl, %eax
xorl 0x1c(%rsp), %eax
movl %eax, 0x1c(%rsp)
movl 0x20(%rsp), %eax
movl 0x18(%rsp), %ecx
movl $0x1, %edx
shll %cl, %edx
movl %edx, %ecx
orl %ecx, %eax
movl %eax, 0x10(%rsp)
movl 0x10(%rsp), %eax
cmpl 0x2c(%rsp), %eax
jle 0x3585d
movl $0x0, 0x14(%rsp)
jmp 0x35894
movl 0x38(%rsp), %eax
movl 0x18(%rsp), %ecx
sarl %cl, %eax
andl $0x1, %eax
movl %eax, 0x14(%rsp)
movq 0x58(%rsp), %rdi
cmpl $0x0, 0x14(%rsp)
setne %al
movl 0x18(%rsp), %ecx
movzbl %al, %esi
andl $0x1, %esi
movl $0x3, %edx
leaq 0x40(%rsp), %r8
callq 0x358c0
movl 0x14(%rsp), %eax
movl 0x18(%rsp), %ecx
shll %cl, %eax
orl 0x20(%rsp), %eax
movl %eax, 0x20(%rsp)
jmp 0x35805
movq 0x40(%rsp), %rax
movl %eax, 0x64(%rsp)
movl 0x64(%rsp), %eax
addq $0x68, %rsp
retq
nopl (%rax)