开源代码赏析之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)*8个bit位
* 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;//元素p中bit位起始偏移
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表明在当前元素为最后一个元素中找bit位1
* 2.剩余未处理bit位个数size=N*BITS_PER_LONG
* 3.剩余未处理bit位个数size=N*BITS_PER_LONG + X, X=[1,BITS_PER_LONG-1]
*/
if (tmp)
//当前元素中一定存在bit位1,直接找到该元素中的第一个有效bit位1
goto found_middle;
/*
* 当前元素中不存在bit位1,跳过当前元素;剩余未处理bit位个数减少BITS_PER_LONG
* 已处理bit位个数增加BITS_PER_LONG
*/
size -=BITS_PER_LONG;
result+= BITS_PER_LONG;
}
/*
* 程序走到这里有两种情况:
* 1.当前元素bit位起始偏移为0,即从当前元素的第0个bit位开始查找
* 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++)))
//当前元素中一定包含bit位1
gotofound_middle;
//当前元素不包含bit位1,则跳过当前元素,检查下一个元素是否包含bit位1
result+= BITS_PER_LONG;
size -=BITS_PER_LONG;
}
//程序走到这里表明size=X, X=[0,BITS_PER_LONG-1]
if (!size)
/*
* 剩余未处理bit位个数size为0时表明没有符合条件的
* 直接返回已处理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;
}
- 开源代码赏析之find_next_bit函数
- JSF 源代码赏析之FacesServlet
- JSF 源代码赏析之Lifecycle
- 代码之美——Doom3源代码赏析
- 代码之美——Doom3源代码赏析
- 代码之美——Doom3源代码赏析
- 代码之美——Doom3源代码赏析
- 代码之美——Doom3源代码赏析
- 代码之美——Doom3源代码赏析
- 代码之美——Doom3源代码赏析
- 转:代码之美——Doom3源代码赏析
- Normalize.css源代码赏析
- 佛祖保佑源代码赏析
- lcd probe函数 赏析
- 走进Linq Linq to SQL源代码赏析
- Win2k泄漏源代码赏析——GetProcAddress
- 代码_规范_Doom3源代码赏析
- CRT字符串函数代码赏析
- Android Studio新功能解析,你真的了解Instant Run吗?
- 玲珑杯round#6 1068 - Lights
- Session的时效性——由验证码引出的问题
- Android-动画之Tween动画 (渐变、缩放、位移、旋转)
- Android Studio中Gradle使用详解
- 开源代码赏析之find_next_bit函数
- 2016年度最受欢迎开源项目,JEECG、JEEWX参与投票
- lintcode,复制带随机指针的链表
- 网络爬虫之BeautifulSoup入门(三)
- 一天一个汇编指令&& mov
- 127. Word Ladder
- 我终于顿悟辗转相除法求最大公约数的原理了
- java输入输出流、字符字节流
- vue全家桶