diff --git a/tests/utils.c b/tests/utils.c index 0f10e7743c41cb7efb568c1e220e25097e05a918..c0540b873524e5f1c33cee11500bcb32e0503667 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 dd70f197b4fe086b2ed2e287a3c482c5dcb27b94..7da3b69be3252b4d38065f5d9189e7a1f475afe2 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 89aee28f5ba9b034cda5076995bbd34c9c027113..e14af8665efef8c66dc3f551655e69ed7bbb94ad 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);