[glib: 1/2] gstrvbuilder: Add a new object to make NULL-terminated string arrays.




commit b2cc8d1740472de73cce437e406d05c5380f471f
Author: Robert Ancell <robert ancell gmail com>
Date:   Wed Oct 14 11:01:24 2020 +0000

    gstrvbuilder: Add a new object to make NULL-terminated string arrays.
    
    GLib uses NULL-terminated string arrays (GStrv) in a number of places, however
    these are quite hard to construct in C when the number of elements is not known
    in advance. GStrvBuilder wraps GPtrArray to make these easy to create with
    type safety and does the memory management for you.

 docs/reference/glib/glib-sections.txt |   6 ++
 glib/glib-autocleanups.h              |   1 +
 glib/glib.h                           |   1 +
 glib/gstrvbuilder.c                   | 134 ++++++++++++++++++++++++++++++++++
 glib/gstrvbuilder.h                   |  58 +++++++++++++++
 glib/meson.build                      |   2 +
 glib/tests/meson.build                |   1 +
 glib/tests/strvbuilder.c              |  80 ++++++++++++++++++++
 8 files changed, 283 insertions(+)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 6c1c86198..e96e6c86b 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -1806,9 +1806,15 @@ g_strjoinv
 
 <SUBSECTION>
 GStrv
+GStrvBuilder
 g_strv_length
 g_strv_contains
 g_strv_equal
+g_strv_builder_new
+g_strv_builder_ref
+g_strv_builder_unref
+g_strv_builder_add
+g_strv_builder_end
 
 <SUBSECTION>
 g_strerror
diff --git a/glib/glib-autocleanups.h b/glib/glib-autocleanups.h
index 2fa4b9698..6457eaff8 100644
--- a/glib/glib-autocleanups.h
+++ b/glib/glib-autocleanups.h
@@ -78,6 +78,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSequence, g_sequence_free)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSList, g_slist_free)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GString, g_autoptr_cleanup_gstring_free)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GStringChunk, g_string_chunk_free)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GStrvBuilder, g_strv_builder_unref)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GThread, g_thread_unref)
 G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GMutex, g_mutex_clear)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMutexLocker, g_mutex_locker_free)
diff --git a/glib/glib.h b/glib/glib.h
index fe8ce88d5..a4d43a9bf 100644
--- a/glib/glib.h
+++ b/glib/glib.h
@@ -82,6 +82,7 @@
 #include <glib/gstrfuncs.h>
 #include <glib/gstringchunk.h>
 #include <glib/gstring.h>
+#include <glib/gstrvbuilder.h>
 #include <glib/gtestutils.h>
 #include <glib/gthread.h>
 #include <glib/gthreadpool.h>
