1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GLib Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GLib at ftp://ftp.gtk.org/pub/gtk/.
32 * Imported in mono cvs from version 1.32 of gnome cvs.
40 #include "mono-hash.h"
41 #include "metadata/gc-internal.h"
43 #define HASH_TABLE_MIN_SIZE 11
44 #define HASH_TABLE_MAX_SIZE 13845163
46 typedef struct _MonoGHashNode MonoGHashNode;
55 struct _MonoGHashTable
59 MonoGHashNode **nodes;
61 GEqualFunc key_equal_func;
62 GDestroyNotify key_destroy_func;
63 GDestroyNotify value_destroy_func;
64 MonoGHashGCType gc_type;
67 #define G_HASH_TABLE_RESIZE(hash_table) \
69 if ((hash_table->size >= 3 * hash_table->nnodes && \
70 hash_table->size > HASH_TABLE_MIN_SIZE) || \
71 (3 * hash_table->size <= hash_table->nnodes && \
72 hash_table->size < HASH_TABLE_MAX_SIZE)) \
73 g_hash_table_resize (hash_table); \
76 static void g_hash_table_resize (MonoGHashTable *hash_table);
77 static MonoGHashNode** g_hash_table_lookup_node (MonoGHashTable *hash_table,
79 static MonoGHashNode* g_hash_node_new (gint gc_type);
80 static void g_hash_node_destroy (MonoGHashNode *hash_node,
82 GDestroyNotify key_destroy_func,
83 GDestroyNotify value_destroy_func);
84 static void g_hash_nodes_destroy (MonoGHashNode *hash_node,
86 GDestroyNotify key_destroy_func,
87 GDestroyNotify value_destroy_func);
88 static guint g_hash_table_foreach_remove_or_steal (MonoGHashTable *hash_table,
94 static void mono_g_hash_mark (void *addr, MonoGCCopyFunc mark_func);
97 G_LOCK_DEFINE_STATIC (g_hash_global);
99 #if defined(HAVE_NULL_GC)
100 static GMemChunk *node_mem_chunk = NULL;
101 static MonoGHashNode *node_free_list = NULL;
102 #elif defined(HAVE_SGEN_GC)
103 static MonoGHashNode *node_free_lists [4] = {NULL};
104 static void *hash_descr = NULL;
105 static GMemChunk *node_mem_chunk = NULL;
107 static void *node_gc_descs [4] = {NULL};
108 static MonoGHashNode *node_free_lists [4] = {NULL};
111 #define SET_NODE_KEY(node, gc_type, val) do { (node)->key = (val); } while (0)
112 #define SET_NODE_VALUE(node, gc_type, val) do { (node)->value = (val); } while (0)
116 * @hash_func: a function to create a hash value from a key.
117 * Hash values are used to determine where keys are stored within the
118 * #GHashTable data structure. The g_direct_hash(), g_int_hash() and
119 * g_str_hash() functions are provided for some common types of keys.
120 * If hash_func is %NULL, g_direct_hash() is used.
121 * @key_equal_func: a function to check two keys for equality. This is
122 * used when looking up keys in the #GHashTable. The g_direct_equal(),
123 * g_int_equal() and g_str_equal() functions are provided for the most
124 * common types of keys. If @key_equal_func is %NULL, keys are compared
125 * directly in a similar fashion to g_direct_equal(), but without the
126 * overhead of a function call.
128 * Creates a new #GHashTable.
130 * Return value: a new #GHashTable.
133 mono_g_hash_table_new (GHashFunc hash_func,
134 GEqualFunc key_equal_func)
136 return mono_g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL);
140 mono_g_hash_table_new_type (GHashFunc hash_func,
141 GEqualFunc key_equal_func,
142 MonoGHashGCType type)
144 MonoGHashTable *table = mono_g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL);
145 if (type == MONO_HASH_KEY_GC || type == MONO_HASH_KEY_VALUE_GC)
146 g_assert (hash_func);
147 table->gc_type = type;
148 #if defined(HAVE_SGEN_GC)
149 if (type < 0 || type > MONO_HASH_KEY_VALUE_GC)
150 g_error ("wrong type for gc hashtable");
152 * We use a user defined marking function to avoid having to register a GC root for
156 hash_descr = mono_gc_make_root_descr_user (mono_g_hash_mark);
157 if (type != MONO_HASH_CONSERVATIVE_GC)
158 mono_gc_register_root_wbarrier ((char*)table, sizeof (MonoGHashTable), hash_descr);
159 #elif defined(HAVE_BOEHM_GC)
160 if (type < 0 || type > MONO_HASH_KEY_VALUE_GC)
161 g_error ("wrong type for gc hashtable");
162 if (!node_gc_descs [type] && type > MONO_HASH_CONSERVATIVE_GC) {
164 if (type & MONO_HASH_KEY_GC)
165 bmap |= 1; /* the first field in the node is the key */
166 if (type & MONO_HASH_VALUE_GC)
167 bmap |= 2; /* the second is the value */
168 bmap |= 4; /* next */
169 node_gc_descs [type] = mono_gc_make_descr_from_bitmap (&bmap, 3);
171 MONO_GC_REGISTER_ROOT (node_free_lists [type]);
180 * g_hash_table_new_full:
181 * @hash_func: a function to create a hash value from a key.
182 * @key_equal_func: a function to check two keys for equality.
183 * @key_destroy_func: a function to free the memory allocated for the key
184 * used when removing the entry from the #GHashTable or %NULL if you
185 * don't want to supply such a function.
186 * @value_destroy_func: a function to free the memory allocated for the
187 * value used when removing the entry from the #GHashTable or %NULL if
188 * you don't want to supply such a function.
190 * Creates a new #GHashTable like g_hash_table_new() and allows to specify
191 * functions to free the memory allocated for the key and value that get
192 * called when removing the entry from the #GHashTable.
194 * Return value: a new #GHashTable.
197 mono_g_hash_table_new_full (GHashFunc hash_func,
198 GEqualFunc key_equal_func,
199 GDestroyNotify key_destroy_func,
200 GDestroyNotify value_destroy_func)
202 MonoGHashTable *hash_table;
204 static gboolean inited = FALSE;
206 MONO_GC_REGISTER_ROOT (node_free_lists [0]);
210 hash_table = GC_MALLOC (sizeof (MonoGHashTable));
212 hash_table = g_new (MonoGHashTable, 1);
214 hash_table->size = HASH_TABLE_MIN_SIZE;
215 hash_table->nnodes = 0;
216 hash_table->hash_func = hash_func ? hash_func : g_direct_hash;
217 hash_table->key_equal_func = key_equal_func == g_direct_equal ? NULL : key_equal_func;
218 hash_table->key_destroy_func = key_destroy_func;
219 hash_table->value_destroy_func = value_destroy_func;
221 hash_table->nodes = GC_MALLOC (sizeof (MonoGHashNode*) * hash_table->size);
223 hash_table->nodes = g_new0 (MonoGHashNode*, hash_table->size);
225 hash_table->gc_type = 0;
231 * g_hash_table_destroy:
232 * @hash_table: a #GHashTable.
234 * Destroys the #GHashTable. If keys and/or values are dynamically
235 * allocated, you should either free them first or create the #GHashTable
236 * using g_hash_table_new_full(). In the latter case the destroy functions
237 * you supplied will be called on all keys and values before destroying
241 mono_g_hash_table_destroy (MonoGHashTable *hash_table)
245 g_return_if_fail (hash_table != NULL);
247 for (i = 0; i < hash_table->size; i++)
248 g_hash_nodes_destroy (hash_table->nodes[i], hash_table->gc_type,
249 hash_table->key_destroy_func,
250 hash_table->value_destroy_func);
255 mono_gc_deregister_root ((char*)hash_table);
257 g_free (hash_table->nodes);
262 static inline MonoGHashNode**
263 g_hash_table_lookup_node (MonoGHashTable *hash_table,
266 MonoGHashNode **node;
268 node = &hash_table->nodes
269 [(* hash_table->hash_func) (key) % hash_table->size];
271 /* Hash table lookup needs to be fast.
272 * We therefore remove the extra conditional of testing
273 * whether to call the key_equal_func or not from
276 if (hash_table->key_equal_func)
277 while (*node && !(*hash_table->key_equal_func) ((*node)->key, key))
278 node = &(*node)->next;
280 while (*node && (*node)->key != key)
281 node = &(*node)->next;
287 * g_hash_table_lookup:
288 * @hash_table: a #GHashTable.
289 * @key: the key to look up.
291 * Looks up a key in a #GHashTable.
293 * Return value: the associated value, or %NULL if the key is not found.
296 mono_g_hash_table_lookup (MonoGHashTable *hash_table,
301 g_return_val_if_fail (hash_table != NULL, NULL);
303 node = *g_hash_table_lookup_node (hash_table, key);
305 return node ? node->value : NULL;
309 * g_hash_table_lookup_extended:
310 * @hash_table: a #GHashTable.
311 * @lookup_key: the key to look up.
312 * @orig_key: returns the original key.
313 * @value: returns the value associated with the key.
315 * Looks up a key in the #GHashTable, returning the original key and the
316 * associated value and a #gboolean which is %TRUE if the key was found. This
317 * is useful if you need to free the memory allocated for the original key,
318 * for example before calling g_hash_table_remove().
320 * Return value: %TRUE if the key was found in the #GHashTable.
323 mono_g_hash_table_lookup_extended (MonoGHashTable *hash_table,
324 gconstpointer lookup_key,
330 g_return_val_if_fail (hash_table != NULL, FALSE);
332 node = *g_hash_table_lookup_node (hash_table, lookup_key);
337 *orig_key = node->key;
339 *value = node->value;
346 static inline MonoGHashNode*
347 g_hash_node_new (gint gc_type)
349 MonoGHashNode *hash_node = NULL;
352 if (node_free_lists [gc_type]) {
353 G_LOCK (g_hash_global);
355 if (node_free_lists [gc_type]) {
356 hash_node = node_free_lists [gc_type];
357 node_free_lists [gc_type] = node_free_lists [gc_type]->next;
359 G_UNLOCK (g_hash_global);
362 if (gc_type != MONO_HASH_CONSERVATIVE_GC) {
363 //hash_node = GC_MALLOC (sizeof (MonoGHashNode));
364 hash_node = GC_MALLOC_EXPLICITLY_TYPED (sizeof (MonoGHashNode), (GC_descr)node_gc_descs [gc_type]);
366 hash_node = GC_MALLOC (sizeof (MonoGHashNode));
369 #elif defined(HAVE_SGEN_GC)
370 if (node_free_lists [gc_type]) {
371 G_LOCK (g_hash_global);
373 if (node_free_lists [gc_type]) {
374 hash_node = node_free_lists [gc_type];
375 node_free_lists [gc_type] = node_free_lists [gc_type]->next;
377 G_UNLOCK (g_hash_global);
380 if (gc_type != MONO_HASH_CONSERVATIVE_GC) {
382 * Marking is handled by the marker function, no need to allocate GC visible
386 node_mem_chunk = g_mem_chunk_new ("hash node mem chunk",
387 sizeof (MonoGHashNode),
389 hash_node = g_chunk_new (MonoGHashNode, node_mem_chunk);
391 hash_node = mono_gc_alloc_fixed (sizeof (MonoGHashNode), NULL);
396 G_LOCK (g_hash_global);
399 hash_node = node_free_list;
400 node_free_list = node_free_list->next;
404 hash_node = g_new0 (MonoGHashNode, 1);
406 G_UNLOCK (g_hash_global);
408 G_LOCK (g_hash_global);
411 hash_node = node_free_list;
412 node_free_list = node_free_list->next;
417 node_mem_chunk = g_mem_chunk_new ("hash node mem chunk",
418 sizeof (MonoGHashNode),
421 hash_node = g_chunk_new (MonoGHashNode, node_mem_chunk);
423 G_UNLOCK (g_hash_global);
427 hash_node->key = NULL;
428 hash_node->value = NULL;
429 hash_node->next = NULL;
435 * g_hash_table_insert:
436 * @hash_table: a #GHashTable.
437 * @key: a key to insert.
438 * @value: the value to associate with the key.
440 * Inserts a new key and value into a #GHashTable.
442 * If the key already exists in the #GHashTable its current value is replaced
443 * with the new value. If you supplied a @value_destroy_func when creating the
444 * #GHashTable, the old value is freed using that function. If you supplied
445 * a @key_destroy_func when creating the #GHashTable, the passed key is freed
446 * using that function.
449 mono_g_hash_table_insert (MonoGHashTable *hash_table,
453 MonoGHashNode **node;
455 g_return_if_fail (hash_table != NULL);
457 node = g_hash_table_lookup_node (hash_table, key);
461 /* do not reset node->key in this place, keeping
462 * the old key is the intended behaviour.
463 * g_hash_table_replace() can be used instead.
466 /* free the passed key */
467 if (hash_table->key_destroy_func)
468 hash_table->key_destroy_func (key);
470 if (hash_table->value_destroy_func)
471 hash_table->value_destroy_func ((*node)->value);
473 SET_NODE_VALUE ((*node), hash_table->gc_type, value);
477 gint gc_type = hash_table->gc_type;
478 *node = g_hash_node_new (gc_type);
479 SET_NODE_KEY (*node, gc_type, key);
480 SET_NODE_VALUE (*node, gc_type, value);
481 hash_table->nnodes++;
482 G_HASH_TABLE_RESIZE (hash_table);
487 * g_hash_table_replace:
488 * @hash_table: a #GHashTable.
489 * @key: a key to insert.
490 * @value: the value to associate with the key.
492 * Inserts a new key and value into a #GHashTable similar to
493 * g_hash_table_insert(). The difference is that if the key already exists
494 * in the #GHashTable, it gets replaced by the new key. If you supplied a
495 * @value_destroy_func when creating the #GHashTable, the old value is freed
496 * using that function. If you supplied a @key_destroy_func when creating the
497 * #GHashTable, the old key is freed using that function.
500 mono_g_hash_table_replace (MonoGHashTable *hash_table,
504 MonoGHashNode **node;
506 g_return_if_fail (hash_table != NULL);
508 node = g_hash_table_lookup_node (hash_table, key);
512 if (hash_table->key_destroy_func)
513 hash_table->key_destroy_func ((*node)->key);
515 if (hash_table->value_destroy_func)
516 hash_table->value_destroy_func ((*node)->value);
518 SET_NODE_KEY ((*node), hash_table->gc_type, key);
519 SET_NODE_VALUE ((*node), hash_table->gc_type, value);
523 gint gc_type = hash_table->gc_type;
524 *node = g_hash_node_new (gc_type);
525 SET_NODE_KEY (*node, gc_type, key);
526 SET_NODE_VALUE (*node, gc_type, value);
527 hash_table->nnodes++;
528 G_HASH_TABLE_RESIZE (hash_table);
533 * g_hash_table_remove:
534 * @hash_table: a #GHashTable.
535 * @key: the key to remove.
537 * Removes a key and its associated value from a #GHashTable.
539 * If the #GHashTable was created using g_hash_table_new_full(), the
540 * key and value are freed using the supplied destroy functions, otherwise
541 * you have to make sure that any dynamically allocated values are freed
544 * Return value: %TRUE if the key was found and removed from the #GHashTable.
547 mono_g_hash_table_remove (MonoGHashTable *hash_table,
550 MonoGHashNode **node, *dest;
552 g_return_val_if_fail (hash_table != NULL, FALSE);
554 node = g_hash_table_lookup_node (hash_table, key);
558 (*node) = dest->next;
559 g_hash_node_destroy (dest, hash_table->gc_type,
560 hash_table->key_destroy_func,
561 hash_table->value_destroy_func);
562 hash_table->nnodes--;
564 G_HASH_TABLE_RESIZE (hash_table);
573 * g_hash_table_steal:
574 * @hash_table: a #GHashTable.
575 * @key: the key to remove.
577 * Removes a key and its associated value from a #GHashTable without
578 * calling the key and value destroy functions.
580 * Return value: %TRUE if the key was found and removed from the #GHashTable.
583 mono_g_hash_table_steal (MonoGHashTable *hash_table,
586 MonoGHashNode **node, *dest;
588 g_return_val_if_fail (hash_table != NULL, FALSE);
590 node = g_hash_table_lookup_node (hash_table, key);
594 (*node) = dest->next;
595 g_hash_node_destroy (dest, hash_table->gc_type, NULL, NULL);
596 hash_table->nnodes--;
598 G_HASH_TABLE_RESIZE (hash_table);
607 * g_hash_table_foreach_remove:
608 * @hash_table: a #GHashTable.
609 * @func: the function to call for each key/value pair.
610 * @user_data: user data to pass to the function.
612 * Calls the given function for each key/value pair in the #GHashTable.
613 * If the function returns %TRUE, then the key/value pair is removed from the
614 * #GHashTable. If you supplied key or value destroy functions when creating
615 * the #GHashTable, they are used to free the memory allocated for the removed
618 * Return value: the number of key/value pairs removed.
621 mono_g_hash_table_foreach_remove (MonoGHashTable *hash_table,
625 g_return_val_if_fail (hash_table != NULL, 0);
626 g_return_val_if_fail (func != NULL, 0);
628 return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, TRUE);
632 * g_hash_table_foreach_steal:
633 * @hash_table: a #GHashTable.
634 * @func: the function to call for each key/value pair.
635 * @user_data: user data to pass to the function.
637 * Calls the given function for each key/value pair in the #GHashTable.
638 * If the function returns %TRUE, then the key/value pair is removed from the
639 * #GHashTable, but no key or value destroy functions are called.
641 * Return value: the number of key/value pairs removed.
644 mono_g_hash_table_foreach_steal (MonoGHashTable *hash_table,
648 g_return_val_if_fail (hash_table != NULL, 0);
649 g_return_val_if_fail (func != NULL, 0);
651 return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, FALSE);
655 g_hash_table_foreach_remove_or_steal (MonoGHashTable *hash_table,
660 MonoGHashNode *node, *prev;
664 for (i = 0; i < hash_table->size; i++)
670 for (node = hash_table->nodes[i]; node; prev = node, node = node->next)
672 if ((* func) (node->key, node->value, user_data))
676 hash_table->nnodes -= 1;
680 prev->next = node->next;
681 g_hash_node_destroy (node, hash_table->gc_type,
682 notify ? hash_table->key_destroy_func : NULL,
683 notify ? hash_table->value_destroy_func : NULL);
688 hash_table->nodes[i] = node->next;
689 g_hash_node_destroy (node, hash_table->gc_type,
690 notify ? hash_table->key_destroy_func : NULL,
691 notify ? hash_table->value_destroy_func : NULL);
698 G_HASH_TABLE_RESIZE (hash_table);
704 * g_hash_table_foreach:
705 * @hash_table: a #GHashTable.
706 * @func: the function to call for each key/value pair.
707 * @user_data: user data to pass to the function.
709 * Calls the given function for each of the key/value pairs in the
710 * #GHashTable. The function is passed the key and value of each
711 * pair, and the given @user_data parameter. The hash table may not
712 * be modified while iterating over it (you can't add/remove
713 * items). To remove all items matching a predicate, use
714 * g_hash_table_remove().
717 mono_g_hash_table_foreach (MonoGHashTable *hash_table,
724 g_return_if_fail (hash_table != NULL);
725 g_return_if_fail (func != NULL);
727 for (i = 0; i < hash_table->size; i++)
728 for (node = hash_table->nodes[i]; node; node = node->next)
729 (* func) (node->key, node->value, user_data);
733 mono_g_hash_table_find (MonoGHashTable *hash_table, GHRFunc predicate, gpointer user_data)
738 g_return_val_if_fail (hash_table != NULL, NULL);
739 g_return_val_if_fail (predicate != NULL, NULL);
741 for (i = 0; i < hash_table->size; i++){
742 for (node = hash_table->nodes[i]; node; node = node->next)
743 if ((*predicate)(node->key, node->value, user_data))
751 * @hash_table: a #GHashTable.
753 * Returns the number of elements contained in the #GHashTable.
755 * Return value: the number of key/value pairs in the #GHashTable.
758 mono_g_hash_table_size (MonoGHashTable *hash_table)
760 g_return_val_if_fail (hash_table != NULL, 0);
762 return hash_table->nnodes;
766 * mono_g_hash_table_remap:
768 * Calls the given function for each key-value pair in the hash table,
769 * and replaces the value stored in the hash table by the value returned by
774 mono_g_hash_table_remap (MonoGHashTable *hash_table,
775 MonoGRemapperFunc func,
781 g_return_if_fail (hash_table != NULL);
782 g_return_if_fail (func != NULL);
784 for (i = 0; i < hash_table->size; i++)
785 for (node = hash_table->nodes[i]; node; node = node->next) {
786 gpointer new_val = (* func) (node->key, node->value, user_data);
787 SET_NODE_VALUE (node, hash_table->gc_type, new_val);
792 MonoGHashTable *hash;
794 MonoGHashNode **nodes;
798 do_resize (void *_data)
800 ResizeData *data = _data;
801 MonoGHashTable *hash_table = data->hash;
802 MonoGHashNode **new_nodes = data->nodes;
806 gint new_size = data->new_size;
808 void *old_nodes = hash_table->nodes;
810 for (i = 0; i < hash_table->size; i++)
811 for (node = hash_table->nodes[i]; node; node = next)
815 hash_val = (* hash_table->hash_func) (node->key) % new_size;
817 node->next = new_nodes[hash_val];
818 new_nodes[hash_val] = node;
821 hash_table->nodes = new_nodes;
822 hash_table->size = new_size;
828 g_hash_table_resize (MonoGHashTable *hash_table)
833 data.hash = hash_table;
834 data.new_size = g_spaced_primes_closest (hash_table->nnodes);
835 data.new_size = CLAMP (data.new_size, HASH_TABLE_MIN_SIZE, HASH_TABLE_MAX_SIZE);
838 data.nodes = GC_MALLOC (sizeof (MonoGHashNode*) * data.new_size);
840 data.nodes = g_new0 (MonoGHashNode*, data.new_size);
843 old_nodes = mono_gc_invoke_with_gc_lock (do_resize, &data);
852 g_hash_node_destroy (MonoGHashNode *hash_node,
853 MonoGHashGCType type,
854 GDestroyNotify key_destroy_func,
855 GDestroyNotify value_destroy_func)
857 if (key_destroy_func)
858 key_destroy_func (hash_node->key);
859 if (value_destroy_func)
860 value_destroy_func (hash_node->value);
862 hash_node->key = NULL;
863 hash_node->value = NULL;
865 G_LOCK (g_hash_global);
866 #if defined(HAVE_SGEN_GC) || defined(HAVE_BOEHM_GC)
867 hash_node->next = node_free_lists [type];
868 node_free_lists [type] = hash_node;
870 hash_node->next = node_free_list;
871 node_free_list = hash_node;
873 G_UNLOCK (g_hash_global);
877 g_hash_nodes_destroy (MonoGHashNode *hash_node,
878 MonoGHashGCType type,
879 GFreeFunc key_destroy_func,
880 GFreeFunc value_destroy_func)
884 MonoGHashNode *node = hash_node;
888 if (key_destroy_func)
889 key_destroy_func (node->key);
890 if (value_destroy_func)
891 value_destroy_func (node->value);
899 if (key_destroy_func)
900 key_destroy_func (node->key);
901 if (value_destroy_func)
902 value_destroy_func (node->value);
907 G_LOCK (g_hash_global);
908 #if defined(HAVE_SGEN_GC) || defined(HAVE_BOEHM_GC)
909 node->next = node_free_lists [type];
910 node_free_lists [type] = hash_node;
912 node->next = node_free_list;
913 node_free_list = hash_node;
915 G_UNLOCK (g_hash_global);
921 /* GC marker function */
923 mono_g_hash_mark (void *addr, MonoGCCopyFunc mark_func)
925 MonoGHashTable *table = (MonoGHashTable*)addr;
929 if (table->gc_type == MONO_HASH_KEY_GC) {
930 for (i = 0; i < table->size; i++) {
931 for (node = table->nodes [i]; node; node = node->next) {
933 node->key = mark_func (node->key);
936 } else if (table->gc_type == MONO_HASH_VALUE_GC) {
937 for (i = 0; i < table->size; i++) {
938 for (node = table->nodes [i]; node; node = node->next) {
940 node->value = mark_func (node->value);
943 } else if (table->gc_type == MONO_HASH_KEY_VALUE_GC) {
944 for (i = 0; i < table->size; i++) {
945 for (node = table->nodes [i]; node; node = node->next) {
947 node->key = mark_func (node->key);
949 node->value = mark_func (node->value);