From d2c3f7f513dfa48a72f52adf0bfbbc675e80302b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 14 Dec 2022 03:18:44 +0100 Subject: [PATCH 01/10] ghash: Add APIs to get hash table keys and values as GPtrArray GPtrArray's are faster than lists and provide more flexibility, so add APIs to get hash keys and values using these containers too. Given that we know the size at array initialization we can optimize the allocation quite a bit, making it faster than the API using GList both at creation time and for consumers. --- docs/reference/glib/glib-sections.txt.in | 2 + glib/ghash.c | 78 ++++++++++++++++++++++++ glib/ghash.h | 6 ++ glib/tests/hash.c | 59 ++++++++++++++++++ 4 files changed, 145 insertions(+) diff --git a/docs/reference/glib/glib-sections.txt.in b/docs/reference/glib/glib-sections.txt.in index 9fbce402c..2ac3af6bb 100644 --- a/docs/reference/glib/glib-sections.txt.in +++ b/docs/reference/glib/glib-sections.txt.in @@ -2584,7 +2584,9 @@ g_hash_table_remove_all g_hash_table_steal_all g_hash_table_get_keys g_hash_table_get_values +g_hash_table_get_values_as_ptr_array g_hash_table_get_keys_as_array +g_hash_table_get_keys_as_ptr_array GHRFunc g_hash_table_freeze g_hash_table_thaw diff --git a/glib/ghash.c b/glib/ghash.c index 158779911..6b6adc501 100644 --- a/glib/ghash.c +++ b/glib/ghash.c @@ -2273,6 +2273,45 @@ g_hash_table_get_keys_as_array (GHashTable *hash_table, return result; } +/** + * g_hash_table_get_keys_as_ptr_array: (skip) + * @hash_table: a #GHashTable + * + * Retrieves every key inside @hash_table, as a #GPtrArray. + * The returned data is valid until changes to the hash release those keys. + * + * This iterates over every entry in the hash table to build its return value. + * To iterate over the entries in a #GHashTable more efficiently, use a + * #GHashTableIter. + * + * You should always unref the returned array with g_ptr_array_unref(). + * + * Returns: (transfer container): a #GPtrArray containing each key from + * the table. Unref with with g_ptr_array_unref() when done. + * + * Since: 2.76 + **/ +GPtrArray * +g_hash_table_get_keys_as_ptr_array (GHashTable *hash_table) +{ + GPtrArray *array; + + g_return_val_if_fail (hash_table != NULL, NULL); + + array = g_ptr_array_sized_new (hash_table->size); + for (gsize i = 0; i < hash_table->size; ++i) + { + if (HASH_IS_REAL (hash_table->hashes[i])) + { + g_ptr_array_add (array, g_hash_table_fetch_key_or_value ( + hash_table->keys, i, hash_table->have_big_keys)); + } + } + g_assert (array->len == (guint) hash_table->nnodes); + + return array; +} + /** * g_hash_table_get_values: * @hash_table: a #GHashTable @@ -2309,6 +2348,45 @@ g_hash_table_get_values (GHashTable *hash_table) return retval; } +/** + * g_hash_table_get_values_as_ptr_array: (skip) + * @hash_table: a #GHashTable + * + * Retrieves every value inside @hash_table, as a #GPtrArray. + * The returned data is valid until changes to the hash release those values. + * + * This iterates over every entry in the hash table to build its return value. + * To iterate over the entries in a #GHashTable more efficiently, use a + * #GHashTableIter. + * + * You should always unref the returned array with g_ptr_array_unref(). + * + * Returns: (transfer container): a #GPtrArray containing each value from + * the table. Unref with with g_ptr_array_unref() when done. + * + * Since: 2.76 + **/ +GPtrArray * +g_hash_table_get_values_as_ptr_array (GHashTable *hash_table) +{ + GPtrArray *array; + + g_return_val_if_fail (hash_table != NULL, NULL); + + array = g_ptr_array_sized_new (hash_table->size); + for (gsize i = 0; i < hash_table->size; ++i) + { + if (HASH_IS_REAL (hash_table->hashes[i])) + { + g_ptr_array_add (array, g_hash_table_fetch_key_or_value ( + hash_table->values, i, hash_table->have_big_values)); + } + } + g_assert (array->len == (guint) hash_table->nnodes); + + return array; +} + /* Hash functions. */ diff --git a/glib/ghash.h b/glib/ghash.h index 396148de5..604b07c8c 100644 --- a/glib/ghash.h +++ b/glib/ghash.h @@ -32,6 +32,7 @@ #endif #include +#include #include G_BEGIN_DECLS @@ -129,6 +130,11 @@ GList * g_hash_table_get_values (GHashTable *hash_table); GLIB_AVAILABLE_IN_2_40 gpointer * g_hash_table_get_keys_as_array (GHashTable *hash_table, guint *length); +GLIB_AVAILABLE_IN_2_76 +GPtrArray * g_hash_table_get_keys_as_ptr_array (GHashTable *hash_table); + +GLIB_AVAILABLE_IN_2_76 +GPtrArray * g_hash_table_get_values_as_ptr_array (GHashTable *hash_table); GLIB_AVAILABLE_IN_ALL void g_hash_table_iter_init (GHashTableIter *iter, diff --git a/glib/tests/hash.c b/glib/tests/hash.c index 604dcc049..d929f531e 100644 --- a/glib/tests/hash.c +++ b/glib/tests/hash.c @@ -1692,6 +1692,63 @@ test_set_to_strv (void) g_strfreev (strv); } +static void +test_set_get_keys_as_ptr_array (void) +{ + GHashTable *set; + GPtrArray *array; + + set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_add (set, g_strdup ("xyz")); + g_hash_table_add (set, g_strdup ("xyz")); + g_hash_table_add (set, g_strdup ("abc")); + + array = g_hash_table_get_keys_as_ptr_array (set); + g_hash_table_steal_all (set); + g_hash_table_unref (set); + g_ptr_array_set_free_func (array, g_free); + + g_assert_cmpint (array->len, ==, 2); + g_ptr_array_add (array, NULL); + + g_assert_true ( + g_strv_equal ((const gchar * const[]) { "xyz", "abc", NULL }, + (const gchar * const*) array->pdata) || + g_strv_equal ((const gchar * const[]) { "abc", "xyz", NULL }, + (const gchar * const*) array->pdata) + ); + + g_clear_pointer (&array, g_ptr_array_unref); +} + +static void +test_set_get_values_as_ptr_array (void) +{ + GHashTable *table; + GPtrArray *array; + + table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_insert (table, g_strdup ("xyz"), GUINT_TO_POINTER (0)); + g_hash_table_insert (table, g_strdup ("xyz"), GUINT_TO_POINTER (1)); + g_hash_table_insert (table, g_strdup ("abc"), GUINT_TO_POINTER (2)); + + array = g_hash_table_get_values_as_ptr_array (table); + g_clear_pointer (&table, g_hash_table_unref); + + g_assert_cmpint (array->len, ==, 2); + g_assert_true (g_ptr_array_find (array, GUINT_TO_POINTER (1), NULL)); + g_assert_true (g_ptr_array_find (array, GUINT_TO_POINTER (2), NULL)); + + g_assert_true ( + memcmp ((gpointer []) { GUINT_TO_POINTER (1), GUINT_TO_POINTER (2) }, + array->pdata, array->len * sizeof (gpointer)) == 0 || + memcmp ((gpointer []) { GUINT_TO_POINTER (2), GUINT_TO_POINTER (1) }, + array->pdata, array->len * sizeof (gpointer)) == 0 + ); + + g_clear_pointer (&array, g_ptr_array_unref); +} + static gboolean is_prime (guint p) { @@ -1774,6 +1831,8 @@ main (int argc, char *argv[]) g_test_add_func ("/hash/iter-replace", test_iter_replace); g_test_add_func ("/hash/set-insert-corruption", test_set_insert_corruption); g_test_add_func ("/hash/set-to-strv", test_set_to_strv); + g_test_add_func ("/hash/get-keys-as-ptr-array", test_set_get_keys_as_ptr_array); + g_test_add_func ("/hash/get-values-as-ptr-array", test_set_get_values_as_ptr_array); g_test_add_func ("/hash/primes", test_primes); return g_test_run (); From d68e7bc84a1e9fe7413388760d9286ed59bcf06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 14 Dec 2022 04:08:10 +0100 Subject: [PATCH 02/10] ghash: Add functions to steal all keys and values preserving ownership Add functions to steal all the keys or values from a ghash (especially useful when it's used as a set), passing the ownership of then to a GPtrArray container that preserves the destroy notify functions. --- docs/reference/glib/glib-sections.txt.in | 2 + glib/ghash.c | 74 ++++++++++++++++ glib/ghash.h | 4 + glib/tests/hash.c | 102 +++++++++++++++++++++++ 4 files changed, 182 insertions(+) diff --git a/docs/reference/glib/glib-sections.txt.in b/docs/reference/glib/glib-sections.txt.in index 2ac3af6bb..ab7453e60 100644 --- a/docs/reference/glib/glib-sections.txt.in +++ b/docs/reference/glib/glib-sections.txt.in @@ -2578,6 +2578,8 @@ GHFunc g_hash_table_remove g_hash_table_steal g_hash_table_steal_extended +g_hash_table_steal_all_keys +g_hash_table_steal_all_values g_hash_table_foreach_remove g_hash_table_foreach_steal g_hash_table_remove_all diff --git a/glib/ghash.c b/glib/ghash.c index 6b6adc501..64edc0a34 100644 --- a/glib/ghash.c +++ b/glib/ghash.c @@ -1942,6 +1942,80 @@ g_hash_table_steal_all (GHashTable *hash_table) g_hash_table_maybe_resize (hash_table); } +/** + * g_hash_table_steal_all_keys: (skip) + * @hash_table: a #GHashTable + * + * Removes all keys and their associated values from a #GHashTable + * without calling the key destroy functions, returning the keys + * as a #GPtrArray with the free func set to the @hash_table key + * destroy function. + * + * Returns: (transfer container): a #GPtrArray containing each key of + * the table. Unref with with g_ptr_array_unref() when done. + * + * Since: 2.76 + */ +GPtrArray * +g_hash_table_steal_all_keys (GHashTable *hash_table) +{ + GPtrArray *array; + GDestroyNotify key_destroy_func; + + g_return_val_if_fail (hash_table != NULL, NULL); + + array = g_hash_table_get_keys_as_ptr_array (hash_table); + + /* Ignore the key destroy notify calls during removal, and use it for the + * array elements instead, but restore it after the hash table has been + * cleared, so that newly added keys will continue using it. + */ + key_destroy_func = g_steal_pointer (&hash_table->key_destroy_func); + g_ptr_array_set_free_func (array, key_destroy_func); + + g_hash_table_remove_all (hash_table); + hash_table->key_destroy_func = g_steal_pointer (&key_destroy_func); + + return array; +} + +/** + * g_hash_table_steal_all_values: (skip) + * @hash_table: a #GHashTable + * + * Removes all keys and their associated values from a #GHashTable + * without calling the value destroy functions, returning the values + * as a #GPtrArray with the free func set to the @hash_table value + * destroy function. + * + * Returns: (transfer container): a #GPtrArray containing each value of + * the table. Unref with with g_ptr_array_unref() when done. + * + * Since: 2.76 + */ +GPtrArray * +g_hash_table_steal_all_values (GHashTable *hash_table) +{ + GPtrArray *array; + GDestroyNotify value_destroy_func; + + g_return_val_if_fail (hash_table != NULL, NULL); + + array = g_hash_table_get_values_as_ptr_array (hash_table); + + /* Ignore the value destroy notify calls during removal, and use it for the + * array elements instead, but restore it after the hash table has been + * cleared, so that newly added values will continue using it. + */ + value_destroy_func = g_steal_pointer (&hash_table->value_destroy_func); + g_ptr_array_set_free_func (array, value_destroy_func); + + g_hash_table_remove_all (hash_table); + hash_table->value_destroy_func = g_steal_pointer (&value_destroy_func); + + return array; +} + /* * g_hash_table_foreach_remove_or_steal: * @hash_table: a #GHashTable diff --git a/glib/ghash.h b/glib/ghash.h index 604b07c8c..3eb8f3be0 100644 --- a/glib/ghash.h +++ b/glib/ghash.h @@ -94,6 +94,10 @@ gboolean g_hash_table_steal_extended (GHashTable *hash_table, gpointer *stolen_value); GLIB_AVAILABLE_IN_ALL void g_hash_table_steal_all (GHashTable *hash_table); +GLIB_AVAILABLE_IN_2_76 +GPtrArray * g_hash_table_steal_all_keys (GHashTable *hash_table); +GLIB_AVAILABLE_IN_2_76 +GPtrArray * g_hash_table_steal_all_values (GHashTable *hash_table); GLIB_AVAILABLE_IN_ALL gpointer g_hash_table_lookup (GHashTable *hash_table, gconstpointer key); diff --git a/glib/tests/hash.c b/glib/tests/hash.c index d929f531e..d08ddd57e 100644 --- a/glib/tests/hash.c +++ b/glib/tests/hash.c @@ -1749,6 +1749,106 @@ test_set_get_values_as_ptr_array (void) g_clear_pointer (&array, g_ptr_array_unref); } +static void +test_steal_all_keys (void) +{ + GHashTable *table; + GPtrArray *array; + + table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_insert (table, g_strdup ("xyz"), GUINT_TO_POINTER (0)); + g_hash_table_insert (table, g_strdup ("xyz"), GUINT_TO_POINTER (1)); + g_hash_table_insert (table, g_strdup ("abc"), GUINT_TO_POINTER (2)); + + array = g_hash_table_steal_all_keys (table); + g_assert_cmpuint (g_hash_table_size (table), ==, 0); + + g_hash_table_insert (table, g_strdup ("do-not-leak-me"), GUINT_TO_POINTER (5)); + g_clear_pointer (&table, g_hash_table_unref); + + g_assert_cmpint (array->len, ==, 2); + g_ptr_array_add (array, NULL); + + g_assert_true ( + g_strv_equal ((const gchar * const[]) { "xyz", "abc", NULL }, + (const gchar * const*) array->pdata) || + g_strv_equal ((const gchar * const[]) { "abc", "xyz", NULL }, + (const gchar * const*) array->pdata) + ); + + g_clear_pointer (&array, g_ptr_array_unref); + + table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + g_hash_table_insert (table, GUINT_TO_POINTER (0), g_strdup ("xyz")); + g_hash_table_insert (table, GUINT_TO_POINTER (1), g_strdup ("xyz")); + g_hash_table_insert (table, GUINT_TO_POINTER (2), g_strdup ("abc")); + + array = g_hash_table_steal_all_keys (table); + g_assert_cmpuint (g_hash_table_size (table), ==, 0); + + g_hash_table_insert (table, GUINT_TO_POINTER (5), g_strdup ("do-not-leak-me")); + g_clear_pointer (&table, g_hash_table_unref); + + g_assert_cmpint (array->len, ==, 3); + g_assert_true (g_ptr_array_find (array, GUINT_TO_POINTER (0), NULL)); + g_assert_true (g_ptr_array_find (array, GUINT_TO_POINTER (1), NULL)); + g_assert_true (g_ptr_array_find (array, GUINT_TO_POINTER (2), NULL)); + + g_clear_pointer (&array, g_ptr_array_unref); +} + +static void +test_steal_all_values (void) +{ + GHashTable *table; + GPtrArray *array; + + table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_hash_table_insert (table, g_strdup ("xyz"), GUINT_TO_POINTER (0)); + g_hash_table_insert (table, g_strdup ("xyz"), GUINT_TO_POINTER (1)); + g_hash_table_insert (table, g_strdup ("abc"), GUINT_TO_POINTER (2)); + + array = g_hash_table_steal_all_values (table); + g_assert_cmpuint (g_hash_table_size (table), ==, 0); + + g_hash_table_insert (table, g_strdup ("do-not-leak-me"), GUINT_TO_POINTER (5)); + g_clear_pointer (&table, g_hash_table_unref); + + g_assert_cmpint (array->len, ==, 2); + g_assert_true (g_ptr_array_find (array, GUINT_TO_POINTER (1), NULL)); + g_assert_true (g_ptr_array_find (array, GUINT_TO_POINTER (2), NULL)); + + g_assert_true ( + memcmp ((gpointer []) { GUINT_TO_POINTER (1), GUINT_TO_POINTER (2) }, + array->pdata, array->len * sizeof (gpointer)) == 0 || + memcmp ((gpointer []) { GUINT_TO_POINTER (2), GUINT_TO_POINTER (1) }, + array->pdata, array->len * sizeof (gpointer)) == 0 + ); + + g_clear_pointer (&array, g_ptr_array_unref); + + table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + g_hash_table_insert (table, GUINT_TO_POINTER (0), g_strdup ("xyz")); + g_hash_table_insert (table, GUINT_TO_POINTER (1), g_strdup ("foo")); + g_hash_table_insert (table, GUINT_TO_POINTER (2), g_strdup ("abc")); + + array = g_hash_table_steal_all_values (table); + g_assert_cmpuint (g_hash_table_size (table), ==, 0); + + g_hash_table_insert (table, GUINT_TO_POINTER (5), g_strdup ("do-not-leak-me")); + g_clear_pointer (&table, g_hash_table_unref); + + g_assert_cmpint (array->len, ==, 3); + g_assert_true ( + g_ptr_array_find_with_equal_func (array, "xyz", g_str_equal, NULL)); + g_assert_true ( + g_ptr_array_find_with_equal_func (array, "foo", g_str_equal, NULL)); + g_assert_true ( + g_ptr_array_find_with_equal_func (array, "abc", g_str_equal, NULL)); + + g_clear_pointer (&array, g_ptr_array_unref); +} + static gboolean is_prime (guint p) { @@ -1821,6 +1921,8 @@ main (int argc, char *argv[]) g_test_add_func ("/hash/foreach-steal", test_foreach_steal); g_test_add_func ("/hash/steal-extended", test_steal_extended); g_test_add_func ("/hash/steal-extended/optional", test_steal_extended_optional); + g_test_add_func ("/hash/steal-all-keys", test_steal_all_keys); + g_test_add_func ("/hash/steal-all-values", test_steal_all_values); g_test_add_func ("/hash/lookup-extended", test_lookup_extended); g_test_add_func ("/hash/new-similar", test_new_similar); From e733a3db10ab0262775300b1e3459601f71ce723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 8 Dec 2022 02:47:39 +0100 Subject: [PATCH 03/10] gdbusconnection: Avoid copying connection registered set values twice --- gio/gdbusconnection.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c index 9f78c4bff..d938f71b9 100644 --- a/gio/gdbusconnection.c +++ b/gio/gdbusconnection.c @@ -4870,8 +4870,6 @@ g_dbus_connection_list_registered_unlocked (GDBusConnection *connection, const gchar *object_path; gsize path_len; GHashTable *set; - GList *keys; - GList *l; CONNECTION_ENSURE_LOCK (connection); @@ -4889,12 +4887,8 @@ g_dbus_connection_list_registered_unlocked (GDBusConnection *connection, while (g_hash_table_iter_next (&hash_iter, (gpointer) &object_path, NULL)) maybe_add_path (path, path_len, object_path, set); - p = g_ptr_array_new (); - keys = g_hash_table_get_keys (set); - for (l = keys; l != NULL; l = l->next) - g_ptr_array_add (p, l->data); + p = g_hash_table_steal_all_keys (set); g_hash_table_unref (set); - g_list_free (keys); g_ptr_array_add (p, NULL); ret = (gchar **) g_ptr_array_free (p, FALSE); From 5d5d12112b232aa9a425d45f66f3b3846a1148ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 8 Dec 2022 03:33:56 +0100 Subject: [PATCH 04/10] gdbusaddress: Use simpler hash table keys as arrays We don't really need the lists overhead here, so let's just use the simpler forms. --- gio/gdbusaddress.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index 523b1b8d0..b24dbde09 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -130,8 +130,8 @@ is_valid_unix (const gchar *address_entry, GError **error) { gboolean ret; - GList *keys; - GList *l; + char **keys; + guint keys_length; const gchar *path; const gchar *dir; const gchar *tmpdir; @@ -144,10 +144,10 @@ is_valid_unix (const gchar *address_entry, tmpdir = NULL; abstract = NULL; - keys = g_hash_table_get_keys (key_value_pairs); - for (l = keys; l != NULL; l = l->next) + keys = (char **) g_hash_table_get_keys_as_array (key_value_pairs, &keys_length); + for (guint i = 0; i < keys_length; ++i) { - const gchar *key = l->data; + const gchar *key = keys[i]; if (g_strcmp0 (key, "path") == 0) path = g_hash_table_lookup (key_value_pairs, key); else if (g_strcmp0 (key, "dir") == 0) @@ -191,7 +191,7 @@ is_valid_unix (const gchar *address_entry, ret = TRUE; out: - g_list_free (keys); + g_free (keys); return ret; } @@ -202,8 +202,8 @@ is_valid_nonce_tcp (const gchar *address_entry, GError **error) { gboolean ret; - GList *keys; - GList *l; + char **keys; + guint keys_length; const gchar *host; const gchar *port; const gchar *family; @@ -218,10 +218,10 @@ is_valid_nonce_tcp (const gchar *address_entry, family = NULL; nonce_file = NULL; - keys = g_hash_table_get_keys (key_value_pairs); - for (l = keys; l != NULL; l = l->next) + keys = (char **) g_hash_table_get_keys_as_array (key_value_pairs, &keys_length); + for (guint i = 0; i < keys_length; ++i) { - const gchar *key = l->data; + const gchar *key = keys[i]; if (g_strcmp0 (key, "host") == 0) host = g_hash_table_lookup (key_value_pairs, key); else if (g_strcmp0 (key, "port") == 0) @@ -284,7 +284,7 @@ is_valid_nonce_tcp (const gchar *address_entry, ret = TRUE; out: - g_list_free (keys); + g_free (keys); return ret; } @@ -295,8 +295,8 @@ is_valid_tcp (const gchar *address_entry, GError **error) { gboolean ret; - GList *keys; - GList *l; + char **keys; + guint keys_length; const gchar *host; const gchar *port; const gchar *family; @@ -309,10 +309,10 @@ is_valid_tcp (const gchar *address_entry, port = NULL; family = NULL; - keys = g_hash_table_get_keys (key_value_pairs); - for (l = keys; l != NULL; l = l->next) + keys = (char **) g_hash_table_get_keys_as_array (key_value_pairs, &keys_length); + for (guint i = 0; i < keys_length; ++i) { - const gchar *key = l->data; + const gchar *key = keys[i]; if (g_strcmp0 (key, "host") == 0) host = g_hash_table_lookup (key_value_pairs, key); else if (g_strcmp0 (key, "port") == 0) @@ -363,7 +363,7 @@ is_valid_tcp (const gchar *address_entry, ret= TRUE; out: - g_list_free (keys); + g_free (keys); return ret; } From 1e699edf0e8b53a2e570dac8b49805891bdab938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 8 Dec 2022 03:33:56 +0100 Subject: [PATCH 05/10] gdbusaddress: Use simpler hash table keys as arrays We don't really need the lists overhead here, so let's just use the simpler forms. --- gio/gdbusaddress.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index b24dbde09..0983ac49c 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -130,24 +130,22 @@ is_valid_unix (const gchar *address_entry, GError **error) { gboolean ret; - char **keys; - guint keys_length; + GPtrArray *keys; const gchar *path; const gchar *dir; const gchar *tmpdir; const gchar *abstract; ret = FALSE; - keys = NULL; path = NULL; dir = NULL; tmpdir = NULL; abstract = NULL; - keys = (char **) g_hash_table_get_keys_as_array (key_value_pairs, &keys_length); - for (guint i = 0; i < keys_length; ++i) + keys = g_hash_table_get_keys_as_ptr_array (key_value_pairs); + for (guint i = 0; i < keys->len; ++i) { - const gchar *key = keys[i]; + const gchar *key = g_ptr_array_index (keys, i); if (g_strcmp0 (key, "path") == 0) path = g_hash_table_lookup (key_value_pairs, key); else if (g_strcmp0 (key, "dir") == 0) @@ -191,7 +189,7 @@ is_valid_unix (const gchar *address_entry, ret = TRUE; out: - g_free (keys); + g_ptr_array_unref (keys); return ret; } @@ -202,8 +200,7 @@ is_valid_nonce_tcp (const gchar *address_entry, GError **error) { gboolean ret; - char **keys; - guint keys_length; + GPtrArray *keys; const gchar *host; const gchar *port; const gchar *family; @@ -212,16 +209,15 @@ is_valid_nonce_tcp (const gchar *address_entry, gchar *endp; ret = FALSE; - keys = NULL; host = NULL; port = NULL; family = NULL; nonce_file = NULL; - keys = (char **) g_hash_table_get_keys_as_array (key_value_pairs, &keys_length); - for (guint i = 0; i < keys_length; ++i) + keys = g_hash_table_get_keys_as_ptr_array (key_value_pairs); + for (guint i = 0; i < keys->len; ++i) { - const gchar *key = keys[i]; + const gchar *key = g_ptr_array_index (keys, i); if (g_strcmp0 (key, "host") == 0) host = g_hash_table_lookup (key_value_pairs, key); else if (g_strcmp0 (key, "port") == 0) @@ -284,7 +280,7 @@ is_valid_nonce_tcp (const gchar *address_entry, ret = TRUE; out: - g_free (keys); + g_ptr_array_unref (keys); return ret; } @@ -295,8 +291,7 @@ is_valid_tcp (const gchar *address_entry, GError **error) { gboolean ret; - char **keys; - guint keys_length; + GPtrArray *keys; const gchar *host; const gchar *port; const gchar *family; @@ -304,15 +299,14 @@ is_valid_tcp (const gchar *address_entry, gchar *endp; ret = FALSE; - keys = NULL; host = NULL; port = NULL; family = NULL; - keys = (char **) g_hash_table_get_keys_as_array (key_value_pairs, &keys_length); - for (guint i = 0; i < keys_length; ++i) + keys = g_hash_table_get_keys_as_ptr_array (key_value_pairs); + for (guint i = 0; i < keys->len; ++i) { - const gchar *key = keys[i]; + const gchar *key = g_ptr_array_index (keys, i); if (g_strcmp0 (key, "host") == 0) host = g_hash_table_lookup (key_value_pairs, key); else if (g_strcmp0 (key, "port") == 0) @@ -363,7 +357,7 @@ is_valid_tcp (const gchar *address_entry, ret= TRUE; out: - g_free (keys); + g_ptr_array_unref (keys); return ret; } From 0e56d2f5db06c016745e0e238cdb6b715c4b1b62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 8 Dec 2022 03:33:07 +0100 Subject: [PATCH 06/10] gdbusmessage: Get message headers keys as arrays We eventually need to return them as an array anyways. Sadly we can't just reuse such memory because each element is a pointer and not a guchar, but still we can be cheaper in various operations. --- gio/gdbusmessage.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c index 7aebdeb90..66da3bdf5 100644 --- a/gio/gdbusmessage.c +++ b/gio/gdbusmessage.c @@ -1094,24 +1094,27 @@ g_dbus_message_set_header (GDBusMessage *message, guchar * g_dbus_message_get_header_fields (GDBusMessage *message) { - GList *keys; - guchar *ret; - guint num_keys; - GList *l; - guint n; + GPtrArray *keys; + GArray *array; g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL); - keys = g_hash_table_get_keys (message->headers); - num_keys = g_list_length (keys); - ret = g_new (guchar, num_keys + 1); - for (l = keys, n = 0; l != NULL; l = l->next, n++) - ret[n] = GPOINTER_TO_UINT (l->data); - g_assert (n == num_keys); - ret[n] = G_DBUS_MESSAGE_HEADER_FIELD_INVALID; - g_list_free (keys); + keys = g_hash_table_get_keys_as_ptr_array (message->headers); + array = g_array_sized_new (FALSE, FALSE, sizeof (guchar), keys->len + 1); - return ret; + for (guint i = 0; i < keys->len; ++i) + { + guchar val = GPOINTER_TO_UINT (g_ptr_array_index (keys, i)); + g_array_append_val (array, val); + } + + g_assert (array->len == keys->len); + g_clear_pointer (&keys, g_ptr_array_unref); + + guchar invalid_field = G_DBUS_MESSAGE_HEADER_FIELD_INVALID; + g_array_append_val (array, invalid_field); + + return (guchar *) g_array_free (array, FALSE); } /* ---------------------------------------------------------------------------------------------------- */ From 1eb7f3177df0773a02d0bcd40ab6bcab24f7d0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 14 Dec 2022 04:57:28 +0100 Subject: [PATCH 07/10] gdbusobjectmanagerclient: Simplify g-name-owner changes code We can avoid further copies and unneeded ref/unrefs. --- gio/gdbusobjectmanagerclient.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/gio/gdbusobjectmanagerclient.c b/gio/gdbusobjectmanagerclient.c index fa5e73041..b6b3b212c 100644 --- a/gio/gdbusobjectmanagerclient.c +++ b/gio/gdbusobjectmanagerclient.c @@ -1355,13 +1355,11 @@ on_notify_g_name_owner (GObject *object, if (g_strcmp0 (old_name_owner, new_name_owner) != 0) { - GList *l; - GList *proxies; + GPtrArray *proxies; /* remote manager changed; nuke all local proxies */ - proxies = g_hash_table_get_values (manager->priv->map_object_path_to_object_proxy); - g_list_foreach (proxies, (GFunc) g_object_ref, NULL); - g_hash_table_remove_all (manager->priv->map_object_path_to_object_proxy); + proxies = g_hash_table_steal_all_values ( + manager->priv->map_object_path_to_object_proxy); g_mutex_unlock (&manager->priv->lock); @@ -1371,12 +1369,13 @@ on_notify_g_name_owner (GObject *object, */ g_object_notify (G_OBJECT (manager), "name-owner"); - for (l = proxies; l != NULL; l = l->next) + for (guint i = 0; i < proxies->len; ++i) { - GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY (l->data); + GDBusObjectProxy *object_proxy = + G_DBUS_OBJECT_PROXY (g_ptr_array_index (proxies, i)); g_signal_emit_by_name (manager, "object-removed", object_proxy); } - g_list_free_full (proxies, g_object_unref); + g_clear_pointer (&proxies, g_ptr_array_unref); /* nuke local filter */ maybe_unsubscribe_signals (manager); From 036dabcff9c406a57c792ce7af383ceaec86aebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 14 Dec 2022 04:59:24 +0100 Subject: [PATCH 08/10] gdbus-tool: Steal set values passing the ownership to an array --- gio/gdbus-tool.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/gio/gdbus-tool.c b/gio/gdbus-tool.c index 5b90e7739..5f9f9dd5a 100644 --- a/gio/gdbus-tool.c +++ b/gio/gdbus-tool.c @@ -317,6 +317,12 @@ print_paths (GDBusConnection *c, ; } +static gint +ptr_strcmp0 (const gchar **a, const gchar **b) +{ + return g_strcmp0 (*a, *b); +} + static void print_names (GDBusConnection *c, gboolean include_unique_names) @@ -326,8 +332,7 @@ print_names (GDBusConnection *c, GVariantIter *iter; gchar *str; GHashTable *name_set; - GList *keys; - GList *l; + GPtrArray *keys; name_set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); @@ -379,17 +384,17 @@ print_names (GDBusConnection *c, g_variant_iter_free (iter); g_variant_unref (result); - keys = g_hash_table_get_keys (name_set); - keys = g_list_sort (keys, (GCompareFunc) g_strcmp0); - for (l = keys; l != NULL; l = l->next) + keys = g_hash_table_steal_all_keys (name_set); + g_ptr_array_sort (keys, (GCompareFunc) ptr_strcmp0); + for (guint i = 0; i < keys->len; ++i) { - const gchar *name = l->data; + const gchar *name = g_ptr_array_index (keys, i); if (!include_unique_names && g_str_has_prefix (name, ":")) continue; g_print ("%s \n", name); } - g_list_free (keys); + g_clear_pointer (&keys, g_ptr_array_unref); out: g_hash_table_unref (name_set); From 52900ed6b0dc5390c89f59946e986b457472b66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 14 Dec 2022 05:12:28 +0100 Subject: [PATCH 09/10] gdbusobjectskeleton: Get the ifaces via array instead of list --- gio/gdbusobjectskeleton.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/gio/gdbusobjectskeleton.c b/gio/gdbusobjectskeleton.c index ec6a2f2bf..0b857ba7d 100644 --- a/gio/gdbusobjectskeleton.c +++ b/gio/gdbusobjectskeleton.c @@ -473,17 +473,21 @@ g_dbus_object_skeleton_get_interfaces (GDBusObject *_object) void g_dbus_object_skeleton_flush (GDBusObjectSkeleton *object) { - GList *to_flush, *l; + GPtrArray *to_flush; g_mutex_lock (&object->priv->lock); - to_flush = g_hash_table_get_values (object->priv->map_name_to_iface); - g_list_foreach (to_flush, (GFunc) g_object_ref, NULL); + to_flush = g_hash_table_get_values_as_ptr_array (object->priv->map_name_to_iface); + g_ptr_array_foreach (to_flush, (GFunc) g_object_ref, NULL); + g_ptr_array_set_free_func (to_flush, g_object_unref); g_mutex_unlock (&object->priv->lock); - for (l = to_flush; l != NULL; l = l->next) - g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (l->data)); + for (guint i = 0; i < to_flush->len; ++i) + { + g_dbus_interface_skeleton_flush ( + G_DBUS_INTERFACE_SKELETON (g_ptr_array_index (to_flush, i))); + } - g_list_free_full (to_flush, g_object_unref); + g_clear_pointer (&to_flush, g_ptr_array_unref); } static void From 3cad948f468f546270ebe2ff36a8a1ba4622491a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 14 Dec 2022 05:19:21 +0100 Subject: [PATCH 10/10] gdbusdaemon: Simplify name listing code using only arrays --- gio/gdbusdaemon.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/gio/gdbusdaemon.c b/gio/gdbusdaemon.c index 5a8e523f0..70009f970 100644 --- a/gio/gdbusdaemon.c +++ b/gio/gdbusdaemon.c @@ -1087,29 +1087,13 @@ handle_list_names (_GFreedesktopDBus *object, { GDBusDaemon *daemon = G_DBUS_DAEMON (object); GPtrArray *array; - GList *clients, *names, *l; + GPtrArray *clients, *names; - array = g_ptr_array_new (); + clients = g_hash_table_get_values_as_ptr_array (daemon->clients); + array = g_steal_pointer (&clients); - clients = g_hash_table_get_values (daemon->clients); - for (l = clients; l != NULL; l = l->next) - { - Client *client = l->data; - - g_ptr_array_add (array, client->id); - } - - g_list_free (clients); - - names = g_hash_table_get_values (daemon->names); - for (l = names; l != NULL; l = l->next) - { - Name *name = l->data; - - g_ptr_array_add (array, name->name); - } - - g_list_free (names); + names = g_hash_table_get_values_as_ptr_array (daemon->names); + g_ptr_array_extend_and_steal (array, g_steal_pointer (&names)); g_ptr_array_add (array, NULL);