VPP程式碼閱讀中文註解---bitmap.h
/** \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函式後面再詳述