nwrap: Add nwrap vector memory management functions
authorRobin Hack <hack.robin@gmail.com>
Mon, 23 Mar 2015 13:10:18 +0000 (14:10 +0100)
committerMichael Adam <obnox@samba.org>
Mon, 11 Jan 2016 11:25:27 +0000 (12:25 +0100)
Nwrap vectors  are just more inteligent arrays.
They can look like very simple version of
vectors from C++.

TESTS: Add nwrap_vector tests.

Signed-off-by: Robin Hack <hack.robin@gmail.com>
Reviewed-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
lib/nss_wrapper/nss_wrapper.c

index e985bb3f4cb4c64108e98b0ed777b8ab1c1634db..69949aaf45892b2c62d8c32981de7979ca6fceab 100644 (file)
@@ -50,6 +50,8 @@
 #include <unistd.h>
 #include <ctype.h>
 
+#include <assert.h>
+
 /*
  * Defining _POSIX_PTHREAD_SEMANTICS before including pwd.h and grp.h  gives us
  * the posix getpwnam_r(), getpwuid_r(), getgrnam_r and getgrgid_r calls on
@@ -477,6 +479,141 @@ struct nwrap_main {
 struct nwrap_main *nwrap_main_global;
 struct nwrap_main __nwrap_main_global;
 
+/*
+ * VECTORS
+ */
+
+#define DEFAULT_VECTOR_CAPACITY 16
+
+struct nwrap_vector {
+       void **items;
+       size_t count;
+       size_t capacity;
+};
+
+/* Macro returns pointer to first element of vector->items array.
+ *
+ * nwrap_vector is used as a memory backend which take care of
+ * memory allocations and other stuff like memory growing.
+ * nwrap_vectors should not be considered as some abstract structures.
+ * On this level, vectors are more handy than direct realloc/malloc
+ * calls.
+ *
+ * nwrap_vector->items is array inside nwrap_vector which can be
+ * directly pointed by libc structure assembled by cwrap itself.
+ *
+ * EXAMPLE:
+ *
+ * 1) struct hostent contains char **h_addr_list element.
+ * 2) nwrap_vector holds array of pointers to addresses.
+ *    It's easier to use vector to store results of
+ *    file parsing etc.
+ *
+ * Now, pretend that cwrap assembled struct hostent and
+ * we need to set h_addr_list to point to nwrap_vector.
+ * Idea behind is to shield users from internal nwrap_vector
+ * implementation.
+ * (Yes, not fully - array terminated by NULL is needed because
+ * it's result expected by libc function caller.)
+ *
+ *
+ * CODE EXAMPLE:
+ *
+ * struct hostent he;
+ * struct nwrap_vector *vector = malloc(sizeof(struct nwrap_vector));
+ * ... don't care about failed allocation now ...
+ *
+ * ... fill nwrap vector ...
+ *
+ * struct hostent he;
+ * he.h_addr_list = nwrap_vector_head(vector);
+ *
+ */
+#define nwrap_vector_head(vect) ((void *)((vect)->items))
+
+#define nwrap_vector_foreach(item, vect, iter) \
+       for (iter = 0, (item) = (vect).items == NULL ? NULL : (vect).items[0]; \
+            item != NULL; \
+            (item) = (vect).items[++iter])
+
+static inline bool nwrap_vector_init(struct nwrap_vector *const vector)
+{
+       if (vector == NULL) {
+               return false;
+       }
+
+       /* count is initialized by ZERO_STRUCTP */
+       ZERO_STRUCTP(vector);
+       vector->items = malloc(sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
+       if (vector->items == NULL) {
+               return false;
+       }
+       vector->capacity = DEFAULT_VECTOR_CAPACITY;
+       memset(vector->items, '\0', sizeof(void *) * (DEFAULT_VECTOR_CAPACITY + 1));
+
+       return true;
+}
+
+static bool nwrap_vector_add_item(struct nwrap_vector *cont, void *const item)
+{
+       assert (cont != NULL);
+
+       if (cont->items == NULL) {
+               nwrap_vector_init(cont);
+       }
+
+       if (cont->count == cont->capacity) {
+               /* Items array _MUST_ be NULL terminated because it's passed
+                * as result to caller which expect NULL terminated array from libc.
+                */
+               void **items = realloc(cont->items, sizeof(void *) * ((cont->capacity * 2) + 1));
+               if (items == NULL) {
+                       return false;
+               }
+               cont->items = items;
+
+               /* Don't count ending NULL to capacity */
+               cont->capacity *= 2;
+       }
+
+       cont->items[cont->count] = item;
+
+       cont->count += 1;
+       cont->items[cont->count] = NULL;
+
+       return true;
+}
+
+static bool nwrap_vector_merge(struct nwrap_vector *dst,
+                              struct nwrap_vector *src)
+{
+       void **dst_items = NULL;
+       size_t count;
+
+       if (src->count == 0) {
+               return true;
+       }
+
+       count = dst->count + src->count;
+
+       /* We don't need reallocation if we have enough capacity. */
+       if (src->count > (dst->capacity - dst->count)) {
+               dst_items = (void **)realloc(dst->items, (count + 1) * sizeof(void *));
+               if (dst_items == NULL) {
+                       return false;
+               }
+               dst->items = dst_items;
+               dst->capacity = count;
+       }
+
+       memcpy((void *)(((long *)dst->items) + dst->count),
+              src->items,
+              src->count * sizeof(void *));
+       dst->count = count;
+
+       return true;
+}
+
 struct nwrap_cache {
        const char *path;
        int fd;