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 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 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 #include #include +#include #include #include #include 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 . + */ + +#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: + * + * |[ + * 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 . + */ + +#ifndef __G_STRVBUILDER_H__ +#define __G_STRVBUILDER_H__ + +#if !defined(__GLIB_H_INSIDE__) && !defined(GLIB_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +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 (); +}