使用Mask进行过滤

遇到一个需求,依据传进来的filter的结构体来进行过滤,返回过滤结果的vector大小。

typedef struct 
{
    int      myMask;
    int      ...;
}ObjectFilter;

filter内含多个条件,其中除了常规需求filter,还有一个类似掩码的mask。mask的取值为0-15,即四位的二进制数(0000-1111),其中四位分别表示另一个enum属性的取值(可以多位为true),分别为1(0001)、2(0010)、4(0100)、8(1000)。上一层的应用传入0-15的mask值,后端根据此mask值,解析出来这enum属性的取值,再分别处理。

注意点:

① 常规需求放在前面,不符合规则的过滤掉。mask需求放在后面,根据传进来的mask(可转换为4位的二进制),判断该enum值的取值,四位都过滤完之后,再执行insert到set的操作。对于未传入mask的情况,则经过normal filter之后,直接push到vector即可。

② mask的处理,使用移位(对二进制除以2)和 对2取模(除以2取余数)完成。哪位为0,则进入哪位的if判断中,则进行对应处理,全0的则不会进入mask处理里面来。

③ 上一步中,对于一个mask,每一位为true的do something函数体里面,可能有pObjectVec的处理,但是对于四位来说,肉具体逻辑包含”某一位为1的时候就将该object放入vector”的逻辑的话,最后会导致有多个1的mask的结果里面有重复的object,所以在进入mask判断前后可以做一个set和vector的互相转换。vector转换为set,直接使用set的构造函数;set转换为vector,使用vector的assign方法。

int getObjectByFilter(const ObjectFilter& pConfig, vector<Object*> &pObjectVec)
{
    for(auto lIter = mObjectMap.begin(); lIter != mObjectMap.end(); lIter++)
    {  
        // check some normal thing
        if (...)
        {
            continue;
        }

        // construct a set, make sure vector elements unique
        std::set<MyObject*> lObjectSet(pObjectVec.begin(), pObjectVec.end());

        // myMask = 13 : 1101
        if (pConfig.myMask)
        {
            // 1101 --> true
            if (pConfig.myMask % 2)
            {   
                // do something
                // eg. lObjectSet.insert(lIter->second);
            }

            //110 --> false
            if ((pConfig.myMask>>1) % 2)
            {
				// do something            
            }

            //11 --> true
            if ((pConfig.myMask>>2) % 2)
            {
                // do something 
            }

            //1 --> true
            if ((pConfig.myMask>>3) % 2)
            {
                // do something 
            }

            pObjectVec.assign(lObjectSet.begin(), lObjectSet.end );

        }
        else
        {
            pObjectVec.push_back(lIter->second);
        }

    }

    return pObjectVec.size();
}


注:经老师提醒,可以使用按位与按位或来实现以上需求:

int getObjectByFilter(const ObjectFilter& pConfig, vector<Object*> &pObjectVec)
{
    for(auto lIter = mObjectMap.begin(); lIter != mObjectMap.end(); lIter++)
    {  
        // check some normal thing
        if (...)
        {
            continue;
        }

        if (pConfig.mUserRoleMask && pConfig.mUserId)
        {

            // 后部分是0001 | 0010
            if (pConfig.myMask & ((uint32)enum_type_A | (uint32)enum_type_B))
            {
                if (...)
                {
                    // do something
                	// eg. pObjectVec.push_back(lIter->second);
                    continue;
                }
            }

            ...

        }
        else
        {
            pObjectVec.push_back(lIter->second);
        }

    }

    return pObjectVec.size();
}