// File: ctSkennerton[P]fxtract/util/str_x.c
// Function: main
int
main(int argc, char **argv)
{
    setvbuf(stdout, NULL, _IOLBF, 0);
    int         count = 10001;  // count MUST be odd, or hash is always zero!
    int         patlen, nr, a;
    if (argc < 4)
        usage("[-v] <file> <count> <str>...\n"
              "Compares STRSTR (SSE4.2) with:\n"
             // "- SSE2: scan for leading pair of chars using SSE2\n"
              //"- BERG: Steven van den Berg's strstr\n"
             // "- WINS: use 2,3,4-byte sliding window\n"
              "- BNDM: Backward Non-deterministic DAWG matching (suffix shift-and)\n"
              "- RG7G: Georgi's Railgun version 7-Gulliver\n"
              "- RG7W: Georgi's Railgun version 7-Wolfram\n");
    argv += verbose = !strcmp(argv[1], "-v");
    MEMBUF x = chomp(slurp(argv[1]));
    if (nilbuf(x)) die(": cannot read %s:", argv[1]);
    count = atoi(argv[2]) | 1;  // count MUST be odd
    MEMREF  *rv = refsplit(x.ptr, '\n', &nr);
    char    **exp = malloc(nr * sizeof(*exp));

    //if (verbose) printf("SSE2 BERG WINS BNDM RG7g RG7w nchrs=%"FSIZE"d\n", x.len);
    if (verbose) printf("BNDM... RG7g... RG7w... nchrs=%"FSIZE"d\n", x.len);
    for (a = 3; argv[a]; ++a) {
        patlen = strlen(argv[a]);
        memset(exp, -1, nr * sizeof(*exp));

#           define DO_MEM(T,F) double T = do_mem(#F, (MEMF)F, rv, nr, count, argv[a], exp)
#           define DO_STR(T,F) double T = do_str(#F, (STRF)F, rv, nr, count, argv[a], exp)
        DO_STR(tbase, strstr);
        //DO_STR(tsse2, sse2str);
        //DO_STR(tberg, bergstr);
        //DO_STR(twins, winstr);
        DO_MEM(tbndm, bndmem);
        DO_MEM(trg7g, Railgun7g);
        DO_MEM(trg7w, Railgun7w);
#           undef  DO_MEM
#           undef  DO_STR
        //if (verbose) printf("%4.0f %4.0f %4.0f %4.0f %4.0f %4.0f P=%d '%s'\n",
        if (verbose) printf("%7.2f %7.2f %7.2f P=%d '%s'\n",
               //tsse2 * 100 / tbase,
               //tberg * 100 / tbase,
               //twins * 100 / tbase,
               tbndm * 100 / tbase,
               trg7g * 100 / tbase,
               trg7w * 100 / tbase,
               patlen, argv[a]);
    }

    free(rv);
    buffree(x);

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq 0x8b20(%rip), %rax      # 0xbfc0
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %ecx
movl $0x1, %edx
movq %rcx, %rsi
callq 0x3030
movl $0x2711, -0x14(%rbp)    # imm = 0x2711
cmpl $0x4, -0x8(%rbp)
jge 0x34cd
leaq 0x5b48(%rip), %rdi      # 0x9010
callq 0x3760
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
leaq 0x5c0c(%rip), %rsi      # 0x90e8
callq 0x3270
cmpl $0x0, %eax
setne %al
xorb $-0x1, %al
andb $0x1, %al
movzbl %al, %ecx
movl %ecx, 0x9390(%rip)      # 0xc884
movq -0x10(%rbp), %rax
movslq %ecx, %rcx
shlq $0x3, %rcx
addq %rcx, %rax
movq %rax, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x7360
movq %rax, -0x40(%rbp)
movq %rdx, -0x38(%rbp)
movq -0x40(%rbp), %rdi
movq -0x38(%rbp), %rsi
callq 0x6890
movq %rax, -0x30(%rbp)
movq %rdx, -0x28(%rbp)
movq -0x30(%rbp), %rdi
movq -0x28(%rbp), %rsi
callq 0x37b0
cmpl $0x0, %eax
je 0x3558
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
leaq 0x5b9a(%rip), %rdi      # 0x90eb
movb $0x0, %al
callq 0x6920
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x32d0
orl $0x1, %eax
movl %eax, -0x14(%rbp)
movq -0x30(%rbp), %rdi
movl $0xa, %esi
leaq -0x1c(%rbp), %rdx
callq 0x7110
movq %rax, -0x48(%rbp)
movslq -0x1c(%rbp), %rdi
shlq $0x3, %rdi
callq 0x3250
movq %rax, -0x50(%rbp)
cmpl $0x0, 0x92eb(%rip)      # 0xc884
je 0x35ad
movq -0x28(%rbp), %rsi
leaq 0x5b57(%rip), %rdi      # 0x90fd
movb $0x0, %al
callq 0x3050
movl $0x3, -0x20(%rbp)
movq -0x10(%rbp), %rax
movslq -0x20(%rbp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0x3739
movq -0x10(%rbp), %rax
movslq -0x20(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
callq 0x30b0
movl %eax, -0x18(%rbp)
movq -0x50(%rbp), %rdi
movslq -0x1c(%rbp), %rdx
shlq $0x3, %rdx
movl $0xff, %esi
callq 0x30f0
movq -0x48(%rbp), %rdx
movl -0x1c(%rbp), %ecx
movl -0x14(%rbp), %r8d
movq -0x10(%rbp), %rax
movslq -0x20(%rbp), %rsi
movq (%rax,%rsi,8), %r9
movq -0x50(%rbp), %rax
leaq 0x5b0d(%rip), %rdi      # 0x9120
movq 0x89ae(%rip), %rsi      # 0xbfc8
movq %rax, (%rsp)
callq 0x37d0
movsd %xmm0, -0x58(%rbp)
movq -0x48(%rbp), %rdx
movl -0x1c(%rbp), %ecx
movl -0x14(%rbp), %r8d
movq -0x10(%rbp), %rax
movslq -0x20(%rbp), %rsi
movq (%rax,%rsi,8), %r9
movq -0x50(%rbp), %rax
leaq 0x5add(%rip), %rdi      # 0x9127
leaq 0x6ff(%rip), %rsi       # 0x3d50
movq %rax, (%rsp)
callq 0x3a80
movsd %xmm0, -0x60(%rbp)
movq -0x48(%rbp), %rdx
movl -0x1c(%rbp), %ecx
movl -0x14(%rbp), %r8d
movq -0x10(%rbp), %rax
movslq -0x20(%rbp), %rsi
movq (%rax,%rsi,8), %r9
movq -0x50(%rbp), %rax
leaq 0x5aad(%rip), %rdi      # 0x912e
leaq 0xc98(%rip), %rsi       # 0x4320
movq %rax, (%rsp)
callq 0x3a80
movsd %xmm0, -0x68(%rbp)
movq -0x48(%rbp), %rdx
movl -0x1c(%rbp), %ecx
movl -0x14(%rbp), %r8d
movq -0x10(%rbp), %rax
movslq -0x20(%rbp), %rsi
movq (%rax,%rsi,8), %r9
movq -0x50(%rbp), %rax
leaq 0x5a80(%rip), %rdi      # 0x9138
leaq 0x1351(%rip), %rsi      # 0x4a10
movq %rax, (%rsp)
callq 0x3a80
movsd %xmm0, -0x70(%rbp)
cmpl $0x0, 0x91b0(%rip)      # 0xc884
je 0x3729
movsd 0x592a(%rip), %xmm0     # 0x9008
mulsd -0x60(%rbp), %xmm0
divsd -0x58(%rbp), %xmm0
movsd 0x5918(%rip), %xmm1     # 0x9008
mulsd -0x68(%rbp), %xmm1
divsd -0x58(%rbp), %xmm1
movsd 0x5906(%rip), %xmm2     # 0x9008
mulsd -0x70(%rbp), %xmm2
divsd -0x58(%rbp), %xmm2
movl -0x18(%rbp), %esi
movq -0x10(%rbp), %rax
movslq -0x20(%rbp), %rcx
movq (%rax,%rcx,8), %rdx
leaq 0x5a20(%rip), %rdi      # 0x9142
movb $0x3, %al
callq 0x3050
jmp 0x372b
movl -0x20(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x20(%rbp)
jmp 0x35b4
movq -0x48(%rbp), %rdi
callq 0x3220
movq -0x30(%rbp), %rdi
movq -0x28(%rbp), %rsi
callq 0x4b20
xorl %eax, %eax
addq $0x80, %rsp
popq %rbp
retq
nopw (%rax,%rax)