/** \file
CLIB vectors are ubiquitous dynamically resized arrays with by user
defined "headers". Many CLIB data structures (e.g. hash, heap,
pool) are vectors with various different headers.
The memory layout looks like this:
~~~~~~~~
user header (aligned to uword boundary)
vector length: number of elements
user's pointer-> vector element #0
vector element #1
...
~~~~~~~~
The user pointer contains the address of vector element # 0. Null
pointer vectors are valid and mean a zero length vector.
You can reset the length of an allocated vector to zero via the
vec_reset_length(v) macro, or by setting the vector length field to
zero (e.g. _vec_len (v) = 0). Vec_reset_length(v) preferred: it
understands Null pointers.
Typically, the header is not present. Headers allow for other
data structures to be built atop CLIB vectors.
Users may specify the alignment for data elements via the
vec_*_aligned macros.
Vectors elements can be any C type e.g. (int, double, struct bar).
This is also true for data types built atop vectors (e.g. heap,
pool, etc.).
Many macros have _a variants supporting alignment of vector data
and _h variants supporting non zero length vector headers.
The _ha variants support both.
Standard programming error: memorize a pointer to the ith element
of a vector then expand it. Vectors expand by 3/2, so such code
may appear to work for a period of time. Memorize vector indices
which are invariant.
*/
简单翻译一下。clib向量即动态数组(尺寸可调整)。动态数组的前面支持包含用户自定义的头部。许多CLIB数据结构都依赖于此动态数组(如哈希,堆,池). 它们都是动态数组,并且拥有自己的特殊的头部。在内存中,这些信息按如下方式组织。
~~~~~~~~
user header (aligned to uword boundary)
vector length: number of elements
user's pointer-> vector element #0
vector element #1
...
~~~~~~~~
用户指针即0号元素的地址。这个指针可以为空,此时表示没有一个数组元素。
建议使用vec_reset_length宏来将数组的长度置0
通常情况下,user header可以不存在
用户可以指明数组元素的对齐方式
数组元素可以是任何的C语言类型
大多数函数宏有3个变体, _h后缀代表有用户自定义头部,_a变体代表需要对齐数元素
_ha代表_h和_a的综合。
典型的编程错误有:在代码中记录下一个数组元素的指针,然后后续继续多次使用。这样会有问题。因为数组动态扩展的原因,随着时间的推移,原有数组的内容会拷贝到新的内存空间,原有数组会释放。大多数时候,数组按原数组3/2的大小进行扩容。
/** \brief Low-level resize allocation function, usually not called directly
@param v pointer to a vector
@param length_increment length increment in elements
@param data_bytes requested size in bytes
@param header_bytes header size in bytes (may be zero)
@param data_align alignment (may be zero)
@return v_prime pointer to resized vector, may or may not equal v
*/
void *vec_resize_allocate_memory (void *v,
word length_increment,
uword data_bytes,
uword header_bytes, uword data_align);
用于重新申请内存的函数,主要用来扩展动态数组。
输入参数: v 当前0号数组元素的地址,length_increment 需要增加的数组元素个数,
data_bytes, 所有数组元素需要占用的内存空间大小
header_bytes, 用户自定义头部所占用的内存空间大小
data_align, 每一个数组元素的内存对齐字节数
返回值: 新数组0号元素的地址(可能和v相等,这个时候表明没有实际申请内存,而是在原有内存空间上尾部增加表项)
/** \brief Low-level vector resize function, usually not called directly
@param v pointer to a vector
@param length_increment length increment in elements
@param data_bytes requested size in bytes
@param header_bytes header size in bytes (may be zero)
@param data_align alignment (may be zero)
@return v_prime pointer to resized vector, may or may not equal v
*/
#define _vec_resize(V,L,DB,HB,A) \
_vec_resize_inline(V,L,DB,HB,clib_max((__alignof__((V)[0])),(A)))
always_inline void *
_vec_resize_inline (void *v,
word length_increment,
uword data_bytes, uword header_bytes, uword data_align)
{
vec_header_t *vh = _vec_find (v);
uword new_data_bytes, aligned_header_bytes;
aligned_header_bytes = vec_header_bytes (header_bytes);
new_data_bytes = data_bytes + aligned_header_bytes;
if (PREDICT_TRUE (v != 0))
{
void *p = v - aligned_header_bytes;
/* Vector header must start heap object. */
ASSERT (clib_mem_is_heap_object (p));
/* Typically we'll not need to resize. */
if (new_data_bytes <= clib_mem_size (p))
{
vh->len += length_increment;
return v;
}
}
/* Slow path: call helper function. */
return vec_resize_allocate_memory (v, length_increment, data_bytes,
header_bytes,
clib_max (sizeof (vec_header_t),
data_align));
}
如上述代码所示,多数情况下,只需要在当前内存增加表项。不需要新申请内存。
vh->len += length_increment;
如果需要申请内存,再走慢路径(slow path)
/** \brief Determine if vector will resize with next allocation
@param v pointer to a vector
@param length_increment length increment in elements
@param data_bytes requested size in bytes
@param header_bytes header size in bytes (may be zero)
@param data_align alignment (may be zero)
@return 1 if vector will resize 0 otherwise
*/
always_inline int
_vec_resize_will_expand (void *v,
word length_increment,
uword data_bytes, uword header_bytes,
uword data_align)
{
uword new_data_bytes, aligned_header_bytes;
aligned_header_bytes = vec_header_bytes (header_bytes);
new_data_bytes = data_bytes + aligned_header_bytes;
if (PREDICT_TRUE (v != 0))
{
void *p = v - aligned_header_bytes;
/* Vector header must start heap object. */
ASSERT (clib_mem_is_heap_object (p));
/* Typically we'll not need to resize. */
if (new_data_bytes <= clib_mem_size (p))
return 0;
}
return 1;
}
判断是否需要申请新的内存(原内存当前是否够用),返回1表示需要重新申请。
/** \brief Predicate function, says whether the supplied vector is a clib heap
object (general version).
@param v pointer to a vector
@param header_bytes vector header size in bytes (may be zero)
@return 0 or 1
*/
uword clib_mem_is_vec_h (void *v, uword header_bytes);
/** \brief Predicate function, says whether the supplied vector is a clib heap
object
@param v pointer to a vector
@return 0 or 1
*/
always_inline uword
clib_mem_is_vec (void *v)
{
return clib_mem_is_vec_h (v, 0);
}
判断此向量(动态数组)是否在CLIB heap这种结构中。
/* Local variable naming macro (prevents collisions with other macro naming). */
#define _v(var) _vec_##var
函数宏内部定义的局部变量加上前缀,这样,其它头文件的局部变量也加上自己的前缀。避免变量名冲突。
/** \brief Resize a vector (general version).
Add N elements to end of given vector V, return pointer to start of vector.
Vector will have room for H header bytes and will have user's data aligned
at alignment A (rounded to next power of 2).
@param V pointer to a vector
@param N number of elements to add
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_resize_ha(V,N,H,A) \
do { \
word _v(n) = (N); \
word _v(l) = vec_len (V); \
V = _vec_resize ((V), _v(n), (_v(l) + _v(n)) * sizeof ((V)[0]), (H), (A)); \
} while (0)
/** \brief Resize a vector (no header, unspecified alignment)
Add N elements to end of given vector V, return pointer to start of vector.
Vector will have room for H header bytes and will have user's data aligned
at alignment A (rounded to next power of 2).
@param V pointer to a vector
@param N number of elements to add
@return V (value-result macro parameter)
*/
#define vec_resize(V,N) vec_resize_ha(V,N,0,0)
/** \brief Resize a vector (no header, alignment specified).
Add N elements to end of given vector V, return pointer to start of vector.
Vector will have room for H header bytes and will have user's data aligned
at alignment A (rounded to next power of 2).
@param V pointer to a vector
@param N number of elements to add
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_resize_aligned(V,N,A) vec_resize_ha(V,N,0,A)
向动态数组V增加N个元素的3种宏。这里只是把空间留出来,这N个元素的内容还没有填值。
/** \brief Allocate space for N more elements
@param V pointer to a vector
@param N number of elements to add
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_alloc_ha(V,N,H,A) \
do { \
uword _v(l) = vec_len (V); \
vec_resize_ha (V, N, H, A); \
_vec_len (V) = _v(l); \
} while (0)
/** \brief Allocate space for N more elements
(no header, unspecified alignment)
@param V pointer to a vector
@param N number of elements to add
@return V (value-result macro parameter)
*/
#define vec_alloc(V,N) vec_alloc_ha(V,N,0,0)
/** \brief Allocate space for N more elements (no header, given alignment)
@param V pointer to a vector
@param N number of elements to add
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_alloc_aligned(V,N,A) vec_alloc_ha(V,N,0,A)
这3个宏与之前略有差别,即申请了需要的内存空间后,原有的数组元素个数保持不变。
/** \brief Create new vector of given type and length (general version).
@param T type of elements in new vector
@param N number of elements to add
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V new vector
*/
#define vec_new_ha(T,N,H,A) \
({ \
word _v(n) = (N); \
_vec_resize ((T *) 0, _v(n), _v(n) * sizeof (T), (H), (A)); \
})
/** \brief Create new vector of given type and length
(unspecified alignment, no header).
@param T type of elements in new vector
@param N number of elements to add
@return V new vector
*/
#define vec_new(T,N) vec_new_ha(T,N,0,0)
/** \brief Create new vector of given type and length
(alignment specified, no header).
@param T type of elements in new vector
@param N number of elements to add
@param A alignment (may be zero)
@return V new vector
*/
#define vec_new_aligned(T,N,A) vec_new_ha(T,N,0,A)
新申请一个动态数组的3个宏。
/** \brief Free vector's memory (general version)
@param V pointer to a vector
@param H size of header in bytes
@return V (value-result parameter, V=0)
*/
#define vec_free_h(V,H) \
do { \
if (V) \
{ \
clib_mem_free (vec_header ((V), (H))); \
V = 0; \
} \
} while (0)
/** \brief Free vector's memory (no header).
@param V pointer to a vector
@return V (value-result parameter, V=0)
*/
#define vec_free(V) vec_free_h(V,0)
/**\brief Free vector user header (syntactic sugar)
@param h vector header
@void
*/
#define vec_free_header(h) clib_mem_free (h)
释放动态数组对应的内存空间
/** \brief Return copy of vector (general version).
@param V pointer to a vector
@param H size of header in bytes
@param A alignment (may be zero)
@return Vdup copy of vector
*/
#define vec_dup_ha(V,H,A) \
({ \
__typeof__ ((V)[0]) * _v(v) = 0; \
uword _v(l) = vec_len (V); \
if (_v(l) > 0) \
{ \
vec_resize_ha (_v(v), _v(l), (H), (A)); \
clib_memcpy (_v(v), (V), _v(l) * sizeof ((V)[0]));\
} \
_v(v); \
})
/** \brief Return copy of vector (no header, no alignment)
@param V pointer to a vector
@return Vdup copy of vector
*/
#define vec_dup(V) vec_dup_ha(V,0,0)
/** \brief Return copy of vector (no header, alignment specified).
@param V pointer to a vector
@param A alignment (may be zero)
@return Vdup copy of vector
*/
#define vec_dup_aligned(V,A) vec_dup_ha(V,0,A)
根据原有的动态数组,生成一个动态数组的副本。
即新动态数组内容与原动态数组相同。
/** \brief Copy a vector, memcpy wrapper. Assumes sizeof(SRC[0]) ==
sizeof(DST[0])
@param DST destination
@param SRC source
*/
#define vec_copy(DST,SRC) clib_memcpy (DST, SRC, vec_len (DST) * \
sizeof ((DST)[0]))
拷贝动态数组,目标动态数组空间足够,才能使用这个。
/** \brief Clone a vector. Make a new vector with the
same size as a given vector but possibly with a different type.
@param NEW_V pointer to new vector
@param OLD_V pointer to old vector
*/
#define vec_clone(NEW_V,OLD_V) \
do { \
(NEW_V) = 0; \
(NEW_V) = _vec_resize ((NEW_V), vec_len (OLD_V), \
vec_len (OLD_V) * sizeof ((NEW_V)[0]), (0), (0)); \
} while (0)
克隆旧数组到新数组, 但新数组的数据没有填值。
/** \brief Make sure vector is long enough for given index (general version).
@param V (possibly NULL) pointer to a vector.
@param I vector index which will be valid upon return
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_validate_ha(V,I,H,A) \
do { \
STATIC_ASSERT(A==0 || ((A % sizeof(V[0]))==0) || ((sizeof(V[0]) % A) == 0),\
"vector validate aligned on incorrectly sized object"); \
word _v(i) = (I); \
word _v(l) = vec_len (V); \
if (_v(i) >= _v(l)) \
{ \
vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A)); \
/* Must zero new space since user may have previously \
used e.g. _vec_len (v) -= 10 */ \
memset ((V) + _v(l), 0, (1 + (_v(i) - _v(l))) * sizeof ((V)[0])); \
} \
} while (0)
/** \brief Make sure vector is long enough for given index
(no header, unspecified alignment)
@param V (possibly NULL) pointer to a vector.
@param I vector index which will be valid upon return
@return V (value-result macro parameter)
*/
#define vec_validate(V,I) vec_validate_ha(V,I,0,0)
/** \brief Make sure vector is long enough for given index
(no header, specified alignment)
@param V (possibly NULL) pointer to a vector.
@param I vector index which will be valid upon return
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_validate_aligned(V,I,A) vec_validate_ha(V,I,0,A)
确保第 i 个数组元素有效,即当前元素个数不大于 i 时,则动态扩展数组。
/** \brief Make sure vector is long enough for given index
and initialize empty space (general version)
@param V (possibly NULL) pointer to a vector.
@param I vector index which will be valid upon return
@param INIT initial value (can be a complex expression!)
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_validate_init_empty_ha(V,I,INIT,H,A) \
do { \
word _v(i) = (I); \
word _v(l) = vec_len (V); \
if (_v(i) >= _v(l)) \
{ \
vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A)); \
while (_v(l) <= _v(i)) \
{ \
(V)[_v(l)] = (INIT); \
_v(l)++; \
} \
} \
} while (0)
/** \brief Make sure vector is long enough for given index
and initialize empty space (no header, unspecified alignment)
@param V (possibly NULL) pointer to a vector.
@param I vector index which will be valid upon return
@param INIT initial value (can be a complex expression!)
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_validate_init_empty(V,I,INIT) \
vec_validate_init_empty_ha(V,I,INIT,0,0)
/** \brief Make sure vector is long enough for given index
and initialize empty space (no header, alignment alignment)
@param V (possibly NULL) pointer to a vector.
@param I vector index which will be valid upon return
@param INIT initial value (can be a complex expression!)
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_validate_init_empty_aligned(V,I,INIT,A) \
vec_validate_init_empty_ha(V,I,INIT,0,A)
同上,对新增加的元素使用INIT表达式初始化
/** \brief Add 1 element to end of vector (general version).
@param V pointer to a vector
@param E element to add
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_add1_ha(V,E,H,A) \
do { \
word _v(l) = vec_len (V); \
V = _vec_resize ((V), 1, (_v(l) + 1) * sizeof ((V)[0]), (H), (A)); \
(V)[_v(l)] = (E); \
} while (0)
/** \brief Add 1 element to end of vector (unspecified alignment).
@param V pointer to a vector
@param E element to add
@return V (value-result macro parameter)
*/
#define vec_add1(V,E) vec_add1_ha(V,E,0,0)
/** \brief Add 1 element to end of vector (alignment specified).
@param V pointer to a vector
@param E element to add
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_add1_aligned(V,E,A) vec_add1_ha(V,E,0,A)
向动态数组尾部增加一个表项
/** \brief Add 1 element to end of vector (alignment specified).
@param V pointer to a vector
@param E element to add
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_add1_aligned(V,E,A) vec_add1_ha(V,E,0,A)
/** \brief Add N elements to end of vector V,
return pointer to new elements in P. (general version)
@param V pointer to a vector
@param P pointer to new vector element(s)
@param N number of elements to add
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V and P (value-result macro parameters)
*/
#define vec_add2_ha(V,P,N,H,A) \
do { \
word _v(n) = (N); \
word _v(l) = vec_len (V); \
V = _vec_resize ((V), _v(n), (_v(l) + _v(n)) * sizeof ((V)[0]), (H), (A)); \
P = (V) + _v(l); \
} while (0)
/** \brief Add N elements to end of vector V,
return pointer to new elements in P. (no header, unspecified alignment)
@param V pointer to a vector
@param P pointer to new vector element(s)
@param N number of elements to add
@return V and P (value-result macro parameters)
*/
#define vec_add2(V,P,N) vec_add2_ha(V,P,N,0,0)
/** \brief Add N elements to end of vector V,
return pointer to new elements in P. (no header, alignment specified)
@param V pointer to a vector
@param P pointer to new vector element(s)
@param N number of elements to add
@param A alignment (may be zero)
@return V and P (value-result macro parameters)
*/
#define vec_add2_aligned(V,P,N,A) vec_add2_ha(V,P,N,0,A)
在动态数组V后添加多个表项,多个表项的首地址为P, 表项数目为N。此函数执行后,只是预留了多个表项的内存,并将P变量指向动态数组中这多个表项的首地址。为后续拷贝数据服务。
/** \brief Add N elements to end of vector V (general version)
@param V pointer to a vector
@param E pointer to element(s) to add
@param N number of elements to add
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_add_ha(V,E,N,H,A) \
do { \
word _v(n) = (N); \
word _v(l) = vec_len (V); \
V = _vec_resize ((V), _v(n), (_v(l) + _v(n)) * sizeof ((V)[0]), (H), (A)); \
clib_memcpy ((V) + _v(l), (E), _v(n) * sizeof ((V)[0])); \
} while (0)
/** \brief Add N elements to end of vector V (no header, unspecified alignment)
@param V pointer to a vector
@param E pointer to element(s) to add
@param N number of elements to add
@return V (value-result macro parameter)
*/
#define vec_add(V,E,N) vec_add_ha(V,E,N,0,0)
/** \brief Add N elements to end of vector V (no header, specified alignment)
@param V pointer to a vector
@param E pointer to element(s) to add
@param N number of elements to add
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_add_aligned(V,E,N,A) vec_add_ha(V,E,N,0,A)
向动态数组添加多个表项,这个时候会拷贝数据。所以用户一般使用这个向动态数组添加数据。
/** \brief Returns last element of a vector and decrements its length
@param V pointer to a vector
@return E element removed from the end of the vector
*/
#define vec_pop(V) \
({ \
uword _v(l) = vec_len (V); \
ASSERT (_v(l) > 0); \
_v(l) -= 1; \
_vec_len (V) = _v (l); \
(V)[_v(l)]; \
})
/** \brief Set E to the last element of a vector, decrement vector length
@param V pointer to a vector
@param E pointer to the last vector element
@return E element removed from the end of the vector
(value-result macro parameter
*/
#define vec_pop2(V,E) \
({ \
uword _v(l) = vec_len (V); \
if (_v(l) > 0) (E) = vec_pop (V); \
_v(l) > 0; \
})
获取动态数组尾部元素的2个宏
/** \brief Insert N vector elements starting at element M,
initialize new elements (general version).
@param V (possibly NULL) pointer to a vector.
@param N number of elements to insert
@param M insertion point
@param INIT initial value (can be a complex expression!)
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_insert_init_empty_ha(V,N,M,INIT,H,A) \
do { \
word _v(l) = vec_len (V); \
word _v(n) = (N); \
word _v(m) = (M); \
V = _vec_resize ((V), \
_v(n), \
(_v(l) + _v(n))*sizeof((V)[0]), \
(H), (A)); \
ASSERT (_v(m) <= _v(l)); \
memmove ((V) + _v(m) + _v(n), \
(V) + _v(m), \
(_v(l) - _v(m)) * sizeof ((V)[0])); \
memset ((V) + _v(m), INIT, _v(n) * sizeof ((V)[0])); \
} while (0)
/** \brief Insert N vector elements starting at element M,
initialize new elements to zero (general version)
@param V (possibly NULL) pointer to a vector.
@param N number of elements to insert
@param M insertion point
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_insert_ha(V,N,M,H,A) vec_insert_init_empty_ha(V,N,M,0,H,A)
/** \brief Insert N vector elements starting at element M,
initialize new elements to zero (no header, unspecified alignment)
@param V (possibly NULL) pointer to a vector.
@param N number of elements to insert
@param M insertion point
@return V (value-result macro parameter)
*/
#define vec_insert(V,N,M) vec_insert_ha(V,N,M,0,0)
/** \brief Insert N vector elements starting at element M,
initialize new elements to zero (no header, alignment specified)
@param V (possibly NULL) pointer to a vector.
@param N number of elements to insert
@param M insertion point
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_insert_aligned(V,N,M,A) vec_insert_ha(V,N,M,0,A)
/** \brief Insert N vector elements starting at element M,
initialize new elements (no header, unspecified alignment)
@param V (possibly NULL) pointer to a vector.
@param N number of elements to insert
@param M insertion point
@param INIT initial value (can be a complex expression!)
@return V (value-result macro parameter)
*/
#define vec_insert_init_empty(V,N,M,INIT) \
vec_insert_init_empty_ha(V,N,M,INIT,0,0)
/* Resize vector by N elements starting from element M, initialize new elements to INIT (alignment specified, no header). */
/** \brief Insert N vector elements starting at element M,
initialize new elements (no header, specified alignment)
@param V (possibly NULL) pointer to a vector.
@param N number of elements to insert
@param M insertion point
@param INIT initial value (can be a complex expression!)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_insert_init_empty_aligned(V,N,M,INIT,A) \
vec_insert_init_empty_ha(V,N,M,INIT,0,A)
在动态数组的首部或者中部插入表项。并初始化新插入的表项。
/** \brief Insert N vector elements starting at element M,
insert given elements (general version)
@param V (possibly NULL) pointer to a vector.
@param E element(s) to insert
@param N number of elements to insert
@param M insertion point
@param H header size in bytes (may be zero)
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_insert_elts_ha(V,E,N,M,H,A) \
do { \
word _v(l) = vec_len (V); \
word _v(n) = (N); \
word _v(m) = (M); \
V = _vec_resize ((V), \
_v(n), \
(_v(l) + _v(n))*sizeof((V)[0]), \
(H), (A)); \
ASSERT (_v(m) <= _v(l)); \
memmove ((V) + _v(m) + _v(n), \
(V) + _v(m), \
(_v(l) - _v(m)) * sizeof ((V)[0])); \
clib_memcpy ((V) + _v(m), (E), \
_v(n) * sizeof ((V)[0])); \
} while (0)
/** \brief Insert N vector elements starting at element M,
insert given elements (no header, unspecified alignment)
@param V (possibly NULL) pointer to a vector.
@param E element(s) to insert
@param N number of elements to insert
@param M insertion point
@return V (value-result macro parameter)
*/
#define vec_insert_elts(V,E,N,M) vec_insert_elts_ha(V,E,N,M,0,0)
/** \brief Insert N vector elements starting at element M,
insert given elements (no header, specified alignment)
@param V (possibly NULL) pointer to a vector.
@param E element(s) to insert
@param N number of elements to insert
@param M insertion point
@param A alignment (may be zero)
@return V (value-result macro parameter)
*/
#define vec_insert_elts_aligned(V,E,N,M,A) vec_insert_elts_ha(V,E,N,M,0,A)
插入多个已有的数据到动态数组中(首部或者中部)
/** \brief Delete N elements starting at element M
@param V pointer to a vector
@param N number of elements to delete
@param M first element to delete
@return V (value-result macro parameter)
*/
#define vec_delete(V,N,M) \
do { \
word _v(l) = vec_len (V); \
word _v(n) = (N); \
word _v(m) = (M); \
/* Copy over deleted elements. */ \
if (_v(l) - _v(n) - _v(m) > 0) \
memmove ((V) + _v(m), (V) + _v(m) + _v(n), \
(_v(l) - _v(n) - _v(m)) * sizeof ((V)[0])); \
/* Zero empty space at end (for future re-allocation). */ \
if (_v(n) > 0) \
memset ((V) + _v(l) - _v(n), 0, _v(n) * sizeof ((V)[0])); \
_vec_len (V) -= _v(n); \
} while (0)
从下标M开始,删除N个元素
/** \brief Delete the element at index I
@param V pointer to a vector
@param I index to delete
*/
#define vec_del1(v,i) \
do { \
uword _vec_del_l = _vec_len (v) - 1; \
uword _vec_del_i = (i); \
if (_vec_del_i < _vec_del_l) \
(v)[_vec_del_i] = (v)[_vec_del_l]; \
_vec_len (v) = _vec_del_l; \
} while (0)
删除下标为 i 的元素
/** \brief Append v2 after v1. Result in v1.
@param V1 target vector
@param V2 vector to append
*/
#define vec_append(v1,v2) \
do { \
uword _v(l1) = vec_len (v1); \
uword _v(l2) = vec_len (v2); \
\
v1 = _vec_resize ((v1), _v(l2), \
(_v(l1) + _v(l2)) * sizeof ((v1)[0]), 0, 0); \
clib_memcpy ((v1) + _v(l1), (v2), _v(l2) * sizeof ((v2)[0])); \
} while (0)
/** \brief Append v2 after v1. Result in v1. Specified alignment.
@param V1 target vector
@param V2 vector to append
@param align required alignment
*/
#define vec_append_aligned(v1,v2,align) \
do { \
uword _v(l1) = vec_len (v1); \
uword _v(l2) = vec_len (v2); \
\
v1 = _vec_resize ((v1), _v(l2), \
(_v(l1) + _v(l2)) * sizeof ((v1)[0]), 0, align); \
clib_memcpy ((v1) + _v(l1), (v2), _v(l2) * sizeof ((v2)[0])); \
} while (0)
连接2个动态数组,V2连接到V1后面,返回V1。
/** \brief Prepend v2 before v1. Result in v1.
@param V1 target vector
@param V2 vector to prepend
*/
#define vec_prepend(v1,v2) \
do { \
uword _v(l1) = vec_len (v1); \
uword _v(l2) = vec_len (v2); \
\
v1 = _vec_resize ((v1), _v(l2), \
(_v(l1) + _v(l2)) * sizeof ((v1)[0]), 0, 0); \
memmove ((v1) + _v(l2), (v1), _v(l1) * sizeof ((v1)[0])); \
clib_memcpy ((v1), (v2), _v(l2) * sizeof ((v2)[0])); \
} while (0)
同上,但V2在V1前面
/** \brief Prepend v2 before v1. Result in v1. Specified alignment
@param V1 target vector
@param V2 vector to prepend
@param align required alignment
*/
#define vec_prepend_aligned(v1,v2,align) \
do { \
uword _v(l1) = vec_len (v1); \
uword _v(l2) = vec_len (v2); \
\
v1 = _vec_resize ((v1), _v(l2), \
(_v(l1) + _v(l2)) * sizeof ((v1)[0]), 0, align); \
memmove ((v1) + _v(l2), (v1), _v(l1) * sizeof ((v1)[0])); \
clib_memcpy ((v1), (v2), _v(l2) * sizeof ((v2)[0])); \
} while (0)
同上
/** \brief Zero all vector elements. Null-pointer tolerant.
@param var Vector to zero
*/
#define vec_zero(var) \
do { \
if (var) \
memset ((var), 0, vec_len (var) * sizeof ((var)[0])); \
} while (0)
所有数组元素清0
/** \brief Set all vector elements to given value. Null-pointer tolerant.
@param v vector to set
@param val value for each vector element
*/
#define vec_set(v,val) \
do { \
word _v(i); \
__typeof__ ((v)[0]) _val = (val); \
for (_v(i) = 0; _v(i) < vec_len (v); _v(i)++) \
(v)[_v(i)] = _val; \
} while (0)
设置所有元素的值为val。
/** \brief Compare two vectors, not NULL-pointer tolerant
@param v1 Pointer to a vector
@param v2 Pointer to a vector
@return 1 if equal, 0 if unequal
*/
#define vec_is_equal(v1,v2) \
(vec_len (v1) == vec_len (v2) && ! memcmp ((v1), (v2), vec_len (v1) * sizeof ((v1)[0])))
/** \brief Compare two vectors (only applicable to vectors of signed numbers).
Used in qsort compare functions.
@param v1 Pointer to a vector
@param v2 Pointer to a vector
@return -1, 0, +1
*/
#define vec_cmp(v1,v2) \
({ \
word _v(i), _v(cmp), _v(l); \
_v(l) = clib_min (vec_len (v1), vec_len (v2)); \
_v(cmp) = 0; \
for (_v(i) = 0; _v(i) < _v(l); _v(i)++) { \
_v(cmp) = (v1)[_v(i)] - (v2)[_v(i)]; \
if (_v(cmp)) \
break; \
} \
if (_v(cmp) == 0 && _v(l) > 0) \
_v(cmp) = vec_len(v1) - vec_len(v2); \
(_v(cmp) < 0 ? -1 : (_v(cmp) > 0 ? +1 : 0)); \
})
判断2个数组是否相等,以及比较2个数组的大小
/** \brief Search a vector for the index of the entry that matches.
@param v1 Pointer to a vector
@param v2 Entry to match
@return index of match or ~0
*/
#define vec_search(v,E) \
({ \
word _v(i) = 0; \
while (_v(i) < vec_len(v)) \
{ \
if ((v)[_v(i)] == E) \
break; \
_v(i)++; \
} \
if (_v(i) == vec_len(v)) \
_v(i) = ~0; \
_v(i); \
})
根据值在动态数组中查找指定的元素,返回元素的下标
/** \brief Search a vector for the index of the entry that matches.
@param v1 Pointer to a vector
@param v2 Pointer to entry to match
@param fn Comparison function !0 => match
@return index of match or ~0
*/
#define vec_search_with_function(v,E,fn) \
({ \
word _v(i) = 0; \
while (_v(i) < vec_len(v)) \
{ \
if (0 != fn(&(v)[_v(i)], (E))) \
break; \
_v(i)++; \
} \
if (_v(i) == vec_len(v)) \
_v(i) = ~0; \
_v(i); \
})
同上,但使用自定义函数来判断表项是否匹配
/** \brief Sort a vector using the supplied element comparison function
@param vec vector to sort
@param f comparison function
*/
#define vec_sort_with_function(vec,f) \
do { \
qsort (vec, vec_len (vec), sizeof (vec[0]), (void *) (f)); \
} while (0)
对动态数组中的所有元素进行快速排序
/** \brief Make a vector containing a NULL terminated c-string.
@param V (possibly NULL) pointer to a vector.
@param S pointer to string buffer.
@param L string length (NOT including the terminating NULL; a la strlen())
*/
#define vec_validate_init_c_string(V, S, L) \
do { \
vec_reset_length (V); \
vec_validate ((V), (L)); \
if ((S) && (L)) \
clib_memcpy ((V), (S), (L)); \
(V)[(L)] = 0; \
} while (0)
/** \brief Test whether a vector is a NULL terminated c-string.
@param V (possibly NULL) pointer to a vector.
@return BOOLEAN indicating if the vector c-string is null terminated.
*/
#define vec_c_string_is_terminated(V) \
(((V) != 0) && (vec_len (V) != 0) && ((V)[vec_len ((V)) - 1] == 0))
/** \brief (If necessary) NULL terminate a vector containing a c-string.
@param V (possibly NULL) pointer to a vector.
@return V (value-result macro parameter)
*/
#define vec_terminate_c_string(V) \
do { \
u32 vl = vec_len ((V)); \
if (!vec_c_string_is_terminated(V)) \
{ \
vec_validate ((V), vl); \
(V)[vl] = 0; \
} \
} while (0)
将1个动态数组变成C风格的字符串('\0'字符结尾)
判断动态数组是否C风格字符串,即是否空字符结尾
初始化一个C风格的字符串为动态数组