On 4/15/20 11:16 AM, Richard W.M. Jones wrote:
Can be used for building up lists of things, especially
lists of strings.
---
  common/include/Makefile.am   |  6 +++
  common/include/test-vector.c | 90 +++++++++++++++++++++++++++++++++
  common/include/vector.h      | 96 ++++++++++++++++++++++++++++++++++++
  .gitignore                   |  1 +
  4 files changed, 193 insertions(+)


+++ b/common/include/vector.h

+/* Simple implementation of appendable vector.  There are two main
+ * use-cases we consider: lists of strings (either with a defined
+ * length, or NULL-terminated), and lists of numbers.  It is generic
+ * so could be used for lists of anything (eg. structs) where being
+ * able to append easily is important.
+ */
+
+#ifndef NBDKIT_VECTOR_H
+#define NBDKIT_VECTOR_H
+
+#include <assert.h>
+
+#define DEFINE_VECTOR_TYPE(name, type)                                  \
+  struct name {                                                         \
+    type *ptr;                 /* Pointer to array of items. */         \
+    size_t size;               /* Number of valid items in the array. */ \
+    size_t alloc;              /* Number of items allocated. */         \
+  };                                                                    \
+  typedef struct name name;                                             \
+  static inline int                                                     \
+  name##_extend (name *v, size_t n)                                     \
+  {                                                                     \
+    return generic_vector_extend ((struct generic_vector *)v, n,        \
+                                  sizeof (type));                       \
+  }                                                                     \
+  static inline int                                                     \
+  name##_append (name *v, type elem)                                    \
+  {                                                                     \
+    if (v->size >= v->alloc) {                                          \
+      if (name##_extend (v, 1) == -1) return -1;                        \
+    }                                                                   \
+    v->ptr[v->size++] = elem;                                           \
+    return 0;                                                           \
+  }                                                                     \
+  static inline void                                                    \
+  name##_iter (name *v, void (*f) (type elem))                          \

Do we want an iterator that can take a void* opaque argument, as in:

name##_iter_arg (name *v, void (*f) (type elem, void *o), void *o)

Of course, since you want to pass 'free' to string_vector, you'll still want the form without an opaque argument as well.

+  {                                                                     \
+    size_t i;                                                           \
+    for (i = 0; i < v->size; ++i)                                       \
+      f (v->ptr[i]);                                                    \
+  }

Should we allow the callback to return a value, where returning 0 can abort the iteration early?

+
+#define empty_vector { .ptr = NULL, .size = 0, .alloc = 0 }

Nice that this initializer is type-agnostic.

+
+struct generic_vector {
+  void *ptr;
+  size_t size;
+  size_t alloc;
+};
+
+static int
+generic_vector_extend (struct generic_vector *v, size_t n, size_t itemsize)
+{
+  void *newptr;
+
+  newptr = realloc (v->ptr, (n + v->alloc) * itemsize);
+  if (newptr == NULL)
+    return -1;
+  v->ptr = newptr;
+  v->alloc += n;
+  return 0;
+}

Do we really want this implemented in the header?

--
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org

_______________________________________________
Libguestfs mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/libguestfs

Reply via email to