// File: ivan-tkatchev[P]yalz77/./lz77.h
// Function: lz77::compress_t::feed[abi:cxx11](unsigned char const*, unsigned char const*)
std::string feed(const unsigned char* i, const unsigned char* e) {

        const unsigned char* i0 = i;

        std::string ret;
        
        std::string unc;

        push_vlq_uint(e - i, ret);

        offsets.clear();

        size_t blocksize = offsets.blocksize;

        while (i != e) {

            unsigned char c = *i;

            // The last MIN_RUN-1 bytes are uncompressable. (At least MIN_RUN bytes
            // are needed to calculate a prefix hash.)

            if (i > e - MIN_RUN) {

                unc +=c;
                ++i;
                continue;
            }

            size_t maxrun = 0;
            size_t maxoffset = 0;
            size_t maxgain = 0;

            uint16_t packed;

            // The MIN_RUN prefix length was chosen empirically, based on a series
            // of unscientific tests.

            pack_bytes(i, packed, blocksize);

            offsets(packed, i0, i, e, maxrun, maxoffset, maxgain);

            if (maxrun < MIN_RUN) {
                unc += c;
                ++i;
                continue;
            }

            if (unc.size() > 0) {
                // Write a packet of uncompressed data.

                size_t msg = (unc.size() << 1) | 1;
                push_vlq_uint(msg, ret);
                ret += unc;
                unc.clear();
            }

            // A compressed string is a length and an offset.
            // First subtract the minimum length (smaller lengths don't exist).
            // Then check if the length fits in SHORTRUN_BITS bits; if it does, then
            // tack it on to the offset. Otherwise write length and offset separately.
            // The rightmost bit is a zero to differentiate from packets of
            // uncompressed data.

            i += maxrun;
            maxrun = maxrun - MIN_RUN + 1;

            if (maxrun < SHORTRUN_MAX) {

                size_t msg = ((maxoffset << SHORTRUN_BITS) | maxrun) << 1;
                push_vlq_uint(msg, ret);

            } else {

                size_t msg = (maxoffset << (SHORTRUN_BITS + 1));
                push_vlq_uint(msg, ret);
                push_vlq_uint(maxrun, ret);
            }
        }

        if (unc.size() > 0) {

            size_t msg = (unc.size() << 1) | 1;
            push_vlq_uint(msg, ret);
            ret += unc;
            unc.clear();
        }

        return ret;
    }

