forked from Mirror/frr
lib: darr: add new access and str functions
- darr_last(), and darr_strdup_cap(). - strcat, strdup, strlen, strnul equivs. Signed-off-by: Christian Hopps <chopps@labn.net>
This commit is contained in:
parent
1bb6f21208
commit
f3d6edc7ee
|
@ -379,6 +379,7 @@ else
|
|||
fi
|
||||
AC_C_FLAG([-Wno-unused-parameter])
|
||||
AC_C_FLAG([-Wno-missing-field-initializers])
|
||||
AC_C_FLAG([-Wno-microsoft-anon-tag])
|
||||
|
||||
AC_C_FLAG([-Wc++-compat], [], [CXX_COMPAT_CFLAGS="-Wc++-compat"])
|
||||
AC_SUBST([CXX_COMPAT_CFLAGS])
|
||||
|
|
39
lib/darr.c
39
lib/darr.c
|
@ -52,6 +52,44 @@ static size_t darr_size(uint count, size_t esize)
|
|||
return count * esize + sizeof(struct darr_metadata);
|
||||
}
|
||||
|
||||
char *__darr_in_vsprintf(char **sp, bool concat, const char *fmt, va_list ap)
|
||||
{
|
||||
size_t inlen = concat ? darr_strlen(*sp) : 0;
|
||||
size_t capcount = strlen(fmt) + MIN(inlen + 64, 128);
|
||||
ssize_t len;
|
||||
|
||||
darr_ensure_cap(*sp, capcount);
|
||||
|
||||
if (!concat)
|
||||
darr_reset(*sp);
|
||||
|
||||
/* code below counts on having a NUL terminated string */
|
||||
if (darr_len(*sp) == 0)
|
||||
*darr_append(*sp) = 0;
|
||||
again:
|
||||
len = vsnprintf(darr_last(*sp), darr_avail(*sp), fmt, ap);
|
||||
if (len < 0)
|
||||
darr_in_strcat(*sp, fmt);
|
||||
else if ((size_t)len < darr_avail(*sp))
|
||||
_darr_len(*sp) += len;
|
||||
else {
|
||||
darr_ensure_cap(*sp, darr_len(*sp) + (size_t)len);
|
||||
goto again;
|
||||
}
|
||||
return *sp;
|
||||
}
|
||||
|
||||
char *__darr_in_sprintf(char **sp, bool concat, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
(void)__darr_in_vsprintf(sp, concat, fmt, ap);
|
||||
va_end(ap);
|
||||
return *sp;
|
||||
}
|
||||
|
||||
|
||||
void *__darr_resize(void *a, uint count, size_t esize)
|
||||
{
|
||||
uint ncount = darr_next_count(count, esize);
|
||||
|
@ -69,7 +107,6 @@ void *__darr_resize(void *a, uint count, size_t esize)
|
|||
|
||||
void *__darr_insert_n(void *a, uint at, uint count, size_t esize, bool zero)
|
||||
{
|
||||
|
||||
struct darr_metadata *dm;
|
||||
uint olen, nlen;
|
||||
|
||||
|
|
362
lib/darr.h
362
lib/darr.h
|
@ -10,15 +10,16 @@
|
|||
* - darr_append_n
|
||||
* - darr_append_nz
|
||||
* - darr_cap
|
||||
* - darr_ensure_avail
|
||||
* - darr_ensure_cap
|
||||
* - darr_ensure_i
|
||||
* - darr_foreach_i
|
||||
* - darr_foreach_p
|
||||
* - darr_free
|
||||
* - darr_insert
|
||||
* - darr_insertz
|
||||
* - darr_insert_n
|
||||
* - darr_insert_nz
|
||||
* - darr_last
|
||||
* - darr_lasti
|
||||
* - darr_len
|
||||
* - darr_maxi
|
||||
* - darr_pop
|
||||
|
@ -28,24 +29,56 @@
|
|||
* - darr_remove_n
|
||||
* - darr_reset
|
||||
* - darr_setlen
|
||||
*
|
||||
* Iteration
|
||||
* ---------
|
||||
* - darr_foreach_i
|
||||
* - darr_foreach_p
|
||||
*
|
||||
* String Utilities
|
||||
* ----------------
|
||||
* - darr_in_strcat_tail
|
||||
* - darr_in_strcatf, darr_in_vstrcatf
|
||||
* - darr_in_strdup
|
||||
* - darr_in_strdup_cap
|
||||
* - darr_in_sprintf, darr_in_vsprintf
|
||||
* - darr_set_strlen
|
||||
* - darr_strdup
|
||||
* - darr_strdup_cap
|
||||
* - darr_strlen
|
||||
* - darr_strnul
|
||||
* - darr_sprintf, darr_vsprintf
|
||||
*/
|
||||
/*
|
||||
* A few assured items
|
||||
*
|
||||
* - DAs will never have capacity 0 unless they are NULL pointers.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE: valgrind by default enables a "length64" heuristic (among others) which
|
||||
* identifies "interior-pointer" 8 bytes forward of a "start-pointer" as a
|
||||
* "start-pointer". This should cause what normally would be "possibly-lost"
|
||||
* errors to instead be definite for dynamic arrays. This is b/c the header is 8 bytes
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include "memory.h"
|
||||
|
||||
DECLARE_MTYPE(DARR);
|
||||
|
||||
struct darr_metadata {
|
||||
uint len;
|
||||
uint cap;
|
||||
uint32_t len;
|
||||
uint32_t cap;
|
||||
};
|
||||
void *__darr_insert_n(void *a, uint at, uint count, size_t esize, bool zero);
|
||||
char *__darr_in_sprintf(char **sp, bool concat, const char *fmt, ...)
|
||||
PRINTFRR(3, 4);
|
||||
char *__darr_in_vsprintf(char **sp, bool concat, const char *fmt, va_list ap)
|
||||
PRINTFRR(3, 0);
|
||||
void *__darr_resize(void *a, uint count, size_t esize);
|
||||
|
||||
|
||||
#define _darr_esize(A) sizeof((A)[0])
|
||||
#define darr_esize(A) sizeof((A)[0])
|
||||
#define _darr_len(A) _darr_meta(A)->len
|
||||
|
@ -55,14 +88,15 @@ void *__darr_resize(void *a, uint count, size_t esize);
|
|||
/* Get the current capacity of the array */
|
||||
#define darr_cap(A) (((A) == NULL) ? 0 : _darr_meta(A)->cap)
|
||||
|
||||
/* Get the current available expansion space */
|
||||
#define darr_avail(A) (((A) == NULL) ? 0 : (darr_cap(A) - darr_len(A)))
|
||||
|
||||
/* Get the largest possible index one can `darr_ensure_i` w/o resizing */
|
||||
#define darr_maxi(A) ((int)darr_cap(A) - 1)
|
||||
|
||||
/**
|
||||
* Get the current length of the array.
|
||||
*
|
||||
* As long as `A` is non-NULL, this macro may be used as an L-value to modify
|
||||
* the length of the array.
|
||||
* darr_len() - Get the current length of the array as a unsigned int.
|
||||
* darr_ilen() - Get the current length of the array as an int.
|
||||
*
|
||||
* Args:
|
||||
* A: The dynamic array, can be NULL.
|
||||
|
@ -70,7 +104,19 @@ void *__darr_resize(void *a, uint count, size_t esize);
|
|||
* Return:
|
||||
* The current length of the array.
|
||||
*/
|
||||
#define darr_len(A) (((A) == NULL) ? 0 : _darr_meta(A)->len)
|
||||
#define darr_len(A) (((A) == NULL) ? 0 : _darr_meta(A)->len)
|
||||
#define darr_ilen(A) (((A) == NULL) ? 0 : (ssize_t)_darr_meta(A)->len)
|
||||
|
||||
/**
|
||||
* darr_lasti() - Get the last element's index.
|
||||
*
|
||||
* Args:
|
||||
* A: The dynamic array, can be NULL.
|
||||
*
|
||||
* Return:
|
||||
* The current last element index, or -1 for none.
|
||||
*/
|
||||
#define darr_lasti(A) (darr_ilen(A) - 1)
|
||||
|
||||
/**
|
||||
* Set the current length of the array `A` to 0.
|
||||
|
@ -99,11 +145,41 @@ void *__darr_resize(void *a, uint count, size_t esize);
|
|||
assert((A) || !(L)); \
|
||||
if ((A)) { \
|
||||
/* have to cast to avoid compiler warning for "0" */ \
|
||||
assert((long long)darr_cap(A) >= (L)); \
|
||||
assert((long long)darr_cap(A) >= (long long)(L)); \
|
||||
_darr_len(A) = (L); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Set the string length of the array `S` to `L`, and NUL
|
||||
* terminate the string at L. The dynamic array length will be `L` + 1.
|
||||
*
|
||||
* Thus after calling:
|
||||
*
|
||||
* darr_len(S) == L + 1
|
||||
* darr_strlen(S) == L
|
||||
* S[L] == 0
|
||||
*
|
||||
* This function does *not* guarantee the `L` + 1 memory is allocated to
|
||||
* the array, use `darr_ensure` or `*_cap` functions for that.
|
||||
*
|
||||
* Args:
|
||||
* S: The dynamic array, cannot be NULL.
|
||||
* L: The new str length of the array, will set
|
||||
*
|
||||
* Return:
|
||||
* A pointer to the end of S (i.e., pointing to the NUL byte).
|
||||
*/
|
||||
#define darr_set_strlen(S, L) \
|
||||
({ \
|
||||
assert((S)); \
|
||||
/* have to cast to avoid compiler warning for "0" */ \
|
||||
assert((long long)darr_cap(S) >= (long long)(L)); \
|
||||
_darr_len(S) = (L) + 1; \
|
||||
*darr_last(S) = 0; \
|
||||
darr_last(S); \
|
||||
})
|
||||
|
||||
/**
|
||||
* Free memory allocated for the dynamic array `A`
|
||||
*
|
||||
|
@ -120,6 +196,31 @@ void *__darr_resize(void *a, uint count, size_t esize);
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Make sure that there is room in the dynamic array `A` to add `C` elements.
|
||||
*
|
||||
* Available space is `darr_cap(a) - darr_len(a)`.
|
||||
*
|
||||
* The value `A` may be changed as a result of this call in which case any
|
||||
* pointers into the previous memory block are no longer valid. The `A` value
|
||||
* is guaranteed not to change if there is sufficient capacity in the array.
|
||||
*
|
||||
* Args:
|
||||
* A: (IN/OUT) the dynamic array, can be NULL.
|
||||
* S: Amount of free space to guarantee.
|
||||
*
|
||||
* Return:
|
||||
* A pointer to the (possibly moved) array.
|
||||
*/
|
||||
#define darr_ensure_avail(A, S) \
|
||||
({ \
|
||||
ssize_t need = (ssize_t)(S) - \
|
||||
(ssize_t)(darr_cap(A) - darr_len(A)); \
|
||||
if (need > 0) \
|
||||
_darr_resize((A), darr_cap(A) + need); \
|
||||
(A); \
|
||||
})
|
||||
|
||||
/**
|
||||
* Make sure that there is room in the dynamic array `A` for `C` elements.
|
||||
*
|
||||
|
@ -129,14 +230,15 @@ void *__darr_resize(void *a, uint count, size_t esize);
|
|||
*
|
||||
* Args:
|
||||
* A: (IN/OUT) the dynamic array, can be NULL.
|
||||
* I: the index to guarantee memory exists for
|
||||
* C: Total capacity to guarantee.
|
||||
*
|
||||
* Return:
|
||||
* A pointer to the (possibly moved) array.
|
||||
*/
|
||||
#define darr_ensure_cap(A, C) \
|
||||
({ \
|
||||
if (darr_cap(A) < (C)) \
|
||||
/* Cast to avoid warning when C == 0 */ \
|
||||
if ((ssize_t)darr_cap(A) < (ssize_t)(C)) \
|
||||
_darr_resize((A), (C)); \
|
||||
(A); \
|
||||
})
|
||||
|
@ -348,6 +450,242 @@ void *__darr_resize(void *a, uint count, size_t esize);
|
|||
*/
|
||||
#define darr_end(A) ((A) + darr_len(A))
|
||||
|
||||
/**
|
||||
* darr_last() - Get a pointer to the last element of the array.
|
||||
* darr_strnul() - Get a pointer to the NUL byte of the darr string or NULL.
|
||||
*
|
||||
* Args:
|
||||
* A: The dynamic array, can be NULL.
|
||||
*
|
||||
* Return:
|
||||
* A pointer to the last element of the array or NULL if the array is
|
||||
* empty.
|
||||
*/
|
||||
#define darr_last(A) \
|
||||
({ \
|
||||
uint __len = darr_len(A); \
|
||||
((__len > 0) ? &(A)[__len - 1] : NULL); \
|
||||
})
|
||||
#define darr_strnul(S) darr_last(S)
|
||||
|
||||
/**
|
||||
* darr_in_sprintf() - sprintf into D.
|
||||
*
|
||||
* Args:
|
||||
* D: The destination darr, D's value may be NULL.
|
||||
* F: The format string
|
||||
* ...: variable arguments for format string.
|
||||
*
|
||||
* Return:
|
||||
* The dynamic_array D with the new string content.
|
||||
*/
|
||||
#define darr_in_sprintf(D, F, ...) __darr_in_sprintf(&(D), 0, F, __VA_ARGS__)
|
||||
|
||||
|
||||
/**
|
||||
* darr_in_strcat() - concat a string into a darr string.
|
||||
*
|
||||
* Args:
|
||||
* D: The destination darr, D's value may be NULL.
|
||||
* S: The string to concat onto D.
|
||||
*
|
||||
* Return:
|
||||
* The dynamic_array D with the new string content.
|
||||
*/
|
||||
#define darr_in_strcat(D, S) \
|
||||
({ \
|
||||
uint __dlen = darr_strlen(D); \
|
||||
uint __slen = strlen(S); \
|
||||
darr_ensure_cap(D, __dlen + __slen + 1); \
|
||||
if (darr_len(D) == 0) \
|
||||
*darr_append(D) = 0; \
|
||||
memcpy(darr_last(D), (S), __slen + 1); \
|
||||
_darr_len(D) += __slen; \
|
||||
D; \
|
||||
})
|
||||
|
||||
/**
|
||||
* darr_in_strcatf() - concat a formatted string into a darr string.
|
||||
*
|
||||
* Args:
|
||||
* D: The destination darr, D's value may be NULL.
|
||||
* F: The format string to concat onto D after adding arguments.
|
||||
* ...: The arguments for the format string.
|
||||
* Return:
|
||||
* The dynamic_array D with the new string content.
|
||||
*/
|
||||
#define darr_in_strcatf(D, F, ...) \
|
||||
__darr_in_sprintf(&(D), true, (F), __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* darr_in_strcat_tail() - copies end of one darr str to another.
|
||||
*
|
||||
* This is a rather specialized function, it takes 2 darr's, a destination and a
|
||||
* source. If the source is not longer than the destination nothing is done.
|
||||
* Otherwise the characters in the source that lie beyond the length of the dest
|
||||
* are added to the dest. No checking is done to make sure the common prefix
|
||||
* matches. For example:
|
||||
*
|
||||
* D: "/foo"
|
||||
* S: "/foo/bar"
|
||||
* -> D: "/foo/bar"
|
||||
*
|
||||
* perhaps surprising results:
|
||||
* D: "/foo"
|
||||
* S: "/zoo/bar"
|
||||
* -> D: "/foo/bar"
|
||||
*
|
||||
* Args:
|
||||
* D: The destination darr, D's value may be NULL.
|
||||
* S: The string to copy the tail from.
|
||||
*
|
||||
* Return:
|
||||
* The dynamic_array D with the extended string content.
|
||||
*/
|
||||
#define darr_in_strcat_tail(D, S) \
|
||||
({ \
|
||||
int __dsize, __ssize, __extra; \
|
||||
\
|
||||
if (darr_len(D) == 0) \
|
||||
*darr_append(D) = 0; \
|
||||
__dsize = darr_ilen(D); \
|
||||
__ssize = darr_ilen(S); \
|
||||
__extra = __ssize - __dsize; \
|
||||
if (__extra > 0) { \
|
||||
darr_ensure_cap(D, (uint)__ssize); \
|
||||
memcpy(darr_last(D), (S) + __dsize - 1, __extra + 1); \
|
||||
_darr_len(D) += __extra; \
|
||||
} \
|
||||
D; \
|
||||
})
|
||||
|
||||
/**
|
||||
* darr_in_strdup_cap() - duplicate the string into a darr reserving capacity.
|
||||
* darr_in_strdup() - duplicate the string into a darr.
|
||||
*
|
||||
* Args:
|
||||
* D: The destination darr, D's value may be NULL.
|
||||
* S: The string to duplicate.
|
||||
* C: The capacity to reserve.
|
||||
*
|
||||
* Return:
|
||||
* The dynamic_array D with the duplicated string.
|
||||
*/
|
||||
#define darr_in_strdup_cap(D, S, C) \
|
||||
({ \
|
||||
size_t __size = strlen(S) + 1; \
|
||||
darr_reset(D); \
|
||||
darr_ensure_cap(D, ((size_t)(C) > __size) ? (size_t)(C) \
|
||||
: __size); \
|
||||
strlcpy(D, (S), darr_cap(D)); \
|
||||
darr_setlen((D), (size_t)__size); \
|
||||
D; \
|
||||
})
|
||||
#define darr_in_strdup(D, S) darr_in_strdup_cap(D, S, 1)
|
||||
|
||||
/**
|
||||
* darr_in_vsprintf() - vsprintf into D.
|
||||
*
|
||||
* Args:
|
||||
* D: The destination darr, D's value may be NULL.
|
||||
* F: The format string
|
||||
* A: Varargs
|
||||
*
|
||||
* Return:
|
||||
* The dynamic_array D with the new string content.
|
||||
*/
|
||||
#define darr_in_vsprintf(D, F, A) __darr_in_vsprintf(&(D), 0, F, A)
|
||||
|
||||
/**
|
||||
* darr_in_vstrcatf() - concat a formatted string into a darr string.
|
||||
*
|
||||
* Args:
|
||||
* D: The destination darr, D's value may be NULL.
|
||||
* F: The format string to concat onto D after adding arguments.
|
||||
* A: Varargs
|
||||
*
|
||||
* Return:
|
||||
* The dynamic_array D with the new string content.
|
||||
*/
|
||||
#define darr_in_vstrcatf(D, F, A) __darr_in_vsprintf(&(D), true, (F), (A))
|
||||
|
||||
/**
|
||||
* darr_sprintf() - sprintf into a new dynamic array.
|
||||
*
|
||||
* Args:
|
||||
* F: The format string
|
||||
* ...: variable arguments for format string.
|
||||
*
|
||||
* Return:
|
||||
* A char * dynamic_array with the new string content.
|
||||
*/
|
||||
#define darr_sprintf(F, ...) \
|
||||
({ \
|
||||
char *d = NULL; \
|
||||
__darr_in_sprintf(&d, false, F, __VA_ARGS__); \
|
||||
d; \
|
||||
})
|
||||
|
||||
/**
|
||||
* darr_strdup_cap() - duplicate the string reserving capacity.
|
||||
* darr_strdup() - duplicate the string into a dynamic array.
|
||||
*
|
||||
* Args:
|
||||
* S: The string to duplicate.
|
||||
* C: The capacity to reserve.
|
||||
*
|
||||
* Return:
|
||||
* The dynamic_array with the duplicated string.
|
||||
*/
|
||||
#define darr_strdup_cap(S, C) \
|
||||
({ \
|
||||
size_t __size = strlen(S) + 1; \
|
||||
char *__s = NULL; \
|
||||
/* Cast to ssize_t to avoid warning when C == 0 */ \
|
||||
darr_ensure_cap(__s, ((ssize_t)(C) > (ssize_t)__size) \
|
||||
? (size_t)(C) \
|
||||
: __size); \
|
||||
strlcpy(__s, (S), darr_cap(__s)); \
|
||||
darr_setlen(__s, (size_t)__size); \
|
||||
__s; \
|
||||
})
|
||||
#define darr_strdup(S) darr_strdup_cap(S, 0)
|
||||
|
||||
/**
|
||||
* darr_strlen() - get the length of the NUL terminated string in a darr.
|
||||
*
|
||||
* Args:
|
||||
* S: The string to measure, value may be NULL.
|
||||
*
|
||||
* Return:
|
||||
* The length of the NUL terminated string in @S
|
||||
*/
|
||||
#define darr_strlen(S) \
|
||||
({ \
|
||||
uint __size = darr_len(S); \
|
||||
if (__size) \
|
||||
__size -= 1; \
|
||||
assert(!(S) || ((char *)(S))[__size] == 0); \
|
||||
__size; \
|
||||
})
|
||||
|
||||
/**
|
||||
* darr_vsprintf() - vsprintf into a new dynamic array.
|
||||
*
|
||||
* Args:
|
||||
* F: The format string
|
||||
* A: Varargs
|
||||
*
|
||||
* Return:
|
||||
* The dynamic_array D with the new string content.
|
||||
*/
|
||||
#define darr_vsprintf(F, A) \
|
||||
({ \
|
||||
char *d = NULL; \
|
||||
darr_in_vsprintf(d, F, A); \
|
||||
d; \
|
||||
})
|
||||
|
||||
/**
|
||||
* Iterate over array `A` using a pointer to each element in `P`.
|
||||
*
|
||||
|
|
|
@ -162,6 +162,7 @@ tests_lib_test_darr_CFLAGS = $(TESTS_CFLAGS)
|
|||
tests_lib_test_darr_CPPFLAGS = $(TESTS_CPPFLAGS)
|
||||
tests_lib_test_darr_LDADD = $(ALL_TESTS_LDADD)
|
||||
tests_lib_test_darr_SOURCES = tests/lib/test_darr.c
|
||||
EXTRA_DIST += tests/lib/test_darr.py
|
||||
|
||||
|
||||
check_PROGRAMS += tests/lib/test_graph
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
* [x] - darr_append_n
|
||||
* [x] - darr_append_nz
|
||||
* [x] - darr_cap
|
||||
* [-] - darr_ensure_cap
|
||||
* [x] - darr_ensure_avail
|
||||
* [x] - darr_ensure_cap
|
||||
* [x] - darr_ensure_i
|
||||
* [x] - darr_foreach_i
|
||||
* [x] - darr_foreach_p
|
||||
|
@ -23,6 +24,15 @@
|
|||
* [ ] - darr_insertz
|
||||
* [x] - darr_insert_n
|
||||
* [x] - darr_insert_nz
|
||||
* [x] - darr_in_sprintf
|
||||
* [x] - darr_in_strcat
|
||||
* [x] - darr_in_strcat_tail
|
||||
* [ ] - darr_in_strcatf
|
||||
* [ ] - darr_in_vstrcatf
|
||||
* [x] - darr_in_strdup
|
||||
* [x] - darr_in_strdup_cap
|
||||
* [-] - darr_in_vsprintf
|
||||
* [x] - darr_lasti
|
||||
* [x] - darr_maxi
|
||||
* [x] - darr_pop
|
||||
* [x] - darr_push
|
||||
|
@ -31,6 +41,13 @@
|
|||
* [x] - darr_remove_n
|
||||
* [x] - darr_reset
|
||||
* [x] - darr_setlen
|
||||
* [x] - darr_set_strlen
|
||||
* [x] - darr_sprintf
|
||||
* [x] - darr_strdup
|
||||
* [x] - darr_strdup_cap
|
||||
* [x] - darr_strlen
|
||||
* [x] - darr_strnul
|
||||
* [ ] - darr_vsprintf
|
||||
*/
|
||||
|
||||
static void test_int(void)
|
||||
|
@ -43,6 +60,11 @@ static void test_int(void)
|
|||
int *dap;
|
||||
uint i;
|
||||
|
||||
assert(darr_len(da1) == 0);
|
||||
assert(darr_lasti(da1) == -1);
|
||||
assert(darr_last(da1) == NULL);
|
||||
assert(darr_end(da1) == NULL);
|
||||
|
||||
darr_ensure_i(da1, 0);
|
||||
da1[0] = 0;
|
||||
assert(darr_len(da1) == 1);
|
||||
|
@ -57,9 +79,11 @@ static void test_int(void)
|
|||
da1[i] = i;
|
||||
|
||||
assert(darr_len(da1) == 5);
|
||||
assert(darr_lasti(da1) == 4);
|
||||
/* minimum non-pow2 array size for long long and smaller */
|
||||
assert(darr_cap(da1) == 8);
|
||||
assert(!memcmp(da1, a1, sizeof(a1)));
|
||||
assert(&da1[darr_lasti(da1)] == darr_last(da1));
|
||||
|
||||
/* reverse the numbers */
|
||||
darr_foreach_p (da1, dap)
|
||||
|
@ -185,6 +209,20 @@ static void test_struct(void)
|
|||
assert(darr_cap(da1) == 8);
|
||||
assert(!memcmp(da1, a1, sizeof(a1)));
|
||||
|
||||
assert(darr_cap(da1) - darr_len(da1) == 3);
|
||||
darr_ensure_avail(da1, 2);
|
||||
assert(darr_cap(da1) == 8);
|
||||
darr_ensure_avail(da1, 3);
|
||||
assert(darr_cap(da1) == 8);
|
||||
darr_ensure_avail(da1, 4);
|
||||
assert(darr_cap(da1) == 16);
|
||||
|
||||
darr_ensure_cap(da1, 16);
|
||||
assert(darr_cap(da1) == 16);
|
||||
|
||||
darr_ensure_cap(da1, 20);
|
||||
assert(darr_cap(da1) == 32);
|
||||
|
||||
darr_append_n(da1, 100);
|
||||
|
||||
assert(darr_len(da1) == 105);
|
||||
|
@ -272,8 +310,116 @@ static void test_struct(void)
|
|||
darr_free(da2);
|
||||
}
|
||||
|
||||
static void test_string(void)
|
||||
{
|
||||
const char *src = "ABCDE";
|
||||
const char *add = "FGHIJ";
|
||||
uint srclen = strlen(src);
|
||||
uint addlen = strlen(add);
|
||||
char *da1 = NULL;
|
||||
char *da2 = NULL;
|
||||
|
||||
assert(darr_strlen(da1) == 0);
|
||||
|
||||
da1 = darr_strdup(src);
|
||||
assert(darr_strlen(da1) == strlen(da1));
|
||||
assert(darr_strlen(da1) == srclen);
|
||||
assert(darr_len(da1) == srclen + 1);
|
||||
assert(darr_ilen(da1) == (int)srclen + 1);
|
||||
assert(darr_cap(da1) >= 8);
|
||||
assert(darr_last(da1) == darr_strnul(da1));
|
||||
assert(darr_strnul(da1) == da1 + darr_strlen(da1));
|
||||
|
||||
da2 = da1;
|
||||
darr_in_strdup(da1, src);
|
||||
assert(da1 == da2);
|
||||
assert(darr_strlen(da1) == strlen(da1));
|
||||
assert(darr_strlen(da1) == srclen);
|
||||
assert(darr_len(da1) == srclen + 1);
|
||||
darr_free(da1);
|
||||
assert(da1 == NULL);
|
||||
|
||||
da1 = darr_strdup_cap(src, 128);
|
||||
assert(darr_strlen(da1) == srclen);
|
||||
assert(darr_cap(da1) >= 128);
|
||||
|
||||
da2 = da1;
|
||||
darr_in_strdup_cap(da1, src, 1024);
|
||||
assert(da1 != da2);
|
||||
assert(darr_strlen(da1) == srclen);
|
||||
assert(darr_cap(da1) >= 1024);
|
||||
darr_free(da1);
|
||||
da2 = NULL;
|
||||
|
||||
da1 = darr_strdup_cap(add, 2);
|
||||
assert(darr_strlen(da1) == addlen);
|
||||
assert(darr_cap(da1) >= 8);
|
||||
|
||||
darr_in_strdup(da1, "ab");
|
||||
darr_in_strcat(da1, "/");
|
||||
darr_in_strcat(da1, "foo");
|
||||
assert(!strcmp("ab/foo", da1));
|
||||
darr_free(da1);
|
||||
|
||||
da1 = darr_in_strcat(da1, "ab");
|
||||
darr_in_strcat(da1, "/");
|
||||
darr_in_strcat(da1, "foo");
|
||||
assert(!strcmp("ab/foo", da1));
|
||||
|
||||
darr_set_strlen(da1, 5);
|
||||
assert(!strcmp("ab/fo", da1));
|
||||
darr_set_strlen(da1, 1);
|
||||
assert(!strcmp("a", da1));
|
||||
|
||||
darr_in_strdup(da1, "ab");
|
||||
da2 = darr_strdup(add);
|
||||
darr_in_strcat_tail(da1, da2);
|
||||
assert(!strcmp("abHIJ", da1));
|
||||
assert(darr_strlen(da1) == 5);
|
||||
assert(darr_len(da1) == 6);
|
||||
darr_free(da1);
|
||||
darr_free(da2);
|
||||
|
||||
da1 = darr_strdup("abcde");
|
||||
da2 = darr_strdup(add);
|
||||
darr_in_strcat_tail(da1, da2);
|
||||
assert(!strcmp("abcde", da1));
|
||||
assert(darr_strlen(da1) == 5);
|
||||
assert(darr_len(da1) == 6);
|
||||
darr_free(da1);
|
||||
darr_free(da2);
|
||||
|
||||
da1 = darr_sprintf("0123456789: %08X", 0xDEADBEEF);
|
||||
assert(!strcmp(da1, "0123456789: DEADBEEF"));
|
||||
assert(darr_strlen(da1) == 20);
|
||||
assert(darr_cap(da1) == 128);
|
||||
da2 = da1;
|
||||
darr_in_sprintf(da1, "9876543210: %08x", 0x0BADF00D);
|
||||
assert(da1 == da2);
|
||||
assert(!strcmp("9876543210: 0badf00d", da2));
|
||||
darr_free(da1);
|
||||
da2 = NULL;
|
||||
|
||||
da1 = NULL;
|
||||
darr_in_sprintf(da1, "0123456789: %08X", 0xDEADBEEF);
|
||||
assert(!strcmp(da1, "0123456789: DEADBEEF"));
|
||||
assert(darr_strlen(da1) == 20);
|
||||
assert(darr_cap(da1) == 128);
|
||||
darr_free(da1);
|
||||
|
||||
da1 = darr_sprintf("0123456789: %08x", 0xDEADBEEF);
|
||||
darr_in_strcatf(da1, " 9876543210: %08x", 0x0BADF00D);
|
||||
assert(!strcmp("0123456789: deadbeef 9876543210: 0badf00d", da1));
|
||||
darr_free(da1);
|
||||
|
||||
da1 = darr_in_strcatf(da1, "0123456789: %08x", 0xDEADBEEF);
|
||||
assert(!strcmp("0123456789: deadbeef", da1));
|
||||
darr_free(da1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_int();
|
||||
test_struct();
|
||||
test_string();
|
||||
}
|
||||
|
|
8
tests/lib/test_darr.py
Normal file
8
tests/lib/test_darr.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
import frrtest
|
||||
|
||||
|
||||
class TestDarr(frrtest.TestMultiOut):
|
||||
program = "./test_darr"
|
||||
|
||||
|
||||
TestDarr.exit_cleanly()
|
Loading…
Reference in a new issue