// File: ctSkennerton[P]fxtract/util/ssearch.c
// Function: ssearch_create
SSEARCH*
ssearch_create(const MEMREF strv[], int nstrs)
{
    int         i, j, cum, nsyms, nsuffixes, suflen;
    const char  *suffix;

    for (i = 0, suflen = 8 * sizeof(MASK); i < nstrs; ++i)
        if (suflen > (int)strv[i].len)
            suflen = strv[i].len;

    if (suflen < 2)
        return NULL;

    SSEARCH        *ssp = calloc(1, sizeof(*ssp));
    ssp->strv   = strv;
    ssp->nstrs  = nstrs;
    ssp->suflen = suflen;

    // Find all distinct bytevals that occur in suffixes
    for (i = nstrs; --i >= 0;)
        for (j = suflen + 1; --j > 0;)
            ssp->symv[(uint8_t)strv[i].ptr[strv[i].len - j]]=1;

    // Create a map from [0..255] to [NONSYM,0..nsyms-1]
    for (i = nsyms = 0; i < 256; ++i)
        ssp->symv[i] = ssp->symv[i] ? nsyms++ : NONSYM;

    // Calculate column count of mapv[][]: a power of 2
    for (ssp->symwid = 1; (1 << ssp->symwid) < nsyms;)
         ++ssp->symwid;

    // Set mapv[][] for each adj pair of bytes in suffixes
    const MASK bits        = (1 << (ssp->suflen - 1)) - 1;
    const int  mapmask  = (1 << 2*ssp->symwid) - 1;

    ssp->mapv   = calloc(nsyms << ssp->symwid, sizeof(MASK));
    for (i = 0 ; i < nstrs; ++i) {
        const char *cp = strv[i].ptr + strv[i].len;
        int            symsym = ssp->symv[(uint8_t)*--cp];
        MASK        mask;

        for (mask = 1; mask & bits; mask <<= 1) {
            int            sym = ssp->symv[(uint8_t)*--cp];
            symsym = ((symsym << ssp->symwid) | sym) & mapmask;
            ssp->mapv[symsym] |= mask;
        }
    }

        // Map each unique suffix to a set of strings

    // Count #(unique suffixes) and #(strings per suffix)
    ssp->suffixh = map_create( (map_diff*)memcmp, 
                                (map_hash*)fnv04, 
                                    VOIDP(ssp->suflen));
    int                *locp, *locv = calloc(nstrs, sizeof(int));
    for (i = nsuffixes = 0; i < nstrs; ++i) {
        suffix        = strv[i].ptr + strv[i].len - ssp->suflen;
        locp = map_get(ssp->suffixh, suffix);
        if (!locp) {
            locp = &locv[nsuffixes++];
            map_set(ssp->suffixh, suffix, locp);
        }
        ++*locp;
    }

    // Convert sublist lengths to sublist offsets in prefixv[].
    // Pre-mark list-ends.
    ssp->prefixv = calloc(nstrs + nsuffixes, sizeof(int));
    for (i = cum = 0; i < nsuffixes; ++i) {
        locv[i] = cum += locv[i] + 1;
        ssp->prefixv[--locv[i]] = NONSTR;
    }

    // Populate lists in prefixv[]
    for (i = nstrs; --i >= 0;) {
        suffix = strv[i].ptr + strv[i].len - ssp->suflen;
        locp = map_get(ssp->suffixh, suffix);
        ssp->prefixv[--*locp] = i;
    }

    // Convert map values from (list**) to (list*)
    map_start(ssp->suffixh); 
    while (map_next(ssp->suffixh, VOIDP(&suffix),
                        VOIDP(&locp))) {
        map_set(ssp->suffixh, suffix, &ssp->prefixv[*locp]);
    }

    free(locv);
    return    ssp;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movl $0x0, -0x18(%rbp)
movl $0x10, -0x2c(%rbp)
movl -0x18(%rbp), %eax
cmpl -0x14(%rbp), %eax
jge 0x5c35
movl -0x2c(%rbp), %eax
movq -0x10(%rbp), %rcx
movslq -0x18(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rcx
movq 0x8(%rcx), %rcx
cmpl %ecx, %eax
jle 0x5c28
movq -0x10(%rbp), %rax
movslq -0x18(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rax
movl %eax, -0x2c(%rbp)
jmp 0x5c2a
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
jmp 0x5bf0
cmpl $0x2, -0x2c(%rbp)
jge 0x5c48
movq $0x0, -0x8(%rbp)
jmp 0x60f2
movl $0x1, %edi
movl $0x230, %esi            # imm = 0x230
callq 0x3100
movq %rax, -0x40(%rbp)
movq -0x10(%rbp), %rcx
movq -0x40(%rbp), %rax
movq %rcx, (%rax)
movl -0x14(%rbp), %ecx
movq -0x40(%rbp), %rax
movl %ecx, 0x8(%rax)
movl -0x2c(%rbp), %ecx
movq -0x40(%rbp), %rax
movl %ecx, 0xc(%rax)
movl -0x14(%rbp), %eax
movl %eax, -0x18(%rbp)
movl -0x18(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x18(%rbp)
cmpl $0x0, %eax
jl 0x5ce4
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x1c(%rbp)
cmpl $0x0, %eax
jle 0x5ce2
movq -0x40(%rbp), %rax
movq -0x10(%rbp), %rcx
movslq -0x18(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rcx
movq (%rcx), %rcx
movq -0x10(%rbp), %rdx
movslq -0x18(%rbp), %rsi
shlq $0x4, %rsi
addq %rsi, %rdx
movq 0x8(%rdx), %rdx
movslq -0x1c(%rbp), %rsi
subq %rsi, %rdx
movzbl (%rcx,%rdx), %ecx
movw $0x1, 0x2c(%rax,%rcx,2)
jmp 0x5c97
jmp 0x5c80
movl $0x0, -0x24(%rbp)
movl $0x0, -0x18(%rbp)
cmpl $0x100, -0x18(%rbp)     # imm = 0x100
jge 0x5d45
movq -0x40(%rbp), %rax
movslq -0x18(%rbp), %rcx
movswl 0x2c(%rax,%rcx,2), %eax
cmpl $0x0, %eax
je 0x5d1d
movl -0x24(%rbp), %eax
movl %eax, %ecx
addl $0x1, %ecx
movl %ecx, -0x24(%rbp)
movl %eax, -0x74(%rbp)
jmp 0x5d27
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movl %eax, -0x74(%rbp)
jmp 0x5d27
movl -0x74(%rbp), %eax
movw %ax, %dx
movq -0x40(%rbp), %rax
movslq -0x18(%rbp), %rcx
movw %dx, 0x2c(%rax,%rcx,2)
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
jmp 0x5cf2
movq -0x40(%rbp), %rax
movl $0x1, 0x28(%rax)
movq -0x40(%rbp), %rax
movl 0x28(%rax), %ecx
movl $0x1, %eax
shll %cl, %eax
cmpl -0x24(%rbp), %eax
jge 0x5d72
movq -0x40(%rbp), %rax
movl 0x28(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x28(%rax)
jmp 0x5d50
movq -0x40(%rbp), %rax
movl 0xc(%rax), %ecx
subl $0x1, %ecx
movl $0x1, %eax
shll %cl, %eax
subl $0x1, %eax
movw %ax, -0x42(%rbp)
movq -0x40(%rbp), %rax
movl 0x28(%rax), %ecx
shll %ecx
movl $0x1, %eax
shll %cl, %eax
subl $0x1, %eax
movl %eax, -0x48(%rbp)
movl -0x24(%rbp), %eax
movq -0x40(%rbp), %rcx
movl 0x28(%rcx), %ecx
shll %cl, %eax
movslq %eax, %rdi
movl $0x2, %esi
callq 0x3100
movq %rax, %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x10(%rax)
movl $0x0, -0x18(%rbp)
movl -0x18(%rbp), %eax
cmpl -0x14(%rbp), %eax
jge 0x5e9e
movq -0x10(%rbp), %rax
movslq -0x18(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rax
movq -0x10(%rbp), %rcx
movslq -0x18(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rcx
addq 0x8(%rcx), %rax
movq %rax, -0x50(%rbp)
movq -0x40(%rbp), %rax
movq -0x50(%rbp), %rcx
movq %rcx, %rdx
addq $-0x1, %rdx
movq %rdx, -0x50(%rbp)
movzbl -0x1(%rcx), %ecx
movswl 0x2c(%rax,%rcx,2), %eax
movl %eax, -0x54(%rbp)
movw $0x1, -0x56(%rbp)
movzwl -0x56(%rbp), %eax
movzwl -0x42(%rbp), %ecx
andl %ecx, %eax
cmpl $0x0, %eax
je 0x5e8e
movq -0x40(%rbp), %rax
movq -0x50(%rbp), %rcx
movq %rcx, %rdx
addq $-0x1, %rdx
movq %rdx, -0x50(%rbp)
movzbl -0x1(%rcx), %ecx
movswl 0x2c(%rax,%rcx,2), %eax
movl %eax, -0x5c(%rbp)
movl -0x54(%rbp), %eax
movq -0x40(%rbp), %rcx
movl 0x28(%rcx), %ecx
shll %cl, %eax
orl -0x5c(%rbp), %eax
andl -0x48(%rbp), %eax
movl %eax, -0x54(%rbp)
movzwl -0x56(%rbp), %esi
movq -0x40(%rbp), %rax
movq 0x10(%rax), %rax
movslq -0x54(%rbp), %rcx
movzwl (%rax,%rcx,2), %edx
orl %esi, %edx
movw %dx, (%rax,%rcx,2)
movzwl -0x56(%rbp), %eax
shll %eax
movw %ax, -0x56(%rbp)
jmp 0x5e25
jmp 0x5e90
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
jmp 0x5dcb
movq -0x40(%rbp), %rax
movslq 0xc(%rax), %rdx
movq 0x611b(%rip), %rdi      # 0xbfc8
leaq 0x86c(%rip), %rsi       # 0x6720
callq 0x6be0
movq %rax, %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x18(%rax)
movslq -0x14(%rbp), %rdi
movl $0x4, %esi
callq 0x3100
movq %rax, -0x70(%rbp)
movl $0x0, -0x28(%rbp)
movl $0x0, -0x18(%rbp)
movl -0x18(%rbp), %eax
cmpl -0x14(%rbp), %eax
jge 0x5f90
movq -0x10(%rbp), %rax
movslq -0x18(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rax
movq -0x10(%rbp), %rcx
movslq -0x18(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rcx
addq 0x8(%rcx), %rax
movq -0x40(%rbp), %rcx
movslq 0xc(%rcx), %rdx
xorl %ecx, %ecx
subq %rdx, %rcx
addq %rcx, %rax
movq %rax, -0x38(%rbp)
movq -0x40(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x38(%rbp), %rsi
callq 0x6f30
movq %rax, -0x68(%rbp)
cmpq $0x0, -0x68(%rbp)
jne 0x5f77
movq -0x70(%rbp), %rax
movl -0x28(%rbp), %ecx
movl %ecx, %edx
addl $0x1, %edx
movl %edx, -0x28(%rbp)
movslq %ecx, %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0x68(%rbp)
movq -0x40(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x38(%rbp), %rsi
movq -0x68(%rbp), %rdx
callq 0x7320
movq -0x68(%rbp), %rax
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
jmp 0x5ee4
movl -0x14(%rbp), %eax
addl -0x28(%rbp), %eax
movslq %eax, %rdi
movl $0x4, %esi
callq 0x3100
movq %rax, %rcx
movq -0x40(%rbp), %rax
movq %rcx, 0x20(%rax)
movl $0x0, -0x20(%rbp)
movl $0x0, -0x18(%rbp)
movl -0x18(%rbp), %eax
cmpl -0x28(%rbp), %eax
jge 0x6011
movq -0x70(%rbp), %rax
movslq -0x18(%rbp), %rcx
movl (%rax,%rcx,4), %edx
addl $0x1, %edx
addl -0x20(%rbp), %edx
movl %edx, -0x20(%rbp)
movq -0x70(%rbp), %rax
movslq -0x18(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movq -0x40(%rbp), %rax
movq 0x20(%rax), %rax
movq -0x70(%rbp), %rdx
movslq -0x18(%rbp), %rsi
movl (%rdx,%rsi,4), %ecx
addl $-0x1, %ecx
movl %ecx, (%rdx,%rsi,4)
movslq %ecx, %rcx
movl $0xffffffff, (%rax,%rcx,4) # imm = 0xFFFFFFFF
movl -0x18(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x18(%rbp)
jmp 0x5fbc
movl -0x14(%rbp), %eax
movl %eax, -0x18(%rbp)
movl -0x18(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x18(%rbp)
cmpl $0x0, %eax
jl 0x6091
movq -0x10(%rbp), %rax
movslq -0x18(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rax
movq -0x10(%rbp), %rcx
movslq -0x18(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rcx
addq 0x8(%rcx), %rax
movq -0x40(%rbp), %rcx
movslq 0xc(%rcx), %rdx
xorl %ecx, %ecx
subq %rdx, %rcx
addq %rcx, %rax
movq %rax, -0x38(%rbp)
movq -0x40(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x38(%rbp), %rsi
callq 0x6f30
movq %rax, -0x68(%rbp)
movl -0x18(%rbp), %edx
movq -0x40(%rbp), %rax
movq 0x20(%rax), %rax
movq -0x68(%rbp), %rsi
movl (%rsi), %ecx
addl $-0x1, %ecx
movl %ecx, (%rsi)
movslq %ecx, %rcx
movl %edx, (%rax,%rcx,4)
jmp 0x6017
movq -0x40(%rbp), %rax
movq 0x18(%rax), %rdi
callq 0x7450
movq -0x40(%rbp), %rax
movq 0x18(%rax), %rdi
leaq -0x38(%rbp), %rsi
leaq -0x68(%rbp), %rdx
callq 0x6fd0
cmpl $0x0, %eax
je 0x60e1
movq -0x40(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x38(%rbp), %rsi
movq -0x40(%rbp), %rax
movq 0x20(%rax), %rdx
movq -0x68(%rbp), %rax
movslq (%rax), %rax
shlq $0x2, %rax
addq %rax, %rdx
callq 0x7320
jmp 0x609e
movq -0x70(%rbp), %rdi
callq 0x3200
movq -0x40(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x80, %rsp
popq %rbp
retq
nop