From d33d21435120213244121977a40d82022689ac86 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Thu, 26 May 2022 13:14:43 +0200 Subject: [PATCH] utils: small fixes --- src/tests/utils/desktop.c | 5 ---- src/utils/array.c | 48 ++++++++++++++++++++++++++++++--- src/utils/array.h | 56 ++++++++++++++++++++++++++++++++++----- src/utils/utils.h | 13 ++++----- 4 files changed, 102 insertions(+), 20 deletions(-) diff --git a/src/tests/utils/desktop.c b/src/tests/utils/desktop.c index c219d8a..8047e1a 100644 --- a/src/tests/utils/desktop.c +++ b/src/tests/utils/desktop.c @@ -33,11 +33,6 @@ static void teardown() { free_desktop(d); } -static void reset() { - teardown(); - setup(); -} - START(init) if (!d) FAIL("new_desktop returned NULL"); diff --git a/src/utils/array.c b/src/utils/array.c index c5299f0..e5bb7ee 100644 --- a/src/utils/array.c +++ b/src/utils/array.c @@ -30,7 +30,8 @@ typedef struct { void *data; } priv_t; -/* make sure we have at least n elements in the buffer, grow if needed */ +/* make sure we have at least n+1 elements in the buffer, grow if needed */ +/* +1 is so we can always end with a NULL value for array_data/convert() */ static int array_assure(array_t *me, size_t nb_elem); /* for qsort operations */ @@ -105,7 +106,7 @@ void array_clear(array_t *me) { // convert to void * data (free the rest) void *array_convert(array_t *me) { priv_t *priv = (priv_t *) me->priv; - void *data = priv->data; + void *data = array_data(me); free(priv); free(me); return data; @@ -113,6 +114,18 @@ void *array_convert(array_t *me) { void *array_data(array_t *me) { priv_t *priv = (priv_t *) me->priv; + + // Note: this should be impossible + if (me->count >= priv->buffer) + array_assure(me, me->count + 1); + + // cast to (char *) because we want 'byte' arithmetic + void *after_end = (void *) (((char *) priv->data) + + (me->count * priv->elem_size)); + + // last item is always NULL + memset(after_end, '\0', priv->elem_size); + return priv->data; } @@ -133,10 +146,39 @@ void *array_newn(array_t *me, size_t how_many) { } void *array_first(array_t *me) { + if (!me->count) + return NULL; + priv_t *priv = (priv_t *) me->priv; return priv->data; } +void *array_last(array_t *me) { + if (!me->count) + return NULL; + + priv_t *priv = (priv_t *) me->priv; + // cast to (char *) because we want 'byte' arithmetic + return (void *) (((char *) priv->data) + ((me->count - 1) * priv->elem_size)); +} + +void *array_prev(array_t *me, void *ptr) { + priv_t *priv = (priv_t *) me->priv; + + // cast to (char *) because we want 'byte' arithmetic + char *cptr = (char *) ptr; + char *cdata = (char*) priv->data; + + if (cptr) { + cptr -= priv->elem_size; + if (cptr >= cdata) { + return cptr; + } + } + + return NULL; +} + void *array_next(array_t *me, void *ptr) { priv_t *priv = (priv_t *) me->priv; @@ -323,7 +365,7 @@ int array_setn(array_t *me, size_t i, void *data, size_t n) { static int array_assure(array_t *me, size_t nb_elem) { priv_t *priv = (priv_t *) me->priv; - if (priv->buffer < nb_elem) { + if (priv->buffer <= nb_elem) { priv->buffer *= 2; if (priv->buffer < nb_elem) { priv->buffer = nb_elem; diff --git a/src/utils/array.h b/src/utils/array.h index 201c2a0..3638562 100644 --- a/src/utils/array.h +++ b/src/utils/array.h @@ -143,7 +143,7 @@ typedef struct { array_t *new_array(size_t elem_size, size_t initial); /** - * Create a new array. + * Initialise a new array. * * @param elem_size the size of one element * @param initial the initial number of items the buffer can hold (not 0) @@ -177,12 +177,17 @@ void uninit_array(array_t *me); /** * Clear the array, that is, resets its current size to 0 (buffer unchanged). + * + * @note if you hold custom structures with owned resources in the array, you + * should deallocate them properly before */ void array_clear(array_t *me); /** * Convert the array to a block of memory where all values are adjacent. * + * @note an extra NULL value is assured to be present as last element + * * @return the data (you must later call `free()` on it) */ void *array_convert(array_t *me); @@ -194,6 +199,8 @@ void *array_convert(array_t *me); * * Be careful if you change the content (you should not). * + * @note an extra NULL value is assured to be present as last element + * * @return the internal storage area */ void *array_data(array_t *me); @@ -227,10 +234,30 @@ void *array_newn(array_t *me, size_t n); * store integers, it will be (int *); if you store strings, it will * be char **). * - * @return a pointer to the first element + * @return a pointer to the first element, or NULL if no elements are + * present */ void *array_first(array_t *me); +/** + * Return a pointer to the last element of the array (for instance, if you + * store integers, it will be (int *); if you store strings, it will + * be char **). + * + * @return a pointer to the last element, or NULL if no elements are + * present + */ +void *array_last(array_t *me); + +/** + * Return the pointer to the previous element, or NULL if it was the first. + * + * @param ptr a pointer from an array (the array must be valid) + * + * @return the previous element, or NULL + */ +void *array_prev(array_t *me, void *ptr); + /** * Return the pointer to the next element, or NULL if it was the last. * @@ -246,6 +273,8 @@ void *array_next(array_t *me, void *ptr); * * @param i the index of the element to retrieve * + * @note if the index is out of bounds, you will get invalid data + * * @return the pointer to the i'th element */ void *array_get(array_t *me, size_t i); @@ -271,6 +300,15 @@ void *array_pop(array_t *me); * Cut the array at the given size and return a pointer to the first element * that was removed if any. * + * @note be careful, the memory pointed to by the element(s) will be reused the + * next time we add an element -- you should not use it after this; in + * short, the return value is mainly so you can call free on + * value(s) pointed to by this pointer (not the pointer itself) if + * it is a pointer to memory you own, or use it locally before continuing + * to use the array + * @note in case this was not clear, do not call free on the + * returned value(s) + * * @return a pointer to the first removed element, or NULL */ void *array_cut_at(array_t *me, size_t n); @@ -335,7 +373,8 @@ void array_qsortl(array_t *me, int rev); void array_qsortf(array_t *me, int rev); /** - * Add an element to the array. + * Add an element to the array (will create a new item in the array and copy the + * data from the given element in it). * * @param data the memory position of the element to add * @@ -345,7 +384,8 @@ void array_qsortf(array_t *me, int rev); int array_push(array_t *me, void *data); /** - * Add multiple elements to the array. + * Add multiple elements to the array (will create new items in the array and + * copy the data from the given elements in them). * * @param data the memory position of the elements to add, adjacent to each * other @@ -382,7 +422,9 @@ int array_copyn(array_t *me, void *target, size_t i, size_t n); /** * Set an element of the array to the given value. - * Can also append a new elements. + * Can also append an element at the end of the array (i.e., i can be + * the size of the array and this will result in an array with one more + * element). * Memory will be copied from the given data to the array. * * @param i the element index @@ -398,7 +440,9 @@ int array_set(array_t *me, size_t i, void *data); /** * Set elements of the array to the given value. - * Can also append some of them to the array if no values were present. + * Can also append elements at the end of the array (i.e., i can be + * the size of the array and this will result in an array with n more + * elements). * Memory will be copied from the given data to the array. * * @param i the element index to start the insertion at diff --git a/src/utils/utils.h b/src/utils/utils.h index 90d4a6a..ef6a9f5 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -57,13 +57,14 @@ size_t strnlen(const char *s, size_t maxlen); #endif #if _POSIX_C_SOURCE < 200809L && _XOPEN_SOURCE < 500 /** - * The strndup() function is similar, but copies at most n bytes. - * If s is longer than n, only n bytes are copied, and a terminating null byte - * ('\0') is added. + * The strdup() function returns a pointer to a new string which is a + * duplicate of the string s. Memory for the new string is obtained with + * malloc(3), and can be freed with free(3). * - * @return On success, the strndup() function returns a pointer to the - * duplicated string. It returns NULL if insufficient memory was - * available, with errno set to indicate the error + * + * @return On success, the strdup() function returns a pointer to the duplicated + * string. It returns NULL if insufficient memory was available, with + * errno set to indicate the error. */ char *strdup(const char *source); #endif -- 2.27.0