//------------------------------------------------------------------------------
// GB_AxB_saxpy3_coarseHash_phase5: C=A*B for coarse hash method, phase 5
//------------------------------------------------------------------------------

// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2025, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//------------------------------------------------------------------------------

{

    //--------------------------------------------------------------------------
    // phase 5: coarse hash task, C=A*B
    //--------------------------------------------------------------------------

    // Initially, Hf [...] < mark for all of Hf.
    // Let f = Hf [hash] and h = Hi [hash]

    // f < mark          : unoccupied.
    // h == i, f == mark : occupied with C(i,j)

    for (int64_t kk = kfirst ; kk <= klast ; kk++)
    {
        int64_t pC_start = GB_Cp_IGET (kk) ;
        int64_t pC_end = GB_Cp_IGET (kk+1) ;
        int64_t pC = pC_start ;
        int64_t cjnz = pC_end - pC ;
        ASSERT (pC_start >= 0) ;
        ASSERT (pC_start <= pC_end) ;
        ASSERT (pC_end <= cnz) ;

        if (cjnz == 0) continue ;   // nothing to do
        GB_GET_B_j ;                // get B(:,j)

        #ifdef GB_CHECK_MASK_ij

            // The mask M is bitmap or as-if-full
            GB_GET_M_j ;                // get M(:,j)
            #ifdef GB_MASK_IS_BITMAP_AND_STRUCTURAL
            // Mjb is the M(:,j) vector, if M is bitmap and structural
            const int8_t *restrict Mjb = Mb + pM_start ;
            #endif

        #else

            // M is not present
            if (bjnz == 1 && (A_is_sparse || A_is_hyper))
            { 
                // C(:,j) = A(:,k)*B(k,j), no mask
                GB_COMPUTE_C_j_WHEN_NNZ_B_j_IS_ONE ;
                continue ;
            }

        #endif

        mark++ ;
        for ( ; pB < pB_end ; pB++)     // scan B(:,j)
        {
            GB_GET_B_kj_INDEX ;         // get index k of B(k,j)
            GB_GET_A_k ;                // get A(:,k)
            if (aknz == 0) continue ;
            GB_GET_B_kj ;               // bkj = B(k,j)
            // scan A(:,k)
            for (int64_t pA = pA_start ; pA < pA_end ; pA++)
            {
                GB_GET_A_ik_INDEX ;     // get index i of A(i,j)
                #ifdef GB_CHECK_MASK_ij
                // check mask condition and skip if C(i,j) is protected by the
                // mask
                GB_CHECK_MASK_ij ;
                #endif
                GB_MULT_A_ik_B_kj ;     // t = A(i,k)*B(k,j)
                for (GB_HASH (i))   // find i in hash table
                {
                    if (Hf [hash] == mark)
                    {
                        // hash entry is occupied
                        if (Hi [hash] == i)
                        { 
                            // i already in the hash table
                            // Hx [hash] += t ;
                            GB_HX_UPDATE (hash, t) ;
                            break ;
                        }
                    }
                    else
                    { 
                        // hash entry is not occupied
                        Hf [hash] = mark ;
                        Hi [hash] = i ;
                        GB_HX_WRITE (hash, t) ; // Hx [hash] = t
                        GB_ISET (Ci, pC, i) ;   // Ci [pC] = i
                        pC++ ;
                        break ;
                    }
                }
            }
        }
        GB_SORT_AND_GATHER_HASHED_C_j (mark) ;  // gather into C(:,j)
    }
}

#undef GB_MASK_IS_BITMAP_AND_STRUCTURAL

