1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-hash.c Generic hash table utility (internal to D-BUS implementation)
4 * Copyright (C) 2002 Red Hat, Inc.
5 * Copyright (c) 1991-1993 The Regents of the University of California.
6 * Copyright (c) 1994 Sun Microsystems, Inc.
8 * Hash table implementation based on generic/tclHash.c from the Tcl
9 * source code. The original Tcl license applies to portions of the
10 * code from tclHash.c; the Tcl license follows this standad D-BUS
11 * license information.
13 * Licensed under the Academic Free License version 2.1
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 * The following copyright applies to code from the Tcl distribution.
33 * Copyright (c) 1991-1993 The Regents of the University of California.
34 * Copyright (c) 1994 Sun Microsystems, Inc.
36 * This software is copyrighted by the Regents of the University of
37 * California, Sun Microsystems, Inc., Scriptics Corporation, and
38 * other parties. The following terms apply to all files associated
39 * with the software unless explicitly disclaimed in individual files.
41 * The authors hereby grant permission to use, copy, modify,
42 * distribute, and license this software and its documentation for any
43 * purpose, provided that existing copyright notices are retained in
44 * all copies and that this notice is included verbatim in any
45 * distributions. No written agreement, license, or royalty fee is
46 * required for any of the authorized uses. Modifications to this
47 * software may be copyrighted by their authors and need not follow
48 * the licensing terms described here, provided that the new terms are
49 * clearly indicated on the first page of each file where they apply.
51 * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
52 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
53 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
54 * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
55 * OF THE POSSIBILITY OF SUCH DAMAGE.
57 * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
58 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
59 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
60 * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
61 * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
62 * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
64 * GOVERNMENT USE: If you are acquiring this software on behalf of the
65 * U.S. government, the Government shall have only "Restricted Rights"
66 * in the software and related documentation as defined in the Federal
67 * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
68 * are acquiring the software on behalf of the Department of Defense,
69 * the software shall be classified as "Commercial Computer Software"
70 * and the Government shall have only "Restricted Rights" as defined
71 * in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the
72 * foregoing, the authors grant the U.S. Government and others acting
73 * in its behalf permission to use and distribute the software in
74 * accordance with the terms specified in this license.
77 #include "dbus-hash.h"
78 #include "dbus-internals.h"
79 #include "dbus-mempool.h"
82 * @defgroup DBusHashTable Hash table
83 * @ingroup DBusInternals
84 * @brief DBusHashTable data structure
86 * Types and functions related to DBusHashTable.
90 * @defgroup DBusHashTableInternals Hash table implementation details
91 * @ingroup DBusInternals
92 * @brief DBusHashTable implementation details
94 * The guts of DBusHashTable.
100 * When there are this many entries per bucket, on average, rebuild
101 * the hash table to make it larger.
103 #define REBUILD_MULTIPLIER 3
106 * Takes a preliminary integer hash value and produces an index into a
107 * hash tables bucket list. The idea is to make it so that
108 * preliminary values that are arbitrarily similar will end up in
109 * different buckets. The hash function was taken from a
110 * random-number generator. (This is used to hash integers.)
112 * The down_shift drops off the high bits of the hash index, and
113 * decreases as we increase the number of hash buckets (to keep more
114 * range in the hash index). The mask also strips high bits and strips
115 * fewer high bits as the number of hash buckets increases.
116 * I don't understand two things: why is the initial downshift 28
117 * to keep 4 bits when the initial mask is 011 to keep 2 bits,
118 * and why do we have both a mask and a downshift?
121 #define RANDOM_INDEX(table, i) \
122 (((((long) (i))*1103515245) >> (table)->down_shift) & (table)->mask)
125 * Initial number of buckets in hash table (hash table statically
126 * allocates its buckets for this size and below).
127 * The initial mask has to be synced to this.
129 #define DBUS_SMALL_HASH_TABLE 4
132 * Typedef for DBusHashEntry
134 typedef struct DBusHashEntry DBusHashEntry;
137 * @brief Internal representation of a hash entry.
139 * A single entry (key-value pair) in the hash table.
140 * Internal to hash table implementation.
144 DBusHashEntry *next; /**< Pointer to next entry in this
145 * hash bucket, or #NULL for end of
148 void *key; /**< Hash key */
149 void *value; /**< Hash value */
153 * Function used to find and optionally create a hash entry.
155 typedef DBusHashEntry* (* DBusFindEntryFunction) (DBusHashTable *table,
157 dbus_bool_t create_if_not_found,
158 DBusHashEntry ***bucket,
159 DBusPreallocatedHash *preallocated);
162 * @brief Internals of DBusHashTable.
164 * Hash table internals. Hash tables are opaque objects, they must be
165 * used via accessor functions.
167 struct DBusHashTable {
168 int refcount; /**< Reference count */
170 DBusHashEntry **buckets; /**< Pointer to bucket array. Each
171 * element points to first entry in
172 * bucket's hash chain, or #NULL.
174 DBusHashEntry *static_buckets[DBUS_SMALL_HASH_TABLE];
175 /**< Bucket array used for small tables
176 * (to avoid mallocs and frees).
178 int n_buckets; /**< Total number of buckets allocated
181 int n_entries; /**< Total number of entries present
184 int hi_rebuild_size; /**< Enlarge table when n_entries gets
187 int lo_rebuild_size; /**< Shrink table when n_entries gets
190 int down_shift; /**< Shift count used in hashing
191 * function. Designed to use high-
192 * order bits of randomized keys.
194 int mask; /**< Mask value used in hashing
197 DBusHashType key_type; /**< Type of keys used in this table */
200 DBusFindEntryFunction find_function; /**< Function for finding entries */
202 DBusFreeFunction free_key_function; /**< Function to free keys */
203 DBusFreeFunction free_value_function; /**< Function to free values */
205 DBusMemPool *entry_pool; /**< Memory pool for hash entries */
209 * @brief Internals of DBusHashIter.
213 DBusHashTable *table; /**< Pointer to table containing entry. */
214 DBusHashEntry **bucket; /**< Pointer to bucket that points to
215 * first entry in this entry's chain:
216 * used for deleting the entry.
218 DBusHashEntry *entry; /**< Current hash entry */
219 DBusHashEntry *next_entry; /**< Next entry to be iterated onto in current bucket */
220 int next_bucket; /**< index of next bucket */
221 int n_entries_on_init; /**< used to detect table resize since initialization */
224 static DBusHashEntry* find_direct_function (DBusHashTable *table,
226 dbus_bool_t create_if_not_found,
227 DBusHashEntry ***bucket,
228 DBusPreallocatedHash *preallocated);
229 static DBusHashEntry* find_string_function (DBusHashTable *table,
231 dbus_bool_t create_if_not_found,
232 DBusHashEntry ***bucket,
233 DBusPreallocatedHash *preallocated);
234 #ifdef DBUS_BUILD_TESTS
235 static DBusHashEntry* find_two_strings_function (DBusHashTable *table,
237 dbus_bool_t create_if_not_found,
238 DBusHashEntry ***bucket,
239 DBusPreallocatedHash *preallocated);
241 static unsigned int string_hash (const char *str);
242 #ifdef DBUS_BUILD_TESTS
243 static unsigned int two_strings_hash (const char *str);
245 static void rebuild_table (DBusHashTable *table);
246 static DBusHashEntry* alloc_entry (DBusHashTable *table);
247 static void remove_entry (DBusHashTable *table,
248 DBusHashEntry **bucket,
249 DBusHashEntry *entry);
250 static void free_entry (DBusHashTable *table,
251 DBusHashEntry *entry);
252 static void free_entry_data (DBusHashTable *table,
253 DBusHashEntry *entry);
259 * @addtogroup DBusHashTable
264 * @typedef DBusHashIter
266 * Public opaque hash table iterator object.
270 * @typedef DBusHashTable
272 * Public opaque hash table object.
276 * @typedef DBusHashType
278 * Indicates the type of a key in the hash table.
282 * Constructs a new hash table. Should be freed with
283 * _dbus_hash_table_unref(). If memory cannot be
284 * allocated for the hash table, returns #NULL.
286 * @param type the type of hash key to use.
287 * @param key_free_function function to free hash keys.
288 * @param value_free_function function to free hash values.
289 * @returns a new DBusHashTable or #NULL if no memory.
292 _dbus_hash_table_new (DBusHashType type,
293 DBusFreeFunction key_free_function,
294 DBusFreeFunction value_free_function)
296 DBusHashTable *table;
297 DBusMemPool *entry_pool;
299 table = dbus_new0 (DBusHashTable, 1);
303 entry_pool = _dbus_mem_pool_new (sizeof (DBusHashEntry), TRUE);
304 if (entry_pool == NULL)
311 table->entry_pool = entry_pool;
313 _dbus_assert (DBUS_SMALL_HASH_TABLE == _DBUS_N_ELEMENTS (table->static_buckets));
315 table->buckets = table->static_buckets;
316 table->n_buckets = DBUS_SMALL_HASH_TABLE;
317 table->n_entries = 0;
318 table->hi_rebuild_size = DBUS_SMALL_HASH_TABLE * REBUILD_MULTIPLIER;
319 table->lo_rebuild_size = 0;
320 table->down_shift = 28;
322 table->key_type = type;
324 _dbus_assert (table->mask < table->n_buckets);
326 switch (table->key_type)
329 case DBUS_HASH_POINTER:
330 case DBUS_HASH_ULONG:
331 table->find_function = find_direct_function;
333 case DBUS_HASH_STRING:
334 table->find_function = find_string_function;
336 case DBUS_HASH_TWO_STRINGS:
337 #ifdef DBUS_BUILD_TESTS
338 table->find_function = find_two_strings_function;
342 _dbus_assert_not_reached ("Unknown hash table type");
346 table->free_key_function = key_free_function;
347 table->free_value_function = value_free_function;
354 * Increments the reference count for a hash table.
356 * @param table the hash table to add a reference to.
357 * @returns the hash table.
360 _dbus_hash_table_ref (DBusHashTable *table)
362 table->refcount += 1;
368 * Decrements the reference count for a hash table,
369 * freeing the hash table if the count reaches zero.
371 * @param table the hash table to remove a reference from.
374 _dbus_hash_table_unref (DBusHashTable *table)
376 table->refcount -= 1;
378 if (table->refcount == 0)
381 DBusHashEntry *entry;
385 /* Free the entries in the table. */
386 for (i = 0; i < table->n_buckets; i++)
388 entry = table->buckets[i];
389 while (entry != NULL)
393 free_entry (table, entry);
399 DBusHashEntry *entry;
402 /* Free the entries in the table. */
403 for (i = 0; i < table->n_buckets; i++)
405 entry = table->buckets[i];
406 while (entry != NULL)
408 free_entry_data (table, entry);
413 /* We can do this very quickly with memory pools ;-) */
414 _dbus_mem_pool_free (table->entry_pool);
417 /* Free the bucket array, if it was dynamically allocated. */
418 if (table->buckets != table->static_buckets)
419 dbus_free (table->buckets);
425 static DBusHashEntry*
426 alloc_entry (DBusHashTable *table)
428 DBusHashEntry *entry;
430 entry = _dbus_mem_pool_alloc (table->entry_pool);
436 free_entry_data (DBusHashTable *table,
437 DBusHashEntry *entry)
439 if (table->free_key_function)
440 (* table->free_key_function) (entry->key);
441 if (table->free_value_function)
442 (* table->free_value_function) (entry->value);
446 free_entry (DBusHashTable *table,
447 DBusHashEntry *entry)
449 free_entry_data (table, entry);
450 _dbus_mem_pool_dealloc (table->entry_pool, entry);
454 remove_entry (DBusHashTable *table,
455 DBusHashEntry **bucket,
456 DBusHashEntry *entry)
458 _dbus_assert (table != NULL);
459 _dbus_assert (bucket != NULL);
460 _dbus_assert (*bucket != NULL);
461 _dbus_assert (entry != NULL);
463 if (*bucket == entry)
464 *bucket = entry->next;
470 while (prev->next != entry)
473 _dbus_assert (prev != NULL);
475 prev->next = entry->next;
478 table->n_entries -= 1;
479 free_entry (table, entry);
483 * Initializes a hash table iterator. To iterate over all entries in a
484 * hash table, use the following code (the printf assumes a hash
485 * from strings to strings obviously):
490 * _dbus_hash_iter_init (table, &iter);
491 * while (_dbus_hash_iter_next (&iter))
493 * printf ("The first key is %s and value is %s\n",
494 * _dbus_hash_iter_get_string_key (&iter),
495 * _dbus_hash_iter_get_value (&iter));
501 * The iterator is initialized pointing "one before" the first hash
502 * entry. The first call to _dbus_hash_iter_next() moves it onto
503 * the first valid entry or returns #FALSE if the hash table is
504 * empty. Subsequent calls move to the next valid entry or return
505 * #FALSE if there are no more entries.
507 * Note that it is guaranteed to be safe to remove a hash entry during
508 * iteration, but it is not safe to add a hash entry.
510 * @param table the hash table to iterate over.
511 * @param iter the iterator to initialize.
514 _dbus_hash_iter_init (DBusHashTable *table,
517 DBusRealHashIter *real;
519 _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
521 real = (DBusRealHashIter*) iter;
526 real->next_entry = NULL;
527 real->next_bucket = 0;
528 real->n_entries_on_init = table->n_entries;
532 * Move the hash iterator forward one step, to the next hash entry.
533 * The documentation for _dbus_hash_iter_init() explains in more
536 * @param iter the iterator to move forward.
537 * @returns #FALSE if there are no more entries to move to.
540 _dbus_hash_iter_next (DBusHashIter *iter)
542 DBusRealHashIter *real;
544 _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
546 real = (DBusRealHashIter*) iter;
548 /* if this assertion failed someone probably added hash entries
549 * during iteration, which is bad.
551 _dbus_assert (real->n_entries_on_init >= real->table->n_entries);
553 /* Remember that real->entry may have been deleted */
555 while (real->next_entry == NULL)
557 if (real->next_bucket >= real->table->n_buckets)
559 /* invalidate iter and return false */
566 real->bucket = &(real->table->buckets[real->next_bucket]);
567 real->next_entry = *(real->bucket);
568 real->next_bucket += 1;
571 _dbus_assert (real->next_entry != NULL);
572 _dbus_assert (real->bucket != NULL);
574 real->entry = real->next_entry;
575 real->next_entry = real->entry->next;
581 * Removes the current entry from the hash table.
582 * If a key_free_function or value_free_function
583 * was provided to _dbus_hash_table_new(),
584 * frees the key and/or value for this entry.
586 * @param iter the hash table iterator.
589 _dbus_hash_iter_remove_entry (DBusHashIter *iter)
591 DBusRealHashIter *real;
593 real = (DBusRealHashIter*) iter;
595 _dbus_assert (real->table != NULL);
596 _dbus_assert (real->entry != NULL);
597 _dbus_assert (real->bucket != NULL);
599 remove_entry (real->table, real->bucket, real->entry);
601 real->entry = NULL; /* make it crash if you try to use this entry */
605 * Gets the value of the current entry.
607 * @param iter the hash table iterator.
610 _dbus_hash_iter_get_value (DBusHashIter *iter)
612 DBusRealHashIter *real;
614 real = (DBusRealHashIter*) iter;
616 _dbus_assert (real->table != NULL);
617 _dbus_assert (real->entry != NULL);
619 return real->entry->value;
623 * Sets the value of the current entry.
624 * If the hash table has a value_free_function
625 * it will be used to free the previous value.
626 * The hash table will own the passed-in value
627 * (it will not be copied).
629 * @param iter the hash table iterator.
630 * @param value the new value.
633 _dbus_hash_iter_set_value (DBusHashIter *iter,
636 DBusRealHashIter *real;
638 real = (DBusRealHashIter*) iter;
640 _dbus_assert (real->table != NULL);
641 _dbus_assert (real->entry != NULL);
643 if (real->table->free_value_function && value != real->entry->value)
644 (* real->table->free_value_function) (real->entry->value);
646 real->entry->value = value;
650 * Gets the key for the current entry.
651 * Only works for hash tables of type #DBUS_HASH_INT.
653 * @param iter the hash table iterator.
656 _dbus_hash_iter_get_int_key (DBusHashIter *iter)
658 DBusRealHashIter *real;
660 real = (DBusRealHashIter*) iter;
662 _dbus_assert (real->table != NULL);
663 _dbus_assert (real->entry != NULL);
665 return _DBUS_POINTER_TO_INT (real->entry->key);
669 * Gets the key for the current entry.
670 * Only works for hash tables of type #DBUS_HASH_ULONG.
672 * @param iter the hash table iterator.
675 _dbus_hash_iter_get_ulong_key (DBusHashIter *iter)
677 DBusRealHashIter *real;
679 real = (DBusRealHashIter*) iter;
681 _dbus_assert (real->table != NULL);
682 _dbus_assert (real->entry != NULL);
684 return (unsigned long) real->entry->key;
688 * Gets the key for the current entry.
689 * Only works for hash tables of type #DBUS_HASH_STRING
690 * @param iter the hash table iterator.
693 _dbus_hash_iter_get_string_key (DBusHashIter *iter)
695 DBusRealHashIter *real;
697 real = (DBusRealHashIter*) iter;
699 _dbus_assert (real->table != NULL);
700 _dbus_assert (real->entry != NULL);
702 return real->entry->key;
705 #ifdef DBUS_BUILD_TESTS
707 * Gets the key for the current entry.
708 * Only works for hash tables of type #DBUS_HASH_TWO_STRINGS
709 * @param iter the hash table iterator.
712 _dbus_hash_iter_get_two_strings_key (DBusHashIter *iter)
714 DBusRealHashIter *real;
716 real = (DBusRealHashIter*) iter;
718 _dbus_assert (real->table != NULL);
719 _dbus_assert (real->entry != NULL);
721 return real->entry->key;
723 #endif /* DBUS_BUILD_TESTS */
726 * A low-level but efficient interface for manipulating the hash
727 * table. It's efficient because you can get, set, and optionally
728 * create the hash entry while only running the hash function one
731 * Note that while calling _dbus_hash_iter_next() on the iterator
732 * filled in by this function may work, it's completely
733 * undefined which entries are after this iter and which
734 * are before it. So it would be silly to iterate using this
737 * If the hash entry is created, its value will be initialized
740 * #FALSE may be returned due to memory allocation failure, or
741 * because create_if_not_found was #FALSE and the entry
744 * If create_if_not_found is #TRUE and the entry is created, the hash
745 * table takes ownership of the key that's passed in.
747 * For a hash table of type #DBUS_HASH_INT, cast the int
748 * key to the key parameter using #_DBUS_INT_TO_POINTER().
750 * @param table the hash table.
751 * @param key the hash key.
752 * @param create_if_not_found if #TRUE, create the entry if it didn't exist.
753 * @param iter the iterator to initialize.
754 * @returns #TRUE if the hash entry now exists (and the iterator is thus valid).
757 _dbus_hash_iter_lookup (DBusHashTable *table,
759 dbus_bool_t create_if_not_found,
762 DBusRealHashIter *real;
763 DBusHashEntry *entry;
764 DBusHashEntry **bucket;
766 _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
768 real = (DBusRealHashIter*) iter;
770 entry = (* table->find_function) (table, key, create_if_not_found, &bucket, NULL);
776 real->bucket = bucket;
778 real->next_entry = entry->next;
779 real->next_bucket = (bucket - table->buckets) + 1;
780 real->n_entries_on_init = table->n_entries;
782 _dbus_assert (&(table->buckets[real->next_bucket-1]) == real->bucket);
788 add_allocated_entry (DBusHashTable *table,
789 DBusHashEntry *entry,
792 DBusHashEntry ***bucket)
798 b = &(table->buckets[idx]);
805 table->n_entries += 1;
807 /* note we ONLY rebuild when ADDING - because you can iterate over a
808 * table and remove entries safely.
810 if (table->n_entries >= table->hi_rebuild_size ||
811 table->n_entries < table->lo_rebuild_size)
812 rebuild_table (table);
815 static DBusHashEntry*
816 add_entry (DBusHashTable *table,
819 DBusHashEntry ***bucket,
820 DBusPreallocatedHash *preallocated)
822 DBusHashEntry *entry;
824 if (preallocated == NULL)
826 entry = alloc_entry (table);
836 entry = (DBusHashEntry*) preallocated;
839 add_allocated_entry (table, entry, idx, key, bucket);
844 /* This is g_str_hash from GLib which was
845 * extensively discussed/tested/profiled
848 string_hash (const char *str)
854 for (p += 1; *p != '\0'; p++)
855 h = (h << 5) - h + *p;
860 #ifdef DBUS_BUILD_TESTS
861 /* This hashes a memory block with two nul-terminated strings
862 * in it, used in dbus-object-registry.c at the moment.
865 two_strings_hash (const char *str)
871 for (p += 1; *p != '\0'; p++)
872 h = (h << 5) - h + *p;
874 for (p += 1; *p != '\0'; p++)
875 h = (h << 5) - h + *p;
879 #endif /* DBUS_BUILD_TESTS */
881 /** Key comparison function */
882 typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b);
884 static DBusHashEntry*
885 find_generic_function (DBusHashTable *table,
888 KeyCompareFunc compare_func,
889 dbus_bool_t create_if_not_found,
890 DBusHashEntry ***bucket,
891 DBusPreallocatedHash *preallocated)
893 DBusHashEntry *entry;
898 /* Search all of the entries in this bucket. */
899 entry = table->buckets[idx];
900 while (entry != NULL)
902 if ((compare_func == NULL && key == entry->key) ||
903 (compare_func != NULL && (* compare_func) (key, entry->key) == 0))
906 *bucket = &(table->buckets[idx]);
909 _dbus_hash_table_free_preallocated_entry (table, preallocated);
917 if (create_if_not_found)
918 entry = add_entry (table, idx, key, bucket, preallocated);
919 else if (preallocated)
920 _dbus_hash_table_free_preallocated_entry (table, preallocated);
925 static DBusHashEntry*
926 find_string_function (DBusHashTable *table,
928 dbus_bool_t create_if_not_found,
929 DBusHashEntry ***bucket,
930 DBusPreallocatedHash *preallocated)
934 idx = string_hash (key) & table->mask;
936 return find_generic_function (table, key, idx,
937 (KeyCompareFunc) strcmp, create_if_not_found, bucket,
941 #ifdef DBUS_BUILD_TESTS
943 two_strings_cmp (const char *a,
957 return strcmp (a + len_a + 1, b + len_b + 1);
961 #ifdef DBUS_BUILD_TESTS
962 static DBusHashEntry*
963 find_two_strings_function (DBusHashTable *table,
965 dbus_bool_t create_if_not_found,
966 DBusHashEntry ***bucket,
967 DBusPreallocatedHash *preallocated)
971 idx = two_strings_hash (key) & table->mask;
973 return find_generic_function (table, key, idx,
974 (KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket,
977 #endif /* DBUS_BUILD_TESTS */
979 static DBusHashEntry*
980 find_direct_function (DBusHashTable *table,
982 dbus_bool_t create_if_not_found,
983 DBusHashEntry ***bucket,
984 DBusPreallocatedHash *preallocated)
988 idx = RANDOM_INDEX (table, key) & table->mask;
991 return find_generic_function (table, key, idx,
992 NULL, create_if_not_found, bucket,
997 rebuild_table (DBusHashTable *table)
1001 DBusHashEntry **old_buckets;
1002 DBusHashEntry **old_chain;
1003 DBusHashEntry *entry;
1004 dbus_bool_t growing;
1007 * Allocate and initialize the new bucket array, and set up
1008 * hashing constants for new array size.
1011 growing = table->n_entries >= table->hi_rebuild_size;
1013 old_size = table->n_buckets;
1014 old_buckets = table->buckets;
1018 /* overflow paranoia */
1019 if (table->n_buckets < _DBUS_INT_MAX / 4 &&
1020 table->down_shift >= 0)
1021 new_buckets = table->n_buckets * 4;
1023 return; /* can't grow anymore */
1027 new_buckets = table->n_buckets / 4;
1028 if (new_buckets < DBUS_SMALL_HASH_TABLE)
1029 return; /* don't bother shrinking this far */
1032 table->buckets = dbus_new0 (DBusHashEntry*, new_buckets);
1033 if (table->buckets == NULL)
1035 /* out of memory, yay - just don't reallocate, the table will
1036 * still work, albeit more slowly.
1038 table->buckets = old_buckets;
1042 table->n_buckets = new_buckets;
1046 table->lo_rebuild_size = table->hi_rebuild_size;
1047 table->hi_rebuild_size *= 4;
1049 table->down_shift -= 2; /* keep 2 more high bits */
1050 table->mask = (table->mask << 2) + 3; /* keep 2 more high bits */
1054 table->hi_rebuild_size = table->lo_rebuild_size;
1055 table->lo_rebuild_size /= 4;
1057 table->down_shift += 2; /* keep 2 fewer high bits */
1058 table->mask = table->mask >> 2; /* keep 2 fewer high bits */
1062 printf ("%s table to lo = %d hi = %d downshift = %d mask = 0x%x\n",
1063 growing ? "GROW" : "SHRINK",
1064 table->lo_rebuild_size,
1065 table->hi_rebuild_size,
1070 _dbus_assert (table->lo_rebuild_size >= 0);
1071 _dbus_assert (table->hi_rebuild_size > table->lo_rebuild_size);
1072 _dbus_assert (table->mask != 0);
1073 /* the mask is essentially the max index */
1074 _dbus_assert (table->mask < table->n_buckets);
1077 * Rehash all of the existing entries into the new bucket array.
1080 for (old_chain = old_buckets; old_size > 0; old_size--, old_chain++)
1082 for (entry = *old_chain; entry != NULL; entry = *old_chain)
1085 DBusHashEntry **bucket;
1087 *old_chain = entry->next;
1088 switch (table->key_type)
1090 case DBUS_HASH_STRING:
1091 idx = string_hash (entry->key) & table->mask;
1093 case DBUS_HASH_TWO_STRINGS:
1094 #ifdef DBUS_BUILD_TESTS
1095 idx = two_strings_hash (entry->key) & table->mask;
1098 _dbus_assert_not_reached ("two-strings is not enabled");
1102 case DBUS_HASH_ULONG:
1103 case DBUS_HASH_POINTER:
1104 idx = RANDOM_INDEX (table, entry->key);
1108 _dbus_assert_not_reached ("Unknown hash table type");
1112 bucket = &(table->buckets[idx]);
1113 entry->next = *bucket;
1118 /* Free the old bucket array, if it was dynamically allocated. */
1120 if (old_buckets != table->static_buckets)
1121 dbus_free (old_buckets);
1125 * Looks up the value for a given string in a hash table
1126 * of type #DBUS_HASH_STRING. Returns %NULL if the value
1127 * is not present. (A not-present entry is indistinguishable
1128 * from an entry with a value of %NULL.)
1129 * @param table the hash table.
1130 * @param key the string to look up.
1131 * @returns the value of the hash entry.
1134 _dbus_hash_table_lookup_string (DBusHashTable *table,
1137 DBusHashEntry *entry;
1139 _dbus_assert (table->key_type == DBUS_HASH_STRING);
1141 entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
1144 return entry->value;
1149 #ifdef DBUS_BUILD_TESTS
1151 * Looks up the value for a given string in a hash table
1152 * of type #DBUS_HASH_TWO_STRINGS. Returns %NULL if the value
1153 * is not present. (A not-present entry is indistinguishable
1154 * from an entry with a value of %NULL.)
1155 * @param table the hash table.
1156 * @param key the string to look up.
1157 * @returns the value of the hash entry.
1160 _dbus_hash_table_lookup_two_strings (DBusHashTable *table,
1163 DBusHashEntry *entry;
1165 _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
1167 entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
1170 return entry->value;
1174 #endif /* DBUS_BUILD_TESTS */
1177 * Looks up the value for a given integer in a hash table
1178 * of type #DBUS_HASH_INT. Returns %NULL if the value
1179 * is not present. (A not-present entry is indistinguishable
1180 * from an entry with a value of %NULL.)
1181 * @param table the hash table.
1182 * @param key the integer to look up.
1183 * @returns the value of the hash entry.
1186 _dbus_hash_table_lookup_int (DBusHashTable *table,
1189 DBusHashEntry *entry;
1191 _dbus_assert (table->key_type == DBUS_HASH_INT);
1193 entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, NULL, NULL);
1196 return entry->value;
1201 #ifdef DBUS_BUILD_TESTS
1202 /* disabled since it's only used for testing */
1204 * Looks up the value for a given integer in a hash table
1205 * of type #DBUS_HASH_POINTER. Returns %NULL if the value
1206 * is not present. (A not-present entry is indistinguishable
1207 * from an entry with a value of %NULL.)
1208 * @param table the hash table.
1209 * @param key the integer to look up.
1210 * @returns the value of the hash entry.
1213 _dbus_hash_table_lookup_pointer (DBusHashTable *table,
1216 DBusHashEntry *entry;
1218 _dbus_assert (table->key_type == DBUS_HASH_POINTER);
1220 entry = (* table->find_function) (table, key, FALSE, NULL, NULL);
1223 return entry->value;
1227 #endif /* DBUS_BUILD_TESTS */
1230 * Looks up the value for a given integer in a hash table
1231 * of type #DBUS_HASH_ULONG. Returns %NULL if the value
1232 * is not present. (A not-present entry is indistinguishable
1233 * from an entry with a value of %NULL.)
1234 * @param table the hash table.
1235 * @param key the integer to look up.
1236 * @returns the value of the hash entry.
1239 _dbus_hash_table_lookup_ulong (DBusHashTable *table,
1242 DBusHashEntry *entry;
1244 _dbus_assert (table->key_type == DBUS_HASH_ULONG);
1246 entry = (* table->find_function) (table, (void*) key, FALSE, NULL, NULL);
1249 return entry->value;
1255 * Removes the hash entry for the given key. If no hash entry
1256 * for the key exists, does nothing.
1258 * @param table the hash table.
1259 * @param key the hash key.
1260 * @returns #TRUE if the entry existed
1263 _dbus_hash_table_remove_string (DBusHashTable *table,
1266 DBusHashEntry *entry;
1267 DBusHashEntry **bucket;
1269 _dbus_assert (table->key_type == DBUS_HASH_STRING);
1271 entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
1275 remove_entry (table, bucket, entry);
1282 #ifdef DBUS_BUILD_TESTS
1284 * Removes the hash entry for the given key. If no hash entry
1285 * for the key exists, does nothing.
1287 * @param table the hash table.
1288 * @param key the hash key.
1289 * @returns #TRUE if the entry existed
1292 _dbus_hash_table_remove_two_strings (DBusHashTable *table,
1295 DBusHashEntry *entry;
1296 DBusHashEntry **bucket;
1298 _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
1300 entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
1304 remove_entry (table, bucket, entry);
1310 #endif /* DBUS_BUILD_TESTS */
1313 * Removes the hash entry for the given key. If no hash entry
1314 * for the key exists, does nothing.
1316 * @param table the hash table.
1317 * @param key the hash key.
1318 * @returns #TRUE if the entry existed
1321 _dbus_hash_table_remove_int (DBusHashTable *table,
1324 DBusHashEntry *entry;
1325 DBusHashEntry **bucket;
1327 _dbus_assert (table->key_type == DBUS_HASH_INT);
1329 entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, &bucket, NULL);
1333 remove_entry (table, bucket, entry);
1340 #ifdef DBUS_BUILD_TESTS
1341 /* disabled since it's only used for testing */
1343 * Removes the hash entry for the given key. If no hash entry
1344 * for the key exists, does nothing.
1346 * @param table the hash table.
1347 * @param key the hash key.
1348 * @returns #TRUE if the entry existed
1351 _dbus_hash_table_remove_pointer (DBusHashTable *table,
1354 DBusHashEntry *entry;
1355 DBusHashEntry **bucket;
1357 _dbus_assert (table->key_type == DBUS_HASH_POINTER);
1359 entry = (* table->find_function) (table, key, FALSE, &bucket, NULL);
1363 remove_entry (table, bucket, entry);
1369 #endif /* DBUS_BUILD_TESTS */
1372 * Removes the hash entry for the given key. If no hash entry
1373 * for the key exists, does nothing.
1375 * @param table the hash table.
1376 * @param key the hash key.
1377 * @returns #TRUE if the entry existed
1380 _dbus_hash_table_remove_ulong (DBusHashTable *table,
1383 DBusHashEntry *entry;
1384 DBusHashEntry **bucket;
1386 _dbus_assert (table->key_type == DBUS_HASH_ULONG);
1388 entry = (* table->find_function) (table, (void*) key, FALSE, &bucket, NULL);
1392 remove_entry (table, bucket, entry);
1400 * Creates a hash entry with the given key and value.
1401 * The key and value are not copied; they are stored
1402 * in the hash table by reference. If an entry with the
1403 * given key already exists, the previous key and value
1404 * are overwritten (and freed if the hash table has
1405 * a key_free_function and/or value_free_function).
1407 * Returns #FALSE if memory for the new hash entry
1408 * can't be allocated.
1410 * @param table the hash table.
1411 * @param key the hash entry key.
1412 * @param value the hash entry value.
1415 _dbus_hash_table_insert_string (DBusHashTable *table,
1419 DBusPreallocatedHash *preallocated;
1421 _dbus_assert (table->key_type == DBUS_HASH_STRING);
1423 preallocated = _dbus_hash_table_preallocate_entry (table);
1424 if (preallocated == NULL)
1427 _dbus_hash_table_insert_string_preallocated (table, preallocated,
1433 #ifdef DBUS_BUILD_TESTS
1435 * Creates a hash entry with the given key and value.
1436 * The key and value are not copied; they are stored
1437 * in the hash table by reference. If an entry with the
1438 * given key already exists, the previous key and value
1439 * are overwritten (and freed if the hash table has
1440 * a key_free_function and/or value_free_function).
1442 * Returns #FALSE if memory for the new hash entry
1443 * can't be allocated.
1445 * @param table the hash table.
1446 * @param key the hash entry key.
1447 * @param value the hash entry value.
1450 _dbus_hash_table_insert_two_strings (DBusHashTable *table,
1454 DBusHashEntry *entry;
1456 _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
1458 entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
1461 return FALSE; /* no memory */
1463 if (table->free_key_function && entry->key != key)
1464 (* table->free_key_function) (entry->key);
1466 if (table->free_value_function && entry->value != value)
1467 (* table->free_value_function) (entry->value);
1470 entry->value = value;
1474 #endif /* DBUS_BUILD_TESTS */
1477 * Creates a hash entry with the given key and value.
1478 * The key and value are not copied; they are stored
1479 * in the hash table by reference. If an entry with the
1480 * given key already exists, the previous key and value
1481 * are overwritten (and freed if the hash table has
1482 * a key_free_function and/or value_free_function).
1484 * Returns #FALSE if memory for the new hash entry
1485 * can't be allocated.
1487 * @param table the hash table.
1488 * @param key the hash entry key.
1489 * @param value the hash entry value.
1492 _dbus_hash_table_insert_int (DBusHashTable *table,
1496 DBusHashEntry *entry;
1498 _dbus_assert (table->key_type == DBUS_HASH_INT);
1500 entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), TRUE, NULL, NULL);
1503 return FALSE; /* no memory */
1505 if (table->free_key_function && entry->key != _DBUS_INT_TO_POINTER (key))
1506 (* table->free_key_function) (entry->key);
1508 if (table->free_value_function && entry->value != value)
1509 (* table->free_value_function) (entry->value);
1511 entry->key = _DBUS_INT_TO_POINTER (key);
1512 entry->value = value;
1517 #ifdef DBUS_BUILD_TESTS
1518 /* disabled since it's only used for testing */
1520 * Creates a hash entry with the given key and value.
1521 * The key and value are not copied; they are stored
1522 * in the hash table by reference. If an entry with the
1523 * given key already exists, the previous key and value
1524 * are overwritten (and freed if the hash table has
1525 * a key_free_function and/or value_free_function).
1527 * Returns #FALSE if memory for the new hash entry
1528 * can't be allocated.
1530 * @param table the hash table.
1531 * @param key the hash entry key.
1532 * @param value the hash entry value.
1535 _dbus_hash_table_insert_pointer (DBusHashTable *table,
1539 DBusHashEntry *entry;
1541 _dbus_assert (table->key_type == DBUS_HASH_POINTER);
1543 entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
1546 return FALSE; /* no memory */
1548 if (table->free_key_function && entry->key != key)
1549 (* table->free_key_function) (entry->key);
1551 if (table->free_value_function && entry->value != value)
1552 (* table->free_value_function) (entry->value);
1555 entry->value = value;
1559 #endif /* DBUS_BUILD_TESTS */
1562 * Creates a hash entry with the given key and value.
1563 * The key and value are not copied; they are stored
1564 * in the hash table by reference. If an entry with the
1565 * given key already exists, the previous key and value
1566 * are overwritten (and freed if the hash table has
1567 * a key_free_function and/or value_free_function).
1569 * Returns #FALSE if memory for the new hash entry
1570 * can't be allocated.
1572 * @param table the hash table.
1573 * @param key the hash entry key.
1574 * @param value the hash entry value.
1577 _dbus_hash_table_insert_ulong (DBusHashTable *table,
1581 DBusHashEntry *entry;
1583 _dbus_assert (table->key_type == DBUS_HASH_ULONG);
1585 entry = (* table->find_function) (table, (void*) key, TRUE, NULL, NULL);
1588 return FALSE; /* no memory */
1590 if (table->free_key_function && entry->key != (void*) key)
1591 (* table->free_key_function) (entry->key);
1593 if (table->free_value_function && entry->value != value)
1594 (* table->free_value_function) (entry->value);
1596 entry->key = (void*) key;
1597 entry->value = value;
1603 * Preallocate an opaque data blob that allows us to insert into the
1604 * hash table at a later time without allocating any memory.
1606 * @param table the hash table
1607 * @returns the preallocated data, or #NULL if no memory
1609 DBusPreallocatedHash*
1610 _dbus_hash_table_preallocate_entry (DBusHashTable *table)
1612 DBusHashEntry *entry;
1614 entry = alloc_entry (table);
1616 return (DBusPreallocatedHash*) entry;
1620 * Frees an opaque DBusPreallocatedHash that was *not* used
1621 * in order to insert into the hash table.
1623 * @param table the hash table
1624 * @param preallocated the preallocated data
1627 _dbus_hash_table_free_preallocated_entry (DBusHashTable *table,
1628 DBusPreallocatedHash *preallocated)
1630 DBusHashEntry *entry;
1632 _dbus_assert (preallocated != NULL);
1634 entry = (DBusHashEntry*) preallocated;
1636 /* Don't use free_entry(), since this entry has no key/data */
1637 _dbus_mem_pool_dealloc (table->entry_pool, entry);
1641 * Inserts a string-keyed entry into the hash table, using a
1642 * preallocated data block from
1643 * _dbus_hash_table_preallocate_entry(). This function cannot fail due
1644 * to lack of memory. The DBusPreallocatedHash object is consumed and
1645 * should not be reused or freed. Otherwise this function works
1646 * just like _dbus_hash_table_insert_string().
1648 * @param table the hash table
1649 * @param preallocated the preallocated data
1650 * @param key the hash key
1651 * @param value the value
1654 _dbus_hash_table_insert_string_preallocated (DBusHashTable *table,
1655 DBusPreallocatedHash *preallocated,
1659 DBusHashEntry *entry;
1661 _dbus_assert (table->key_type == DBUS_HASH_STRING);
1662 _dbus_assert (preallocated != NULL);
1664 entry = (* table->find_function) (table, key, TRUE, NULL, preallocated);
1666 _dbus_assert (entry != NULL);
1668 if (table->free_key_function && entry->key != key)
1669 (* table->free_key_function) (entry->key);
1671 if (table->free_value_function && entry->value != value)
1672 (* table->free_value_function) (entry->value);
1675 entry->value = value;
1679 * Gets the number of hash entries in a hash table.
1681 * @param table the hash table.
1682 * @returns the number of entries in the table.
1685 _dbus_hash_table_get_n_entries (DBusHashTable *table)
1687 return table->n_entries;
1692 #ifdef DBUS_BUILD_TESTS
1693 #include "dbus-test.h"
1696 /* If you're wondering why the hash table test takes
1697 * forever to run, it's because we call this function
1698 * in inner loops thus making things quadratic.
1701 count_entries (DBusHashTable *table)
1707 _dbus_hash_iter_init (table, &iter);
1708 while (_dbus_hash_iter_next (&iter))
1711 _dbus_assert (count == _dbus_hash_table_get_n_entries (table));
1716 /* Copy the foo\0bar\0 double string thing */
1718 _dbus_strdup2 (const char *str)
1727 len += strlen ((str + len + 1));
1729 copy = dbus_malloc (len + 2);
1733 memcpy (copy, str, len + 2);
1739 * @ingroup DBusHashTableInternals
1740 * Unit test for DBusHashTable
1741 * @returns #TRUE on success.
1744 _dbus_hash_test (void)
1747 DBusHashTable *table1;
1748 DBusHashTable *table2;
1749 DBusHashTable *table3;
1750 DBusHashTable *table4;
1752 #define N_HASH_KEYS 5000
1754 dbus_bool_t ret = FALSE;
1756 keys = dbus_new (char *, N_HASH_KEYS);
1758 _dbus_assert_not_reached ("no memory");
1760 for (i = 0; i < N_HASH_KEYS; i++)
1762 keys[i] = dbus_malloc (128);
1764 if (keys[i] == NULL)
1765 _dbus_assert_not_reached ("no memory");
1768 printf ("Computing test hash keys...\n");
1770 while (i < N_HASH_KEYS)
1774 /* all the hash keys are TWO_STRINGS, but
1775 * then we can also use those as regular strings.
1778 len = sprintf (keys[i], "Hash key %d", i);
1779 sprintf (keys[i] + len + 1, "Two string %d", i);
1780 _dbus_assert (*(keys[i] + len) == '\0');
1781 _dbus_assert (*(keys[i] + len + 1) != '\0');
1784 printf ("... done.\n");
1786 table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
1787 dbus_free, dbus_free);
1791 table2 = _dbus_hash_table_new (DBUS_HASH_INT,
1796 table3 = _dbus_hash_table_new (DBUS_HASH_ULONG,
1801 table4 = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS,
1802 dbus_free, dbus_free);
1807 /* Insert and remove a bunch of stuff, counting the table in between
1808 * to be sure it's not broken and that iteration works
1816 key = _dbus_strdup (keys[i]);
1819 value = _dbus_strdup ("Value!");
1823 if (!_dbus_hash_table_insert_string (table1,
1827 value = _dbus_strdup (keys[i]);
1831 if (!_dbus_hash_table_insert_int (table2,
1835 value = _dbus_strdup (keys[i]);
1839 if (!_dbus_hash_table_insert_ulong (table3,
1843 key = _dbus_strdup2 (keys[i]);
1846 value = _dbus_strdup ("Value!");
1850 if (!_dbus_hash_table_insert_two_strings (table4,
1854 _dbus_assert (count_entries (table1) == i + 1);
1855 _dbus_assert (count_entries (table2) == i + 1);
1856 _dbus_assert (count_entries (table3) == i + 1);
1857 _dbus_assert (count_entries (table4) == i + 1);
1859 value = _dbus_hash_table_lookup_string (table1, keys[i]);
1860 _dbus_assert (value != NULL);
1861 _dbus_assert (strcmp (value, "Value!") == 0);
1863 value = _dbus_hash_table_lookup_int (table2, i);
1864 _dbus_assert (value != NULL);
1865 _dbus_assert (strcmp (value, keys[i]) == 0);
1867 value = _dbus_hash_table_lookup_ulong (table3, i);
1868 _dbus_assert (value != NULL);
1869 _dbus_assert (strcmp (value, keys[i]) == 0);
1871 value = _dbus_hash_table_lookup_two_strings (table4, keys[i]);
1872 _dbus_assert (value != NULL);
1873 _dbus_assert (strcmp (value, "Value!") == 0);
1881 _dbus_hash_table_remove_string (table1,
1884 _dbus_hash_table_remove_int (table2, i);
1886 _dbus_hash_table_remove_ulong (table3, i);
1888 _dbus_hash_table_remove_two_strings (table4,
1891 _dbus_assert (count_entries (table1) == i);
1892 _dbus_assert (count_entries (table2) == i);
1893 _dbus_assert (count_entries (table3) == i);
1894 _dbus_assert (count_entries (table4) == i);
1899 _dbus_hash_table_ref (table1);
1900 _dbus_hash_table_ref (table2);
1901 _dbus_hash_table_ref (table3);
1902 _dbus_hash_table_ref (table4);
1903 _dbus_hash_table_unref (table1);
1904 _dbus_hash_table_unref (table2);
1905 _dbus_hash_table_unref (table3);
1906 _dbus_hash_table_unref (table4);
1907 _dbus_hash_table_unref (table1);
1908 _dbus_hash_table_unref (table2);
1909 _dbus_hash_table_unref (table3);
1910 _dbus_hash_table_unref (table4);
1913 /* Insert a bunch of stuff then check
1914 * that iteration works correctly (finds the right
1915 * values, iter_set_value works, etc.)
1917 table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
1918 dbus_free, dbus_free);
1922 table2 = _dbus_hash_table_new (DBUS_HASH_INT,
1933 key = _dbus_strdup (keys[i]);
1936 value = _dbus_strdup ("Value!");
1940 if (!_dbus_hash_table_insert_string (table1,
1944 value = _dbus_strdup (keys[i]);
1948 if (!_dbus_hash_table_insert_int (table2,
1952 _dbus_assert (count_entries (table1) == i + 1);
1953 _dbus_assert (count_entries (table2) == i + 1);
1958 _dbus_hash_iter_init (table1, &iter);
1959 while (_dbus_hash_iter_next (&iter))
1964 key = _dbus_hash_iter_get_string_key (&iter);
1965 value = _dbus_hash_iter_get_value (&iter);
1967 _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value);
1969 value = _dbus_strdup ("Different value!");
1973 _dbus_hash_iter_set_value (&iter, value);
1975 _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value);
1978 _dbus_hash_iter_init (table1, &iter);
1979 while (_dbus_hash_iter_next (&iter))
1981 _dbus_hash_iter_remove_entry (&iter);
1982 _dbus_assert (count_entries (table1) == i - 1);
1986 _dbus_hash_iter_init (table2, &iter);
1987 while (_dbus_hash_iter_next (&iter))
1992 key = _dbus_hash_iter_get_int_key (&iter);
1993 value = _dbus_hash_iter_get_value (&iter);
1995 _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value);
1997 value = _dbus_strdup ("Different value!");
2001 _dbus_hash_iter_set_value (&iter, value);
2003 _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value);
2006 i = count_entries (table2);
2007 _dbus_hash_iter_init (table2, &iter);
2008 while (_dbus_hash_iter_next (&iter))
2010 _dbus_hash_iter_remove_entry (&iter);
2011 _dbus_assert (count_entries (table2) + 1 == i);
2015 /* add/remove interleaved, to check that we grow/shrink the table
2024 key = _dbus_strdup (keys[i]);
2028 value = _dbus_strdup ("Value!");
2032 if (!_dbus_hash_table_insert_string (table1,
2045 key = _dbus_strdup (keys[i]);
2048 value = _dbus_strdup ("Value!");
2052 if (!_dbus_hash_table_remove_string (table1, keys[i]))
2055 if (!_dbus_hash_table_insert_string (table1,
2059 if (!_dbus_hash_table_remove_string (table1, keys[i]))
2062 _dbus_assert (_dbus_hash_table_get_n_entries (table1) == i);
2067 /* nuke these tables */
2068 _dbus_hash_table_unref (table1);
2069 _dbus_hash_table_unref (table2);
2072 /* Now do a bunch of things again using _dbus_hash_iter_lookup() to
2073 * be sure that interface works.
2075 table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
2076 dbus_free, dbus_free);
2080 table2 = _dbus_hash_table_new (DBUS_HASH_INT,
2091 key = _dbus_strdup (keys[i]);
2094 value = _dbus_strdup ("Value!");
2098 if (!_dbus_hash_iter_lookup (table1,
2101 _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL);
2102 _dbus_hash_iter_set_value (&iter, value);
2104 value = _dbus_strdup (keys[i]);
2108 if (!_dbus_hash_iter_lookup (table2,
2109 _DBUS_INT_TO_POINTER (i), TRUE, &iter))
2111 _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL);
2112 _dbus_hash_iter_set_value (&iter, value);
2114 _dbus_assert (count_entries (table1) == i + 1);
2115 _dbus_assert (count_entries (table2) == i + 1);
2117 if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter))
2120 value = _dbus_hash_iter_get_value (&iter);
2121 _dbus_assert (value != NULL);
2122 _dbus_assert (strcmp (value, "Value!") == 0);
2124 /* Iterate just to be sure it works, though
2125 * it's a stupid thing to do
2127 while (_dbus_hash_iter_next (&iter))
2130 if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter))
2133 value = _dbus_hash_iter_get_value (&iter);
2134 _dbus_assert (value != NULL);
2135 _dbus_assert (strcmp (value, keys[i]) == 0);
2137 /* Iterate just to be sure it works, though
2138 * it's a stupid thing to do
2140 while (_dbus_hash_iter_next (&iter))
2149 if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter))
2150 _dbus_assert_not_reached ("hash entry should have existed");
2151 _dbus_hash_iter_remove_entry (&iter);
2153 if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter))
2154 _dbus_assert_not_reached ("hash entry should have existed");
2155 _dbus_hash_iter_remove_entry (&iter);
2157 _dbus_assert (count_entries (table1) == i);
2158 _dbus_assert (count_entries (table2) == i);
2163 _dbus_hash_table_unref (table1);
2164 _dbus_hash_table_unref (table2);
2169 for (i = 0; i < N_HASH_KEYS; i++)
2170 dbus_free (keys[i]);
2177 #endif /* DBUS_BUILD_TESTS */