1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1999 The Free Software Foundation
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
28 #define HASH_TABLE_MIN_SIZE 11
29 #define HASH_TABLE_MAX_SIZE 13845163
32 typedef struct _GHashNode GHashNode;
48 GCompareFunc key_compare_func;
52 static void g_hash_table_resize (GHashTable *hash_table);
53 static GHashNode* g_hash_table_lookup_node (GHashTable *hash_table,
57 static GHashNode* g_hash_node_new (gpointer key,
59 static void g_hash_node_destroy (GHashNode *hash_node);
60 static void g_hash_nodes_destroy (GHashNode *hash_node);
62 #define G_HASH_BUCKET(table,key) \
63 ((* (table)->hash_func) (key) % (table)->size)
65 G_LOCK_DECLARE_STATIC (g_hash_global);
67 static GMemChunk *node_mem_chunk = NULL;
68 static GHashNode *node_free_list = NULL;
72 g_hash_table_new (GHashFunc hash_func,
73 GCompareFunc key_compare_func)
75 GHashTable *hash_table;
78 hash_table = g_new (GHashTable, 1);
79 hash_table->size = HASH_TABLE_MIN_SIZE;
80 hash_table->nnodes = 0;
81 hash_table->frozen = FALSE;
82 hash_table->hash_func = hash_func ? hash_func : g_direct_hash;
83 hash_table->key_compare_func = key_compare_func;
84 hash_table->nodes = g_new (GHashNode*, hash_table->size);
86 for (i = 0; i < hash_table->size; i++)
87 hash_table->nodes[i] = NULL;
93 g_hash_table_destroy (GHashTable *hash_table)
97 g_return_if_fail (hash_table != NULL);
99 for (i = 0; i < hash_table->size; i++)
100 g_hash_nodes_destroy (hash_table->nodes[i]);
102 g_free (hash_table->nodes);
106 static inline GHashNode*
107 g_hash_table_lookup_node (GHashTable *hash_table,
112 GHashNode *node, *last = NULL;
115 bucket = G_HASH_BUCKET (hash_table, key);
116 node = hash_table->nodes [bucket];
118 /* Hash table lookup needs to be fast.
119 * We therefore remove the extra conditional of testing
120 * whether to call the key_compare_func or not from
123 if (hash_table->key_compare_func)
124 while (node && !(*hash_table->key_compare_func) (node->key, key))
130 while (node && node->key != key)
145 g_hash_table_lookup (GHashTable *hash_table,
150 g_return_val_if_fail (hash_table != NULL, NULL);
152 node = g_hash_table_lookup_node (hash_table, key, NULL, NULL);
154 return node ? node->value : NULL;
158 g_hash_table_insert (GHashTable *hash_table,
162 GHashNode *node, *last;
165 g_return_if_fail (hash_table != NULL);
167 node = g_hash_table_lookup_node (hash_table, key, &last, &bucket);
171 node = g_hash_node_new (key, value);
174 hash_table->nodes [bucket] = node;
178 hash_table->nnodes++;
179 if (!hash_table->frozen)
180 g_hash_table_resize (hash_table);
184 /* do not reset node->key in this place, keeping
185 * the old key might be intended.
186 * a g_hash_table_remove/g_hash_table_insert pair
187 * can be used otherwise.
189 * node->key = key; */
196 g_hash_table_remove (GHashTable *hash_table,
199 GHashNode *node, *last;
202 g_return_if_fail (hash_table != NULL);
204 node = g_hash_table_lookup_node (hash_table, key, &last, &bucket);
209 hash_table->nodes [bucket] = node->next;
211 last->next = node->next;
213 g_hash_node_destroy (node);
215 hash_table->nnodes--;
217 if (!hash_table->frozen)
218 g_hash_table_resize (hash_table);
223 g_hash_table_lookup_extended (GHashTable *hash_table,
224 gconstpointer lookup_key,
230 g_return_val_if_fail (hash_table != NULL, FALSE);
232 node = g_hash_table_lookup_node (hash_table, lookup_key, NULL, NULL);
237 *orig_key = node->key;
239 *value = node->value;
247 g_hash_table_freeze (GHashTable *hash_table)
249 g_return_if_fail (hash_table != NULL);
251 hash_table->frozen++;
255 g_hash_table_thaw (GHashTable *hash_table)
257 g_return_if_fail (hash_table != NULL);
259 if (hash_table->frozen)
260 if (!(--hash_table->frozen))
261 g_hash_table_resize (hash_table);
265 g_hash_table_foreach_remove (GHashTable *hash_table,
269 GHashNode *node, *prev;
273 g_return_val_if_fail (hash_table != NULL, 0);
274 g_return_val_if_fail (func != NULL, 0);
276 for (i = 0; i < hash_table->size; i++)
282 for (node = hash_table->nodes[i]; node; prev = node, node = node->next)
284 if ((* func) (node->key, node->value, user_data))
288 hash_table->nnodes -= 1;
292 prev->next = node->next;
293 g_hash_node_destroy (node);
298 hash_table->nodes[i] = node->next;
299 g_hash_node_destroy (node);
306 if (!hash_table->frozen)
307 g_hash_table_resize (hash_table);
313 g_hash_table_foreach (GHashTable *hash_table,
320 g_return_if_fail (hash_table != NULL);
321 g_return_if_fail (func != NULL);
323 for (i = 0; i < hash_table->size; i++)
324 for (node = hash_table->nodes[i]; node; node = node->next)
325 (* func) (node->key, node->value, user_data);
328 /* Returns the number of elements contained in the hash table. */
330 g_hash_table_size (GHashTable *hash_table)
332 g_return_val_if_fail (hash_table != NULL, 0);
334 return hash_table->nnodes;
338 g_hash_table_resize (GHashTable *hash_table)
340 GHashNode **new_nodes;
343 gfloat nodes_per_list;
348 nodes_per_list = (gfloat) hash_table->nnodes / (gfloat) hash_table->size;
350 if ((nodes_per_list > 0.3 || hash_table->size <= HASH_TABLE_MIN_SIZE) &&
351 (nodes_per_list < 3.0 || hash_table->size >= HASH_TABLE_MAX_SIZE))
354 new_size = CLAMP(g_spaced_primes_closest (hash_table->nnodes),
356 HASH_TABLE_MAX_SIZE);
357 new_nodes = g_new0 (GHashNode*, new_size);
359 for (i = 0; i < hash_table->size; i++)
360 for (node = hash_table->nodes[i]; node; node = next)
364 hash_val = (* hash_table->hash_func) (node->key) % new_size;
366 node->next = new_nodes[hash_val];
367 new_nodes[hash_val] = node;
370 g_free (hash_table->nodes);
371 hash_table->nodes = new_nodes;
372 hash_table->size = new_size;
376 g_hash_node_new (gpointer key,
379 GHashNode *hash_node;
381 G_LOCK (g_hash_global);
384 hash_node = node_free_list;
385 node_free_list = node_free_list->next;
390 node_mem_chunk = g_mem_chunk_new ("hash node mem chunk",
394 hash_node = g_chunk_new (GHashNode, node_mem_chunk);
396 G_UNLOCK (g_hash_global);
398 hash_node->key = key;
399 hash_node->value = value;
400 hash_node->next = NULL;
406 g_hash_node_destroy (GHashNode *hash_node)
408 G_LOCK (g_hash_global);
409 hash_node->next = node_free_list;
410 node_free_list = hash_node;
411 G_UNLOCK (g_hash_global);
415 g_hash_nodes_destroy (GHashNode *hash_node)
419 GHashNode *node = hash_node;
424 G_LOCK (g_hash_global);
425 node->next = node_free_list;
426 node_free_list = hash_node;
427 G_UNLOCK (g_hash_global);