// File: /workspace/github_c_makefile_star2_O1/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 $0x88, %rsp
movq %rcx, %r12
movq %rdx, %rbx
movl %esi, %ebp
movq %rdi, %r15
movl %esi, %eax
movq %rax, 0x48(%rsp)
leaq (,%rax,4), %rdi
callq 0x2320
cmpl $0x1, %ebp
movq %r15, 0x40(%rsp)
movq %r12, 0x58(%rsp)
movq %rbx, 0x10(%rsp)
movq %rax, 0x38(%rsp)
movl %ebp, 0x2c(%rsp)
jne 0xf1fb
movq %rax, %r14
movl $0x0, (%rax)
movl $0x1, %eax
jmp 0xf503
movl 0x18(%r12), %eax
movq %rax, 0x20(%rsp)
leal -0x1(%rax), %ebx
movl %ebx, %r14d
andl $-0x8, %r14d
addl $0x8, %r14d
movslq %r14d, %rdi
movq %rdi, 0x60(%rsp)
callq 0x2320
movq %rax, %r13
testl %ebp, %ebp
je 0xf4d0
movl %r14d, %ebp
sarl $0x3, %ebp
movq 0x20(%rsp), %rdx
leal -0x1(%rdx), %eax
movq %rax, 0x80(%rsp)
leal 0x3(%rbx), %eax
testl %ebx, %ebx
cmovnsl %ebx, %eax
sarl $0x2, %eax
andl $0x3, %edx
leaq 0xf41a(%rip), %rcx      # 0x1e670
movb (%rdx,%rcx), %cl
movb %cl, 0xf(%rsp)
movslq %eax, %rcx
leaq 0x1(%rcx,%r13), %rax
movq %rax, 0x70(%rsp)
movq %rcx, %rax
movq %rcx, 0x78(%rsp)
notl %eax
addl %r14d, %eax
cltq
movq %rax, 0x68(%rsp)
movq $0x0, 0x30(%rsp)
xorl %ecx, %ecx
movq $0x0, 0x18(%rsp)
movl %r14d, 0x54(%rsp)
movq %rcx, 0x20(%rsp)
movq %rcx, %rax
shlq $0x4, %rax
movq (%r15,%rax), %rbx
movq %rbx, %rcx
shrq $0x20, %rcx
movl %ebx, %edx
shrl %edx
movq 0x10(%r12), %rax
imulq $0x58, %rcx, %rcx
movq 0x40(%rax,%rcx), %rsi
movl (%rsi,%rdx,4), %edx
movl %edx, %esi
shrl %esi
movq 0x80(%rsp), %r8
leal (%r8,%rsi), %edi
movl %edi, %r15d
notl %r15d
addl %r15d, %r15d
andl $0x6, %r15d
movl %edx, %r14d
andl $0x6, %r14d
leal (%r8,%rsi), %r12d
addl $0x3, %r12d
testl %edi, %edi
cmovnsl %edi, %r12d
sarl $0x2, %r12d
shrl $0x3, %edx
subl %edx, %r12d
leal 0x1(%r12), %edi
movq 0x18(%rax,%rcx), %rsi
addq %rdx, %rsi
movslq %edi, %rdx
movq %r13, %rdi
callq 0x22c0
testb $0x1, %bl
cmovnel %r15d, %r14d
leaq 0xf24b(%rip), %r8       # 0x1e570
je 0xf37b
testl %r12d, %r12d
jle 0xf361
movl %r12d, %ecx
movq %rcx, %rdx
xorl %eax, %eax
movzbl (%r13,%rax), %esi
movzbl (%r13,%rdx), %edi
movb (%rdi,%r8), %dil
movb %dil, (%r13,%rax)
movb (%rsi,%r8), %sil
movb %sil, (%r13,%rdx)
incq %rax
decq %rdx
cmpq %rdx, %rax
jl 0xf334
subl %eax, %ecx
jmp 0xf366
xorl %eax, %eax
movl %r12d, %ecx
cmpl %ecx, %eax
jne 0xf37b
movl %eax, %eax
movzbl (%r13,%rax), %ecx
movb (%rcx,%r8), %cl
movb %cl, (%r13,%rax)
testl %r12d, %r12d
jle 0xf3b7
movl $0x8, %eax
subl %r14d, %eax
movl %r12d, %edx
xorl %esi, %esi
movzbl (%r13,%rsi), %edi
movl %r14d, %ecx
shll %cl, %edi
movzbl 0x1(%r13,%rsi), %r8d
movl %eax, %ecx
shrl %cl, %r8d
orl %edi, %r8d
movb %r8b, (%r13,%rsi)
leaq 0x1(%rsi), %rcx
movq %rcx, %rsi
cmpq %rcx, %rdx
jne 0xf38d
movslq %r12d, %rax
movzbl (%r13,%rax), %edx
movl %r14d, %ecx
shll %cl, %edx
movb %dl, (%r13,%rax)
movb 0xf(%rsp), %al
movq 0x78(%rsp), %rcx
andb %al, (%r13,%rcx)
xorl %ebx, %ebx
movq 0x70(%rsp), %rdi
xorl %esi, %esi
movq 0x68(%rsp), %rdx
callq 0x21e0
movq 0x30(%rsp), %r11
testl %r11d, %r11d
setg %al
movq 0x40(%rsp), %r15
movq 0x58(%rsp), %r12
movq 0x38(%rsp), %r10
movl 0x54(%rsp), %r14d
jle 0xf44f
movl %r11d, %edx
movq 0x18(%rsp), %rsi
xorl %ecx, %ecx
movl %eax, %edi
testl %ebp, %ebp
jle 0xf4cc
xorl %r8d, %r8d
movq (%r13,%r8,8), %r9
cmpq (%rsi,%r8,8), %r9
jne 0xf438
incq %r8
cmpq %r8, %rbp
jne 0xf423
jmp 0xf45a
incq %rcx
cmpq %rdx, %rcx
setb %dil
addq 0x60(%rsp), %rsi
cmpq %rdx, %rcx
jne 0xf418
movl %r11d, %ebx
movq 0x20(%rsp), %rax
movl %ebx, (%r10,%rax,4)
jmp 0xf46e
movl %edi, %eax
movq 0x20(%rsp), %rdx
movl %ecx, (%r10,%rdx,4)
testb $0x1, %al
je 0xf46e
movq %rdx, %rcx
jmp 0xf4b7
leal 0x1(%r11), %ebx
movl %ebx, %eax
imull %r14d, %eax
movslq %eax, %rsi
movq 0x18(%rsp), %rdi
movq %r12, %r15
movq %r11, %r12
callq 0x2360
imull %r14d, %r12d
movslq %r12d, %rdi
movq %r15, %r12
movq 0x40(%rsp), %r15
movq %rax, 0x18(%rsp)
addq %rax, %rdi
movq %r13, %rsi
movq 0x60(%rsp), %rdx
callq 0x22c0
movq 0x20(%rsp), %rcx
movl %ebx, %r11d
movq %r11, 0x30(%rsp)
incq %rcx
cmpq 0x48(%rsp), %rcx
jne 0xf297
jmp 0xf4e2
xorl %ecx, %ecx
jmp 0xf45c
movq $0x0, 0x18(%rsp)
movq $0x0, 0x30(%rsp)
movq %r13, %rdi
callq 0x2060
movq 0x18(%rsp), %rdi
callq 0x2060
movq 0x10(%rsp), %rbx
movq 0x38(%rsp), %r14
movq 0x30(%rsp), %rax
movq %rax, %r15
movslq %eax, %r13
movl $0x4, %esi
movq %r13, %rdi
callq 0x2250
movq %rax, %rbp
cmpl $0x0, 0x2c(%rsp)
movq 0x48(%rsp), %rdx
je 0xf537
xorl %eax, %eax
movslq (%r14,%rax,4), %rcx
incl (%rbp,%rcx,4)
incq %rax
cmpq %rax, %rdx
jne 0xf527
testl %r15d, %r15d
jle 0xf5d6
xorl %r14d, %r14d
movl $0x2, %r12d
movq 0x8(%rbx), %rax
cmpq %rax, (%rbx)
jne 0xf572
leaq (%rax,%rax), %rsi
testq %rax, %rax
cmoveq %r12, %rsi
movq %rsi, 0x8(%rbx)
movq 0x10(%rbx), %rdi
shlq $0x5, %rsi
callq 0x2360
movq %rax, 0x10(%rbx)
movq 0x10(%rsp), %rax
movq (%rax), %rbx
movq 0x10(%rsp), %rax
movq 0x10(%rax), %r15
leaq 0x1(%rbx), %rax
movq 0x10(%rsp), %rcx
movq %rax, (%rcx)
shlq $0x5, %rbx
movq 0x40(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, (%r15,%rbx)
movq $-0x1, 0x8(%r15,%rbx)
movl $0x0, 0x10(%r15,%rbx)
movl (%rbp,%r14,4), %edi
shlq $0x3, %rdi
callq 0x2320
movq %rax, 0x18(%r15,%rbx)
movq 0x10(%rsp), %rbx
incq %r14
cmpq %r14, %r13
jne 0xf549
cmpl $0x0, 0x2c(%rsp)
movq 0x40(%rsp), %rdx
movq 0x58(%rsp), %r15
movq 0x48(%rsp), %r12
je 0xf6a1
xorl %eax, %eax
movq (%rbx), %rdi
subq %r13, %rdi
movq 0x38(%rsp), %rcx
movslq (%rcx,%rax,4), %r14
shlq $0x5, %rdi
addq 0x10(%rbx), %rdi
movq %r14, %r8
shlq $0x5, %r8
movq (%rdx), %rcx
leaq (%r8,%rdi), %rsi
addq $0x8, %rsi
movq 0x10(%rsi), %r9
movl 0x8(%rsi), %r10d
movl %r10d, %r11d
andl $0x7fffffff, %r11d      # imm = 0x7FFFFFFF
leal 0x1(%r10), %ebx
andl $0x7fffffff, %ebx       # imm = 0x7FFFFFFF
andl $0x80000000, %r10d      # imm = 0x80000000
orl %ebx, %r10d
movl %r10d, 0x8(%rsi)
movq %rcx, (%r9,%r11,8)
movq 0x10(%r15), %r9
movq (%rdx), %r10
movq %r10, %rcx
shrq $0x20, %rcx
imulq $0x58, %rcx, %r11
movq 0x48(%r9,%r11), %rcx
shrl %r10d
movq (%rcx,%r10,8), %rcx
movq (%rsi), %rbx
cmpq $-0x1, %rbx
je 0xf677
cmpq %rcx, %rbx
je 0xf67a
jmp 0xf6c4
movq %rcx, (%rsi)
subq %r13, %r14
movq 0x10(%rsp), %rbx
addq (%rbx), %r14
addq %r14, %r14
movq 0x50(%r9,%r11), %rcx
movq %r14, (%rcx,%r10,8)
incq %rax
addq $0x10, %rdx
cmpq %rax, %r12
jne 0xf5f2
movq %rbp, %rdi
callq 0x2060
movq 0x38(%rsp), %rdi
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2060
addq %r8, %rdi
callq 0x29ce