// File: alexandres[P]terashuf/terashuf.cc
// Function: fillBufAndMarkLines(_IO_FILE*, char*, unsigned long, std::vector<unsigned long, std::allocator<unsigned long>>&, char, float)
bool fillBufAndMarkLines(FILE *f, char *buf, const ll bufBytes, std::vector<ll> &shufIndexes, char sep, float memory)
{
    static ll bufPos = 0, lastLineEndPos = 0;
    static bool memoryOverheadDisplayed;

    // see if anything left from previous fillBuf
    if (bufPos)
    {
        ll bytesToCpy = bufBytes - lastLineEndPos;
        memmove(buf, buf + lastLineEndPos, bytesToCpy);
        bufPos = bytesToCpy;
    }

    bufPos += fread(buf + bufPos, sizeof(char), bufBytes - bufPos, f);
    // if got nothing in buffer, signal we're done
    if (!bufPos)
        return true;

    // handle missing sep on last line
    // buffer not full and previous position is not newline
    if (bufPos < bufBytes && buf[bufPos - 1] != sep)
        buf[bufPos++] = sep;

    // mark lines and store pos in shufIndexes
    ll lineStart = 0;
    shufIndexes.clear();
    lastLineEndPos = 0;
    for (ll i = 0; i < bufPos; i++)
    {
        if (buf[i] != sep)
            continue;
        shufIndexes.push_back(lineStart);
        lineStart = i + 1;
        lastLineEndPos = i + 1;
        if (!memoryOverheadDisplayed && shufIndexes.size() >= LINES_BEFORE_ESTIMATING_MEMORY_OVERHEAD)
        {
            memoryOverheadDisplayed = true;
            double averageBytesPerLine = (double)i / (double)shufIndexes.size();
            double memoryOverhead = sizeof(ll) / averageBytesPerLine + 1;
            fprintf(stderr, "mean line-length is %.2f, estimated memory usage is %.2f * %.2f GB = %.2f GB\nTip: If you would like use exactly %.2f GB of memory, use MEMORY=%.4f ./terashuf ...\n", averageBytesPerLine - 1, memoryOverhead, memory, memoryOverhead * memory, memory, memory / memoryOverhead);
        }
    }
    if (shufIndexes.size() == 0)
    {
        fprintf(
            stderr,
            "\nFATAL ERROR: line too long to fit in buffer (> %zu bytes):\n",
            bufBytes);
        fwrite(buf, sizeof(char), std::min(bufBytes, (ll)50), stderr);
        fprintf(stderr, "...\n");
        exit(1); // line was too long to fit in buf, can't be shuffled
    }
    // if buffer isn't full, signal we're done
    return bufPos < bufBytes;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movb %r8b, %al
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
movb %al, -0x29(%rbp)
movss %xmm0, -0x30(%rbp)
cmpq $0x0, 0x8b22(%rip)      # 0xb150
je 0x2662
movq -0x20(%rbp), %rax
subq 0x8b1d(%rip), %rax      # 0xb158
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rdi
movq -0x18(%rbp), %rsi
addq 0x8b0a(%rip), %rsi      # 0xb158
movq -0x38(%rbp), %rdx
callq 0x21f0
movq -0x38(%rbp), %rax
movq %rax, 0x8aee(%rip)      # 0xb150
movq -0x18(%rbp), %rdi
addq 0x8ae3(%rip), %rdi      # 0xb150
movq -0x20(%rbp), %rdx
subq 0x8ad8(%rip), %rdx      # 0xb150
movq -0x10(%rbp), %rcx
movl $0x1, %esi
callq 0x21c0
addq 0x8ac3(%rip), %rax      # 0xb150
movq %rax, 0x8abc(%rip)      # 0xb150
cmpq $0x0, 0x8ab4(%rip)      # 0xb150
jne 0x26a7
movb $0x1, -0x1(%rbp)
jmp 0x292d
movq 0x8aa2(%rip), %rax      # 0xb150
cmpq -0x20(%rbp), %rax
jae 0x26ee
movq -0x18(%rbp), %rax
movq 0x8a91(%rip), %rcx      # 0xb150
subq $0x1, %rcx
movsbl (%rax,%rcx), %eax
movsbl -0x29(%rbp), %ecx
cmpl %ecx, %eax
je 0x26ee
movb -0x29(%rbp), %dl
movq -0x18(%rbp), %rax
movq 0x8a73(%rip), %rcx      # 0xb150
movq %rcx, %rsi
addq $0x1, %rsi
movq %rsi, 0x8a65(%rip)      # 0xb150
movb %dl, (%rax,%rcx)
movq $0x0, -0x40(%rbp)
movq -0x28(%rbp), %rdi
callq 0x37e0
movq $0x0, 0x8a4e(%rip) # 0xb158
movq $0x0, -0x48(%rbp)
movq -0x48(%rbp), %rax
cmpq 0x8a33(%rip), %rax      # 0xb150
jae 0x288f
movq -0x18(%rbp), %rax
movq -0x48(%rbp), %rcx
movsbl (%rax,%rcx), %eax
movsbl -0x29(%rbp), %ecx
cmpl %ecx, %eax
je 0x273c
jmp 0x287e
movq -0x28(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x3800
movq -0x48(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x40(%rbp)
movq -0x48(%rbp), %rax
addq $0x1, %rax
movq %rax, 0x89f4(%rip)      # 0xb158
testb $0x1, 0x89f5(%rip)      # 0xb160
jne 0x287c
movq -0x28(%rbp), %rdi
callq 0x3870
cmpq $0xf4240, %rax          # imm = 0xF4240
jb 0x287c
movb $0x1, 0x89d3(%rip)      # 0xb160
movq -0x48(%rbp), %xmm0
movaps 0x4897(%rip), %xmm1     # 0x7030
movaps %xmm1, -0x90(%rbp)
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0x4894(%rip), %xmm1     # 0x7040
movaps %xmm1, -0x80(%rbp)
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movsd %xmm0, -0x68(%rbp)
movq -0x28(%rbp), %rdi
callq 0x3870
movaps -0x90(%rbp), %xmm3
movaps -0x80(%rbp), %xmm2
movsd -0x68(%rbp), %xmm0
movq %rax, %xmm1
punpckldq %xmm3, %xmm1    # xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
subpd %xmm2, %xmm1
movaps %xmm1, %xmm2
unpckhpd %xmm1, %xmm1            # xmm1 = xmm1[1,1]
addsd %xmm2, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0x50(%rbp)
movsd 0x480a(%rip), %xmm0     # 0x7010
divsd -0x50(%rbp), %xmm0
movsd 0x47f5(%rip), %xmm1     # 0x7008
addsd %xmm1, %xmm0
movsd %xmm0, -0x58(%rbp)
movq 0x87b5(%rip), %rax      # 0xafd8
movq (%rax), %rdi
movsd -0x50(%rbp), %xmm0
movsd 0x47d5(%rip), %xmm1     # 0x7008
subsd %xmm1, %xmm0
movsd -0x58(%rbp), %xmm1
movss -0x30(%rbp), %xmm2
cvtss2sd %xmm2, %xmm2
movsd -0x58(%rbp), %xmm3
movss -0x30(%rbp), %xmm4
cvtss2sd %xmm4, %xmm4
mulsd %xmm4, %xmm3
movss -0x30(%rbp), %xmm4
cvtss2sd %xmm4, %xmm4
movss -0x30(%rbp), %xmm5
cvtss2sd %xmm5, %xmm5
divsd -0x58(%rbp), %xmm5
leaq 0x482c(%rip), %rsi      # 0x70a1
movb $0x6, %al
callq 0x21b0
jmp 0x287e
movq -0x48(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x48(%rbp)
jmp 0x2712
movq -0x28(%rbp), %rdi
callq 0x3870
cmpq $0x0, %rax
jne 0x291a
movq 0x8733(%rip), %rax      # 0xafd8
movq (%rax), %rdi
movq -0x20(%rbp), %rdx
leaq 0x4891(%rip), %rsi      # 0x7144
movb $0x0, %al
callq 0x21b0
movq -0x18(%rbp), %rax
movq %rax, -0x98(%rbp)
movq $0x32, -0x60(%rbp)
leaq -0x20(%rbp), %rdi
leaq -0x60(%rbp), %rsi
callq 0x3890
movq -0x98(%rbp), %rdi
movq (%rax), %rdx
movq 0x86ed(%rip), %rax      # 0xafd8
movq (%rax), %rcx
movl $0x1, %esi
callq 0x2240
movq 0x86d9(%rip), %rax      # 0xafd8
movq (%rax), %rdi
leaq 0x4836(%rip), %rsi      # 0x713f
movb $0x0, %al
callq 0x21b0
movl $0x1, %edi
callq 0x2150
movq 0x882f(%rip), %rax      # 0xb150
cmpq -0x20(%rbp), %rax
setb %al
andb $0x1, %al
movb %al, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0xa0, %rsp
popq %rbp
retq
nopl (%rax,%rax)