/** \file
Bitmaps built as vectors of machine words
*/
#include <vppinfra/vec.h>
#include <vppinfra/random.h>
#include <vppinfra/error.h>
#include <vppinfra/bitops.h> /* for count_set_bits */
typedef uword clib_bitmap_t;
位图是基于动态数组来构建的。这里的位图容量可以简单认为是无限制的。
/** predicate function; is an entire bitmap empty?
@param ai - pointer to a bitmap
@returns 1 if the entire bitmap is zero, 0 otherwise
*/
always_inline uword
clib_bitmap_is_zero (uword * ai)
{
uword i;
for (i = 0; i < vec_len (ai); i++)
if (ai[i] != 0)
return 0;
return 1;
}
主要判断位图的所有位是否都为0. 如果是,则返回1, 否则返回0.
/** predicate function; are two bitmaps equal?
@param a - pointer to a bitmap
@param b - pointer to a bitmap
@returns 1 if the bitmaps are equal, 0 otherwise
*/
always_inline uword
clib_bitmap_is_equal (uword * a, uword * b)
{
uword i;
if (vec_len (a) != vec_len (b))
return 0;
for (i = 0; i < vec_len (a); i++)
if (a[i] != b[i])
return 0;
return 1;
}
2个位图是否相等。如果相等,返回1. 否则返回0
/** Duplicate a bitmap
@param v - pointer to a bitmap
@returns a duplicate of the bitmap
*/
#define clib_bitmap_dup(v) vec_dup(v)
生成已有位图的副本。
/** Free a bitmap
@param v - pointer to the bitmap to free
*/
#define clib_bitmap_free(v) vec_free(v)
释放位图内存空间
/** Number of bytes in a bitmap
@param v - pointer to the bitmap
*/
#define clib_bitmap_bytes(v) vec_bytes(v)
计算位图所占用的字节数
/** Clear a bitmap
@param v - pointer to the bitmap to clear
*/
#define clib_bitmap_zero(v) vec_zero(v)
清空位图,所有bit置0
/** Allocate a bitmap with the supplied number of bits
@param [out] v - the resulting bitmap
@param n_bits - the required number of bits
*/
#define clib_bitmap_alloc(v,n_bits) \
v = vec_new (uword, ((n_bits) + BITS (uword) - 1) / BITS (uword))
申请位图的内存空间
#define clib_bitmap_vec_validate(v,i) vec_validate_aligned((v),(i),sizeof(uword))
/* Make sure that a bitmap is at least n_bits in size */
#define clib_bitmap_validate(v,n_bits) \
clib_bitmap_vec_validate ((v), ((n_bits) - 1) / BITS (uword))
确保位图至少有n_bits位,即动态数组扩展到此位置。
/* low-level routine to remove trailing zeros from a bitmap */
always_inline uword *
_clib_bitmap_remove_trailing_zeros (uword * a)
{
word i;
if (a)
{
for (i = _vec_len (a) - 1; i >= 0; i--)
if (a[i] != 0)
break;
_vec_len (a) = i + 1;
}
return a;
}
去掉位图尾部的连续0bit。 借此减少动态数组大小。
/** Sets the ith bit of a bitmap to new_value.
No sanity checking. Be careful.
@param a - pointer to the bitmap
@param i - the bit position to interrogate
@param new_value - new value for the bit
@returns the old value of the bit
*/
always_inline uword
clib_bitmap_set_no_check (uword * a, uword i, uword new_value)
{
uword i0 = i / BITS (a[0]);
uword i1 = i % BITS (a[0]);
uword bit = (uword) 1 << i1;
uword ai, old_value;
/* Removed ASSERT since uword * a may not be a vector. */
/* ASSERT (i0 < vec_len (a)); */
ai = a[i0];
old_value = (ai & bit) != 0;
ai &= ~bit;
ai |= ((uword) (new_value != 0)) << i1;
a[i0] = ai;
return old_value;
}
将位图的第i位设置成新值,并返回原来这一位的值。本函数此过程不检查i位置的合法性
/** Sets the ith bit of a bitmap to new_value
Removes trailing zeros from the bitmap
@param ai - pointer to the bitmap
@param i - the bit position to interrogate
@param value - new value for the bit
@returns the old value of the bit
*/
always_inline uword *
clib_bitmap_set (uword * ai, uword i, uword value)
{
uword i0 = i / BITS (ai[0]);
uword i1 = i % BITS (ai[0]);
uword a;
/* Check for writing a zero to beyond end of bitmap. */
if (value == 0 && i0 >= vec_len (ai))
return ai; /* Implied trailing zeros. */
clib_bitmap_vec_validate (ai, i0);
a = ai[i0];
a &= ~((uword) 1 << i1);
a |= ((uword) (value != 0)) << i1;
ai[i0] = a;
/* If bits have been cleared, test for zero. */
if (a == 0)
ai = _clib_bitmap_remove_trailing_zeros (ai);
return ai;
}
本函数也是设置第 i 位的 值。但比上一个版本更健壮。
在当前位图范围之外设置0,相当于空操作
如果在当前位图范围之外设置1,则扩展动态数组之后,再设置1。
如果设置了一个0. 导致末尾的word被截短。
/** Gets the ith bit value from a bitmap
@param ai - pointer to the bitmap
@param i - the bit position to interrogate
@returns the indicated bit value
*/
always_inline uword
clib_bitmap_get (uword * ai, uword i)
{
uword i0 = i / BITS (ai[0]);
uword i1 = i % BITS (ai[0]);
return i0 < vec_len (ai) && 0 != ((ai[i0] >> i1) & 1);
}
获取第 i 位 位图的值。
/** Gets the ith bit value from a bitmap
Does not sanity-check the bit position. Be careful.
@param ai - pointer to the bitmap
@param i - the bit position to interrogate
@returns the indicated bit value, or garbage if the bit position is
out of range.
*/
always_inline uword
clib_bitmap_get_no_check (uword * ai, uword i)
{
uword i0 = i / BITS (ai[0]);
uword i1 = i % BITS (ai[0]);
return 0 != ((ai[i0] >> i1) & 1);
}
同上,没有判断i的合法性。
always_inline uword
clib_bitmap_get_multiple_no_check (uword * ai, uword i, uword n_bits)
{
uword i0 = i / BITS (ai[0]);
uword i1 = i % BITS (ai[0]);
ASSERT (i1 + n_bits <= BITS (uword));
return 0 != ((ai[i0] >> i1) & pow2_mask (n_bits));
}
读取位图中,处于同一个word的多个连续bit的值,这个版本假设了这多个连续bit在一个word中。
/** Gets the ith through ith + n_bits bit values from a bitmap
@param bitmap - pointer to the bitmap
@param i - the first bit position to retrieve
@param n_bits - the number of bit positions to retrieve
@returns the indicated range of bits
*/
always_inline uword
clib_bitmap_get_multiple (uword * bitmap, uword i, uword n_bits)
{
uword i0, i1, result;
uword l = vec_len (bitmap);
ASSERT (n_bits <= BITS (result));
i0 = i / BITS (bitmap[0]);
i1 = i % BITS (bitmap[0]);
/* Check first word. */
result = 0;
if (i0 < l)
{
result |= (bitmap[i0] >> i1);
if (n_bits < BITS (bitmap[0]))
result &= (((uword) 1 << n_bits) - 1);
}
/* Check for overlap into next word. */
i0++;
if (i1 + n_bits > BITS (bitmap[0]) && i0 < l)
{
n_bits -= BITS (bitmap[0]) - i1;
result |=
(bitmap[i0] & (((uword) 1 << n_bits) - 1)) << (BITS (bitmap[0]) - i1);
}
return result;
}
与上一个函数类似,从位图的第i位获取连续的n位的值,比上一个版本限制更少。n不能超过1个word那么长,所以最多是由相邻的2个word组成的值,不会存在3个word的内容来组成结果。
/** sets the ith through ith + n_bits bits in a bitmap
@param bitmap - pointer to the bitmap
@param i - the first bit position to retrieve
@param value - the values to set
@param n_bits - the number of bit positions to set
@returns a pointer to the updated bitmap, which may expand and move
*/
always_inline uword *
clib_bitmap_set_multiple (uword * bitmap, uword i, uword value, uword n_bits)
{
uword i0, i1, l, t, m;
ASSERT (n_bits <= BITS (value));
i0 = i / BITS (bitmap[0]);
i1 = i % BITS (bitmap[0]);
/* Allocate bitmap. */
clib_bitmap_vec_validate (bitmap, (i + n_bits) / BITS (bitmap[0]));
l = vec_len (bitmap);
m = ~0;
if (n_bits < BITS (value))
m = (((uword) 1 << n_bits) - 1);
value &= m;
/* Insert into first word. */
t = bitmap[i0];
t &= ~(m << i1);
t |= value << i1;
bitmap[i0] = t;
/* Insert into second word. */
i0++;
if (i1 + n_bits > BITS (bitmap[0]) && i0 < l)
{
t = BITS (bitmap[0]) - i1;
value >>= t;
n_bits -= t;
t = bitmap[i0];
m = ((uword) 1 << n_bits) - 1;
t &= ~m;
t |= value;
bitmap[i0] = t;
}
return bitmap;
}
与上一个函数相反,设置连续的nbit到位图中,从第i位开始。 n_bits <= sizeof(uword)*8
always_inline uword *
clib_bitmap_set_region (uword * bitmap, uword i, uword value, uword n_bits)
{
uword a0, a1, b0;
uword i_end, mask;
a0 = i / BITS (bitmap[0]);
a1 = i % BITS (bitmap[0]);
i_end = i + n_bits;
b0 = i_end / BITS (bitmap[0]);
clib_bitmap_vec_validate (bitmap, b0);
/* First word. */
mask = n_bits < BITS (bitmap[0]) ? pow2_mask (n_bits) : ~0;
mask <<= a1;
if (value)
bitmap[a0] |= mask;
else
bitmap[a0] &= ~mask;
for (a0++; a0 < b0; a0++)
bitmap[a0] = value ? ~0 : 0;
if (a0 == b0)
{
word n_bits_left = n_bits - (BITS (bitmap[0]) - a1);
mask = pow2_mask (n_bits_left);
if (value)
bitmap[a0] |= mask;
else
bitmap[a0] &= ~mask;
}
return bitmap;
}
将位图中某连续的n_bits位设置成全0或者全1。n_bits可以超过sizeof(uword)*8
/** Macro to iterate across set bits in a bitmap
@param i - the current set bit
@param ai - the bitmap
@param body - the expression to evaluate for each set bit
*/
#define clib_bitmap_foreach(i,ai,body) \
do { \
uword __bitmap_i, __bitmap_ai, __bitmap_len, __bitmap_first_set; \
__bitmap_len = vec_len ((ai)); \
for (__bitmap_i = 0; __bitmap_i < __bitmap_len; __bitmap_i++) \
{ \
__bitmap_ai = (ai)[__bitmap_i]; \
while (__bitmap_ai != 0) \
{ \
__bitmap_first_set = first_set (__bitmap_ai); \
(i) = (__bitmap_i * BITS ((ai)[0]) \
+ min_log2 (__bitmap_first_set)); \
do { body; } while (0); \
__bitmap_ai ^= __bitmap_first_set; \
} \
} \
} while (0)
遍历位图中每个置1的位,并执行用户指定的动作body。
/** Return the lowest numbered set bit in a bitmap
@param ai - pointer to the bitmap
@returns lowest numbered set bit, or ~0 if the entire bitmap is zero
*/
always_inline uword
clib_bitmap_first_set (uword * ai)
{
uword i = 0;
#if uword_bits == 64
#if defined(CLIB_HAVE_VEC256)
while (i + 7 < vec_len (ai))
{
u64x4 v;
v = u64x4_load_unaligned (ai + i) | u64x4_load_unaligned (ai + i + 4);
if (!u64x4_is_all_zero (v))
break;
i += 8;
}
#elif defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
while (i + 3 < vec_len (ai))
{
u64x2 v;
v = u64x2_load_unaligned (ai + i) | u64x2_load_unaligned (ai + i + 2);
if (!u64x2_is_all_zero (v))
break;
i += 4;
}
#endif
#endif
for (; i < vec_len (ai); i++)
{
uword x = ai[i];
if (x != 0)
return i * BITS (ai[0]) + log2_first_set (x);
}
return ~0;
}
查找位图中第1个设置为1的bit的位置。
/** Return the higest numbered set bit in a bitmap
@param ai - pointer to the bitmap
@returns lowest numbered set bit, or ~0 if the entire bitmap is zero
*/
always_inline uword
clib_bitmap_last_set (uword * ai)
{
uword i;
for (i = vec_len (ai); i > 0; i--)
{
uword x = ai[i - 1];
if (x != 0)
{
uword first_bit;
first_bit = count_leading_zeros (x);
return (i) * BITS (ai[0]) - first_bit - 1;
}
}
return ~0;
}
查找位图中最后一个设置为1的bit的位置。
/** Return the lowest numbered clear bit in a bitmap
@param ai - pointer to the bitmap
@returns lowest numbered clear bit
*/
always_inline uword
clib_bitmap_first_clear (uword * ai)
{
uword i;
for (i = 0; i < vec_len (ai); i++)
{
uword x = ~ai[i];
if (x != 0)
return i * BITS (ai[0]) + log2_first_set (x);
}
return i * BITS (ai[0]);
}
查找位图中第1个淸0的bit位置
/** Return the number of set bits in a bitmap
@param ai - pointer to the bitmap
@returns the number of set bits in the bitmap
*/
always_inline uword
clib_bitmap_count_set_bits (uword * ai)
{
uword i;
uword n_set = 0;
for (i = 0; i < vec_len (ai); i++)
n_set += count_set_bits (ai[i]);
return n_set;
}
求位图中置1的bit的总个数
/** Logical operator across two bitmaps
@param ai - pointer to the destination bitmap
@param bi - pointer to the source bitmap
@returns ai = ai and bi. ai is modified, bi is not modified
*/
always_inline uword *clib_bitmap_and (uword * ai, uword * bi);
/** Logical operator across two bitmaps
@param ai - pointer to the destination bitmap
@param bi - pointer to the source bitmap
@returns ai = ai & ~bi. ai is modified, bi is not modified
*/
always_inline uword *clib_bitmap_andnot (uword * ai, uword * bi);
/** Logical operator across two bitmaps
@param ai - pointer to the destination bitmap
@param bi - pointer to the source bitmap
@returns ai = ai & ~bi. ai is modified, bi is not modified
*/
always_inline uword *clib_bitmap_or (uword * ai, uword * bi);
/** Logical operator across two bitmaps
@param ai - pointer to the destination bitmap
@param bi - pointer to the source bitmap
@returns ai = ai or bi. ai is modified, bi is not modified
*/
always_inline uword *clib_bitmap_or (uword * ai, uword * bi);
/** Logical operator across two bitmaps
@param ai - pointer to the destination bitmap
@param bi - pointer to the source bitmap
@returns ai = ai xor bi. ai is modified, bi is not modified
*/
always_inline uword *clib_bitmap_xor (uword * ai, uword * bi);
/* ALU function definition macro for functions taking two bitmaps. */
#define _(name, body, check_zero) \
always_inline uword * \
clib_bitmap_##name (uword * ai, uword * bi) \
{ \
uword i, a, b, bi_len, n_trailing_zeros; \
\
n_trailing_zeros = 0; \
bi_len = vec_len (bi); \
if (bi_len > 0) \
clib_bitmap_vec_validate (ai, bi_len - 1); \
for (i = 0; i < vec_len (ai); i++) \
{ \
a = ai[i]; \
b = i < bi_len ? bi[i] : 0; \
do { body; } while (0); \
ai[i] = a; \
if (check_zero) \
n_trailing_zeros = a ? 0 : (n_trailing_zeros + 1); \
} \
if (check_zero) \
_vec_len (ai) -= n_trailing_zeros; \
return ai; \
}
/* ALU functions: */
/* *INDENT-OFF* */
_(and, a = a & b, 1)
_(andnot, a = a & ~b, 1)
_(or, a = a | b, 0)
_(xor, a = a ^ b, 1)
/* *INDENT-ON* */
#undef _
2个位图之间的4种位运算的定义,实际上是分别对每一位做相应的运算。结果存储在第一个位图中。
/** Logical operator across two bitmaps which duplicates the first bitmap
@param ai - pointer to the destination bitmap
@param bi - pointer to the source bitmap
@returns aiDup = ai and bi. Neither ai nor bi are modified
*/
always_inline uword *clib_bitmap_dup_and (uword * ai, uword * bi);
/** Logical operator across two bitmaps which duplicates the first bitmap
@param ai - pointer to the destination bitmap
@param bi - pointer to the source bitmap
@returns aiDup = ai & ~bi. Neither ai nor bi are modified
*/
always_inline uword *clib_bitmap_dup_andnot (uword * ai, uword * bi);
/** Logical operator across two bitmaps which duplicates the first bitmap
@param ai - pointer to the destination bitmap
@param bi - pointer to the source bitmap
@returns aiDup = ai or bi. Neither ai nor bi are modified
*/
always_inline uword *clib_bitmap_dup_or (uword * ai, uword * bi);
/** Logical operator across two bitmaps which duplicates the first bitmap
@param ai - pointer to the destination bitmap
@param bi - pointer to the source bitmap
@returns aiDup = ai xor bi. Neither ai nor bi are modified
*/
always_inline uword *clib_bitmap_dup_xor (uword * ai, uword * bi);
#define _(name) \
always_inline uword * \
clib_bitmap_dup_##name (uword * ai, uword * bi) \
{ return clib_bitmap_##name (clib_bitmap_dup (ai), bi); }
/* *INDENT-OFF* */
_(and);
_(andnot);
_(or);
_(xor);
/* *INDENT-ON* */
#undef _
同上,但结果存在第一个位图的副本中
/* ALU function definition macro for functions taking one bitmap and an
* immediate. */
#define _(name, body, check_zero) \
always_inline uword * \
clib_bitmap_##name (uword * ai, uword i) \
{ \
uword i0 = i / BITS (ai[0]); \
uword i1 = i % BITS (ai[0]); \
uword a, b; \
clib_bitmap_vec_validate (ai, i0); \
a = ai[i0]; \
b = (uword) 1 << i1; \
do { body; } while (0); \
ai[i0] = a; \
if (check_zero && a == 0) \
ai = _clib_bitmap_remove_trailing_zeros (ai); \
return ai; \
}
/* ALU functions immediate: */
/* *INDENT-OFF* */
_(andi, a = a & b, 1)
_(andnoti, a = a & ~b, 1)
_(ori, a = a | b, 0)
_(xori, a = a ^ b, 1)
/* *INDENT-ON* */
#undef _
位图和常量之间的位运算,结果存在位图中。这里的常量指的是第i位为1,其它位为0的位图。
/* ALU function definition macro for functions taking one bitmap and an
* immediate. No tail trimming */
#define _(name, body) \
always_inline uword * \
clib_bitmap_##name##_notrim (uword * ai, uword i) \
{ \
uword i0 = i / BITS (ai[0]); \
uword i1 = i % BITS (ai[0]); \
uword a, b; \
clib_bitmap_vec_validate (ai, i0); \
a = ai[i0]; \
b = (uword) 1 << i1; \
do { body; } while (0); \
ai[i0] = a; \
return ai; \
}
/* ALU functions immediate: */
/* *INDENT-OFF* */
_(andi, a = a & b)
_(andnoti, a = a & ~b)
_(ori, a = a | b)
_(xori, a = a ^ b)
#undef _
同上,但这个版本不会截断尾部的0。
/** Return a random bitmap of the requested length
@param ai - pointer to the destination bitmap
@param n_bits - number of bits to allocate
@param [in,out] seed - pointer to the random number seed
@returns a reasonably random bitmap based. See random.h.
*/
always_inline uword *
clib_bitmap_random (uword * ai, uword n_bits, u32 * seed)
{
vec_reset_length (ai);
if (n_bits > 0)
{
uword i = n_bits - 1;
uword i0, i1;
uword log2_rand_max;
log2_rand_max = min_log2 (random_u32_max ());
i0 = i / BITS (ai[0]);
i1 = i % BITS (ai[0]);
clib_bitmap_vec_validate (ai, i0);
for (i = 0; i <= i0; i++)
{
uword n;
for (n = 0; n < BITS (ai[i]); n += log2_rand_max)
ai[i] |= random_u32 (seed) << n;
}
if (i1 + 1 < BITS (ai[0]))
ai[i0] &= (((uword) 1 << (i1 + 1)) - 1);
}
return ai;
}
生成指定成都的随机位图
/** Return the next set bit in a bitmap starting at bit i
@param ai - pointer to the bitmap
@param i - first bit position to test
@returns first set bit position at or after i,
~0 if no further set bits are found
*/
always_inline uword
clib_bitmap_next_set (uword * ai, uword i)
{
uword i0 = i / BITS (ai[0]);
uword i1 = i % BITS (ai[0]);
uword t;
if (i0 < vec_len (ai))
{
t = (ai[i0] >> i1) << i1;
if (t)
return log2_first_set (t) + i0 * BITS (ai[0]);
for (i0++; i0 < vec_len (ai); i0++)
{
t = ai[i0];
if (t)
return log2_first_set (t) + i0 * BITS (ai[0]);
}
}
return ~0;
}
从指定的位置开始寻找下一个设置为1的位的位置
/** Return the next clear bit in a bitmap starting at bit i
@param ai - pointer to the bitmap
@param i - first bit position to test
@returns first clear bit position at or after i
*/
always_inline uword
clib_bitmap_next_clear (uword * ai, uword i)
{
uword i0 = i / BITS (ai[0]);
uword i1 = i % BITS (ai[0]);
uword t;
if (i0 < vec_len (ai))
{
t = (~ai[i0] >> i1) << i1;
if (t)
return log2_first_set (t) + i0 * BITS (ai[0]);
for (i0++; i0 < vec_len (ai); i0++)
{
t = ~ai[i0];
if (t)
return log2_first_set (t) + i0 * BITS (ai[0]);
}
/* no clear bit left in bitmap, return bit just beyond bitmap */
return (i0 + 1) * BITS (ai[0]);
}
return i;
}
从指定的位置开始,寻找下一个设置为0的bit的位置。
剩余3个unformat和format函数后面再详述