[Libguestfs] [PATCH nbdkit 1/9] common: Add a generic implementation of vectors.

Richard W.M. Jones
Wed, 15 Apr 2020 16:16:42 -0000

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(+)

diff --git a/common/include/Makefile.am b/common/include/Makefile.am
index 4482de37..3089a0a1 100644
--- a/common/include/Makefile.am
+++ b/common/include/Makefile.am
@@ -45,6 +45,7 @@ EXTRA_DIST = \
 	random.h \
 	rounding.h \
 	tvdiff.h \
+	vector.h \
 	$(NULL)

 # Unit tests.
@@ -59,6 +60,7 @@ TESTS = \
 	test-nextnonzero \
 	test-random \
 	test-tvdiff \
+	test-vector \
 	$(NULL)
 check_PROGRAMS = $(TESTS)

@@ -97,3 +99,7 @@ test_random_CFLAGS = $(WARNINGS_CFLAGS)
 test_tvdiff_SOURCES = test-tvdiff.c tvdiff.h
 test_tvdiff_CPPFLAGS = -I$(srcdir)
 test_tvdiff_CFLAGS = $(WARNINGS_CFLAGS)
+
+test_vector_SOURCES = test-vector.c vector.h
+test_vector_CPPFLAGS = -I$(srcdir)
+test_vector_CFLAGS = $(WARNINGS_CFLAGS)
diff --git a/common/include/test-vector.c b/common/include/test-vector.c
new file mode 100644
index 00000000..8bf6e349
--- /dev/null
+++ b/common/include/test-vector.c
@@ -0,0 +1,90 @@
+/* nbdkit
+ * Copyright (C) 2020 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS
IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "vector.h"
+
+DEFINE_VECTOR_TYPE(int64_vector, int64_t);
+DEFINE_VECTOR_TYPE(string_vector, char *);
+
+static void
+test_int64_vector (void)
+{
+  int64_vector v = empty_vector;
+  size_t i;
+
+  for (i = 0; i < 10; ++i)
+    assert (int64_vector_append (&v, i) == 0);
+  for (i = 0; i < 10; ++i)
+    assert (v.ptr[i] == i);
+  free (v.ptr);
+}
+
+static void
+test_string_vector (void)
+{
+  string_vector v = empty_vector;
+  size_t i;
+
+  for (i = 0; i < 10; ++i) {
+    char *s;
+
+    assert (asprintf (&s, "number %zu", i) >= 0);
+    assert (string_vector_append (&v, s) == 0);
+  }
+  /* NULL-terminate the strings. */
+  assert (string_vector_append (&v, NULL) == 0);
+
+  /* Now print them. */
+  for (i = 0; v.ptr[i] != NULL; ++i)
+    printf ("%s\n", v.ptr[i]);
+  assert (i == 10);
+
+  /* And free them.  We can use the generated iter function here
+   * even though it calls free on the final NULL pointer.
+   */
+  string_vector_iter (&v, (void*)free);
+  free (v.ptr);
+}
+
+int
+main (int argc, char *argv[])
+{
+  test_int64_vector ();
+  test_string_vector ();
+}
diff --git a/common/include/vector.h b/common/include/vector.h
new file mode 100644
index 00000000..69a350be
--- /dev/null
+++ b/common/include/vector.h
@@ -0,0 +1,96 @@
+/* nbdkit
+ * Copyright (C) 2020 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS
IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* 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))                          \
+  {                                                                     \
+    size_t i;                                                           \
+    for (i = 0; i < v->size; ++i)                                       \
+      f (v->ptr[i]);                                                    \
+  }
+
+#define empty_vector { .ptr = NULL, .size = 0, .alloc = 0 }
+
+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;
+}
+
+#endif /* NBDKIT_VECTOR_H */
diff --git a/.gitignore b/.gitignore
index c44fb40d..8974b64f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ plugins/*/*.3
 /common/include/test-nextnonzero
 /common/include/test-random
 /common/include/test-tvdiff
+/common/include/test-vector
 /common/protocol/generate-protostrings.sh
 /common/protocol/protostrings.c
 /common/utils/test-quotes
--
2.25.0