开源代码赏析之find_next_bit函数

来源:互联网 发布:wps数据分析在哪里 编辑:程序博客网 时间:2024/04/30 08:36

开源代码赏析之find_next_bit函数

1 函数功能

假定unsigned long数组addr有n个元素,则其可以表示n*sizeof(unsignedlong)*8个bit位。find_next_bit可以找到从第offset个bit位开始、在offset~size区间的第一个值为1的bit位位置,如果没有找到满足条件的bit位则返回最大尺寸size。

2 函数原型

/*

*@brief\

* addr表示的bit位图数组中,查找offset~size区间中第一个1bit位的索引值

*@input\

* addr: unsigned long数组,每个元素表示sizeof(unsigned long)*8bit

* size: 查找结束位置

* offset:查询起始位置

*/

unsigned long find_next_bit(constunsignedlong*addr,unsignedlongsize,unsignedlongoffset)

3 实现逻辑


图1 unsigned long数组表示的bit位图(64位系统)

如图1所示,addr数组中的每一个元素表示64个bit位,每一个元素按低位向高位依次进行排列。n个数可表示的最大bit位个数为n* sizeof(unsigned long)*8,即64*n。根据上图可以看出:最大尺寸size可以是1~64n之间的任意值,而起始偏移值为0~size之间的任意值。针对size和offset不同的可能取值,有以下几种情况:

(1)、size为size_1,即最大尺寸不是BITS_PER_LONG的整数倍,这表明数组addr的最后一个元素中部分高bit位没有使用,在处理的时候需要考虑到这种情况;

(2)、size为size_2,即最大尺寸为BITS_PER_LONG的整数倍,则不存在(1)中描述的无效bit位;

(3)、起始索引值offse为offset_1或offset_3,即offset是BITS_PER_LONG的整数倍;

(4)、起始索引值offse为offset_2或offset_4,即offset不是BITS_PER_LONG的整数倍;

针对上面的情况,下面进行具体分析:

(a)、首先,找到起始索引offset所在的元素,即:addr[j]= addr+offset/BITS_PER_LONG,则已跳过的元素中包含的bit位个数为:(offset/BITS_PER_LONG)*BITS_PER_LONG。处理将从该元素的第offset% BITS_PER_LONG个bit位开始。

(b)、假定offset为offset_4,则当前元素是最后一个元素,只需要从offset_4%BITS_PER_LONG到BITS_PER_LONG-1位依次比较,找出第一个1bit位即可。但当size为size_1时,addr[n-1]中存在BITS_PER_LONG-size_1% BITS_PER_LONG个无效的bit位;因此,在比较最后一个元素时,需要置高位的BITS_PER_LONG-size_1%BITS_PER_LONG个无效bit位和低位已跳过的offset_4%BITS_PER_LONG个bit位为0。

(c)、假定offset为offset_2,则当前元素不是最后一个元素,且当前元素中不可能存在无效的bit位。因此,只需要取出当前元素,跳过当前元素中的offset_2%BITS_PER_LONG个低位bit位后逐个比较bit位。如果找到了bit位1就直接返回其索引值,如果没有找到需要跳到下一个元素继续查找,如果下一个元素还没有符合条件的bit位则继续下一个元素,直到最后一个元素。

(d)、跳到最后一个元素时可能会出现size为size_1或size_2的情况,如果size为size_1就需要进行(b)中一样的处理流程。最后,如果找到符合条件的bit位1就返回索引值,如果没有找到就返回最大尺寸值。

对于find_next_zero_bit处理逻辑与find_next_bit完全一致,只是查找条件是bit位0而非bit位1。

4 代码赏析

unsigned long find_next_bit(constunsigned long *addr,unsigned longsize,

unsigned long offset)

