/** \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)--)
以指针或者下标形式遍历动态数组中的每一个元素