diff --git a/glib/gstrvbuilder.c b/glib/gstrvbuilder.c
new file mode 100644
index 000000000..909360c95
--- /dev/null
+++ b/glib/gstrvbuilder.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright © 2020 Canonical Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gstrvbuilder.h"
+
+#include "garray.h"
+#include "gmem.h"
+
+/**
+ * SECTION:gstrvbuilder
+ * @title: GStrvBuilder
+ * @short_description: Helper to create NULL-terminated string arrays.
+ *
+ * #GStrvBuilder is a method of easily building dynamically sized
+ * NULL-terminated string arrays.
+ *
+ * The following example shows how to build a two element array:
+ *
+ * |[<!-- language="C" -->
+ *   g_autoptr(GStrvBuilder) builder = g_strv_builder_new ();
+ *   g_strv_builder_add (builder, "hello");
+ *   g_strv_builder_add (builder, "world");
+ *   g_auto(GStrv) array = g_strv_builder_end (builder);
+ * ]|
+ *
+ * Since: 2.68
+ */
+
+struct _GStrvBuilder
+{
+  GPtrArray array;
+};
+
+/**
+ * g_strv_builder_new:
+ *
+ * Creates a new #GStrvBuilder with a reference count of 1.
+ * Use g_strv_builder_unref() on the returned value when no longer needed.
+ *
+ * Returns: (transfer full): the new #GStrvBuilder
+ *
+ * Since: 2.68
+ */
+GStrvBuilder *
+g_strv_builder_new (void)
+{
+  return (GStrvBuilder *) g_ptr_array_new_with_free_func (g_free);
+}
+
+/**
+ * g_strv_builder_unref:
+ * @builder: (transfer full): a #GStrvBuilder allocated by g_strv_builder_new()
+ *
+ * Decreases the reference count on @builder.
+ *
+ * In the event that there are no more references, releases all memory
+ * associated with the #GStrvBuilder.
+ *
+ * Since: 2.68
+ **/
+void
+g_strv_builder_unref (GStrvBuilder *builder)
+{
+  g_ptr_array_unref (&builder->array);
+}
+
+/**
+ * g_strv_builder_ref:
+ * @builder: (transfer none): a #GStrvBuilder
+ *
+ * Atomically increments the reference count of @builder by one.
+ * This function is thread-safe and may be called from any thread.
+ *
+ * Returns: (transfer full): The passed in #GStrvBuilder
+ *
+ * Since: 2.68
+ */
+GStrvBuilder *
+g_strv_builder_ref (GStrvBuilder *builder)
+{
+  return (GStrvBuilder *) g_ptr_array_ref (&builder->array);
+}
+
+/**
+ * g_strv_builder_add:
+ * @builder: a #GStrvBuilder
+ * @value: a string.
+ *
+ * Add a string to the end of the array.
+ *
+ * Since 2.68
+ */
+void
+g_strv_builder_add (GStrvBuilder *builder,
+                    const char   *value)
+{
+  g_ptr_array_add (&builder->array, g_strdup (value));
+}
+
+/**
+ * g_strv_builder_end:
+ * @builder: a #GStrvBuilder
+ *
+ * Ends the builder process and returns the constructed NULL-terminated string
+ * array. The returned value should be freed with g_strfreev() when no longer
+ * needed.
+ *
+ * Returns: (transfer full): the constructed string array.
+ *
+ * Since 2.68
+ */
+GStrv
+g_strv_builder_end (GStrvBuilder *builder)
+{
+  /* Add NULL terminator */
+  g_ptr_array_add (&builder->array, NULL);
+  return (GStrv) g_ptr_array_steal (&builder->array, NULL);
+}
diff --git a/glib/gstrvbuilder.h b/glib/gstrvbuilder.h
new file mode 100644
index 000000000..395bcfbbe
--- /dev/null
+++ b/glib/gstrvbuilder.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2020 Canonical Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __G_STRVBUILDER_H__
+#define __G_STRVBUILDER_H__
+
+#if !defined(__GLIB_H_INSIDE__) && !defined(GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#include <glib/gstrfuncs.h>
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GStrvBuilder:
+ * 
+ * A helper object to build a %NULL-terminated string array
+ * by appending. See g_strv_builder_new().
+ *
+ * Since: 2.68
+ */
+typedef struct _GStrvBuilder GStrvBuilder;
+
+GLIB_AVAILABLE_IN_2_68
+GStrvBuilder *g_strv_builder_new (void);
+
+GLIB_AVAILABLE_IN_2_68
+void g_strv_builder_unref (GStrvBuilder *builder);
+
+GLIB_AVAILABLE_IN_2_68
+GStrvBuilder *g_strv_builder_ref (GStrvBuilder *builder);
+
+GLIB_AVAILABLE_IN_2_68
+void g_strv_builder_add (GStrvBuilder *builder,
+                         const char *value);
+
+GLIB_AVAILABLE_IN_2_68
+GStrv g_strv_builder_end (GStrvBuilder *builder);
+
+G_END_DECLS
+
+#endif /* __G_STRVBUILDER_H__ */
diff --git a/glib/meson.build b/glib/meson.build
index 7e0edb905..aaf40a218 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -198,6 +198,7 @@ glib_sub_headers = files(
   'gspawn.h',
   'gstdio.h',
   'gstrfuncs.h',
+  'gstrvbuilder.h',
   'gtestutils.h',
   'gstring.h',
   'gstringchunk.h',
@@ -286,6 +287,7 @@ glib_sources = files(
   'gstrfuncs.c',
   'gstring.c',
   'gstringchunk.c',
+  'gstrvbuilder.c',
   'gtestutils.c',
   'gthread.c',
   'gthreadpool.c',
diff --git a/glib/tests/meson.build b/glib/tests/meson.build
index 6eb23e8a7..567f5eda4 100644
--- a/glib/tests/meson.build
+++ b/glib/tests/meson.build
@@ -92,6 +92,7 @@ glib_tests = {
   'spawn-singlethread' : {},
   'strfuncs' : {},
   'string' : {},
+  'strvbuilder' : {},
   'testing' : {},
   'test-printf' : {},
   'thread' : {},
diff --git a/glib/tests/strvbuilder.c b/glib/tests/strvbuilder.c
new file mode 100644
index 000000000..5f3b9329f
--- /dev/null
+++ b/glib/tests/strvbuilder.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2020 Canonical Ltd.
+ *
+ * This work is provided "as is"; redistribution and modification
+ * in whole or in part, in any medium, physical or electronic is
+ * permitted without restriction.
+ *
+ * This work is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * In no event shall the authors 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 "glib.h"
+
+static void
+test_strvbuilder_empty (void)
+{
+  GStrvBuilder *builder;
+  GStrv result;
+
+  builder = g_strv_builder_new ();
+  result = g_strv_builder_end (builder);
+  g_assert_nonnull (result);
+  g_assert_cmpint (g_strv_length (result), ==, 0);
+
+  g_strfreev (result);
+  g_strv_builder_unref (builder);
+}
+
+static void
+test_strvbuilder_add (void)
+{
+  GStrvBuilder *builder;
+  GStrv result;
+  const gchar *expected[] = { "one", "two", "three", NULL };
+
+  builder = g_strv_builder_new ();
+  g_strv_builder_add (builder, "one");
+  g_strv_builder_add (builder, "two");
+  g_strv_builder_add (builder, "three");
+  result = g_strv_builder_end (builder);
+  g_assert_nonnull (result);
+  g_assert_true (g_strv_equal ((const gchar *const *) result, expected));
+
+  g_strfreev (result);
+  g_strv_builder_unref (builder);
+}
+
+static void
+test_strvbuilder_ref (void)
+{
+  GStrvBuilder *builder;
+
+  builder = g_strv_builder_new ();
+  g_strv_builder_ref (builder);
+  g_strv_builder_unref (builder);
+  g_strv_builder_unref (builder);
+}
+
+int
+main (int argc,
+      char *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/strvbuilder/empty", test_strvbuilder_empty);
+  g_test_add_func ("/strvbuilder/add", test_strvbuilder_add);
+  g_test_add_func ("/strvbuilder/ref", test_strvbuilder_ref);
+
+  return g_test_run ();
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]