{

    /*

   * 1.addr数组中的每一个元素为一个bitmap,可以表示sizeof(unsigned long)*8个元素

   * 2.size为最大尺寸,可以是[1,数组元素个数*sizeof(unsigned long)*8]中的任意值

   * 3.offset=[0,size]

   */

const unsigned long *p = addr +BITOP_WORD(offset);//定位到起始元素

unsigned long result = offset &~(BITS_PER_LONG-1);//已经跳过的bit位个数

unsigned long tmp;

 

if (offset >= size)//起始偏移超过了最大尺寸,直接返回最大尺寸

           return size;

   

size -= result;//剩余未处理的bit位个数

offset %=BITS_PER_LONG;//元素pbit位起始偏移

if (offset) {

           tmp =*(p++);

           tmp&= (~0UL << offset);//将已经跳过的bit位置为无效bit

       

           if (size < BITS_PER_LONG)

            /*

            * 当前元素是最后一个元素,size不是BITS_PER_LONG的整数倍

            * 且最后一个元素存在无效(0)bit(bit位无效)

           */

                    goto found_first;

 

        /*

       * 程序走到这里有三种情况:

       * 1.剩余未处理bit位个数size=BITS_PER_LONG表明在当前元素为最后一个元素中找bit1

       * 2.剩余未处理bit位个数size=N*BITS_PER_LONG

       * 3.剩余未处理bit位个数size=N*BITS_PER_LONG + X, X=[1,BITS_PER_LONG-1]

       */

           if (tmp)

            //当前元素中一定存在bit1,直接找到该元素中的第一个有效bit1

                    goto found_middle;

 

        /*

       * 当前元素中不存在bit1,跳过当前元素;剩余未处理bit位个数减少BITS_PER_LONG

       * 已处理bit位个数增加BITS_PER_LONG

       */

           size -=BITS_PER_LONG;

           result+= BITS_PER_LONG;

}

 

    /*

   * 程序走到这里有两种情况:

   * 1.当前元素bit位起始偏移为0,即从当前元素的第0bit位开始查找

   * 2.当前元素bit位起始偏移非0,size=N*BITS_PER_LONG + X,X=[0,BITS_PER_LONG-1],N>=0

   */

while (size & ~(BITS_PER_LONG-1)) {//size>=BITS_PER_LONG

           if ((tmp = *(p++)))

            //当前元素中一定包含bit1

                    gotofound_middle;

 

        //当前元素不包含bit1,则跳过当前元素,检查下一个元素是否包含bit1

           result+= BITS_PER_LONG;

           size -=BITS_PER_LONG;

}

 

    //程序走到这里表明size=X, X=[0,BITS_PER_LONG-1]

if (!size)

        /*

       * 剩余未处理bit位个数size0时表明没有符合条件的

       * 直接返回已处理bit位个数,即最大尺寸

       */

           return result;

   

tmp = *p;

 

found_first:

    /*

   * 程序走到这里表明size=X, X=[1,BITS_PER_LONG-1],即最大尺寸不是

   * BITS_PER_LONG的整数倍,最后一个元素存在无效的高bit.此时,需要

   * 将无效的高位bit位置为无效位;而根据上一句tmp=*p表明低位bit位已

   * 全是不合条件的无效bit

   */

tmp &= (~0UL>> (BITS_PER_LONG - size));//置高位bit位无效

if (tmp == 0UL)            /*Are any bits set? */

        //最后一个元素也没有符合条件的bit,直接返回最大尺寸作为返回值

           return result + size;      /* Nope. */

 

    //tmp不为0则表明当前元素中一定存在有效bit

found_middle:

    /*

   * 程序走到这里有两种情况:

   * 1.size=N*BITS_PER_LONG, N>=1

   * 2.size=N*BITS_PER_LONG + X, N>=0, X[1,BITS_PER_LONG-1],N=0则表明

   *   当前元素是最后一个元素,且当前元素的存在无效的高位bit

   */

return result + __ffs(tmp);

}

 

static __always_inlineunsignedlong __ffs(unsignedlong word)

{

int num = 0;

 

#if BITS_PER_LONG == 64

if ((word & 0xffffffff) == 0) {

           num +=32;

           word>>= 32;

}

#endif

if ((word & 0xffff) == 0) {

           num +=16;

           word>>= 16;

}

if ((word & 0xff) == 0) {

           num +=8;

           word>>= 8;

}

if ((word & 0xf) == 0) {

           num +=4;

           word>>= 4;

}

if ((word & 0x3) == 0) {

           num +=2;

           word>>= 2;

}

if ((word & 0x1) == 0)

           num +=1;

return num;

}


1 0