// Assembly:
subq $0xd8, %rsp
movq %rdi, 0x20(%rsp)
movq %rdi, %rax
movq %rax, 0x10(%rsp)
movq %rdi, 0xd0(%rsp)
movq %rsi, 0xc8(%rsp)
movq %rdx, 0xc0(%rsp)
movq %rcx, 0xb8(%rsp)
movq 0xc8(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0xc0(%rsp), %rax
movq %rax, 0xb0(%rsp)
movb $0x0, 0xaf(%rsp)
callq 0x2270
leaq 0x88(%rsp), %rdi
callq 0x2270
movq 0x20(%rsp), %rsi
movq 0xb8(%rsp), %rdi
movq 0xc0(%rsp), %rax
subq %rax, %rdi
callq 0x44e0
jmp 0x41fa
movq 0x18(%rsp), %rdi
callq 0x4550
jmp 0x4206
movq 0x18(%rsp), %rax
movq 0x20(%rax), %rax
movq %rax, 0x70(%rsp)
movq 0xc0(%rsp), %rax
cmpq 0xb8(%rsp), %rax
je 0x4441
movq 0xc0(%rsp), %rax
movb (%rax), %al
movb %al, 0x6f(%rsp)
movq 0xc0(%rsp), %rax
movq 0xb8(%rsp), %rcx
addq $-0x5, %rcx
cmpq %rcx, %rax
jbe 0x42a8
movsbl 0x6f(%rsp), %esi
leaq 0x88(%rsp), %rdi
callq 0x2100
jmp 0x4265
movq 0xc0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xc0(%rsp)
jmp 0x4214
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x80(%rsp)
movl %eax, 0x7c(%rsp)
leaq 0x88(%rsp), %rdi
callq 0x20f0
movq 0x20(%rsp), %rdi
callq 0x20f0
jmp 0x44d3
movq $0x0, 0x60(%rsp)
movq $0x0, 0x58(%rsp)
movq $0x0, 0x50(%rsp)
movq 0xc0(%rsp), %rdi
movq 0x70(%rsp), %rdx
leaq 0x4e(%rsp), %rsi
callq 0x4590
jmp 0x42dc
movq 0x18(%rsp), %rdi
movzwl 0x4e(%rsp), %esi
movq 0xb0(%rsp), %rdx
movq 0xc0(%rsp), %rcx
movq 0xb8(%rsp), %r8
movq %rsp, %rax
leaq 0x50(%rsp), %r9
movq %r9, 0x8(%rax)
leaq 0x58(%rsp), %r9
movq %r9, (%rax)
leaq 0x60(%rsp), %r9
callq 0x45e0
jmp 0x431e
cmpq $0x5, 0x60(%rsp)
jae 0x4353
movsbl 0x6f(%rsp), %esi
leaq 0x88(%rsp), %rdi
callq 0x2100
jmp 0x433a
movq 0xc0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xc0(%rsp)
jmp 0x4214
leaq 0x88(%rsp), %rdi
callq 0x2120
cmpq $0x0, %rax
jbe 0x43af
leaq 0x88(%rsp), %rdi
callq 0x2120
movq 0x20(%rsp), %rsi
leaq 0x1(%rax,%rax), %rax
movq %rax, 0x40(%rsp)
movq 0x40(%rsp), %rdi
callq 0x44e0
jmp 0x438e
movq 0x20(%rsp), %rdi
leaq 0x88(%rsp), %rsi
callq 0x2230
jmp 0x43a2
leaq 0x88(%rsp), %rdi
callq 0x2250
movq 0x60(%rsp), %rax
addq 0xc0(%rsp), %rax
movq %rax, 0xc0(%rsp)
movq 0x60(%rsp), %rax
subq $0x5, %rax
addq $0x1, %rax
movq %rax, 0x60(%rsp)
cmpq $0x8, 0x60(%rsp)
jae 0x440a
movq 0x20(%rsp), %rsi
movq 0x58(%rsp), %rax
movq 0x60(%rsp), %rcx
addq %rcx, %rcx
shlq $0x4, %rax
orq %rcx, %rax
movq %rax, 0x38(%rsp)
movq 0x38(%rsp), %rdi
callq 0x44e0
jmp 0x4408
jmp 0x443c
movq 0x20(%rsp), %rsi
movq 0x58(%rsp), %rax
shlq $0x4, %rax
movq %rax, 0x30(%rsp)
movq 0x30(%rsp), %rdi
callq 0x44e0
jmp 0x4429
movq 0x20(%rsp), %rsi
movq 0x60(%rsp), %rdi
callq 0x44e0
jmp 0x443a
jmp 0x443c
jmp 0x4214
leaq 0x88(%rsp), %rdi
callq 0x2120
cmpq $0x0, %rax
jbe 0x449d
leaq 0x88(%rsp), %rdi
callq 0x2120
movq 0x20(%rsp), %rsi
leaq 0x1(%rax,%rax), %rax
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rdi
callq 0x44e0
jmp 0x447c
movq 0x20(%rsp), %rdi
leaq 0x88(%rsp), %rsi
callq 0x2230
jmp 0x4490
leaq 0x88(%rsp), %rdi
callq 0x2250
movb $0x1, 0xaf(%rsp)
leaq 0x88(%rsp), %rdi
callq 0x20f0
testb $0x1, 0xaf(%rsp)
jne 0x44c6
movq 0x20(%rsp), %rdi
callq 0x20f0
movq 0x10(%rsp), %rax
addq $0xd8, %rsp
retq
movq 0x80(%rsp), %rdi
callq 0x2300