// File: /workspace/github_c_makefile_star2_O2/c-zhou[P]oatk/syncmer.c
// Function: process_kmer_cluster
static void process_kmer_cluster(uint128_t *scm, uint32_t n, syncmer_db_t *scm_db, sr_db_t *sr_db)
{
    int n_clus, *clus;
    MYMALLOC(clus, n);

    if (n == 1) {
        // no hash collision for sure
        n_clus = 1;
        clus[0] = 0;
    } else {
        int i, j, k, b, c, B, C, p0, p1, rev, res;
        uint8_t *kmer, *kmer_list;
        uint32_t n_s;
        uint64_t sid;
        size_t s;

        k = sr_db->k;
        B = (((k - 1) >> 3) + 1) << 3; // maxmum number bytes to hold syncmer 64bit aligned
        C = B >> 3; // number of comparsions of 64bit interger
        n_clus = 0;
        kmer_list = 0;
        MYMALLOC(kmer, B);

        for (s = 0; s < n; ++s) {
            sid = (uint64_t) scm[s] >> 32;
            n_s = (uint32_t) ((uint64_t) scm[s]) >> 1;
            rev = scm[s] & 1;
            p0 = sr_db->a[sid].m_pos[n_s] >> 1;
            p1 = p0 + k - 1;
            res = rev? ((p1&3)^3)<<1 : (p0&3)<<1;
            b = p1 / 4 - p0 / 4 + 1; // actual number bytes holding syncmer
            memcpy(kmer, sr_db->a[sid].hoco_s + p0 / 4, b);
            // do reverse complementary
            if (rev) {
                for (i = 0, j = b - 1; i < j; ++i, --j) {
                    c = kmer[i];
                    kmer[i] = comp_seq8_table[kmer[j]];
                    kmer[j] = comp_seq8_table[c];
                }
                if (i == j) kmer[i] = comp_seq8_table[kmer[i]];
            }
            // do bit shift to align syncmer bytes
            for (i = 0; i < b - 1; ++i) {
                kmer[i] <<= res;
                kmer[i] |= kmer[i+1] >> (8-res);
            }
            kmer[b-1] <<= res;
            // real bytes
            b = (k - 1) / 4 + 1;
            // mask the lower bits
            kmer[b-1] &= lmask[k&3];
            // mask the remaining bytes
            MYBZERO(&kmer[b], B - b);
            // compare to the existing kmers to find hash collision
            for (i = 0; i < n_clus; ++i)
                if (equal_array(kmer, &kmer_list[i * B], C))
                    break;
            clus[s] = i;
            if (i >= n_clus) {
                // new kmer
                // add to kmer list
                ++n_clus;
                MYREALLOC(kmer_list, n_clus * B);
                memcpy(&kmer_list[(n_clus - 1) * B], kmer, B);
            }
        }
#ifdef DEBUG_CHECK_HASH_COLLISION
        uint64_t h64 = (uint64_t) (scm[0] >> 64);
        for (i = 0; i < n_clus; ++i)
            assert(h64 == MurmurHash64A(&kmer_list[i * B], (k - 1) / 4 + 1, murmur3_seed));
#endif
        free(kmer);
        free(kmer_list);
    }

    // add each cluster to syncmer database
    uint32_t s, *cnts;
    MYCALLOC(cnts, n_clus);
    for (s = 0; s < n; ++s)
        ++cnts[clus[s]];

    syncmer_t *syncmer;
    int i;
    for (i = 0; i < n_clus; ++i) {
        kv_pushp(syncmer_t, *scm_db, &syncmer);
        syncmer->h = (uint64_t) (scm[0] >> 64);
        syncmer->s = UINT64_MAX; // UINT64_MAX cannot be a smer as the first bit of smer is always zero
        syncmer->cov = 0;
        syncmer->del = 0;
        MYMALLOC(syncmer->m_pos, cnts[i]);
    }

    uint64_t smer;
    for (s = 0; s < n; ++s) {
        // update syncmer database
        syncmer = &scm_db->a[scm_db->n - n_clus + clus[s]];
        syncmer->m_pos[syncmer->cov++] = (uint64_t) scm[s];
        smer = sr_db->a[(uint64_t) scm[s] >> 32].s_mer[(uint32_t) ((uint64_t) scm[s]) >> 1];
        if (syncmer->s == UINT64_MAX) {
            syncmer->s = smer;
        } else if (syncmer->s != smer) {
            fprintf(stderr, "[E::%s] identical kmers have different smers\n", __func__);
            fprintf(stderr, "[E::%s] kmer hash  : %lu\n", __func__, syncmer->h);
            fprintf(stderr, "[E::%s] smer code 0: %lu; read id: %lu\n", __func__, syncmer->s, syncmer->m_pos[0] >> 32);
            fprintf(stderr, "[E::%s] smer code 1: %lu; read id: %lu\n", __func__, smer, (uint64_t) scm[s] >> 32);
            exit(EXIT_FAILURE);
        }
        // update read database
        sr_db->a[(uint64_t) scm[s] >> 32].k_mer[(uint32_t) ((uint64_t) scm[s]) >> 1] = (scm_db->n - n_clus + clus[s]) << 1;
    }

#ifdef DEBUG_CHECK_HASH_COLLISION
    if (n_clus > 1) {
        fprintf(stderr, "[DEBUG_CHECK_HASH_COLLISION::%s] hash collision: hash = %lu; clus = %d\n", 
                __func__, (uint64_t) (scm[0] >> 64), n_clus);
        for (i = 0; i < n_clus; ++i)
            fprintf(stderr, "[DEBUG_CHECK_HASH_COLLISION::%s] clus %d: read id %lu\n", 
                    __func__, i, scm_db->a[scm_db->n - n_clus + i].m_pos[0] >> 32);
    }
#endif    

    free(cnts);
    free(clus);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rcx, %r15
movq %rdx, 0x20(%rsp)
movl %esi, %ebp
movq %rdi, 0x18(%rsp)
movl %esi, %r14d
leaq (,%r14,4), %rdi
movq %rdi, 0x70(%rsp)
callq 0x2310
cmpl $0x1, %ebp
movq %r15, 0x40(%rsp)
movq %rax, 0x10(%rsp)
jne 0xc3e4
movq %rax, %rbx
pushq $0x1
popq %rax
andl $0x0, (%rbx)
jmp 0xc66e
movl 0x18(%r15), %r13d
leal -0x1(%r13), %ebx
movl %ebx, %eax
andl $-0x8, %eax
movq %rax, 0x8(%rsp)
leal 0x8(%rax), %r12d
movslq %r12d, %rdi
sarl $0x3, %r12d
movq %rdi, 0x38(%rsp)
callq 0x2310
movq %rax, %rbp
pushq $0x4
popq %rcx
movl %ebx, 0x34(%rsp)
movl %ebx, %eax
cltd
idivl %ecx
andl $0x3, %r13d
movq %r13, 0x60(%rsp)
cltq
leaq (%rax,%rbp), %rcx
incq %rcx
movq %rcx, 0x50(%rsp)
movq %rax, 0x58(%rsp)
notl %eax
movq 0x8(%rsp), %rcx
addl %ecx, %eax
addl $0x8, %eax
cltq
movq %rax, 0x48(%rsp)
xorl %ecx, %ecx
testl %r12d, %r12d
movl $0x0, %eax
movq %rax, (%rsp)
cmovlel %ecx, %r12d
xorl %eax, %eax
xorl %r9d, %r9d
movq %r14, 0x68(%rsp)
movq %r9, 0x8(%rsp)
cmpq %r14, %rax
je 0xc653
movq %rax, 0x28(%rsp)
shlq $0x4, %rax
movq 0x18(%rsp), %rcx
movq (%rcx,%rax), %rbx
movq %rbx, %rax
shrq $0x20, %rax
movl %ebx, %ecx
shrl %ecx
movq 0x10(%r15), %rsi
imulq $0x58, %rax, %rdi
movq 0x40(%rsi,%rdi), %rax
movl (%rax,%rcx,4), %ecx
movl %ecx, %eax
shrl %eax
addl 0x34(%rsp), %eax
movl %eax, %r15d
notl %r15d
addl %r15d, %r15d
andl $0x6, %r15d
movl %ecx, %r13d
andl $0x6, %r13d
cltd
pushq $0x4
popq %r8
idivl %r8d
movl %eax, %r14d
shrl $0x3, %ecx
subl %ecx, %r14d
leal 0x1(%r14), %eax
movq 0x18(%rsi,%rdi), %rsi
addq %rcx, %rsi
movslq %eax, %rdx
movq %rbp, %rdi
callq 0x22b0
testb $0x1, %bl
cmovnel %r15d, %r13d
je 0xc535
movslq %r14d, %rcx
xorl %eax, %eax
leaq 0xe0c7(%rip), %rdi      # 0x1a5c0
cmpq %rcx, %rax
jge 0xc520
movzbl (%rbp,%rax), %edx
movzbl (%rbp,%rcx), %esi
movb (%rsi,%rdi), %sil
movb %sil, (%rbp,%rax)
movb (%rdx,%rdi), %dl
movb %dl, (%rbp,%rcx)
incq %rax
decq %rcx
jmp 0xc4f9
jne 0xc535
movzbl (%rbp,%rax), %ecx
leaq 0xe092(%rip), %rdx      # 0x1a5c0
movb (%rcx,%rdx), %cl
movb %cl, (%rbp,%rax)
testl %r14d, %r14d
movl $0x0, %eax
cmovgl %r14d, %eax
xorl %edx, %edx
movq 0x40(%rsp), %r15
cmpq %rdx, %rax
je 0xc56a
movzbl 0x1(%rbp,%rdx), %ecx
movzbl (%rbp,%rdx), %ebx
shll $0x8, %ebx
orl %ecx, %ebx
movl %r13d, %ecx
shll %cl, %ebx
movb %bh, (%rbp,%rdx)
incq %rdx
jmp 0xc548
movslq %r14d, %rax
movzbl (%rbp,%rax), %edx
movl %r13d, %ecx
shll %cl, %edx
movb %dl, (%rbp,%rax)
movq 0x60(%rsp), %rax
leaq 0xe139(%rip), %rcx      # 0x1a6c0
movb (%rax,%rcx), %al
movq 0x58(%rsp), %rcx
andb %al, (%rbp,%rcx)
movq 0x50(%rsp), %rdi
xorl %esi, %esi
movq 0x48(%rsp), %rdx
callq 0x21e0
movq 0x8(%rsp), %r9
testl %r9d, %r9d
movl $0x0, %eax
cmovgl %r9d, %eax
movq (%rsp), %rdx
xorl %ecx, %ecx
movq 0x68(%rsp), %r14
cmpq %rax, %rcx
je 0xc600
xorl %esi, %esi
cmpq %rsi, %r12
je 0xc5e8
movq (%rbp,%rsi,8), %rdi
leaq 0x1(%rsi), %r8
cmpq (%rdx,%rsi,8), %rdi
movq %r8, %rsi
je 0xc5c7
incq %rcx
addq 0x38(%rsp), %rdx
jmp 0xc5c0
movq 0x10(%rsp), %rax
movq 0x28(%rsp), %rdx
movl %ecx, (%rax,%rdx,4)
movq %rdx, %rax
incq %rax
jmp 0xc465
movq 0x10(%rsp), %rcx
movq 0x28(%rsp), %rdx
movl %eax, (%rcx,%rdx,4)
leal 0x1(%r9), %eax
movl %eax, 0x30(%rsp)
movq 0x38(%rsp), %rbx
imull %ebx, %eax
movslq %eax, %rsi
movq (%rsp), %rdi
movq %r9, %r13
callq 0x2350
imull %ebx, %r13d
movslq %r13d, %rdi
movq %rax, (%rsp)
addq %rax, %rdi
movq %rbp, %rsi
movq %rbx, %rdx
callq 0x22b0
movq 0x28(%rsp), %rax
movl 0x30(%rsp), %ecx
movl %ecx, %r9d
jmp 0xc5f8
movq %rbp, %rdi
callq 0x2060
movq (%rsp), %rdi
callq 0x2060
movq 0x10(%rsp), %rbx
movq 0x8(%rsp), %rax
movq %rax, %r12
movslq %eax, %r13
pushq $0x4
popq %rsi
movq %r13, %rdi
callq 0x2250
movq %rax, %rbp
xorl %eax, %eax
movq 0x20(%rsp), %rdx
cmpq %rax, %r14
je 0xc69b
movslq (%rbx,%rax,4), %rcx
incl (%rbp,%rcx,4)
incq %rax
jmp 0xc689
xorl %ebx, %ebx
testl %r12d, %r12d
cmovlel %ebx, %r12d
cmpq %rbx, %r12
je 0xc72f
movq (%rdx), %r15
movq 0x10(%rdx), %r14
cmpq 0x8(%rdx), %r15
jne 0xc6e7
leaq (%r15,%r15), %rsi
testq %r15, %r15
pushq $0x2
popq %rax
cmoveq %rax, %rsi
movq %rsi, 0x8(%rdx)
shlq $0x5, %rsi
movq %r14, %rdi
callq 0x2350
movq 0x20(%rsp), %rdx
movq %rax, %r14
movq %rax, 0x10(%rdx)
movq (%rdx), %r15
leaq 0x1(%r15), %rax
movq %rax, (%rdx)
shlq $0x5, %r15
movq 0x18(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, (%r14,%r15)
orq $-0x1, 0x8(%r14,%r15)
andl $0x0, 0x10(%r14,%r15)
movl (%rbp,%rbx,4), %edi
shlq $0x3, %rdi
callq 0x2310
movq 0x20(%rsp), %rdx
movq %rax, 0x18(%r14,%r15)
incq %rbx
movq 0x40(%rsp), %r15
jmp 0xc6a4
xorl %ebx, %ebx
movq 0x18(%rsp), %r11
cmpq %rbx, 0x70(%rsp)
movq 0x10(%rsp), %r14
je 0xc7ee
movq (%rdx), %rcx
subq %r13, %rcx
movslq (%r14,%rbx), %rax
shlq $0x5, %rcx
addq 0x10(%rdx), %rcx
movq %rax, %rdx
shlq $0x5, %rdx
leaq (%rcx,%rdx), %r12
movq (%r11,%rbx,4), %rsi
movq 0x18(%rdx,%rcx), %rdi
movl 0x10(%rdx,%rcx), %r8d
movl %r8d, %r9d
andl $0x7fffffff, %r9d       # imm = 0x7FFFFFFF
leal 0x1(%r8), %r10d
andl $0x7fffffff, %r10d      # imm = 0x7FFFFFFF
andl $0x80000000, %r8d       # imm = 0x80000000
orl %r10d, %r8d
movl %r8d, 0x10(%rdx,%rcx)
movq %rsi, (%rdi,%r9,8)
movq 0x10(%r15), %rsi
movq (%r11,%rbx,4), %rdi
movq %rdi, %r8
shrq $0x20, %r8
imulq $0x58, %r8, %r8
movq 0x48(%rsi,%r8), %r9
shrl %edi
movq (%r9,%rdi,8), %r14
movq 0x8(%rdx,%rcx), %rcx
cmpq $-0x1, %rcx
je 0xc7c9
cmpq %r14, %rcx
je 0xc7ce
jmp 0xc80c
movq %r14, 0x8(%r12)
subq %r13, %rax
movq 0x20(%rsp), %rdx
addq (%rdx), %rax
addq %rax, %rax
movq 0x50(%rsi,%r8), %rcx
movq %rax, (%rcx,%rdi,8)
addq $0x4, %rbx
jmp 0xc736
movq %rbp, %rdi
callq 0x2060
movq %r14, %rdi
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2060
movq 0x147dd(%rip), %r13     # 0x20ff0
movq (%r13), %rdi
leaq 0xdce7(%rip), %rsi      # 0x1a505
leaq 0xdd0e(%rip), %r15      # 0x1a533
movq %r15, %rdx
xorl %eax, %eax
callq 0x2280
movq (%r13), %rdi
movq (%r12), %rcx
leaq 0xdd0a(%rip), %rsi      # 0x1a548
movq %r15, %rdx
xorl %eax, %eax
callq 0x2280
movq (%r13), %rdi
movq 0x8(%r12), %rcx
movq 0x18(%r12), %rax
movl 0x4(%rax), %r8d
leaq 0xdd01(%rip), %rsi      # 0x1a562
movq %r15, %rdx
xorl %eax, %eax
callq 0x2280
movq (%r13), %rdi
movq 0x18(%rsp), %rax
movl 0x4(%rax,%rbx,4), %r8d
leaq 0xdd0a(%rip), %rsi      # 0x1a58a
movq %r15, %rdx
movq %r14, %rcx
xorl %eax, %eax
callq 0x2280
pushq $0x1
popq %rdi
callq 0x2440