source: trunk/third/glib2/glib/ghash.c @ 21369

Revision 21369, 20.8 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21368, which included commits to RCS files with non-trunk default branches.
Line 
1/* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
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.
8 *
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.
13 *
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.
18 */
19
20/*
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/.
25 */
26
27/*
28 * MT safe
29 */
30
31#include "config.h"
32
33#include "glib.h"
34
35
36#define HASH_TABLE_MIN_SIZE 11
37#define HASH_TABLE_MAX_SIZE 13845163
38
39
40typedef struct _GHashNode      GHashNode;
41
42struct _GHashNode
43{
44  gpointer   key;
45  gpointer   value;
46  GHashNode *next;
47};
48
49struct _GHashTable
50{
51  gint             size;
52  gint             nnodes;
53  GHashNode      **nodes;
54  GHashFunc        hash_func;
55  GEqualFunc       key_equal_func;
56  GDestroyNotify   key_destroy_func;
57  GDestroyNotify   value_destroy_func;
58};
59
60#define G_HASH_TABLE_RESIZE(hash_table)                         \
61   G_STMT_START {                                               \
62     if ((hash_table->size >= 3 * hash_table->nnodes &&         \
63          hash_table->size > HASH_TABLE_MIN_SIZE) ||            \
64         (3 * hash_table->size <= hash_table->nnodes &&         \
65          hash_table->size < HASH_TABLE_MAX_SIZE))              \
66           g_hash_table_resize (hash_table);                    \
67   } G_STMT_END
68
69static void             g_hash_table_resize       (GHashTable     *hash_table);
70static GHashNode**      g_hash_table_lookup_node  (GHashTable     *hash_table,
71                                                   gconstpointer   key);
72static GHashNode*       g_hash_node_new           (gpointer        key,
73                                                   gpointer        value);
74static void             g_hash_node_destroy       (GHashNode      *hash_node,
75                                                   GDestroyNotify  key_destroy_func,
76                                                   GDestroyNotify  value_destroy_func);
77static void             g_hash_nodes_destroy      (GHashNode      *hash_node,
78                                                  GDestroyNotify   key_destroy_func,
79                                                  GDestroyNotify   value_destroy_func);
80static guint g_hash_table_foreach_remove_or_steal (GHashTable     *hash_table,
81                                                   GHRFunc         func,
82                                                   gpointer        user_data,
83                                                   gboolean        notify);
84
85
86#ifndef DISABLE_MEM_POOLS
87G_LOCK_DEFINE_STATIC (g_hash_global);
88
89static GMemChunk *node_mem_chunk = NULL;
90static GHashNode *node_free_list = NULL;
91#endif
92
93/**
94 * g_hash_table_new:
95 * @hash_func: a function to create a hash value from a key.
96 *   Hash values are used to determine where keys are stored within the
97 *   #GHashTable data structure. The g_direct_hash(), g_int_hash() and
98 *   g_str_hash() functions are provided for some common types of keys.
99 *   If hash_func is %NULL, g_direct_hash() is used.
100 * @key_equal_func: a function to check two keys for equality.  This is
101 *   used when looking up keys in the #GHashTable.  The g_direct_equal(),
102 *   g_int_equal() and g_str_equal() functions are provided for the most
103 *   common types of keys. If @key_equal_func is %NULL, keys are compared
104 *   directly in a similar fashion to g_direct_equal(), but without the
105 *   overhead of a function call.
106 *
107 * Creates a new #GHashTable.
108 *
109 * Return value: a new #GHashTable.
110 **/
111GHashTable*
112g_hash_table_new (GHashFunc    hash_func,
113                  GEqualFunc   key_equal_func)
114{
115  return g_hash_table_new_full (hash_func, key_equal_func, NULL, NULL);
116}
117
118
119/**
120 * g_hash_table_new_full:
121 * @hash_func: a function to create a hash value from a key.
122 * @key_equal_func: a function to check two keys for equality.
123 * @key_destroy_func: a function to free the memory allocated for the key
124 *   used when removing the entry from the #GHashTable or %NULL if you
125 *   don't want to supply such a function.
126 * @value_destroy_func: a function to free the memory allocated for the
127 *   value used when removing the entry from the #GHashTable or %NULL if
128 *   you don't want to supply such a function.
129 *
130 * Creates a new #GHashTable like g_hash_table_new() and allows to specify
131 * functions to free the memory allocated for the key and value that get
132 * called when removing the entry from the #GHashTable.
133 *
134 * Return value: a new #GHashTable.
135 **/
136GHashTable*
137g_hash_table_new_full (GHashFunc       hash_func,
138                       GEqualFunc      key_equal_func,
139                       GDestroyNotify  key_destroy_func,
140                       GDestroyNotify  value_destroy_func)
141{
142  GHashTable *hash_table;
143  guint i;
144 
145  hash_table = g_new (GHashTable, 1);
146  hash_table->size               = HASH_TABLE_MIN_SIZE;
147  hash_table->nnodes             = 0;
148  hash_table->hash_func          = hash_func ? hash_func : g_direct_hash;
149  hash_table->key_equal_func     = key_equal_func;
150  hash_table->key_destroy_func   = key_destroy_func;
151  hash_table->value_destroy_func = value_destroy_func;
152  hash_table->nodes              = g_new (GHashNode*, hash_table->size);
153 
154  for (i = 0; i < hash_table->size; i++)
155    hash_table->nodes[i] = NULL;
156 
157  return hash_table;
158}
159
160/**
161 * g_hash_table_destroy:
162 * @hash_table: a #GHashTable.
163 *
164 * Destroys the #GHashTable. If keys and/or values are dynamically
165 * allocated, you should either free them first or create the #GHashTable
166 * using g_hash_table_new_full(). In the latter case the destroy functions
167 * you supplied will be called on all keys and values before destroying
168 * the #GHashTable.
169 **/
170void
171g_hash_table_destroy (GHashTable *hash_table)
172{
173  guint i;
174 
175  g_return_if_fail (hash_table != NULL);
176 
177  for (i = 0; i < hash_table->size; i++)
178    g_hash_nodes_destroy (hash_table->nodes[i],
179                          hash_table->key_destroy_func,
180                          hash_table->value_destroy_func);
181 
182  g_free (hash_table->nodes);
183  g_free (hash_table);
184}
185
186static inline GHashNode**
187g_hash_table_lookup_node (GHashTable    *hash_table,
188                          gconstpointer  key)
189{
190  GHashNode **node;
191 
192  node = &hash_table->nodes
193    [(* hash_table->hash_func) (key) % hash_table->size];
194 
195  /* Hash table lookup needs to be fast.
196   *  We therefore remove the extra conditional of testing
197   *  whether to call the key_equal_func or not from
198   *  the inner loop.
199   */
200  if (hash_table->key_equal_func)
201    while (*node && !(*hash_table->key_equal_func) ((*node)->key, key))
202      node = &(*node)->next;
203  else
204    while (*node && (*node)->key != key)
205      node = &(*node)->next;
206 
207  return node;
208}
209
210/**
211 * g_hash_table_lookup:
212 * @hash_table: a #GHashTable.
213 * @key: the key to look up.
214 *
215 * Looks up a key in a #GHashTable. Note that this function cannot
216 * distinguish between a key that is not present and one which is present
217 * and has the value %NULL. If you need this distinction, use
218 * g_hash_table_lookup_extended().
219 *
220 * Return value: the associated value, or %NULL if the key is not found.
221 **/
222gpointer
223g_hash_table_lookup (GHashTable   *hash_table,
224                     gconstpointer key)
225{
226  GHashNode *node;
227 
228  g_return_val_if_fail (hash_table != NULL, NULL);
229 
230  node = *g_hash_table_lookup_node (hash_table, key);
231 
232  return node ? node->value : NULL;
233}
234
235/**
236 * g_hash_table_lookup_extended:
237 * @hash_table: a #GHashTable.
238 * @lookup_key: the key to look up.
239 * @orig_key: returns the original key.
240 * @value: returns the value associated with the key.
241 *
242 * Looks up a key in the #GHashTable, returning the original key and the
243 * associated value and a #gboolean which is %TRUE if the key was found. This
244 * is useful if you need to free the memory allocated for the original key,
245 * for example before calling g_hash_table_remove().
246 *
247 * Return value: %TRUE if the key was found in the #GHashTable.
248 **/
249gboolean
250g_hash_table_lookup_extended (GHashTable    *hash_table,
251                              gconstpointer  lookup_key,
252                              gpointer      *orig_key,
253                              gpointer      *value)
254{
255  GHashNode *node;
256 
257  g_return_val_if_fail (hash_table != NULL, FALSE);
258 
259  node = *g_hash_table_lookup_node (hash_table, lookup_key);
260 
261  if (node)
262    {
263      if (orig_key)
264        *orig_key = node->key;
265      if (value)
266        *value = node->value;
267      return TRUE;
268    }
269  else
270    return FALSE;
271}
272
273/**
274 * g_hash_table_insert:
275 * @hash_table: a #GHashTable.
276 * @key: a key to insert.
277 * @value: the value to associate with the key.
278 *
279 * Inserts a new key and value into a #GHashTable.
280 *
281 * If the key already exists in the #GHashTable its current value is replaced
282 * with the new value. If you supplied a @value_destroy_func when creating the
283 * #GHashTable, the old value is freed using that function. If you supplied
284 * a @key_destroy_func when creating the #GHashTable, the passed key is freed
285 * using that function.
286 **/
287void
288g_hash_table_insert (GHashTable *hash_table,
289                     gpointer    key,
290                     gpointer    value)
291{
292  GHashNode **node;
293 
294  g_return_if_fail (hash_table != NULL);
295 
296  node = g_hash_table_lookup_node (hash_table, key);
297 
298  if (*node)
299    {
300      /* do not reset node->key in this place, keeping
301       * the old key is the intended behaviour.
302       * g_hash_table_replace() can be used instead.
303       */
304
305      /* free the passed key */
306      if (hash_table->key_destroy_func)
307        hash_table->key_destroy_func (key);
308     
309      if (hash_table->value_destroy_func)
310        hash_table->value_destroy_func ((*node)->value);
311
312      (*node)->value = value;
313    }
314  else
315    {
316      *node = g_hash_node_new (key, value);
317      hash_table->nnodes++;
318      G_HASH_TABLE_RESIZE (hash_table);
319    }
320}
321
322/**
323 * g_hash_table_replace:
324 * @hash_table: a #GHashTable.
325 * @key: a key to insert.
326 * @value: the value to associate with the key.
327 *
328 * Inserts a new key and value into a #GHashTable similar to
329 * g_hash_table_insert(). The difference is that if the key already exists
330 * in the #GHashTable, it gets replaced by the new key. If you supplied a
331 * @value_destroy_func when creating the #GHashTable, the old value is freed
332 * using that function. If you supplied a @key_destroy_func when creating the
333 * #GHashTable, the old key is freed using that function.
334 **/
335void
336g_hash_table_replace (GHashTable *hash_table,
337                      gpointer    key,
338                      gpointer    value)
339{
340  GHashNode **node;
341 
342  g_return_if_fail (hash_table != NULL);
343 
344  node = g_hash_table_lookup_node (hash_table, key);
345 
346  if (*node)
347    {
348      if (hash_table->key_destroy_func)
349        hash_table->key_destroy_func ((*node)->key);
350     
351      if (hash_table->value_destroy_func)
352        hash_table->value_destroy_func ((*node)->value);
353
354      (*node)->key   = key;
355      (*node)->value = value;
356    }
357  else
358    {
359      *node = g_hash_node_new (key, value);
360      hash_table->nnodes++;
361      G_HASH_TABLE_RESIZE (hash_table);
362    }
363}
364
365/**
366 * g_hash_table_remove:
367 * @hash_table: a #GHashTable.
368 * @key: the key to remove.
369 *
370 * Removes a key and its associated value from a #GHashTable.
371 *
372 * If the #GHashTable was created using g_hash_table_new_full(), the
373 * key and value are freed using the supplied destroy functions, otherwise
374 * you have to make sure that any dynamically allocated values are freed
375 * yourself.
376 *
377 * Return value: %TRUE if the key was found and removed from the #GHashTable.
378 **/
379gboolean
380g_hash_table_remove (GHashTable    *hash_table,
381                     gconstpointer  key)
382{
383  GHashNode **node, *dest;
384 
385  g_return_val_if_fail (hash_table != NULL, FALSE);
386 
387  node = g_hash_table_lookup_node (hash_table, key);
388  if (*node)
389    {
390      dest = *node;
391      (*node) = dest->next;
392      g_hash_node_destroy (dest,
393                           hash_table->key_destroy_func,
394                           hash_table->value_destroy_func);
395      hash_table->nnodes--;
396 
397      G_HASH_TABLE_RESIZE (hash_table);
398
399      return TRUE;
400    }
401
402  return FALSE;
403}
404
405/**
406 * g_hash_table_steal:
407 * @hash_table: a #GHashTable.
408 * @key: the key to remove.
409 *
410 * Removes a key and its associated value from a #GHashTable without
411 * calling the key and value destroy functions.
412 *
413 * Return value: %TRUE if the key was found and removed from the #GHashTable.
414 **/
415gboolean
416g_hash_table_steal (GHashTable    *hash_table,
417                    gconstpointer  key)
418{
419  GHashNode **node, *dest;
420 
421  g_return_val_if_fail (hash_table != NULL, FALSE);
422 
423  node = g_hash_table_lookup_node (hash_table, key);
424  if (*node)
425    {
426      dest = *node;
427      (*node) = dest->next;
428      g_hash_node_destroy (dest, NULL, NULL);
429      hash_table->nnodes--;
430 
431      G_HASH_TABLE_RESIZE (hash_table);
432
433      return TRUE;
434    }
435
436  return FALSE;
437}
438
439/**
440 * g_hash_table_foreach_remove:
441 * @hash_table: a #GHashTable.
442 * @func: the function to call for each key/value pair.
443 * @user_data: user data to pass to the function.
444 *
445 * Calls the given function for each key/value pair in the #GHashTable.
446 * If the function returns %TRUE, then the key/value pair is removed from the
447 * #GHashTable. If you supplied key or value destroy functions when creating
448 * the #GHashTable, they are used to free the memory allocated for the removed
449 * keys and values.
450 *
451 * Return value: the number of key/value pairs removed.
452 **/
453guint
454g_hash_table_foreach_remove (GHashTable *hash_table,
455                             GHRFunc     func,
456                             gpointer    user_data)
457{
458  g_return_val_if_fail (hash_table != NULL, 0);
459  g_return_val_if_fail (func != NULL, 0);
460 
461  return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, TRUE);
462}
463
464/**
465 * g_hash_table_foreach_steal:
466 * @hash_table: a #GHashTable.
467 * @func: the function to call for each key/value pair.
468 * @user_data: user data to pass to the function.
469 *
470 * Calls the given function for each key/value pair in the #GHashTable.
471 * If the function returns %TRUE, then the key/value pair is removed from the
472 * #GHashTable, but no key or value destroy functions are called.
473 *
474 * Return value: the number of key/value pairs removed.
475 **/
476guint
477g_hash_table_foreach_steal (GHashTable *hash_table,
478                            GHRFunc     func,
479                            gpointer    user_data)
480{
481  g_return_val_if_fail (hash_table != NULL, 0);
482  g_return_val_if_fail (func != NULL, 0);
483 
484  return g_hash_table_foreach_remove_or_steal (hash_table, func, user_data, FALSE);
485}
486
487static guint
488g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
489                                      GHRFunc     func,
490                                      gpointer    user_data,
491                                      gboolean    notify)
492{
493  GHashNode *node, *prev;
494  guint i;
495  guint deleted = 0;
496 
497  for (i = 0; i < hash_table->size; i++)
498    {
499    restart:
500     
501      prev = NULL;
502     
503      for (node = hash_table->nodes[i]; node; prev = node, node = node->next)
504        {
505          if ((* func) (node->key, node->value, user_data))
506            {
507              deleted += 1;
508             
509              hash_table->nnodes -= 1;
510             
511              if (prev)
512                {
513                  prev->next = node->next;
514                  g_hash_node_destroy (node,
515                                       notify ? hash_table->key_destroy_func : NULL,
516                                       notify ? hash_table->value_destroy_func : NULL);
517                  node = prev;
518                }
519              else
520                {
521                  hash_table->nodes[i] = node->next;
522                  g_hash_node_destroy (node,
523                                       notify ? hash_table->key_destroy_func : NULL,
524                                       notify ? hash_table->value_destroy_func : NULL);
525                  goto restart;
526                }
527            }
528        }
529    }
530 
531  G_HASH_TABLE_RESIZE (hash_table);
532 
533  return deleted;
534}
535
536/**
537 * g_hash_table_foreach:
538 * @hash_table: a #GHashTable.
539 * @func: the function to call for each key/value pair.
540 * @user_data: user data to pass to the function.
541 *
542 * Calls the given function for each of the key/value pairs in the
543 * #GHashTable.  The function is passed the key and value of each
544 * pair, and the given @user_data parameter.  The hash table may not
545 * be modified while iterating over it (you can't add/remove
546 * items). To remove all items matching a predicate, use
547 * g_hash_table_remove().
548 **/
549void
550g_hash_table_foreach (GHashTable *hash_table,
551                      GHFunc      func,
552                      gpointer    user_data)
553{
554  GHashNode *node;
555  gint i;
556 
557  g_return_if_fail (hash_table != NULL);
558  g_return_if_fail (func != NULL);
559 
560  for (i = 0; i < hash_table->size; i++)
561    for (node = hash_table->nodes[i]; node; node = node->next)
562      (* func) (node->key, node->value, user_data);
563}
564
565/**
566 * g_hash_table_find:
567 * @hash_table: a #GHashTable.
568 * @predicate:  function to test the key/value pairs for a certain property.
569 * @user_data:  user data to pass to the function.
570 *
571 * Calls the given function for key/value pairs in the #GHashTable until
572 * @predicate returns %TRUE.  The function is passed the key and value of
573 * each pair, and the given @user_data parameter. The hash table may not
574 * be modified while iterating over it (you can't add/remove items).
575 *
576 * Return value: The value of the first key/value pair is returned, for which
577 * func evaluates to %TRUE. If no pair with the requested property is found,
578 * %NULL is returned.
579 *
580 * Since: 2.4
581 **/
582gpointer
583g_hash_table_find (GHashTable      *hash_table,
584                   GHRFunc          predicate,
585                   gpointer         user_data)
586{
587  GHashNode *node;
588  gint i;
589 
590  g_return_val_if_fail (hash_table != NULL, NULL);
591  g_return_val_if_fail (predicate != NULL, NULL);
592 
593  for (i = 0; i < hash_table->size; i++)
594    for (node = hash_table->nodes[i]; node; node = node->next)
595      if (predicate (node->key, node->value, user_data))
596        return node->value;       
597  return NULL;
598}
599
600/**
601 * g_hash_table_size:
602 * @hash_table: a #GHashTable.
603 *
604 * Returns the number of elements contained in the #GHashTable.
605 *
606 * Return value: the number of key/value pairs in the #GHashTable.
607 **/
608guint
609g_hash_table_size (GHashTable *hash_table)
610{
611  g_return_val_if_fail (hash_table != NULL, 0);
612 
613  return hash_table->nnodes;
614}
615
616static void
617g_hash_table_resize (GHashTable *hash_table)
618{
619  GHashNode **new_nodes;
620  GHashNode *node;
621  GHashNode *next;
622  guint hash_val;
623  gint new_size;
624  gint i;
625
626  new_size = g_spaced_primes_closest (hash_table->nnodes);
627  new_size = CLAMP (new_size, HASH_TABLE_MIN_SIZE, HASH_TABLE_MAX_SIZE);
628 
629  new_nodes = g_new0 (GHashNode*, new_size);
630 
631  for (i = 0; i < hash_table->size; i++)
632    for (node = hash_table->nodes[i]; node; node = next)
633      {
634        next = node->next;
635
636        hash_val = (* hash_table->hash_func) (node->key) % new_size;
637
638        node->next = new_nodes[hash_val];
639        new_nodes[hash_val] = node;
640      }
641 
642  g_free (hash_table->nodes);
643  hash_table->nodes = new_nodes;
644  hash_table->size = new_size;
645}
646
647static GHashNode*
648g_hash_node_new (gpointer key,
649                 gpointer value)
650{
651  GHashNode *hash_node;
652 
653#ifdef DISABLE_MEM_POOLS
654  hash_node = g_new (GHashNode, 1);
655#else
656  G_LOCK (g_hash_global);
657  if (node_free_list)
658    {
659      hash_node = node_free_list;
660      node_free_list = node_free_list->next;
661    }
662  else
663    {
664      if (!node_mem_chunk)
665        node_mem_chunk = g_mem_chunk_new ("hash node mem chunk",
666                                          sizeof (GHashNode),
667                                          1024, G_ALLOC_ONLY);
668     
669      hash_node = g_chunk_new (GHashNode, node_mem_chunk);
670    }
671  G_UNLOCK (g_hash_global);
672#endif
673 
674  hash_node->key = key;
675  hash_node->value = value;
676  hash_node->next = NULL;
677 
678  return hash_node;
679}
680
681static void
682g_hash_node_destroy (GHashNode      *hash_node,
683                     GDestroyNotify  key_destroy_func,
684                     GDestroyNotify  value_destroy_func)
685{
686  if (key_destroy_func)
687    key_destroy_func (hash_node->key);
688  if (value_destroy_func)
689    value_destroy_func (hash_node->value);
690 
691#ifdef ENABLE_GC_FRIENDLY
692  hash_node->key = NULL;
693  hash_node->value = NULL;
694#endif /* ENABLE_GC_FRIENDLY */
695
696#ifdef DISABLE_MEM_POOLS
697  g_free (hash_node);
698#else
699  G_LOCK (g_hash_global);
700  hash_node->next = node_free_list;
701  node_free_list = hash_node;
702  G_UNLOCK (g_hash_global);
703#endif
704}
705
706static void
707g_hash_nodes_destroy (GHashNode *hash_node,
708                      GFreeFunc  key_destroy_func,
709                      GFreeFunc  value_destroy_func)
710{
711#ifdef DISABLE_MEM_POOLS
712  while (hash_node)
713    {
714      GHashNode *next = hash_node->next;
715
716      if (key_destroy_func)
717        key_destroy_func (hash_node->key);
718      if (value_destroy_func)
719        value_destroy_func (hash_node->value);
720
721      g_free (hash_node);
722      hash_node = next;
723    } 
724#else
725  if (hash_node)
726    {
727      GHashNode *node = hash_node;
728 
729      while (node->next)
730        {
731          if (key_destroy_func)
732            key_destroy_func (node->key);
733          if (value_destroy_func)
734            value_destroy_func (node->value);
735
736#ifdef ENABLE_GC_FRIENDLY
737          node->key = NULL;
738          node->value = NULL;
739#endif /* ENABLE_GC_FRIENDLY */
740
741          node = node->next;
742        }
743
744      if (key_destroy_func)
745        key_destroy_func (node->key);
746      if (value_destroy_func)
747        value_destroy_func (node->value);
748
749#ifdef ENABLE_GC_FRIENDLY
750      node->key = NULL;
751      node->value = NULL;
752#endif /* ENABLE_GC_FRIENDLY */
753 
754      G_LOCK (g_hash_global);
755      node->next = node_free_list;
756      node_free_list = hash_node;
757      G_UNLOCK (g_hash_global);
758    }
759#endif
760}
Note: See TracBrowser for help on using the repository browser.