VPP代码阅读中文注解--vec_bootstrap.h

/** \file
    Vector bootstrap header file
*/

/* Bootstrap include so that #include <vppinfra/mem.h> can include e.g.
   <vppinfra/mheap.h> which depends on <vppinfra/vec.h>. */

/** \brief vector header structure

   Bookkeeping header preceding vector elements in memory.
   User header information may preceed standard vec header.
   If you change u32 len -> u64 len, single vectors can
   exceed 2**32 elements. Clib heaps are vectors. */

typedef struct
{
#if CLIB_VEC64 > 0
  u64 len;
#else
  u32 len; /**< Number of elements in vector (NOT its allocated length). */
  u32 dlmalloc_header_offset;	/**< offset to memory allocator offset  */
#endif
  u8 vector_data[0];  /**< Vector data . */
} vec_header_t;

向量即动态数组,这里的vec_header_t只是动态数组的头结构,表示这个数组有多少个数组元素,即它的规模。数组0号元素的位置是vector_data对应的内存地址。

使用这个结构的时候,也可以在vec_header_t前再加1个额外的头结构,描述这个具体动态数组整体更详细的一些信息,这个具体使用时具体分析。

dlmalloc_header_offset暂不分析。

/** \brief Find the vector header

    Given the user's pointer to a vector, find the corresponding
    vector header

    @param v pointer to a vector
    @return pointer to the vector's vector_header_t
*/
#define _vec_find(v)	((vec_header_t *) (v) - 1)

根据动态数组0号元素的地址计算出vec_header_t头部的地址

#define _vec_round_size(s) \
  (((s) + sizeof (uword) - 1) &~ (sizeof (uword) - 1))

可能增加s的值,使得其是cpu字长的整数倍。如4的整数倍或者8的整数倍

always_inline uword
vec_header_bytes (uword header_bytes)
{
  return round_pow2 (header_bytes + sizeof (vec_header_t),
		     sizeof (vec_header_t));
}

用户定义的头部长度加上动态数组自己的头部长度,并8字节对齐。

用户定义的头部长度可以为0。

/** \brief Find a user vector header

    Finds the user header of a vector with unspecified alignment given
    the user pointer to the vector.
*/

always_inline void *
vec_header (void *v, uword header_bytes)
{
  return v - vec_header_bytes (header_bytes);
}

根据动态数组第0号元素的地址获取用户自定义头的内存地址,如果没有用户自定义头,则获取到的是动态数组头的地址。

/** \brief Find the end of user vector header

    Finds the end of the user header of a vector with unspecified
    alignment given the user pointer to the vector.
*/

always_inline void *
vec_header_end (void *v, uword header_bytes)
{
  return v + vec_header_bytes (header_bytes);
}

根据用户自定义头的内存地址,获取动态数组第0号元素的地址

always_inline uword
vec_aligned_header_bytes (uword header_bytes, uword align)
{
  return round_pow2 (header_bytes + sizeof (vec_header_t), align);
}

always_inline void *
vec_aligned_header (void *v, uword header_bytes, uword align)
{
  return v - vec_aligned_header_bytes (header_bytes, align);
}

always_inline void *
vec_aligned_header_end (void *v, uword header_bytes, uword align)
{
  return v + vec_aligned_header_bytes (header_bytes, align);
}

和前面的代码类似,只是不再是8字节内存对齐,而是通过align参数来控制对齐。

/** \brief Number of elements in vector (lvalue-capable)

   _vec_len (v) does not check for null, but can be used as a lvalue
   (e.g. _vec_len (v) = 99).
*/

#define _vec_len(v)	(_vec_find(v)->len)

读取动态数组的元素个数,可以作为左值,进行赋值

/** \brief Number of elements in vector (rvalue-only, NULL tolerant)

    vec_len (v) checks for NULL, but cannot be used as an lvalue.
    If in doubt, use vec_len...
*/

#define vec_len(v)	((v) ? _vec_len(v) : 0)

同上,只能做为右值,但右空指针判断。

如果v为空指针,表示当前动态数组没有有效的元素,可能只有数组头部,也可能有用户自定义的头部,还可能动态数组的内存空间已经申请好,只是没有使用而已。

/** \brief Reset vector length to zero
    NULL-pointer tolerant
*/

#define vec_reset_length(v) do { if (v) _vec_len (v) = 0; } while (0)

将数组长度置0,其实就是宣布当前数组中的内容失效。

/** \brief Number of data bytes in vector. */

#define vec_bytes(v) (vec_len (v) * sizeof (v[0]))

计算当前数组数据部分已占用的内存空间(字节数). 即每一个数组元素的大小乘以数组元素个数

/** \brief Total number of bytes that can fit in vector with current allocation. */

#define vec_capacity(v,b)							\
({										\
  void * _vec_capacity_v = (void *) (v);					\
  uword _vec_capacity_b = (b);							\
  _vec_capacity_b = sizeof (vec_header_t) + _vec_round_size (_vec_capacity_b);	\
  _vec_capacity_v ? clib_mem_size (_vec_capacity_v - _vec_capacity_b) : 0;	\
})

计算动态数组占用的内存空间,也包含2种类型的头部,不仅仅是数据部分

/** \brief Total number of elements that can fit into vector. */
#define vec_max_len(v) (vec_capacity(v,0) / sizeof (v[0]))

当前已分配的内存最多容纳的元素个数,实际上达不到,因为忽略了8字节的数组头部。

/** \brief End (last data address) of vector. */
#define vec_end(v)	((v) + vec_len (v))

当前数组元素的最后一个元素的下一个位置,新元素在这里追加

/** \brief True if given pointer is within given vector. */
#define vec_is_member(v,e) ((e) >= (v) && (e) < vec_end (v))

判断一个元素是否合法的数组元素,是否越界

/** \brief Get vector value at index i checking that i is in bounds. */
#define vec_elt_at_index(v,i)			\
({						\
  ASSERT ((i) < vec_len (v));			\
  (v) + (i);					\
})

读取第i号数组元素

/** \brief Get vector value at index i */
#define vec_elt(v,i) (vec_elt_at_index(v,i))[0]

同上,不过不是指针形式,而是结构体形式。

/** \brief Vector iterator */
#define vec_foreach(var,vec) for (var = (vec); var < vec_end (vec); var++)

/** \brief Vector iterator (reverse) */
#define vec_foreach_backwards(var,vec) \
for (var = vec_end (vec) - 1; var >= (vec); var--)

/** \brief Iterate over vector indices. */
#define vec_foreach_index(var,v) for ((var) = 0; (var) < vec_len (v); (var)++)

/** \brief Iterate over vector indices (reverse). */
#define vec_foreach_index_backwards(var,v) \
  for ((var) = vec_len((v)) - 1; (var) >= 0; (var)--)

以指针或者下标形式遍历动态数组中的每一个元素

猜你喜欢

转载自blog.csdn.net/weixin_40870382/article/details/83094536