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
;
102 #if 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
);
395 G_LOCK (g_hash_global
);
398 hash_node
= node_free_list
;
399 node_free_list
= node_free_list
->next
;
404 node_mem_chunk
= g_mem_chunk_new ("hash node mem chunk",
405 sizeof (MonoGHashNode
),
408 hash_node
= g_chunk_new (MonoGHashNode
, node_mem_chunk
);
410 G_UNLOCK (g_hash_global
);
413 hash_node
->key
= NULL
;
414 hash_node
->value
= NULL
;
415 hash_node
->next
= NULL
;
421 * g_hash_table_insert:
422 * @hash_table: a #GHashTable.
423 * @key: a key to insert.
424 * @value: the value to associate with the key.
426 * Inserts a new key and value into a #GHashTable.
428 * If the key already exists in the #GHashTable its current value is replaced
429 * with the new value. If you supplied a @value_destroy_func when creating the
430 * #GHashTable, the old value is freed using that function. If you supplied
431 * a @key_destroy_func when creating the #GHashTable, the passed key is freed
432 * using that function.
435 mono_g_hash_table_insert (MonoGHashTable
*hash_table
,
439 MonoGHashNode
**node
;
441 g_return_if_fail (hash_table
!= NULL
);
443 node
= g_hash_table_lookup_node (hash_table
, key
);
447 /* do not reset node->key in this place, keeping
448 * the old key is the intended behaviour.
449 * g_hash_table_replace() can be used instead.
452 /* free the passed key */
453 if (hash_table
->key_destroy_func
)
454 hash_table
->key_destroy_func (key
);
456 if (hash_table
->value_destroy_func
)
457 hash_table
->value_destroy_func ((*node
)->value
);
459 SET_NODE_VALUE ((*node
), hash_table
->gc_type
, value
);
463 gint gc_type
= hash_table
->gc_type
;
464 *node
= g_hash_node_new (gc_type
);
465 SET_NODE_KEY (*node
, gc_type
, key
);
466 SET_NODE_VALUE (*node
, gc_type
, value
);
467 hash_table
->nnodes
++;
468 G_HASH_TABLE_RESIZE (hash_table
);
473 * g_hash_table_replace:
474 * @hash_table: a #GHashTable.
475 * @key: a key to insert.
476 * @value: the value to associate with the key.
478 * Inserts a new key and value into a #GHashTable similar to
479 * g_hash_table_insert(). The difference is that if the key already exists
480 * in the #GHashTable, it gets replaced by the new key. If you supplied a
481 * @value_destroy_func when creating the #GHashTable, the old value is freed
482 * using that function. If you supplied a @key_destroy_func when creating the
483 * #GHashTable, the old key is freed using that function.
486 mono_g_hash_table_replace (MonoGHashTable
*hash_table
,
490 MonoGHashNode
**node
;
492 g_return_if_fail (hash_table
!= NULL
);
494 node
= g_hash_table_lookup_node (hash_table
, key
);
498 if (hash_table
->key_destroy_func
)
499 hash_table
->key_destroy_func ((*node
)->key
);
501 if (hash_table
->value_destroy_func
)
502 hash_table
->value_destroy_func ((*node
)->value
);
504 SET_NODE_KEY ((*node
), hash_table
->gc_type
, key
);
505 SET_NODE_VALUE ((*node
), hash_table
->gc_type
, value
);
509 gint gc_type
= hash_table
->gc_type
;
510 *node
= g_hash_node_new (gc_type
);
511 SET_NODE_KEY (*node
, gc_type
, key
);
512 SET_NODE_VALUE (*node
, gc_type
, value
);
513 hash_table
->nnodes
++;
514 G_HASH_TABLE_RESIZE (hash_table
);
519 * g_hash_table_remove:
520 * @hash_table: a #GHashTable.
521 * @key: the key to remove.
523 * Removes a key and its associated value from a #GHashTable.
525 * If the #GHashTable was created using g_hash_table_new_full(), the
526 * key and value are freed using the supplied destroy functions, otherwise
527 * you have to make sure that any dynamically allocated values are freed
530 * Return value: %TRUE if the key was found and removed from the #GHashTable.
533 mono_g_hash_table_remove (MonoGHashTable
*hash_table
,
536 MonoGHashNode
**node
, *dest
;
538 g_return_val_if_fail (hash_table
!= NULL
, FALSE
);
540 node
= g_hash_table_lookup_node (hash_table
, key
);
544 (*node
) = dest
->next
;
545 g_hash_node_destroy (dest
, hash_table
->gc_type
,
546 hash_table
->key_destroy_func
,
547 hash_table
->value_destroy_func
);
548 hash_table
->nnodes
--;
550 G_HASH_TABLE_RESIZE (hash_table
);
559 * g_hash_table_steal:
560 * @hash_table: a #GHashTable.
561 * @key: the key to remove.
563 * Removes a key and its associated value from a #GHashTable without
564 * calling the key and value destroy functions.
566 * Return value: %TRUE if the key was found and removed from the #GHashTable.
569 mono_g_hash_table_steal (MonoGHashTable
*hash_table
,
572 MonoGHashNode
**node
, *dest
;
574 g_return_val_if_fail (hash_table
!= NULL
, FALSE
);
576 node
= g_hash_table_lookup_node (hash_table
, key
);
580 (*node
) = dest
->next
;
581 g_hash_node_destroy (dest
, hash_table
->gc_type
, NULL
, NULL
);
582 hash_table
->nnodes
--;
584 G_HASH_TABLE_RESIZE (hash_table
);
593 * g_hash_table_foreach_remove:
594 * @hash_table: a #GHashTable.
595 * @func: the function to call for each key/value pair.
596 * @user_data: user data to pass to the function.
598 * Calls the given function for each key/value pair in the #GHashTable.
599 * If the function returns %TRUE, then the key/value pair is removed from the
600 * #GHashTable. If you supplied key or value destroy functions when creating
601 * the #GHashTable, they are used to free the memory allocated for the removed
604 * Return value: the number of key/value pairs removed.
607 mono_g_hash_table_foreach_remove (MonoGHashTable
*hash_table
,
611 g_return_val_if_fail (hash_table
!= NULL
, 0);
612 g_return_val_if_fail (func
!= NULL
, 0);
614 return g_hash_table_foreach_remove_or_steal (hash_table
, func
, user_data
, TRUE
);
618 * g_hash_table_foreach_steal:
619 * @hash_table: a #GHashTable.
620 * @func: the function to call for each key/value pair.
621 * @user_data: user data to pass to the function.
623 * Calls the given function for each key/value pair in the #GHashTable.
624 * If the function returns %TRUE, then the key/value pair is removed from the
625 * #GHashTable, but no key or value destroy functions are called.
627 * Return value: the number of key/value pairs removed.
630 mono_g_hash_table_foreach_steal (MonoGHashTable
*hash_table
,
634 g_return_val_if_fail (hash_table
!= NULL
, 0);
635 g_return_val_if_fail (func
!= NULL
, 0);
637 return g_hash_table_foreach_remove_or_steal (hash_table
, func
, user_data
, FALSE
);
641 g_hash_table_foreach_remove_or_steal (MonoGHashTable
*hash_table
,
646 MonoGHashNode
*node
, *prev
;
650 for (i
= 0; i
< hash_table
->size
; i
++)
656 for (node
= hash_table
->nodes
[i
]; node
; prev
= node
, node
= node
->next
)
658 if ((* func
) (node
->key
, node
->value
, user_data
))
662 hash_table
->nnodes
-= 1;
666 prev
->next
= node
->next
;
667 g_hash_node_destroy (node
, hash_table
->gc_type
,
668 notify
? hash_table
->key_destroy_func
: NULL
,
669 notify
? hash_table
->value_destroy_func
: NULL
);
674 hash_table
->nodes
[i
] = node
->next
;
675 g_hash_node_destroy (node
, hash_table
->gc_type
,
676 notify
? hash_table
->key_destroy_func
: NULL
,
677 notify
? hash_table
->value_destroy_func
: NULL
);
684 G_HASH_TABLE_RESIZE (hash_table
);
690 * g_hash_table_foreach:
691 * @hash_table: a #GHashTable.
692 * @func: the function to call for each key/value pair.
693 * @user_data: user data to pass to the function.
695 * Calls the given function for each of the key/value pairs in the
696 * #GHashTable. The function is passed the key and value of each
697 * pair, and the given @user_data parameter. The hash table may not
698 * be modified while iterating over it (you can't add/remove
699 * items). To remove all items matching a predicate, use
700 * g_hash_table_remove().
703 mono_g_hash_table_foreach (MonoGHashTable
*hash_table
,
710 g_return_if_fail (hash_table
!= NULL
);
711 g_return_if_fail (func
!= NULL
);
713 for (i
= 0; i
< hash_table
->size
; i
++)
714 for (node
= hash_table
->nodes
[i
]; node
; node
= node
->next
)
715 (* func
) (node
->key
, node
->value
, user_data
);
719 mono_g_hash_table_find (MonoGHashTable
*hash_table
, GHRFunc predicate
, gpointer user_data
)
724 g_return_val_if_fail (hash_table
!= NULL
, NULL
);
725 g_return_val_if_fail (predicate
!= NULL
, NULL
);
727 for (i
= 0; i
< hash_table
->size
; i
++){
728 for (node
= hash_table
->nodes
[i
]; node
; node
= node
->next
)
729 if ((*predicate
)(node
->key
, node
->value
, user_data
))
737 * @hash_table: a #GHashTable.
739 * Returns the number of elements contained in the #GHashTable.
741 * Return value: the number of key/value pairs in the #GHashTable.
744 mono_g_hash_table_size (MonoGHashTable
*hash_table
)
746 g_return_val_if_fail (hash_table
!= NULL
, 0);
748 return hash_table
->nnodes
;
752 * mono_g_hash_table_remap:
754 * Calls the given function for each key-value pair in the hash table,
755 * and replaces the value stored in the hash table by the value returned by
760 mono_g_hash_table_remap (MonoGHashTable
*hash_table
,
761 MonoGRemapperFunc func
,
767 g_return_if_fail (hash_table
!= NULL
);
768 g_return_if_fail (func
!= NULL
);
770 for (i
= 0; i
< hash_table
->size
; i
++)
771 for (node
= hash_table
->nodes
[i
]; node
; node
= node
->next
) {
772 gpointer new_val
= (* func
) (node
->key
, node
->value
, user_data
);
773 SET_NODE_VALUE (node
, hash_table
->gc_type
, new_val
);
778 g_hash_table_resize (MonoGHashTable
*hash_table
)
780 MonoGHashNode
**new_nodes
;
787 new_size
= g_spaced_primes_closest (hash_table
->nnodes
);
788 new_size
= CLAMP (new_size
, HASH_TABLE_MIN_SIZE
, HASH_TABLE_MAX_SIZE
);
791 new_nodes
= GC_MALLOC (sizeof (MonoGHashNode
*) * new_size
);
793 new_nodes
= g_new0 (MonoGHashNode
*, new_size
);
796 for (i
= 0; i
< hash_table
->size
; i
++)
797 for (node
= hash_table
->nodes
[i
]; node
; node
= next
)
801 hash_val
= (* hash_table
->hash_func
) (node
->key
) % new_size
;
803 node
->next
= new_nodes
[hash_val
];
804 new_nodes
[hash_val
] = node
;
809 g_free (hash_table
->nodes
);
811 hash_table
->nodes
= new_nodes
;
812 hash_table
->size
= new_size
;
816 g_hash_node_destroy (MonoGHashNode
*hash_node
,
817 MonoGHashGCType type
,
818 GDestroyNotify key_destroy_func
,
819 GDestroyNotify value_destroy_func
)
821 if (key_destroy_func
)
822 key_destroy_func (hash_node
->key
);
823 if (value_destroy_func
)
824 value_destroy_func (hash_node
->value
);
826 hash_node
->key
= NULL
;
827 hash_node
->value
= NULL
;
829 G_LOCK (g_hash_global
);
830 #if defined(HAVE_SGEN_GC) || defined(HAVE_BOEHM_GC)
831 hash_node
->next
= node_free_lists
[type
];
832 node_free_lists
[type
] = hash_node
;
834 hash_node
->next
= node_free_list
;
835 node_free_list
= hash_node
;
837 G_UNLOCK (g_hash_global
);
841 g_hash_nodes_destroy (MonoGHashNode
*hash_node
,
842 MonoGHashGCType type
,
843 GFreeFunc key_destroy_func
,
844 GFreeFunc value_destroy_func
)
848 MonoGHashNode
*node
= hash_node
;
852 if (key_destroy_func
)
853 key_destroy_func (node
->key
);
854 if (value_destroy_func
)
855 value_destroy_func (node
->value
);
863 if (key_destroy_func
)
864 key_destroy_func (node
->key
);
865 if (value_destroy_func
)
866 value_destroy_func (node
->value
);
871 G_LOCK (g_hash_global
);
872 #if defined(HAVE_SGEN_GC) || defined(HAVE_BOEHM_GC)
873 node
->next
= node_free_lists
[type
];
874 node_free_lists
[type
] = hash_node
;
876 node
->next
= node_free_list
;
877 node_free_list
= hash_node
;
879 G_UNLOCK (g_hash_global
);
885 /* GC marker function */
887 mono_g_hash_mark (void *addr
, MonoGCCopyFunc mark_func
)
889 MonoGHashTable
*table
= (MonoGHashTable
*)addr
;
893 if (table
->gc_type
== MONO_HASH_KEY_GC
) {
894 for (i
= 0; i
< table
->size
; i
++) {
895 for (node
= table
->nodes
[i
]; node
; node
= node
->next
) {
897 node
->key
= mark_func (node
->key
);
900 } else if (table
->gc_type
== MONO_HASH_VALUE_GC
) {
901 for (i
= 0; i
< table
->size
; i
++) {
902 for (node
= table
->nodes
[i
]; node
; node
= node
->next
) {
904 node
->value
= mark_func (node
->value
);
907 } else if (table
->gc_type
== MONO_HASH_KEY_VALUE_GC
) {
908 for (i
= 0; i
< table
->size
; i
++) {
909 for (node
= table
->nodes
[i
]; node
; node
= node
->next
) {
911 node
->key
= mark_func (node
->key
);
913 node
->value
= mark_func (node
->value
);