From 79058b6d2b0fdc06494b901eba0edd3f9591292a Mon Sep 17 00:00:00 2001 From: Simon McVittie <smcv@collabora.com> Date: Fri, 3 Jul 2020 12:39:09 +0100 Subject: [PATCH] utils: Add and test ptr_list_free_to_array Inspired by g_ptr_array_free(., FALSE) and g_bytes_unref_to_array(), this lets us convert a ptr_list into a raw array suitable for use with qsort() and bsearch(). Signed-off-by: Simon McVittie <smcv@collabora.com> --- tests/utils.c | 43 +++++++++++++++++++++++++++++++++++++++++++ utils/utils.c | 35 +++++++++++++++++++++++++++++++++++ utils/utils.h | 1 + 3 files changed, 79 insertions(+) diff --git a/tests/utils.c b/tests/utils.c index 0f10e7743..c0540b873 100644 --- a/tests/utils.c +++ b/tests/utils.c @@ -134,6 +134,48 @@ test_build_filename (Fixture *f, } } +static void +test_ptr_list (Fixture *f, + gconstpointer data) +{ + size_t n; + ptr_list *list; + void **array; + + list = ptr_list_alloc (0); + ptr_list_push_ptr (list, (char *) "hello"); + ptr_list_add_ptr (list, (char *) "world", g_str_equal); + ptr_list_add_ptr (list, (char *) "hello", g_str_equal); // duplicate, not added + ptr_list_add_ptr (list, (char *) "world", g_str_equal); // duplicate, not added + ptr_list_push_ptr (list, (char *) "hello"); + ptr_list_push_ptr (list, NULL); + ptr_list_push_addr (list, 23); + + g_assert_cmpstr (ptr_list_nth_ptr (list, 0), ==, "hello"); + g_assert_cmpstr (ptr_list_nth_ptr (list, 1), ==, "world"); + g_assert_cmpstr (ptr_list_nth_ptr (list, 2), ==, "hello"); + g_assert_cmpstr (ptr_list_nth_ptr (list, 3), ==, NULL); + g_assert_cmpuint (GPOINTER_TO_SIZE (ptr_list_nth_ptr (list, 4)), ==, 23); + g_assert_cmpstr (ptr_list_nth_ptr (list, 5), ==, NULL); + g_assert_cmpstr (ptr_list_nth_ptr (list, 47), ==, NULL); + g_assert_true (ptr_list_contains (list, 23)); + g_assert_true (ptr_list_contains (list, (ElfW(Addr)) ptr_list_nth_ptr (list, 1))); + g_assert_false (ptr_list_contains (list, 1)); + + array = ptr_list_free_to_array (list, &n); + g_assert_cmpint (n, ==, 5); + g_assert_cmpstr (array[0], ==, "hello"); + g_assert_cmpstr (array[1], ==, "world"); + g_assert_cmpstr (array[2], ==, "hello"); + g_assert_cmpstr (array[3], ==, NULL); + g_assert_cmpuint (GPOINTER_TO_SIZE (array[4]), ==, 23); + g_assert_cmpstr (array[5], ==, NULL); + free (array); + + list = ptr_list_alloc (0); + ptr_list_free (list); +} + static void teardown (Fixture *f, gconstpointer data) @@ -149,6 +191,7 @@ main (int argc, g_test_add ("/build-filename", Fixture, NULL, setup, test_build_filename, teardown); + g_test_add ("/ptr-list", Fixture, NULL, setup, test_ptr_list, teardown); return g_test_run (); } diff --git a/utils/utils.c b/utils/utils.c index dd70f197b..7da3b69be 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -462,6 +462,41 @@ ptr_list_alloc(size_t size) return list; } +/* + * ptr_list_free_to_array: + * @list: (transfer full): list to free + * @n: (out) (optional): if not %NULL, used to return the number of + * items that were in @list + * + * Add an extra %NULL entry to @list, then return an array with the + * same contents as @list, freeing @list. If @n is not %NULL, set it + * to the number of elements in the returned array before the %NULL + * added by this function. + */ +void ** +ptr_list_free_to_array (ptr_list *list, size_t *n) +{ + void *ret; + + // Without these assertions, it's unsafe to assign a ptr_item * + // to a void ** + static_assert( alignof( void * ) == alignof( ptr_item ), + "union {void *, ElfW(Addr)} assumed to be same size " + "as void *"); + static_assert( sizeof( void * ) == sizeof( ptr_item ), + "union {void *, ElfW(Addr)} assumed to be same " + "alignment as void *"); + + if( n != NULL ) + *n = list->next; + + ptr_list_push_ptr( list, NULL ); + ret = list->loc; + list->loc = NULL; + ptr_list_free (list); + return ret; +} + void ptr_list_free (ptr_list *list) { diff --git a/utils/utils.h b/utils/utils.h index 89aee28f5..e14af8665 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -75,6 +75,7 @@ typedef int (*ptrcmp) (const void *a, const void *b); ptr_list *ptr_list_alloc (size_t size); void *ptr_list_nth_ptr (ptr_list *list, size_t nth); void ptr_list_free (ptr_list *list); +void **ptr_list_free_to_array (ptr_list *list, size_t *n); void ptr_list_push_ptr (ptr_list *list, void *ptr); void ptr_list_push_addr (ptr_list *list, ElfW(Addr) addr); int ptr_list_contains (ptr_list *list, ElfW(Addr) addr); -- GitLab