From 58ba7d78fbd7ecb4c0df2dc7e251627ebbffb9d5 Mon Sep 17 00:00:00 2001 From: Ernestas Kulik Date: Sat, 23 Nov 2019 17:41:54 +0100 Subject: [PATCH] list, slist: Add g_clear_{s,}list() Although not quite as often-occurring, this should help with constructs like this: if (list) { g_list_free_full (list, foo); list = NULL; } Closes https://gitlab.gnome.org/GNOME/glib/issues/1943 --- docs/reference/glib/glib-sections.txt | 2 ++ glib/glist.c | 29 ++++++++++++++++ glib/glist.h | 21 +++++++++++ glib/gslist.c | 29 ++++++++++++++++ glib/gslist.h | 21 +++++++++++ glib/tests/utils.c | 50 +++++++++++++++++++++++++++ 6 files changed, 152 insertions(+) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index e9dfa73e9..460feecc0 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -2503,6 +2503,7 @@ g_list_delete_link g_list_remove_all g_list_free g_list_free_full +g_clear_list g_list_alloc @@ -2559,6 +2560,7 @@ g_slist_free g_slist_free_full g_slist_free_1 g_slist_free1 +g_clear_slist g_slist_length diff --git a/glib/glist.c b/glib/glist.c index 39143fa7e..7b64ba1d6 100644 --- a/glib/glist.c +++ b/glib/glist.c @@ -1313,3 +1313,32 @@ g_list_sort_with_data (GList *list, { return g_list_sort_real (list, (GFunc) compare_func, user_data); } + +/** + * g_clear_list: (skip) + * @list_ptr: (not nullable): a #GList return location + * @destroy: (nullable): the function to pass to g_list_free_full() or %NULL to not free elements + * + * Clears a pointer to a #GList, freeing it and, optionally, freeing its elements using @destroy. + * + * @list_ptr must be a valid pointer. If @list_ptr points to a null #GList, this does nothing. + * + * Since: 2.64 + */ +void +(g_clear_list) (GList **list_ptr, + GDestroyNotify destroy) +{ + GList *list; + + list = *list_ptr; + if (list) + { + *list_ptr = NULL; + + if (destroy) + g_list_free_full (list, destroy); + else + g_list_free (list); + } +} diff --git a/glib/glist.h b/glib/glist.h index 8b4703e17..ddea3cf35 100644 --- a/glib/glist.h +++ b/glib/glist.h @@ -147,6 +147,27 @@ GLIB_AVAILABLE_IN_ALL gpointer g_list_nth_data (GList *list, guint n); +GLIB_AVAILABLE_IN_2_64 +void g_clear_list (GList **list_ptr, + GDestroyNotify destroy); + +#define g_clear_list(list_ptr, destroy) \ + G_STMT_START { \ + GList *_list; \ + \ + _list = *(list_ptr); \ + if (_list) \ + { \ + *list_ptr = NULL; \ + \ + if ((destroy) != NULL) \ + g_list_free_full (_list, (destroy)); \ + else \ + g_list_free (_list); \ + } \ + } G_STMT_END \ + GLIB_AVAILABLE_MACRO_IN_2_64 + #define g_list_previous(list) ((list) ? (((GList *)(list))->prev) : NULL) #define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL) diff --git a/glib/gslist.c b/glib/gslist.c index 8f616cb47..ef711f634 100644 --- a/glib/gslist.c +++ b/glib/gslist.c @@ -1065,3 +1065,32 @@ g_slist_sort_with_data (GSList *list, { return g_slist_sort_real (list, (GFunc) compare_func, user_data); } + +/** + * g_clear_slist: (skip) + * @slist_ptr: (not nullable): a #GSList return location + * @destroy: (nullable): the function to pass to g_slist_free_full() or %NULL to not free elements + * + * Clears a pointer to a #GSList, freeing it and, optionally, freeing its elements using @destroy. + * + * @slist_ptr must be a valid pointer. If @slist_ptr points to a null #GSList, this does nothing. + * + * Since: 2.64 + */ +void +(g_clear_slist) (GSList **slist_ptr, + GDestroyNotify destroy) +{ + GSList *slist; + + slist = *slist_ptr; + if (slist) + { + *slist_ptr = NULL; + + if (destroy) + g_slist_free_full (slist, destroy); + else + g_slist_free (slist); + } +} diff --git a/glib/gslist.h b/glib/gslist.h index 2704ef7d3..249417986 100644 --- a/glib/gslist.h +++ b/glib/gslist.h @@ -136,6 +136,27 @@ GLIB_AVAILABLE_IN_ALL gpointer g_slist_nth_data (GSList *list, guint n); +GLIB_AVAILABLE_IN_2_64 +void g_clear_slist (GSList **slist_ptr, + GDestroyNotify destroy); + +#define g_clear_slist(slist_ptr, destroy) \ + G_STMT_START { \ + GSList *_slist; \ + \ + _slist = *(slist_ptr); \ + if (_slist) \ + { \ + *slist_ptr = NULL; \ + \ + if ((destroy) != NULL) \ + g_slist_free_full (_slist, (destroy)); \ + else \ + g_slist_free (_slist); \ + } \ + } G_STMT_END \ + GLIB_AVAILABLE_MACRO_IN_2_64 + #define g_slist_next(slist) ((slist) ? (((GSList *)(slist))->next) : NULL) G_END_DECLS diff --git a/glib/tests/utils.c b/glib/tests/utils.c index cf8a5cbc3..ed1d63d57 100644 --- a/glib/tests/utils.c +++ b/glib/tests/utils.c @@ -760,6 +760,54 @@ test_int_limits (void) g_free (str); } +static void +test_clear_list (void) +{ + GList *list = NULL; + + g_clear_list (&list, NULL); + g_assert_null (list); + + list = g_list_prepend (list, "test"); + g_assert_nonnull (list); + + g_clear_list (&list, NULL); + g_assert_null (list); + + g_clear_list (&list, g_free); + g_assert_null (list); + + list = g_list_prepend (list, g_malloc (16)); + g_assert_nonnull (list); + + g_clear_list (&list, g_free); + g_assert_null (list); +} + +static void +test_clear_slist (void) +{ + GSList *slist = NULL; + + g_clear_slist (&slist, NULL); + g_assert_null (slist); + + slist = g_slist_prepend (slist, "test"); + g_assert_nonnull (slist); + + g_clear_slist (&slist, NULL); + g_assert_null (slist); + + g_clear_slist (&slist, g_free); + g_assert_null (slist); + + slist = g_slist_prepend (slist, g_malloc (16)); + g_assert_nonnull (slist); + + g_clear_slist (&slist, g_free); + g_assert_null (slist); +} + int main (int argc, char *argv[]) @@ -814,6 +862,8 @@ main (int argc, g_test_add_func ("/utils/atexit", test_atexit); g_test_add_func ("/utils/check-setuid", test_check_setuid); g_test_add_func ("/utils/int-limits", test_int_limits); + g_test_add_func ("/utils/clear-list", test_clear_list); + g_test_add_func ("/utils/clear-slist", test_clear_slist); return g_test_run (); }