// File: /workspace/github_cpp_makefile_star2_O1/alexandres[P]terashuf/terashuf.cc
// Function: main
int main()
{
    char const *sepStr = std::getenv("SEP");
    const char sep = (sepStr != NULL && strlen(sepStr)) ? sepStr[0] : '\n';

    char *seedStr = std::getenv("SEED");
    const int seed = (seedStr != NULL && strlen(seedStr)) ? strtol(seedStr, NULL, 10) : time(NULL);
    std::mt19937_64 rng(seed);

    char *skipStr = std::getenv("SKIP");
    const int skipLines = (skipStr != NULL && strlen(skipStr)) ? strtol(skipStr, NULL, 10) : 0;

    char const *tmpDir = std::getenv("TMPDIR");
    if (tmpDir == NULL)
        tmpDir = "/tmp";
    char *tmpNameTemplate = (char *)malloc((strlen(tmpDir) + sizeof(TMP_NAME_TEMPLATE)) * sizeof(char));
    strcpy(tmpNameTemplate, tmpDir);
    strcat(tmpNameTemplate, TMP_NAME_TEMPLATE);

    char *memoryStr = std::getenv("MEMORY");
    const float memory = (memoryStr != NULL && strlen(memoryStr)) ? strtof(memoryStr, NULL) : 4;

    std::vector<ll> shufIndexes;

    const ll bufBytes = sizeof(char) * (ll)(memory * 1024. * 1024. * 1024.);
    char *buf = (char *)malloc(bufBytes);
    fprintf(stderr, "trying to allocate %zu bytes\n", bufBytes);
    if (buf == NULL)
    {
        fprintf(stderr, "failed to allocate buf memory\n");
        return 1;
    }

    fprintf(stderr, "\nstarting read\n");

    for (int i = 0; i < skipLines;)
    {
        char c = fgetc(stdin);
        if (c == EOF)
            return 0;
        if (fputc(c, stdout) == EOF)
        {
            fprintf(stderr, "failed to write SKIP lines. is disk full?");
            return 1;
        }
        if (c == sep)
            i++;
    }
    fprintf(stderr, "skipped %d lines\n", skipLines);

    ll totalBytesRead = 0, totalLinesRead = 0;
    std::vector<TmpFile> files;
    bool reachedEof = false;
    while (!reachedEof)
    {
        reachedEof = fillBufAndMarkLines(stdin, buf, bufBytes, shufIndexes, sep, memory);
        TmpFile tmpFile;
        // default output is stdout. if input fit in buffer, no need to use
        // temp files, just write to stdout.
        tmpFile.f = stdout;
        if (!reachedEof || files.size() > 0)
        {
            // haven't reached eof so have to call fillBuf again.
            // or we did did reach eof but there is already a temp file,
            // so we are already in temp file mode, not direct to stdout.
            tmpFile.path = (char *)malloc((strlen(tmpNameTemplate) + 1) * sizeof(char));
            strcpy(tmpFile.path, tmpNameTemplate);
            int fd = mkstemp(tmpFile.path);
            if (fd == -1)
            {
                fprintf(stderr, "failed to create fd tmp file %s\n",
                        tmpNameTemplate);
                return 1;
            }
            tmpFile.f = fdopen(fd, "wb+");
            if (tmpFile.f == NULL)
            {
                fprintf(stderr, "failed to create tmp file %s\n",
                        tmpFile.path);
                return 1;
            }
        }
        totalBytesRead += shufFlushBuf(buf, shufIndexes, rng, sep, tmpFile.f);
        totalLinesRead += shufIndexes.size();
        tmpFile.lines = shufIndexes.size();
        fprintf(stderr, "\rlines read: %zu, gb read: %zu", totalLinesRead,
                totalBytesRead / (1024 * 1024 * 1024));
        files.push_back(tmpFile);
    }

    // inform totalLines and totalBytesRead
    fprintf(stderr, "\nRead %zu lines, %zu bytes, have %d tmp files\n",
            totalLinesRead, totalBytesRead, (int)files.size());

    if (files.size() == 1)
    {
        fprintf(
            stderr,
            "\nShuffled directly to stdout without using tmpfiles, done!\n");
        return 0;
    }

    std::vector<ll> linesRemainingPerFile;

    for (auto &file : files)
    {
        rewind(file.f);
        // for bufferedFgetc
        file.buf = (char *)malloc(IO_CHUNK);
        file.bufPos = 0;
        file.bufN = 0;
        file.eof = false;
        linesRemainingPerFile.push_back(file.lines);
    }

    auto fenwickTree = FenwickTree(linesRemainingPerFile);

    ll totalBytesWritten = 0, linesRemaining = totalLinesRead, totalBytesWrittenForProgress = 0;

    fprintf(stderr, "\nstarting write to output\n");

    while (linesRemaining)
    {
        ll randLine = std::uniform_int_distribution<ll>{0, linesRemaining - 1}(rng);
        auto fileIdx = fenwickTree.findIndexAndDraw(randLine + 1);
        auto linesRemainingInFile = fenwickTree.getCountAtIndex(fileIdx);
        linesRemaining--;
        TmpFile &file = files[fileIdx];
        ll bytesRead = readLine(buf, sep, file);
        if (!linesRemainingInFile)
        {
            fclose(file.f);
            unlink(file.path);
        }
        ll bytesWritten = fwrite(buf, sizeof(char), bytesRead, stdout);
        if (bytesRead != bytesWritten)
        {
            fprintf(stderr, "\nFATAL ERROR: failed to write line to disk. is there space left?\n");
            return 1;
        }
        totalBytesWritten += bytesWritten;
        totalBytesWrittenForProgress += bytesWritten;
        // progress report
        if (!linesRemaining || totalBytesWrittenForProgress >= bufBytes)
        {
            fprintf(stderr, "\rlines written: %zu, gb written: %zu",
                    totalLinesRead - linesRemaining, totalBytesWritten / (1024 * 1024 * 1024));
            totalBytesWrittenForProgress = 0;
        }
    }
    fprintf(stderr, "\ndone\n");
    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa98, %rsp            # imm = 0xA98
leaq 0x1f55(%rip), %rdi      # 0x318d
callq 0x1140
movb $0xa, %bpl
testq %rax, %rax
je 0x1250
movzbl (%rax), %eax
testb %al, %al
pushq $0xa
popq %rbp
cmovnel %eax, %ebp
leaq 0x1f3a(%rip), %rdi      # 0x3191
callq 0x1140
testq %rax, %rax
je 0x1266
cmpb $0x0, (%rax)
jne 0x126f
xorl %edi, %edi
callq 0x10d0
jmp 0x127c
pushq $0xa
popq %rdx
movq %rax, %rdi
xorl %esi, %esi
callq 0x1180
movslq %eax, %rsi
movq %rsi, 0xd0(%rsp)
pushq $0x1
popq %rax
movabsq $0x5851f42d4c957f2d, %rcx # imm = 0x5851F42D4C957F2D
movq %rsi, %rdx
shrq $0x3e, %rdx
xorq %rsi, %rdx
imulq %rcx, %rdx
addq %rax, %rdx
movq %rdx, 0xd0(%rsp,%rax,8)
incq %rax
movq %rdx, %rsi
cmpq $0x138, %rax            # imm = 0x138
jne 0x1297
movq $0x138, 0xa90(%rsp) # imm = 0x138
leaq 0x1ec8(%rip), %rdi      # 0x3196
callq 0x1140
xorl %r15d, %r15d
testq %rax, %rax
je 0x12f0
cmpb $0x0, (%rax)
je 0x12f0
pushq $0xa
popq %rdx
movq %rax, %rdi
xorl %esi, %esi
callq 0x1180
movq %rax, %r15
leaq 0x1ea4(%rip), %rdi      # 0x319b
callq 0x1140
testq %rax, %rax
leaq 0x1e9c(%rip), %rbx      # 0x31a2
cmovneq %rax, %rbx
movq %rbx, %rdi
callq 0x1070
leaq 0x13(%rax), %rdi
callq 0x1160
movq %rax, %r14
movq %rax, %rdi
movq %rbx, %rsi
callq 0x10e0
movq %r14, %rdi
callq 0x1070
movaps 0x20a8(%rip), %xmm0     # 0x33e0
movups %xmm0, (%r14,%rax)
movq %r14, 0x80(%rsp)
movl $0x585858, 0xf(%r14,%rax) # imm = 0x585858
leaq 0x1e52(%rip), %rdi      # 0x31a7
callq 0x1140
movss 0x1ca2(%rip), %xmm0     # 0x3004
testq %rax, %rax
je 0x1376
cmpb $0x0, (%rax)
je 0x1376
movq %rax, %rdi
xorl %esi, %esi
callq 0x1170
xorps %xmm1, %xmm1
andq $0x0, 0x70(%rsp)
movaps %xmm1, 0x60(%rsp)
movss %xmm0, 0x3c(%rsp)
cvtss2sd %xmm0, %xmm0
movsd 0x1c72(%rip), %xmm1     # 0x3008
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
subsd 0x1c5a(%rip), %xmm0     # 0x3010
cvttsd2si %xmm0, %rbx
andq %rcx, %rbx
orq %rax, %rbx
movq %rbx, %rdi
callq 0x1160
movq %rax, %r12
movq 0x3c05(%rip), %r14      # 0x4fd8
movq (%r14), %rdi
leaq 0x1dd1(%rip), %rsi      # 0x31ae
xorl %r13d, %r13d
movq %rbx, 0x78(%rsp)
movq %rbx, %rdx
xorl %eax, %eax
callq 0x1190
movq (%r14), %rcx
movq %r12, 0x30(%rsp)
testq %r12, %r12
jne 0x1417
leaq 0x1dc9(%rip), %rdi      # 0x31cc
pushq $0x1e
popq %rsi
pushq $0x1
popq %rdx
callq 0x1200
pushq $0x1
popq %r12
jmp 0x14cc
leaq 0x1dcd(%rip), %rdi      # 0x31eb
pushq $0xf
popq %rsi
pushq $0x1
popq %rdx
callq 0x1200
movl %ebp, 0x38(%rsp)
movsbl %bpl, %eax
movl %eax, (%rsp)
xorl %ebp, %ebp
movl %r13d, %r14d
cmpl %r15d, %r13d
jge 0x14c4
movq 0x3b87(%rip), %rax      # 0x4fd0
movq (%rax), %rdi
callq 0x11c0
movl %eax, %edx
shll $0x18, %edx
xorl %ecx, %ecx
movl %r14d, %r13d
movl $0x0, %r12d
cmpl $0xff000000, %edx       # imm = 0xFF000000
je 0x1494
movsbl %al, %ebx
movq 0x3b45(%rip), %rax      # 0x4fb8
movq (%rax), %rsi
movl %ebx, %edi
callq 0x1150
cmpl $-0x1, %eax
je 0x149d
xorl %r13d, %r13d
cmpl (%rsp), %ebx
sete %r13b
addl %r14d, %r13d
movb $0x1, %cl
movl %ebp, %r12d
movl %r12d, %ebp
testb %cl, %cl
jne 0x1436
jmp 0x14c7
movq 0x3b34(%rip), %rax      # 0x4fd8
movq (%rax), %rcx
leaq 0x1d4d(%rip), %rdi      # 0x31fb
pushq $0x29
popq %rsi
pushq $0x1
popq %rdx
callq 0x1200
xorl %ecx, %ecx
movl %r14d, %r13d
pushq $0x1
popq %r12
jmp 0x1494
movl %ebp, %r12d
cmpl %r15d, %r14d
jge 0x14f8
movq 0x60(%rsp), %rdi
testq %rdi, %rdi
je 0x14e3
movq 0x70(%rsp), %rsi
subq %rdi, %rsi
callq 0x1110
movl %r12d, %eax
addq $0xa98, %rsp            # imm = 0xA98
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x3ad9(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
leaq 0x1d1c(%rip), %rsi      # 0x3225
xorl %r14d, %r14d
movl %r15d, %edx
xorl %eax, %eax
callq 0x1190
leaq 0x10(%rsp), %rax
andq $0x0, 0x10(%rax)
xorpd %xmm0, %xmm0
movapd %xmm0, (%rax)
movq $0x0, 0x8(%rsp)
xorl %ebx, %ebx
movq 0x78(%rsp), %r13
testb $0x1, %r14b
jne 0x172b
movq 0x3a87(%rip), %rax      # 0x4fd0
movq (%rax), %rdi
movq 0x30(%rsp), %rsi
movq %r13, %rdx
leaq 0x60(%rsp), %rcx
movl (%rsp), %r8d
movss 0x3c(%rsp), %xmm0
callq 0x1e01
movl %eax, %r14d
movq 0x3a46(%rip), %rax      # 0x4fb8
movq (%rax), %rax
movq %rax, 0x88(%rsp)
testb %r14b, %r14b
je 0x158e
movq 0x18(%rsp), %rax
cmpq 0x10(%rsp), %rax
je 0x160b
movq 0x80(%rsp), %rbp
movq %rbp, %rdi
callq 0x1070
leaq 0x1(%rax), %rdi
callq 0x1160
movq %rax, %r15
movq %rax, 0x90(%rsp)
movq %rax, %rdi
movq %rbp, %rsi
callq 0x10e0
movq %r15, %rdi
callq 0x1050
cmpl $-0x1, %eax
je 0x16c9
movl %eax, %edi
leaq 0x1c81(%rip), %rsi      # 0x3258
callq 0x1120
movq %rax, 0x88(%rsp)
movb $0x1, %bpl
testq %rax, %rax
je 0x16e6
testb %bpl, %bpl
jne 0x160b
xorl %ebp, %ebp
movq %rbx, %r15
movq %r15, %rbx
testb %bpl, %bpl
jne 0x1538
jmp 0x19d3
movq 0x88(%rsp), %r8
movq 0x30(%rsp), %rdi
leaq 0x60(%rsp), %rsi
leaq 0xd0(%rsp), %rdx
movl (%rsp), %ecx
callq 0x1cdc
movq %rax, %r15
addq %rbx, %r15
movq 0x68(%rsp), %rax
subq 0x60(%rsp), %rax
sarq $0x3, %rax
movq 0x8(%rsp), %rdx
addq %rax, %rdx
movq %rax, 0x98(%rsp)
movq 0x3980(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
movq %r15, %rcx
shrq $0x1e, %rcx
leaq 0x1c11(%rip), %rsi      # 0x327a
movq %rdx, 0x8(%rsp)
xorl %eax, %eax
callq 0x1190
movq 0x18(%rsp), %rsi
cmpq 0x20(%rsp), %rsi
je 0x1711
movq 0xb8(%rsp), %rax
movq %rax, 0x30(%rsi)
movupd 0x88(%rsp), %xmm0
movupd 0x98(%rsp), %xmm1
movups 0xa8(%rsp), %xmm2
movups %xmm2, 0x20(%rsi)
movupd %xmm1, 0x10(%rsi)
movupd %xmm0, (%rsi)
addq $0x38, %rsi
movq %rsi, 0x18(%rsp)
movb $0x1, %bpl
jmp 0x15fa
movq 0x3908(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
xorl %ebp, %ebp
leaq 0x1b5b(%rip), %rsi      # 0x3237
movq 0x80(%rsp), %rdx
jmp 0x1701
movq 0x38eb(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
movq 0x90(%rsp), %rdx
xorl %ebp, %ebp
leaq 0x1b5b(%rip), %rsi      # 0x325c
xorl %eax, %eax
callq 0x1190
pushq $0x1
popq %r12
jmp 0x15f0
movb $0x1, %bpl
leaq 0x10(%rsp), %rdi
leaq 0x88(%rsp), %rdx
callq 0x2632
jmp 0x15fa
movq 0x38a6(%rip), %r14      # 0x4fd8
movq (%r14), %rdi
movq 0x18(%rsp), %rax
subq 0x10(%rsp), %rax
pushq $0x38
popq %rcx
cqto
idivq %rcx
leaq 0x1b4b(%rip), %rsi      # 0x3299
movq 0x8(%rsp), %rdx
movq %rbx, %rcx
movl %eax, %r8d
xorl %eax, %eax
callq 0x1190
movq 0x10(%rsp), %rbx
movq 0x18(%rsp), %r15
movq %r15, %rax
subq %rbx, %rax
cmpq $0x38, %rax
jne 0x1793
movq (%r14), %rcx
leaq 0x1b48(%rip), %rdi      # 0x32c8
pushq $0x3b
popq %rsi
pushq $0x1
popq %rdx
callq 0x1200
xorl %r12d, %r12d
jmp 0x19d3
xorpd %xmm0, %xmm0
movapd %xmm0, 0x40(%rsp)
andq $0x0, 0x50(%rsp)
cmpq %r15, %rbx
je 0x180e
addq $0x10, %rbx
leaq 0x40(%rsp), %r14
movq -0x10(%rbx), %rdi
callq 0x1030
movl $0x10000, %edi          # imm = 0x10000
callq 0x1160
movq %rax, 0x8(%rbx)
xorpd %xmm0, %xmm0
movupd %xmm0, 0x10(%rbx)
movb $0x0, 0x20(%rbx)
movq 0x48(%rsp), %rsi
cmpq 0x50(%rsp), %rsi
je 0x17f2
movq (%rbx), %rax
movq %rax, (%rsi)
addq $0x8, %rsi
movq %rsi, 0x48(%rsp)
jmp 0x17fd
movq %r14, %rdi
movq %rbx, %rdx
callq 0x2512
leaq -0x10(%rbx), %rax
addq $0x38, %rbx
addq $0x38, %rax
cmpq %r15, %rax
jne 0x17b1
leaq 0x88(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x20f8
movq 0x37b1(%rip), %rax      # 0x4fd8
movq (%rax), %rcx
leaq 0x1ad3(%rip), %rdi      # 0x3304
pushq $0x1a
popq %rsi
pushq $0x1
popq %rdx
callq 0x1200
movq $0x0, (%rsp)
movq 0x8(%rsp), %r14
xorl %ebp, %ebp
subq $0x1, %r14
jb 0x1980
andq $0x0, 0xc0(%rsp)
movq %r14, 0xc8(%rsp)
leaq 0xc0(%rsp), %rdi
leaq 0xd0(%rsp), %rsi
movq %rdi, %rdx
callq 0x2338
incq %rax
leaq 0x88(%rsp), %rdi
movq %rax, %rsi
callq 0x21b4
movslq 0xa4(%rsp), %rcx
cltq
addq %rax, %rcx
movq 0x88(%rsp), %rdx
movq (%rdx,%rcx,8), %r13
imulq $0x38, %rax, %rbx
addq 0x10(%rsp), %rbx
xorl %r15d, %r15d
movq %rbx, %rdi
callq 0x1d68
cmpb $-0x1, %al
je 0x18d6
movq 0x30(%rsp), %rcx
movb %al, (%rcx,%r15)
incq %r15
cmpb 0x38(%rsp), %al
jne 0x18b6
jmp 0x18d9
xorl %r15d, %r15d
testq %r13, %r13
jne 0x18ef
movq (%rbx), %rdi
callq 0x10f0
movq 0x8(%rbx), %rdi
callq 0x1080
movq 0x36c2(%rip), %rax      # 0x4fb8
movq (%rax), %rcx
movq 0x30(%rsp), %rdi
pushq $0x1
popq %rsi
movq %r15, %rdx
callq 0x1200
movq %rax, %rbx
cmpq %rax, %r15
movq 0x78(%rsp), %rax
jne 0x1932
addq %rbx, (%rsp)
testq %r14, %r14
je 0x1954
addq %rbx, %rbp
cmpq %rax, %rbp
jae 0x1954
cmpq %rbx, %r15
je 0x184b
jmp 0x199f
movq 0x369f(%rip), %rax      # 0x4fd8
movq (%rax), %rcx
leaq 0x19dc(%rip), %rdi      # 0x331f
pushq $0x41
popq %rsi
pushq $0x1
popq %rdx
callq 0x1200
pushq $0x1
popq %r12
jmp 0x1927
movq 0x367d(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
movq 0x8(%rsp), %rdx
subq %r14, %rdx
movq (%rsp), %rcx
shrq $0x1e, %rcx
leaq 0x19ec(%rip), %rsi      # 0x3361
xorl %eax, %eax
callq 0x1190
xorl %ebp, %ebp
jmp 0x1927
movq 0x3651(%rip), %rax      # 0x4fd8
movq (%rax), %rcx
leaq 0x19f5(%rip), %rdi      # 0x3386
pushq $0x6
popq %rsi
pushq $0x1
popq %rdx
callq 0x1200
xorl %r12d, %r12d
movq 0x88(%rsp), %rdi
testq %rdi, %rdi
je 0x19bc
movq 0x98(%rsp), %rsi
subq %rdi, %rsi
callq 0x1110
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0x19d3
movq 0x50(%rsp), %rsi
subq %rdi, %rsi
callq 0x1110
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x14cc
movq 0x20(%rsp), %rsi
subq %rdi, %rsi
callq 0x1110
jmp 0x14cc
jmp 0x1a17
movq %rax, %rbx
movq 0x88(%rsp), %rdi
testq %rdi, %rdi
je 0x1a1a
movq 0x98(%rsp), %rsi
subq %rdi, %rsi
callq 0x1110
jmp 0x1a1a
movq %rax, %rbx
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0x1a3a
movq 0x50(%rsp), %rsi
subq %rdi, %rsi
callq 0x1110
jmp 0x1a3a
jmp 0x1a37
jmp 0x1a37
movq %rax, %rbx
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x1a51
movq 0x20(%rsp), %rsi
subq %rdi, %rsi
callq 0x1110
movq 0x60(%rsp), %rdi
testq %rdi, %rdi
je 0x1a68
movq 0x70(%rsp), %rsi
subq %rdi, %rsi
callq 0x1110
movq %rbx, %rdi
callq 0x11e0