From: Markus Teich Date: Wed, 7 Sep 2016 22:31:05 +0000 (+0000) Subject: gnunetutil: add 2d and 3d allocation including tests X-Git-Tag: initial-import-from-subversion-38251~285 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=2a6a2e9713184f13df1972ca3b10004f0bccd282;p=oweals%2Fgnunet.git gnunetutil: add 2d and 3d allocation including tests --- diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h index cc42cac86..2438b179c 100644 --- a/src/include/gnunet_common.h +++ b/src/include/gnunet_common.h @@ -798,6 +798,29 @@ GNUNET_ntoh_double (double d); */ #define GNUNET_new_array(n, type) (type *) GNUNET_malloc ((n) * sizeof (type)) +/** + * @ingroup memory + * Allocate a size @a n times @a m array + * with structs or unions of the given @a type. + * + * @param n size of the first dimension + * @param m size of the second dimension + * @param type name of the struct or union, i.e. pass 'struct Foo'. + */ +#define GNUNET_new_array_2d(n, m, type) (type **) GNUNET_xnew_array_2d_ (n, m, sizeof (type)) + +/** + * @ingroup memory + * Allocate a size @a n times @a m times @a o array + * with structs or unions of the given @a type. + * + * @param n size of the first dimension + * @param m size of the second dimension + * @param o size of the third dimension + * @param type name of the struct or union, i.e. pass 'struct Foo'. + */ +#define GNUNET_new_array_3d(n, m, o, type) (type ***) GNUNET_xnew_array_3d_ (n, m, o, sizeof (type)) + /** * @ingroup memory * Wrapper around malloc. Allocates size bytes of memory. @@ -967,6 +990,39 @@ void * GNUNET_xmalloc_ (size_t size, const char *filename, int linenumber); +/** + * Allocate memory for a two dimensional array in one block + * and set up pointers. Aborts if no more memory is available. + * Don't use GNUNET_xnew_array_2d_ directly. Use the + * #GNUNET_new_array_2d macro. + * The memory of the elements will be zero'ed out. + * + * @param n size of the first dimension + * @param m size of the second dimension + * @param elementSize size of a single element in bytes + * @return allocated memory, never NULL + */ +void ** +GNUNET_xnew_array_2d_ (size_t n, size_t m, size_t elementSize); + + +/** + * Allocate memory for a three dimensional array in one block + * and set up pointers. Aborts if no more memory is available. + * Don't use GNUNET_xnew_array_3d_ directly. Use the + * #GNUNET_new_array_3d macro. + * The memory of the elements will be zero'ed out. + * + * @param n size of the first dimension + * @param m size of the second dimension + * @param o size of the third dimension + * @param elementSize size of a single element in bytes + * @return allocated memory, never NULL + */ +void *** +GNUNET_xnew_array_3d_ (size_t n, size_t m, size_t o, size_t elementSize); + + /** * Allocate and initialize memory. Checks the return value, aborts if no more * memory is available. Don't use GNUNET_xmemdup_ directly. Use the diff --git a/src/util/common_allocation.c b/src/util/common_allocation.c index 71dd46bf1..f0299a223 100644 --- a/src/util/common_allocation.c +++ b/src/util/common_allocation.c @@ -85,6 +85,71 @@ GNUNET_xmalloc_ (size_t size, } +/** + * Allocate memory for a two dimensional array in one block + * and set up pointers. Aborts if no more memory is available. + * Don't use GNUNET_xnew_array_2d_ directly. Use the + * #GNUNET_new_array_2d macro. + * The memory of the elements will be zero'ed out. + * + * @param n size of the first dimension + * @param m size of the second dimension + * @param elementSize size of a single element in bytes + * @return allocated memory, never NULL + */ +void ** +GNUNET_xnew_array_2d_ (size_t n, size_t m, size_t elementSize) +{ + /* use char pointer internally to avoid void pointer arithmetic warnings */ + char **ret = GNUNET_malloc (n * sizeof (void *) + /* 1. dim header */ + n * m * elementSize); /* element data */ + + for (size_t i = 0; i < n; i++) + ret[i] = (char *)ret + /* base address */ + n * sizeof (void *) + /* skip 1. dim header */ + i * m * elementSize; /* skip to 2. dim row header */ + return (void **)ret; +} + + +/** + * Allocate memory for a three dimensional array in one block + * and set up pointers. Aborts if no more memory is available. + * Don't use GNUNET_xnew_array_3d_ directly. Use the + * #GNUNET_new_array_3d macro. + * The memory of the elements will be zero'ed out. + * + * @param n size of the first dimension + * @param m size of the second dimension + * @param o size of the third dimension + * @param elementSize size of a single element in bytes + * @return allocated memory, never NULL + */ +void *** +GNUNET_xnew_array_3d_ (size_t n, size_t m, size_t o, size_t elementSize) +{ + /* use char pointer internally to avoid void pointer arithmetic warnings */ + char ***ret = GNUNET_malloc (n * sizeof (void **) + /* 1. dim header */ + n * m * sizeof (void *) + /* 2. dim header */ + n * m * o * elementSize); /* element data */ + + for (size_t i = 0; i < n; i++) + { + /* need to cast to (char *) temporarily for byte level acuracy */ + ret[i] = (char **)((char *)ret + /* base address */ + n * sizeof (void **) + /* skip 1. dim header */ + i * m * sizeof (void *)); /* skip to 2. dim header */ + for (size_t j = 0; j < m; j++) + ret[i][j] = (char *)ret + /* base address */ + n * sizeof (void **) + /* skip 1. dim header */ + n * m * sizeof (void *) + /* skip 2. dim header */ + i * m * o * elementSize + /* skip to 2. dim part */ + j * o * elementSize; /* skip to 3. dim row data */ + } + return (void ***)ret; +} + + /** * Allocate and initialize memory. Checks the return value, aborts if no more * memory is available. Don't use #GNUNET_xmemdup_() directly. Use the diff --git a/src/util/test_common_allocation.c b/src/util/test_common_allocation.c index aa4809f58..4ef98b629 100644 --- a/src/util/test_common_allocation.c +++ b/src/util/test_common_allocation.c @@ -30,6 +30,8 @@ check () { #define MAX_TESTVAL 1024 char *ptrs[MAX_TESTVAL]; + unsigned int **a2; + char ***a3; int i; int j; int k; @@ -93,6 +95,34 @@ check () if (ptrs[0] != NULL) return 9; + /* GNUNET_new_array_2d tests */ + a2 = GNUNET_new_array_2d (17, 22, unsigned int); + for (i = 0; i < 17; i++) + { + for (j = 0; j < 22; j++) + { + if (0 != a2[i][j]) + return 10; + a2[i][j] = i * 100 + j; + } + } + free (a2); + + /* GNUNET_new_array_3d tests */ + a3 = GNUNET_new_array_3d (2, 3, 4, char); + for (i = 0; i < 2; i++) + { + for (j = 0; j < 3; j++) + { + for (k = 0; k < 4; k++) + { + if (0 != a3[i][j][k]) + return 11; + a3[i][j][k] = i * 100 + j * 10 + k; + } + } + } + free (a3); return 0; }