// File: /workspace/github_cpp_makefile_star2_O2/cristian-bicheru[P]arith/./arith.h
// Function: arith::CompressBuffer(std::vector<unsigned char, std::allocator<unsigned char>>&, arith::CodecProbabilityTable&, buffer::CodecByteStream&)
void CompressBuffer(std::vector<unsigned char>& InputBuffer,
                        CodecProbabilityTable& ProbabilityTable,
                        buffer::CodecByteStream& OutputBuffer) {
        uint64_t high = MAXVAL;
        uint64_t low = 0ull;
        uint8_t shift = ProbabilityTable.GetShift();
        buffer::CodecBufferWrapper Buffer(InputBuffer, shift);
        OutputBuffer.WriteByte(shift);
        OutputBuffer.WriteByte((InputBuffer[InputBuffer.size()-1]<<shift)+(InputBuffer[0]>>(8u-shift))); // residual due to shift
        uint64_t pLow, pUp, pDenom, range;

        // Rate Stuff
        auto StartTime = std::chrono::high_resolution_clock::now();
        uint64_t BufSizePct = Buffer.Size()/100ull;


        for (uint64_t i = 0; i < Buffer.Size(); i++) {

            if ((i<<44ll>>44ull) == 0ull) {
                std::cout << "\33[2K\r";
                std::cout << "Compressing... " << i/BufSizePct+1 << "%  @" << double(i)/std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - StartTime).count() << " Bytes/Second." << std::flush;
            }

            range = high - low + 1ull;
            std::tie(pLow, pUp, pDenom) = ProbabilityTable.GetProbability(Buffer[i]);
            high = low + (range * pUp / pDenom) - 1ull;
            low = low + (range * pLow / pDenom);

            while (true) {
                if (high < HALF) {
                    OutputBuffer.WriteBitBuffered(0u);
                } else if (low >= HALF) {
                    OutputBuffer.WriteBitBuffered(1u);
                } else if (high < THREE_QUARTERS && low >= QUARTER) {
                    OutputBuffer.IncPendingBits();
                    low -= QUARTER;
                    high -= QUARTER;
                } else {
                    break;
                }
                high <<= 1ull;
                high++;
                low <<= 1ull;
                high &= MAXVAL;
                low &= MAXVAL;
            }
        }

        OutputBuffer.IncPendingBits();
        if (low < QUARTER) {
            OutputBuffer.WriteBitBuffered(0);
        } else {
            OutputBuffer.WriteBitBuffered(1);
        }

        std::cout << std::endl;
    }

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa8, %rsp
movq %rdx, %rbx
movq %rdi, %r15
movq %rsi, 0x20(%rsp)
movzbl 0x404(%rsi), %ebp
leaq 0x50(%rsp), %rdi
movq %r15, %rsi
movl %ebp, %edx
callq 0x35c6
movq %rbx, %rdi
movl %ebp, %esi
callq 0x3616
movq 0x8(%r15), %rax
movzbl -0x1(%rax), %eax
movl %ebp, %ecx
shll %cl, %eax
movq (%r15), %rcx
movzbl (%rcx), %edx
movb $0x8, %cl
subb %bpl, %cl
shrl %cl, %edx
addl %eax, %edx
movzbl %dl, %esi
movq %rbx, %rdi
callq 0x3616
movl $0x80000000, %r13d      # imm = 0x80000000
callq 0x2030
movq %rax, 0x8(%rsp)
movq 0x70(%rsp), %rcx
xorl %r14d, %r14d
pushq $0x64
popq %rsi
movq %rcx, %rax
xorl %edx, %edx
divq %rsi
movq %rax, 0x10(%rsp)
leaq 0x7fffffff(%r13), %rbp
leaq 0x40000000(%r13), %r12
movq $-0x40000000, %r15      # imm = 0xC0000000
xorl %eax, %eax
cmpq %rcx, %rax
jae 0x2a04
movq %rax, (%rsp)
shlq $0x2c, %rax
jne 0x2908
movq 0xa778(%rip), %rdi      # 0xcfc8
leaq 0x57e9(%rip), %rsi      # 0x8040
callq 0x21b0
movq 0xa765(%rip), %rdi      # 0xcfc8
leaq 0x57dc(%rip), %rsi      # 0x8046
callq 0x21b0
movq %rax, %rdi
movq (%rsp), %rax
xorl %edx, %edx
divq 0x10(%rsp)
leaq 0x1(%rax), %rsi
callq 0x2110
movq %rax, %rdi
leaq 0x57c6(%rip), %rsi      # 0x8056
callq 0x21b0
movq %rax, 0x18(%rsp)
movsd (%rsp), %xmm0
unpcklps 0x576a(%rip), %xmm0     # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x5772(%rip), %xmm0     # 0x8020
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movapd %xmm1, 0x90(%rsp)
callq 0x2030
subq 0x8(%rsp), %rax
cvtsi2sd %rax, %xmm1
divsd 0x575e(%rip), %xmm1     # 0x8038
movapd 0x90(%rsp), %xmm0
divsd %xmm1, %xmm0
movq 0x18(%rsp), %rdi
callq 0x2290
movq %rax, %rdi
leaq 0x5760(%rip), %rsi      # 0x805b
callq 0x21b0
movq %rax, %rdi
callq 0x2120
movq 0x50(%rsp), %rax
movq (%rsp), %rsi
movzbl (%rax,%rsi), %edx
movb 0x68(%rsp), %cl
shll %cl, %edx
movzbl 0x1(%rax,%rsi), %eax
movb 0x69(%rsp), %cl
shrl %cl, %eax
addl %edx, %eax
movzbl %al, %eax
movq 0x20(%rsp), %rdx
movl 0x400(%rdx), %ecx
movl %ecx, 0x44(%rsp)
movq (%rdx,%rax,4), %xmm0
pshufd $0xe1, %xmm0, %xmm0     # xmm0 = xmm0[1,0,2,3]
movq %xmm0, 0x48(%rsp)
subq %r14, %rbp
incq %rbp
leaq 0x28(%rsp), %rax
movq %rax, 0x78(%rsp)
leaq 0x30(%rsp), %rax
movq %rax, 0x80(%rsp)
leaq 0x38(%rsp), %rax
movq %rax, 0x88(%rsp)
leaq 0x78(%rsp), %rdi
leaq 0x44(%rsp), %rsi
callq 0x3652
movq 0x30(%rsp), %rax
imulq %rbp, %rax
movq 0x28(%rsp), %rcx
xorl %edx, %edx
divq %rcx
leaq (%r14,%rax), %rsi
decq %rsi
imulq 0x38(%rsp), %rbp
movq %rbp, %rax
xorl %edx, %edx
divq %rcx
addq %rax, %r14
movq %rsi, %rbp
cmpq %r13, %rbp
jae 0x29ba
xorl %eax, %eax
jmp 0x29c5
movb $0x1, %al
cmpq $0x7fffffff, %r14       # imm = 0x7FFFFFFF
jbe 0x29d2
movzbl %al, %esi
movq %rbx, %rdi
callq 0x3668
jmp 0x29e9
cmpq %r12, %rbp
jae 0x29f3
cmpq $0x40000000, %r14       # imm = 0x40000000
jb 0x29f3
incl 0x28(%rbx)
addq %r15, %r14
addq %r15, %rbp
addl %ebp, %ebp
addl %r14d, %r14d
incq %rbp
jmp 0x29b1
movq (%rsp), %rax
incq %rax
movq 0x70(%rsp), %rcx
jmp 0x2832
incl 0x28(%rbx)
xorl %esi, %esi
cmpq $0x40000000, %r14       # imm = 0x40000000
setae %sil
movq %rbx, %rdi
callq 0x3668
movq 0xa5a5(%rip), %rdi      # 0xcfc8
callq 0x20c0
leaq 0x50(%rsp), %rdi
callq 0x44a6
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2a4c
jmp 0x2a4c
jmp 0x2a4c
jmp 0x2a4c
movq %rax, %rbx
leaq 0x50(%rsp), %rdi
callq 0x44a6
movq %rbx, %rdi
callq 0x22e0