GNOME Bugzilla – Bug 52084
PATCH API GHashIter - Hash Iterator
Last modified: 2011-02-18 16:13:45 UTC
This patch implements an iterator widget for GHashTables. Because they are opaque, the only way to iterate (currently) is g_hash_table_foreach(). This provides an alternative. We've found it tremendously useful. By standardizing it, we will not have to maintain a patched glib, which will make us and our customers happy :) I hope this doesn't mangle the patch. thockin@sun.com Sun Microsystems, Inc. Cobalt Server Appliances diff -ruN glib-1.3.2/ghash.c our-1.3.2/ghash.c --- glib-1.3.2/ghash.c Mon Oct 30 08:09:03 2000 +++ our-1.3.2/ghash.c Tue Mar 13 14:24:27 2001 @@ -53,6 +53,12 @@ GEqualFunc key_equal_func; }; +struct _GHashIter +{ + GHashTable *hash; + gint i; + GHashNode *node; +}; static void g_hash_table_resize (GHashTable *hash_table); static GHashNode** g_hash_table_lookup_node (GHashTable *hash_table, @@ -414,4 +420,80 @@ node_free_list = hash_node; G_UNLOCK (g_hash_global); } +} + +/* + * a thread-safe iterator object -- make the iterator + * local to your thread and you're safe. This iterator + * might be preferable to "foreach" if you want to avoid + * pass a lot of data about. + */ +GHashIter * +g_hash_iter_new(GHashTable *t) +{ + GHashIter *it; + gpointer key, val; + + if (!t) { + return NULL; + } + + it = g_new(GHashIter, 1); + it->hash = t; + it->node = NULL; + g_hash_iter_first(it, &key, &val); + + return it; +} + +void +g_hash_iter_destroy(GHashIter *it) +{ + g_free(it); +} + +gpointer +g_hash_iter_first(GHashIter *it, gpointer *key, gpointer *val) +{ + *key = NULL; + *val = NULL; + + it->i = 0; + + while (it->i < it->hash->size) { + it->node = it->hash->nodes[it->i]; + if (it->node) { + *key = it->node->key; + *val = it->node->value; + return *key; + } + (it->i)++; + } + + return NULL; +} + +gpointer +g_hash_iter_next(GHashIter *it, gpointer *key, gpointer *val) +{ + *key = NULL; + *val = NULL; + it->node = it->node->next; + + while (1) { + if (it->node) { + *key = it->node->key; + *val = it->node->value; + return *key; + } else { + it->i++; + if (it->i < it->hash->size) { + it->node = it->hash->nodes[it->i]; + } else { + break; + } + } + } + + return NULL; } diff -ruN glib-1.3.2/ghash.h our-1.3.2/ghash.h --- glib-1.3.2/ghash.h Mon Oct 30 08:09:03 2000 +++ our-1.3.2/ghash.h Tue Mar 13 13:19:09 2001 @@ -32,6 +32,7 @@ G_BEGIN_DECLS typedef struct _GHashTable GHashTable; +typedef struct _GHashIter GHashIter; typedef gboolean (*GHRFunc) (gpointer key, gpointer value, @@ -85,6 +86,13 @@ guint g_direct_hash (gconstpointer v) G_GNUC_CONST; gboolean g_direct_equal (gconstpointer v, gconstpointer v2) G_GNUC_CONST; + +/* GHashIter - alternate iterator for GHashTable objects + */ +GHashIter *g_hash_iter_new (GHashTable *hash_table); +gpointer g_hash_iter_first (GHashIter *i, gpointer *key, gpointer *val); +gpointer g_hash_iter_next (GHashIter *i, gpointer *key, gpointer *val); +void g_hash_iter_destroy (GHashIter *i); G_END_DECLS diff -ruN glib-1.3.2/tests/hash-test.c our-1.3.2/tests/hash-test.c --- glib-1.3.2/tests/hash-test.c Mon Oct 30 08:09:05 2000 +++ our-1.3.2/tests/hash-test.c Tue Mar 13 13:58:17 2001 @@ -325,7 +325,59 @@ g_hash_table_destroy (h); } +int +hash_iter_test (void) +{ + GHashTable *hash_table; + gint i; + int keyarr[10000]; + int valarr[10000]; + + /* initialize hash */ + hash_table = g_hash_table_new(my_hash, my_hash_equal); + for (i = 0; i < 10000; i++) + { + keyarr[i] = i; + valarr[i] = i + 100; + g_hash_table_insert(hash_table, &keyarr[i], &valarr[i]); + } + + { + int count; + gpointer key, val; + GHashIter *it; + + count = 0; + it = g_hash_iter_new(hash_table); + + g_hash_iter_first(it, &key, &val); + for (; key; g_hash_iter_next(it, &key, &val)) { + int *iP = val; + (*iP)++; + count++; + } + g_hash_iter_destroy(it); + g_assert(count == 10000); + } + + { + int errs = 0; + for (i = 0; i < 10000; i++) { + if (valarr[i] != 100+i+1) { + if (errs < 20) { + fprintf(stderr,"%d: %d = %d ( != %d )\n", + i, keyarr[i], valarr[i], 100+i+1 ); + } + errs++; + } + } + g_assert(errs == 0); + } + + g_hash_table_destroy(hash_table); + return 0; +} int main (int argc, @@ -367,7 +419,9 @@ second_hash_test (TRUE); second_hash_test (FALSE); direct_hash_test (); + hash_iter_test (); return 0; } +
See: http://mail.gnome.org/archives/gtk-devel-list/2001-April/msg00247.html For something along the same lines, though more generalized. Both of these are post 2.0.0 issues, since we are currently in a slushy API freeze and trying to get scheduled improvements nailed down.
*** This bug has been marked as a duplicate of 83729 ***