在linux内核中,inlucde / linux / word_at_a_time.h,有两个功能:
static inline long find_zero(unsigned long mask)
{
long byte = 0;
#ifdef CONFIG_64BIT
if (mask >> 32)
mask >>= 32;
else
byte = 4;
#endif
if (mask >> 16)
mask >>= 16;
else
byte += 2;
return (mask >> 8) ? byte : byte + 1;
}
static inline bool has_zero(unsigned long val,
unsigned long *data,
const struct word_at_a_time *c)
{
unsigned long rhs = val | c->low_bits;
*data = rhs;
return (val + c->high_bits) & ~rhs;
}
它在哈希函数中使用,在git log中它说:
- has_zero(): take a word, and determine if it has a zero byte in it. It gets the word, the pointer to the constant pool, and a pointer to an intermediate "data" field it can set.
但我仍然没有得到
(1)这个功能做什么?,和 (2)他们是如何做到的?
答案 0 :(得分:5)
假设位从最低有效位(LSB)(编号0)到最高有效位(MSB)编号。
函数find_zero()
使用类似于分而治之的技术从左侧搜索第一个 N
(< = 7)字节,其值为零。
假设一个64位系统定义了CONFIG_64BIT
,然后执行以下代码:
#ifdef CONFIG_64BIT
if (mask >> 32) //Any bit=1 in left 32 bits
mask >>= 32;
else
byte = 4; //<--No, fist 4 bytes are zero
首先注释mask
为unsigned
,因此>>
是无符号右筛选。 (like Java's >>>)
首先检查mask
值是否大于2 32 (或者我们可以说unsigned long mask
位是否在编号为32
的位之间63
是一个。)
mask >> 32
将生成一个纯值,即mask
右移,0
扩展为32
位,并导致32
高位包含零。
例如,如果maks
位如下:
63 56 55 48 47 40 39 32 31 24 23 16 15 7 0
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
0000 1000 0000 0000 0000 0000 0000 0100 0000 0000 0000 0000 0000 0000 0001 0101
▲ ▲
MSB LSM
在此示例中,位号34
和59
为1,因此(mask >> 32)
== true
(或称为非零!0
)。因此,对于此示例if (mask >> 32)
== if(!0)
在一般情况下,如果位号32
到63
中的任何位为1,则mask
将更新为mask >>= 32;
== mask = mask >> 32;
(如果为真,则为声明执行)。这导致高阶32
位由于右移而变为低阶32
位(并且位32到63变为0
)。
在上面的示例中,mask
变为:
shifted OLD bit number ----> 63 45 32
63 47 32 31 15 0
▼ ▼ ▼ ▼ ▼ ▼
0000 0000 0000 0000 0000 0000 0000 0000 0000 1000 0000 0000 0000 0000 0000 0100
▲ ▲
MSB LSM
|-------------------------------------|
| All are zero |
注意:从32到63的位是0
,从0
到31
的位从上面从位32
复制到63
。
到此为止:
<强>案例-1:强>
如果32
到63
中的任何位在原始mask
中一个,则if
执行true并屏蔽更新。 (正如我上面解释的那样)。变量long byte
仍为0
。然后在下一个if(mask >> 16)
中,函数find_zero()
将继续在位48
到63
内搜索值为零的字节(在if(mask >> 16)
中,位编号为{如果任何位为1,将检查{1}}到48
。
<强>案例-2:强>
如果原始63
中32
到63
的所有位均为零,那么mask
条件将变为false(即if
== if(mask >> 32)
)并且if(0)
没有更新,变量mask
变为long byte
,这表明4
中的高四字节为0
。在mask
之后,函数if(mask >> 16)
将搜索位范围为find_zero()
到16
的零字节。
同样,在第二个31
中:
if()
它将检查编号为if (mask >> 16)
mask >>= 16;
else
byte += 2;
的位之间是否有任何位。如果所有位都为零,那么16 to 31
将在其他部分递增byte
,在if部分掩码将通过无符号右移16位更新。
(注意:如果2
更新mask
,那么实际上mask
检查if(mask >> 16)
之间的任何位是否为1,否则为48 to 63
}原始掩码中的16
随后,最后一个条件运算符以类似的方式工作,以检查位为31
到8
之间的位是否为1。
15
因此,函数 long byte = 0;
64 bit `mask`
|
|
▼
if(any bit from 32 to 62 is one)---+
| |
|False: if(0) |True: if(!0)
all bits between 32 to 64 |A byte=Zero NOT found
are zero Some bits are one from bit 32-63
| |
| |
byte = 4 byte= 0, and
64 bit `mask` <--Orignal `mask` updated as `mask >>= 32;`
| |
| |
▼ ▼
if(Any bit from 16 to 31 is one) if(Any bit from 48 to 63 is one)
|Because high order bits are Zero |Note due to >> all high order
|It check for bits numbered 16-31 |bits becomes zero.
| |2nd if checks for bit from 16-31
| |that were originally bit
| | numbered 48 to 63
| |
▼ ▼
Case False: if(0) Case False: if(0)
All bits Zero from 16-31 All bits Zero from 49-63
mask will NOT updated and mask will NOT updated and
byte = 6 byte = 2
Case True: if(!0) Case False: if(!0)
Some bits are one from 16-31 Some bits are one from 49-63
mask updated mask Updated
byte = 4 byte = 0
| |
| |
▼ ▼
more four cases more four cases
Total 8 different answer outputs from `0` to `7`
从左侧搜索值为零的第一个 find_zero()
个字节。输出字节值可以从N
到0
,也不考虑最右边的字节(7
)。
(*注意:long为64位长= 8 * 8位= 8字节。*)
"8"
byte = byte NUMBER ("):
"1" "2" "3" "4" "5" "6" "7" "8"
63 56 55 48 47 40 39 32 31 24 23 16 15 7 0
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
0000 1000 0000 0000 0000 0000 0000 0100 0000 0000 0000 0000 0000 0000 0001 0101
▲ ▲
MSB LSM
- &gt;意味着第一个字节不为零
byte = 0
- &gt;高位字节为零,位编号为1
到56
byte = 63
- &gt;两个高位字节为零,位编号为2
到48
byte = 63
- &gt;三个高位字节为零,位编号为3
到40
:
:
同样,byte = 63
- &gt;左起七个字节是0,(或全0)。
下面我写了一个小代码,用不同的值调用7
函数,帮助你理解函数:
find_zero()
请观察输出以了解功能:
int main(){
printf("\nmask=0x0, all bytes are zero, result =%ld", find_zero(0x0L)); // not prints 8
printf("\nmask=0xff, left seven bytes are zero, result =%ld", find_zero(0xffL));
printf("\nmask=0xffff, left six bytes are zero, result =%ld", find_zero(0xffffL));
printf("\nmask=0xffffff, left five bytes are zero, result =%ld", find_zero(0xffffffL));
printf("\nmask=0xffffffff, left four bytes are zero, result =%ld", find_zero(0xffffffffL));
printf("\nmask=0xffffffffff, left three bytes are zero, result =%ld", find_zero(0xffffffffffL));
printf("\nmask=0xffffffffffff, left two bytes are zero, result =%ld", find_zero(0xffffffffffffL));
printf("\nmask=0xffffffffffffff, left most one byte is zero, result =%ld", find_zero(0xffffffffffffffL));
printf("\nmask=0xffffffffffffffff, No byte is zero, result =%ld", find_zero(0xffffffffffffffffL));
printf("\nmask=0x8000000000000000L, first byte is NOT zero (so no search), result =%ld", find_zero(0x8000000000000000LL));
printf("\n");
return 1;
}
注意:如果所有字节都为零,则打印mask=0x0, all bytes are zero, result =7
mask=0xff, left seven bytes are zero, result =7
mask=0xffff, left six bytes are zero, result =6
mask=0xffffff, left five bytes are zero, result =5
mask=0xffffffff, left four bytes are zero, result =4
mask=0xffffffffff, left three bytes are zero, result =3
mask=0xffffffffffff, left two bytes are zero, result =2
mask=0xffffffffffffff, left most one byte is zero, result =1
mask=0xffffffffffffffff, No byte is zero, result =0
mask=0x8000000000000000L, first byte is NOT zero (so no search), result =0
而不是8.
答案 1 :(得分:0)
第一个函数查找掩码中非空的第一个字节,并从左侧开始返回索引。
64位示例,xx
表示“任意字节”,“nn”表示“非零字节”:
.nn.xx.xx.xx.xx.xx.xx.xx -> find_zero() -> 0
.00.nn.xx.xx.xx.xx.xx.xx -> find_zero() -> 1
.00.00.nn.xx.xx.xx.xx.xx -> find_zero() -> 2
...
.00.00.00.00.00.00.00.nn -> find_zero() -> 7
.00.00.00.00.00.00.00.00 -> find_zero() -> 7 (this one is strange)
如果不是最后一个含糊不清的情况,我会将此函数命名为find_first_significant_byte_index()
...
第二个函数根据位掩码拆分val
,将其“low_bits”存储在* data中以供进一步引用,并在val上返回一些奇怪的op结果。 (无法确定最后一个)。
答案 2 :(得分:0)
请参阅&#34;一次一个字界面&#34;:https://lwn.net/Articles/501492/
如果输入中包含零字节,则has_zero()返回非零掩码。
find_zero()找到 第一个零点使用掩码作为输入的位置(从技术上讲,它不是那个掩码,但该掩码进一步按摩了另外两个功能)。 find_zero()没有在输入掩码中找到零。
请参阅链接文章中的示例用法:
if (has_zero(value, &bits, &constants)) {
bits = prep_zero_mask(value, bits, &constants);
bits = create_zero_mask(bits);
zero_byte = find_zero(bits);
/* ... */