1. 程式人生 > >VPP程式碼閱讀中文註解--vec.h

VPP程式碼閱讀中文註解--vec.h

/** \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風格的字串為動態陣列