• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-hash.c Generic hash table utility (internal to D-Bus implementation)
3  *
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.
7  *
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.
12  *
13  * Licensed under the Academic Free License version 2.1
14  *
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.
19  *
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.
24  *
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
28  *
29  */
30 /*
31  * The following copyright applies to code from the Tcl distribution.
32  *
33  * Copyright (c) 1991-1993 The Regents of the University of California.
34  * Copyright (c) 1994 Sun Microsystems, Inc.
35  *
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.
40  *
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.
50  *
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.
56  *
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.
63  *
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.
75  */
76 
77 #include <config.h>
78 #include "dbus-hash.h"
79 #include "dbus-internals.h"
80 #include "dbus-mempool.h"
81 
82 /**
83  * @defgroup DBusHashTable Hash table
84  * @ingroup  DBusInternals
85  * @brief DBusHashTable data structure
86  *
87  * Types and functions related to DBusHashTable.
88  */
89 
90 /**
91  * @defgroup DBusHashTableInternals Hash table implementation details
92  * @ingroup  DBusInternals
93  * @brief DBusHashTable implementation details
94  *
95  * The guts of DBusHashTable.
96  *
97  * @{
98  */
99 
100 /**
101  * When there are this many entries per bucket, on average, rebuild
102  * the hash table to make it larger.
103  */
104 #define REBUILD_MULTIPLIER  3
105 
106 /**
107  * Takes a preliminary integer hash value and produces an index into a
108  * hash tables bucket list.  The idea is to make it so that
109  * preliminary values that are arbitrarily similar will end up in
110  * different buckets.  The hash function was taken from a
111  * random-number generator. (This is used to hash integers.)
112  *
113  * The down_shift drops off the high bits of the hash index, and
114  * decreases as we increase the number of hash buckets (to keep more
115  * range in the hash index). The mask also strips high bits and strips
116  * fewer high bits as the number of hash buckets increases.
117  * I don't understand two things: why is the initial downshift 28
118  * to keep 4 bits when the initial mask is 011 to keep 2 bits,
119  * and why do we have both a mask and a downshift?
120  *
121  */
122 #define RANDOM_INDEX(table, i) \
123     (((((intptr_t) (i))*1103515245) >> (table)->down_shift) & (table)->mask)
124 
125 /**
126  * Initial number of buckets in hash table (hash table statically
127  * allocates its buckets for this size and below).
128  * The initial mask has to be synced to this.
129  */
130 #define DBUS_SMALL_HASH_TABLE 4
131 
132 /**
133  * Typedef for DBusHashEntry
134  */
135 typedef struct DBusHashEntry DBusHashEntry;
136 
137 /**
138  * @brief Internal representation of a hash entry.
139  *
140  * A single entry (key-value pair) in the hash table.
141  * Internal to hash table implementation.
142  */
143 struct DBusHashEntry
144 {
145   DBusHashEntry *next;    /**< Pointer to next entry in this
146                            * hash bucket, or #NULL for end of
147                            * chain.
148                            */
149   void *key;              /**< Hash key */
150   void *value;            /**< Hash value */
151 };
152 
153 /**
154  * Function used to find and optionally create a hash entry.
155  */
156 typedef DBusHashEntry* (* DBusFindEntryFunction) (DBusHashTable        *table,
157                                                   void                 *key,
158                                                   dbus_bool_t           create_if_not_found,
159                                                   DBusHashEntry      ***bucket,
160                                                   DBusPreallocatedHash *preallocated);
161 
162 /**
163  * @brief Internals of DBusHashTable.
164  *
165  * Hash table internals. Hash tables are opaque objects, they must be
166  * used via accessor functions.
167  */
168 struct DBusHashTable {
169   int refcount;                       /**< Reference count */
170 
171   DBusHashEntry **buckets;            /**< Pointer to bucket array.  Each
172                                        * element points to first entry in
173                                        * bucket's hash chain, or #NULL.
174                                        */
175   DBusHashEntry *static_buckets[DBUS_SMALL_HASH_TABLE];
176                                        /**< Bucket array used for small tables
177                                         * (to avoid mallocs and frees).
178                                         */
179   int n_buckets;                       /**< Total number of buckets allocated
180                                         * at **buckets.
181                                         */
182   int n_entries;                       /**< Total number of entries present
183                                         * in table.
184                                         */
185   int hi_rebuild_size;                 /**< Enlarge table when n_entries gets
186                                         * to be this large.
187                                         */
188   int lo_rebuild_size;                 /**< Shrink table when n_entries gets
189                                         * below this.
190                                         */
191   int down_shift;                      /**< Shift count used in hashing
192                                         * function.  Designed to use high-
193                                         * order bits of randomized keys.
194                                         */
195   int mask;                            /**< Mask value used in hashing
196                                         * function.
197                                         */
198   DBusHashType key_type;               /**< Type of keys used in this table */
199 
200 
201   DBusFindEntryFunction find_function; /**< Function for finding entries */
202 
203   DBusFreeFunction free_key_function;   /**< Function to free keys */
204   DBusFreeFunction free_value_function; /**< Function to free values */
205 
206   DBusMemPool *entry_pool;              /**< Memory pool for hash entries */
207 };
208 
209 /**
210  * @brief Internals of DBusHashIter.
211  */
212 typedef struct
213 {
214   DBusHashTable *table;     /**< Pointer to table containing entry. */
215   DBusHashEntry **bucket;   /**< Pointer to bucket that points to
216                              * first entry in this entry's chain:
217                              * used for deleting the entry.
218                              */
219   DBusHashEntry *entry;      /**< Current hash entry */
220   DBusHashEntry *next_entry; /**< Next entry to be iterated onto in current bucket */
221   int next_bucket;           /**< index of next bucket */
222   int n_entries_on_init;     /**< used to detect table resize since initialization */
223 } DBusRealHashIter;
224 
225 static DBusHashEntry* find_direct_function      (DBusHashTable          *table,
226                                                  void                   *key,
227                                                  dbus_bool_t             create_if_not_found,
228                                                  DBusHashEntry        ***bucket,
229                                                  DBusPreallocatedHash   *preallocated);
230 static DBusHashEntry* find_string_function      (DBusHashTable          *table,
231                                                  void                   *key,
232                                                  dbus_bool_t             create_if_not_found,
233                                                  DBusHashEntry        ***bucket,
234                                                  DBusPreallocatedHash   *preallocated);
235 #ifdef DBUS_BUILD_TESTS
236 static DBusHashEntry* find_two_strings_function (DBusHashTable          *table,
237                                                  void                   *key,
238                                                  dbus_bool_t             create_if_not_found,
239                                                  DBusHashEntry        ***bucket,
240                                                  DBusPreallocatedHash   *preallocated);
241 #endif
242 static unsigned int   string_hash               (const char             *str);
243 #ifdef DBUS_BUILD_TESTS
244 static unsigned int   two_strings_hash          (const char             *str);
245 #endif
246 static void           rebuild_table             (DBusHashTable          *table);
247 static DBusHashEntry* alloc_entry               (DBusHashTable          *table);
248 static void           remove_entry              (DBusHashTable          *table,
249                                                  DBusHashEntry         **bucket,
250                                                  DBusHashEntry          *entry);
251 static void           free_entry                (DBusHashTable          *table,
252                                                  DBusHashEntry          *entry);
253 static void           free_entry_data           (DBusHashTable          *table,
254                                                  DBusHashEntry          *entry);
255 
256 
257 /** @} */
258 
259 /**
260  * @addtogroup DBusHashTable
261  * @{
262  */
263 
264 /**
265  * @typedef DBusHashIter
266  *
267  * Public opaque hash table iterator object.
268  */
269 
270 /**
271  * @typedef DBusHashTable
272  *
273  * Public opaque hash table object.
274  */
275 
276 /**
277  * @typedef DBusHashType
278  *
279  * Indicates the type of a key in the hash table.
280  */
281 
282 /**
283  * Constructs a new hash table. Should be freed with
284  * _dbus_hash_table_unref(). If memory cannot be
285  * allocated for the hash table, returns #NULL.
286  *
287  * @param type the type of hash key to use.
288  * @param key_free_function function to free hash keys.
289  * @param value_free_function function to free hash values.
290  * @returns a new DBusHashTable or #NULL if no memory.
291  */
292 DBusHashTable*
_dbus_hash_table_new(DBusHashType type,DBusFreeFunction key_free_function,DBusFreeFunction value_free_function)293 _dbus_hash_table_new (DBusHashType     type,
294                       DBusFreeFunction key_free_function,
295                       DBusFreeFunction value_free_function)
296 {
297   DBusHashTable *table;
298   DBusMemPool *entry_pool;
299 
300   table = dbus_new0 (DBusHashTable, 1);
301   if (table == NULL)
302     return NULL;
303 
304   entry_pool = _dbus_mem_pool_new (sizeof (DBusHashEntry), TRUE);
305   if (entry_pool == NULL)
306     {
307       dbus_free (table);
308       return NULL;
309     }
310 
311   table->refcount = 1;
312   table->entry_pool = entry_pool;
313 
314   _dbus_assert (DBUS_SMALL_HASH_TABLE == _DBUS_N_ELEMENTS (table->static_buckets));
315 
316   table->buckets = table->static_buckets;
317   table->n_buckets = DBUS_SMALL_HASH_TABLE;
318   table->n_entries = 0;
319   table->hi_rebuild_size = DBUS_SMALL_HASH_TABLE * REBUILD_MULTIPLIER;
320   table->lo_rebuild_size = 0;
321   table->down_shift = 28;
322   table->mask = 3;
323   table->key_type = type;
324 
325   _dbus_assert (table->mask < table->n_buckets);
326 
327   switch (table->key_type)
328     {
329     case DBUS_HASH_INT:
330     case DBUS_HASH_POINTER:
331     case DBUS_HASH_UINTPTR:
332       table->find_function = find_direct_function;
333       break;
334     case DBUS_HASH_STRING:
335       table->find_function = find_string_function;
336       break;
337     case DBUS_HASH_TWO_STRINGS:
338 #ifdef DBUS_BUILD_TESTS
339       table->find_function = find_two_strings_function;
340 #endif
341       break;
342     default:
343       _dbus_assert_not_reached ("Unknown hash table type");
344       break;
345     }
346 
347   table->free_key_function = key_free_function;
348   table->free_value_function = value_free_function;
349 
350   return table;
351 }
352 
353 
354 /**
355  * Increments the reference count for a hash table.
356  *
357  * @param table the hash table to add a reference to.
358  * @returns the hash table.
359  */
360 DBusHashTable *
_dbus_hash_table_ref(DBusHashTable * table)361 _dbus_hash_table_ref (DBusHashTable *table)
362 {
363   table->refcount += 1;
364 
365   return table;
366 }
367 
368 /**
369  * Decrements the reference count for a hash table,
370  * freeing the hash table if the count reaches zero.
371  *
372  * @param table the hash table to remove a reference from.
373  */
374 void
_dbus_hash_table_unref(DBusHashTable * table)375 _dbus_hash_table_unref (DBusHashTable *table)
376 {
377   table->refcount -= 1;
378 
379   if (table->refcount == 0)
380     {
381 #if 0
382       DBusHashEntry *entry;
383       DBusHashEntry *next;
384       int i;
385 
386       /* Free the entries in the table. */
387       for (i = 0; i < table->n_buckets; i++)
388         {
389           entry = table->buckets[i];
390           while (entry != NULL)
391             {
392               next = entry->next;
393 
394               free_entry (table, entry);
395 
396               entry = next;
397             }
398         }
399 #else
400       DBusHashEntry *entry;
401       int i;
402 
403       /* Free the entries in the table. */
404       for (i = 0; i < table->n_buckets; i++)
405         {
406           entry = table->buckets[i];
407           while (entry != NULL)
408             {
409               free_entry_data (table, entry);
410 
411               entry = entry->next;
412             }
413         }
414       /* We can do this very quickly with memory pools ;-) */
415       _dbus_mem_pool_free (table->entry_pool);
416 #endif
417 
418       /* Free the bucket array, if it was dynamically allocated. */
419       if (table->buckets != table->static_buckets)
420         dbus_free (table->buckets);
421 
422       dbus_free (table);
423     }
424 }
425 
426 /**
427  * Removed all entries from a hash table.
428  *
429  * @param table the hash table to remove all entries from.
430  */
431 void
_dbus_hash_table_remove_all(DBusHashTable * table)432 _dbus_hash_table_remove_all (DBusHashTable *table)
433 {
434   DBusHashIter iter;
435   _dbus_hash_iter_init (table, &iter);
436   while (_dbus_hash_iter_next (&iter))
437     {
438       _dbus_hash_iter_remove_entry(&iter);
439     }
440 }
441 
442 static DBusHashEntry*
alloc_entry(DBusHashTable * table)443 alloc_entry (DBusHashTable *table)
444 {
445   DBusHashEntry *entry;
446 
447   entry = _dbus_mem_pool_alloc (table->entry_pool);
448 
449   return entry;
450 }
451 
452 static void
free_entry_data(DBusHashTable * table,DBusHashEntry * entry)453 free_entry_data (DBusHashTable  *table,
454 		 DBusHashEntry  *entry)
455 {
456   if (table->free_key_function)
457     (* table->free_key_function) (entry->key);
458   if (table->free_value_function)
459     (* table->free_value_function) (entry->value);
460 }
461 
462 static void
free_entry(DBusHashTable * table,DBusHashEntry * entry)463 free_entry (DBusHashTable  *table,
464             DBusHashEntry  *entry)
465 {
466   free_entry_data (table, entry);
467   _dbus_mem_pool_dealloc (table->entry_pool, entry);
468 }
469 
470 static void
remove_entry(DBusHashTable * table,DBusHashEntry ** bucket,DBusHashEntry * entry)471 remove_entry (DBusHashTable  *table,
472               DBusHashEntry **bucket,
473               DBusHashEntry  *entry)
474 {
475   _dbus_assert (table != NULL);
476   _dbus_assert (bucket != NULL);
477   _dbus_assert (*bucket != NULL);
478   _dbus_assert (entry != NULL);
479 
480   if (*bucket == entry)
481     *bucket = entry->next;
482   else
483     {
484       DBusHashEntry *prev;
485       prev = *bucket;
486 
487       while (prev->next != entry)
488         prev = prev->next;
489 
490       _dbus_assert (prev != NULL);
491 
492       prev->next = entry->next;
493     }
494 
495   table->n_entries -= 1;
496   free_entry (table, entry);
497 }
498 
499 /**
500  * Initializes a hash table iterator. To iterate over all entries in a
501  * hash table, use the following code (the printf assumes a hash
502  * from strings to strings obviously):
503  *
504  * @code
505  * DBusHashIter iter;
506  *
507  * _dbus_hash_iter_init (table, &iter);
508  * while (_dbus_hash_iter_next (&iter))
509  *   {
510  *      printf ("The first key is %s and value is %s\n",
511  *              _dbus_hash_iter_get_string_key (&iter),
512  *              _dbus_hash_iter_get_value (&iter));
513  *   }
514  *
515  *
516  * @endcode
517  *
518  * The iterator is initialized pointing "one before" the first hash
519  * entry. The first call to _dbus_hash_iter_next() moves it onto
520  * the first valid entry or returns #FALSE if the hash table is
521  * empty. Subsequent calls move to the next valid entry or return
522  * #FALSE if there are no more entries.
523  *
524  * Note that it is guaranteed to be safe to remove a hash entry during
525  * iteration, but it is not safe to add a hash entry.
526  *
527  * @param table the hash table to iterate over.
528  * @param iter the iterator to initialize.
529  */
530 void
_dbus_hash_iter_init(DBusHashTable * table,DBusHashIter * iter)531 _dbus_hash_iter_init (DBusHashTable *table,
532                       DBusHashIter  *iter)
533 {
534   DBusRealHashIter *real;
535 
536   _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
537 
538   real = (DBusRealHashIter*) iter;
539 
540   real->table = table;
541   real->bucket = NULL;
542   real->entry = NULL;
543   real->next_entry = NULL;
544   real->next_bucket = 0;
545   real->n_entries_on_init = table->n_entries;
546 }
547 
548 /**
549  * Move the hash iterator forward one step, to the next hash entry.
550  * The documentation for _dbus_hash_iter_init() explains in more
551  * detail.
552  *
553  * @param iter the iterator to move forward.
554  * @returns #FALSE if there are no more entries to move to.
555  */
556 dbus_bool_t
_dbus_hash_iter_next(DBusHashIter * iter)557 _dbus_hash_iter_next (DBusHashIter  *iter)
558 {
559   DBusRealHashIter *real;
560 
561   _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
562 
563   real = (DBusRealHashIter*) iter;
564 
565   /* if this assertion failed someone probably added hash entries
566    * during iteration, which is bad.
567    */
568   _dbus_assert (real->n_entries_on_init >= real->table->n_entries);
569 
570   /* Remember that real->entry may have been deleted */
571 
572   while (real->next_entry == NULL)
573     {
574       if (real->next_bucket >= real->table->n_buckets)
575         {
576           /* invalidate iter and return false */
577           real->entry = NULL;
578           real->table = NULL;
579           real->bucket = NULL;
580           return FALSE;
581         }
582 
583       real->bucket = &(real->table->buckets[real->next_bucket]);
584       real->next_entry = *(real->bucket);
585       real->next_bucket += 1;
586     }
587 
588   _dbus_assert (real->next_entry != NULL);
589   _dbus_assert (real->bucket != NULL);
590 
591   real->entry = real->next_entry;
592   real->next_entry = real->entry->next;
593 
594   return TRUE;
595 }
596 
597 /**
598  * Removes the current entry from the hash table.
599  * If a key_free_function or value_free_function
600  * was provided to _dbus_hash_table_new(),
601  * frees the key and/or value for this entry.
602  *
603  * @param iter the hash table iterator.
604  */
605 void
_dbus_hash_iter_remove_entry(DBusHashIter * iter)606 _dbus_hash_iter_remove_entry (DBusHashIter *iter)
607 {
608   DBusRealHashIter *real;
609 
610   real = (DBusRealHashIter*) iter;
611 
612   _dbus_assert (real->table != NULL);
613   _dbus_assert (real->entry != NULL);
614   _dbus_assert (real->bucket != NULL);
615 
616   remove_entry (real->table, real->bucket, real->entry);
617 
618   real->entry = NULL; /* make it crash if you try to use this entry */
619 }
620 
621 /**
622  * Gets the value of the current entry.
623  *
624  * @param iter the hash table iterator.
625  */
626 void*
_dbus_hash_iter_get_value(DBusHashIter * iter)627 _dbus_hash_iter_get_value (DBusHashIter *iter)
628 {
629   DBusRealHashIter *real;
630 
631   real = (DBusRealHashIter*) iter;
632 
633   _dbus_assert (real->table != NULL);
634   _dbus_assert (real->entry != NULL);
635 
636   return real->entry->value;
637 }
638 
639 /**
640  * Sets the value of the current entry.
641  * If the hash table has a value_free_function
642  * it will be used to free the previous value.
643  * The hash table will own the passed-in value
644  * (it will not be copied).
645  *
646  * @param iter the hash table iterator.
647  * @param value the new value.
648  */
649 void
_dbus_hash_iter_set_value(DBusHashIter * iter,void * value)650 _dbus_hash_iter_set_value (DBusHashIter *iter,
651                            void         *value)
652 {
653   DBusRealHashIter *real;
654 
655   real = (DBusRealHashIter*) iter;
656 
657   _dbus_assert (real->table != NULL);
658   _dbus_assert (real->entry != NULL);
659 
660   if (real->table->free_value_function && value != real->entry->value)
661     (* real->table->free_value_function) (real->entry->value);
662 
663   real->entry->value = value;
664 }
665 
666 /**
667  * Gets the key for the current entry.
668  * Only works for hash tables of type #DBUS_HASH_INT.
669  *
670  * @param iter the hash table iterator.
671  */
672 int
_dbus_hash_iter_get_int_key(DBusHashIter * iter)673 _dbus_hash_iter_get_int_key (DBusHashIter *iter)
674 {
675   DBusRealHashIter *real;
676 
677   real = (DBusRealHashIter*) iter;
678 
679   _dbus_assert (real->table != NULL);
680   _dbus_assert (real->entry != NULL);
681 
682   return _DBUS_POINTER_TO_INT (real->entry->key);
683 }
684 
685 /**
686  * Gets the key for the current entry.
687  * Only works for hash tables of type #DBUS_HASH_UINTPTR.
688  *
689  * @param iter the hash table iterator.
690  */
691 uintptr_t
_dbus_hash_iter_get_uintptr_key(DBusHashIter * iter)692 _dbus_hash_iter_get_uintptr_key (DBusHashIter *iter)
693 {
694   DBusRealHashIter *real;
695 
696   real = (DBusRealHashIter*) iter;
697 
698   _dbus_assert (real->table != NULL);
699   _dbus_assert (real->entry != NULL);
700 
701   return (uintptr_t) real->entry->key;
702 }
703 
704 /**
705  * Gets the key for the current entry.
706  * Only works for hash tables of type #DBUS_HASH_STRING
707  * @param iter the hash table iterator.
708  */
709 const char*
_dbus_hash_iter_get_string_key(DBusHashIter * iter)710 _dbus_hash_iter_get_string_key (DBusHashIter *iter)
711 {
712   DBusRealHashIter *real;
713 
714   real = (DBusRealHashIter*) iter;
715 
716   _dbus_assert (real->table != NULL);
717   _dbus_assert (real->entry != NULL);
718 
719   return real->entry->key;
720 }
721 
722 #ifdef DBUS_BUILD_TESTS
723 /**
724  * Gets the key for the current entry.
725  * Only works for hash tables of type #DBUS_HASH_TWO_STRINGS
726  * @param iter the hash table iterator.
727  */
728 const char*
_dbus_hash_iter_get_two_strings_key(DBusHashIter * iter)729 _dbus_hash_iter_get_two_strings_key (DBusHashIter *iter)
730 {
731   DBusRealHashIter *real;
732 
733   real = (DBusRealHashIter*) iter;
734 
735   _dbus_assert (real->table != NULL);
736   _dbus_assert (real->entry != NULL);
737 
738   return real->entry->key;
739 }
740 #endif /* DBUS_BUILD_TESTS */
741 
742 /**
743  * A low-level but efficient interface for manipulating the hash
744  * table.  It's efficient because you can get, set, and optionally
745  * create the hash entry while only running the hash function one
746  * time.
747  *
748  * Note that while calling _dbus_hash_iter_next() on the iterator
749  * filled in by this function may work, it's completely
750  * undefined which entries are after this iter and which
751  * are before it. So it would be silly to iterate using this
752  * iterator.
753  *
754  * If the hash entry is created, its value will be initialized
755  * to all bits zero.
756  *
757  * #FALSE may be returned due to memory allocation failure, or
758  * because create_if_not_found was #FALSE and the entry
759  * did not exist.
760  *
761  * If create_if_not_found is #TRUE and the entry is created, the hash
762  * table takes ownership of the key that's passed in.
763  *
764  * For a hash table of type #DBUS_HASH_INT, cast the int
765  * key to the key parameter using #_DBUS_INT_TO_POINTER().
766  *
767  * @param table the hash table.
768  * @param key the hash key.
769  * @param create_if_not_found if #TRUE, create the entry if it didn't exist.
770  * @param iter the iterator to initialize.
771  * @returns #TRUE if the hash entry now exists (and the iterator is thus valid).
772  */
773 dbus_bool_t
_dbus_hash_iter_lookup(DBusHashTable * table,void * key,dbus_bool_t create_if_not_found,DBusHashIter * iter)774 _dbus_hash_iter_lookup (DBusHashTable *table,
775                         void          *key,
776                         dbus_bool_t    create_if_not_found,
777                         DBusHashIter  *iter)
778 {
779   DBusRealHashIter *real;
780   DBusHashEntry *entry;
781   DBusHashEntry **bucket;
782 
783   _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
784 
785   real = (DBusRealHashIter*) iter;
786 
787   entry = (* table->find_function) (table, key, create_if_not_found, &bucket, NULL);
788 
789   if (entry == NULL)
790     return FALSE;
791 
792   real->table = table;
793   real->bucket = bucket;
794   real->entry = entry;
795   real->next_entry = entry->next;
796   real->next_bucket = (bucket - table->buckets) + 1;
797   real->n_entries_on_init = table->n_entries;
798 
799   _dbus_assert (&(table->buckets[real->next_bucket-1]) == real->bucket);
800 
801   return TRUE;
802 }
803 
804 static void
add_allocated_entry(DBusHashTable * table,DBusHashEntry * entry,unsigned int idx,void * key,DBusHashEntry *** bucket)805 add_allocated_entry (DBusHashTable   *table,
806                      DBusHashEntry   *entry,
807                      unsigned int     idx,
808                      void            *key,
809                      DBusHashEntry ***bucket)
810 {
811   DBusHashEntry **b;
812 
813   entry->key = key;
814 
815   b = &(table->buckets[idx]);
816   entry->next = *b;
817   *b = entry;
818 
819   if (bucket)
820     *bucket = b;
821 
822   table->n_entries += 1;
823 
824   /* note we ONLY rebuild when ADDING - because you can iterate over a
825    * table and remove entries safely.
826    */
827   if (table->n_entries >= table->hi_rebuild_size ||
828       table->n_entries < table->lo_rebuild_size)
829     rebuild_table (table);
830 }
831 
832 static DBusHashEntry*
add_entry(DBusHashTable * table,unsigned int idx,void * key,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)833 add_entry (DBusHashTable        *table,
834            unsigned int          idx,
835            void                 *key,
836            DBusHashEntry      ***bucket,
837            DBusPreallocatedHash *preallocated)
838 {
839   DBusHashEntry  *entry;
840 
841   if (preallocated == NULL)
842     {
843       entry = alloc_entry (table);
844       if (entry == NULL)
845         {
846           if (bucket)
847             *bucket = NULL;
848           return NULL;
849         }
850     }
851   else
852     {
853       entry = (DBusHashEntry*) preallocated;
854     }
855 
856   add_allocated_entry (table, entry, idx, key, bucket);
857 
858   return entry;
859 }
860 
861 /* This is g_str_hash from GLib which was
862  * extensively discussed/tested/profiled
863  */
864 static unsigned int
string_hash(const char * str)865 string_hash (const char *str)
866 {
867   const char *p = str;
868   unsigned int h = *p;
869 
870   if (h)
871     for (p += 1; *p != '\0'; p++)
872       h = (h << 5) - h + *p;
873 
874   return h;
875 }
876 
877 #ifdef DBUS_BUILD_TESTS
878 /* This hashes a memory block with two nul-terminated strings
879  * in it, used in dbus-object-registry.c at the moment.
880  */
881 static unsigned int
two_strings_hash(const char * str)882 two_strings_hash (const char *str)
883 {
884   const char *p = str;
885   unsigned int h = *p;
886 
887   if (h)
888     for (p += 1; *p != '\0'; p++)
889       h = (h << 5) - h + *p;
890 
891   for (p += 1; *p != '\0'; p++)
892     h = (h << 5) - h + *p;
893 
894   return h;
895 }
896 #endif /* DBUS_BUILD_TESTS */
897 
898 /** Key comparison function */
899 typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b);
900 
901 static DBusHashEntry*
find_generic_function(DBusHashTable * table,void * key,unsigned int idx,KeyCompareFunc compare_func,dbus_bool_t create_if_not_found,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)902 find_generic_function (DBusHashTable        *table,
903                        void                 *key,
904                        unsigned int          idx,
905                        KeyCompareFunc        compare_func,
906                        dbus_bool_t           create_if_not_found,
907                        DBusHashEntry      ***bucket,
908                        DBusPreallocatedHash *preallocated)
909 {
910   DBusHashEntry *entry;
911 
912   if (bucket)
913     *bucket = NULL;
914 
915   /* Search all of the entries in this bucket. */
916   entry = table->buckets[idx];
917   while (entry != NULL)
918     {
919       if ((compare_func == NULL && key == entry->key) ||
920           (compare_func != NULL && (* compare_func) (key, entry->key) == 0))
921         {
922           if (bucket)
923             *bucket = &(table->buckets[idx]);
924 
925           if (preallocated)
926             _dbus_hash_table_free_preallocated_entry (table, preallocated);
927 
928           return entry;
929         }
930 
931       entry = entry->next;
932     }
933 
934   if (create_if_not_found)
935     entry = add_entry (table, idx, key, bucket, preallocated);
936   else if (preallocated)
937     _dbus_hash_table_free_preallocated_entry (table, preallocated);
938 
939   return entry;
940 }
941 
942 static DBusHashEntry*
find_string_function(DBusHashTable * table,void * key,dbus_bool_t create_if_not_found,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)943 find_string_function (DBusHashTable        *table,
944                       void                 *key,
945                       dbus_bool_t           create_if_not_found,
946                       DBusHashEntry      ***bucket,
947                       DBusPreallocatedHash *preallocated)
948 {
949   unsigned int idx;
950 
951   idx = string_hash (key) & table->mask;
952 
953   return find_generic_function (table, key, idx,
954                                 (KeyCompareFunc) strcmp, create_if_not_found, bucket,
955                                 preallocated);
956 }
957 
958 #ifdef DBUS_BUILD_TESTS
959 static int
two_strings_cmp(const char * a,const char * b)960 two_strings_cmp (const char *a,
961                  const char *b)
962 {
963   size_t len_a;
964   size_t len_b;
965   int res;
966 
967   res = strcmp (a, b);
968   if (res != 0)
969     return res;
970 
971   len_a = strlen (a);
972   len_b = strlen (b);
973 
974   return strcmp (a + len_a + 1, b + len_b + 1);
975 }
976 #endif
977 
978 #ifdef DBUS_BUILD_TESTS
979 static DBusHashEntry*
find_two_strings_function(DBusHashTable * table,void * key,dbus_bool_t create_if_not_found,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)980 find_two_strings_function (DBusHashTable        *table,
981                            void                 *key,
982                            dbus_bool_t           create_if_not_found,
983                            DBusHashEntry      ***bucket,
984                            DBusPreallocatedHash *preallocated)
985 {
986   unsigned int idx;
987 
988   idx = two_strings_hash (key) & table->mask;
989 
990   return find_generic_function (table, key, idx,
991                                 (KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket,
992                                 preallocated);
993 }
994 #endif /* DBUS_BUILD_TESTS */
995 
996 static DBusHashEntry*
find_direct_function(DBusHashTable * table,void * key,dbus_bool_t create_if_not_found,DBusHashEntry *** bucket,DBusPreallocatedHash * preallocated)997 find_direct_function (DBusHashTable        *table,
998                       void                 *key,
999                       dbus_bool_t           create_if_not_found,
1000                       DBusHashEntry      ***bucket,
1001                       DBusPreallocatedHash *preallocated)
1002 {
1003   unsigned int idx;
1004 
1005   idx = RANDOM_INDEX (table, key) & table->mask;
1006 
1007 
1008   return find_generic_function (table, key, idx,
1009                                 NULL, create_if_not_found, bucket,
1010                                 preallocated);
1011 }
1012 
1013 static void
rebuild_table(DBusHashTable * table)1014 rebuild_table (DBusHashTable *table)
1015 {
1016   int old_size;
1017   int new_buckets;
1018   DBusHashEntry **old_buckets;
1019   DBusHashEntry **old_chain;
1020   DBusHashEntry *entry;
1021   dbus_bool_t growing;
1022 
1023   /*
1024    * Allocate and initialize the new bucket array, and set up
1025    * hashing constants for new array size.
1026    */
1027 
1028   growing = table->n_entries >= table->hi_rebuild_size;
1029 
1030   old_size = table->n_buckets;
1031   old_buckets = table->buckets;
1032 
1033   if (growing)
1034     {
1035       /* overflow paranoia */
1036       if (table->n_buckets < _DBUS_INT_MAX / 4 &&
1037           table->down_shift >= 0)
1038         new_buckets = table->n_buckets * 4;
1039       else
1040         return; /* can't grow anymore */
1041     }
1042   else
1043     {
1044       new_buckets = table->n_buckets / 4;
1045       if (new_buckets < DBUS_SMALL_HASH_TABLE)
1046         return; /* don't bother shrinking this far */
1047     }
1048 
1049   table->buckets = dbus_new0 (DBusHashEntry*, new_buckets);
1050   if (table->buckets == NULL)
1051     {
1052       /* out of memory, yay - just don't reallocate, the table will
1053        * still work, albeit more slowly.
1054        */
1055       table->buckets = old_buckets;
1056       return;
1057     }
1058 
1059   table->n_buckets = new_buckets;
1060 
1061   if (growing)
1062     {
1063       table->lo_rebuild_size = table->hi_rebuild_size;
1064       table->hi_rebuild_size *= 4;
1065 
1066       table->down_shift -= 2;               /* keep 2 more high bits */
1067       table->mask = (table->mask << 2) + 3; /* keep 2 more high bits */
1068     }
1069   else
1070     {
1071       table->hi_rebuild_size = table->lo_rebuild_size;
1072       table->lo_rebuild_size /= 4;
1073 
1074       table->down_shift += 2;         /* keep 2 fewer high bits */
1075       table->mask = table->mask >> 2; /* keep 2 fewer high bits */
1076     }
1077 
1078 #if 0
1079   printf ("%s table to lo = %d hi = %d downshift = %d mask = 0x%x\n",
1080           growing ? "GROW" : "SHRINK",
1081           table->lo_rebuild_size,
1082           table->hi_rebuild_size,
1083           table->down_shift,
1084           table->mask);
1085 #endif
1086 
1087   _dbus_assert (table->lo_rebuild_size >= 0);
1088   _dbus_assert (table->hi_rebuild_size > table->lo_rebuild_size);
1089   _dbus_assert (table->mask != 0);
1090   /* the mask is essentially the max index */
1091   _dbus_assert (table->mask < table->n_buckets);
1092 
1093   /*
1094    * Rehash all of the existing entries into the new bucket array.
1095    */
1096 
1097   for (old_chain = old_buckets; old_size > 0; old_size--, old_chain++)
1098     {
1099       for (entry = *old_chain; entry != NULL; entry = *old_chain)
1100         {
1101           unsigned int idx;
1102           DBusHashEntry **bucket;
1103 
1104           *old_chain = entry->next;
1105           switch (table->key_type)
1106             {
1107             case DBUS_HASH_STRING:
1108               idx = string_hash (entry->key) & table->mask;
1109               break;
1110             case DBUS_HASH_TWO_STRINGS:
1111 #ifdef DBUS_BUILD_TESTS
1112               idx = two_strings_hash (entry->key) & table->mask;
1113 #else
1114               idx = 0;
1115               _dbus_assert_not_reached ("two-strings is not enabled");
1116 #endif
1117               break;
1118             case DBUS_HASH_INT:
1119             case DBUS_HASH_UINTPTR:
1120             case DBUS_HASH_POINTER:
1121               idx = RANDOM_INDEX (table, entry->key);
1122               break;
1123             default:
1124               idx = 0;
1125               _dbus_assert_not_reached ("Unknown hash table type");
1126               break;
1127             }
1128 
1129           bucket = &(table->buckets[idx]);
1130           entry->next = *bucket;
1131           *bucket = entry;
1132         }
1133     }
1134 
1135   /* Free the old bucket array, if it was dynamically allocated. */
1136 
1137   if (old_buckets != table->static_buckets)
1138     dbus_free (old_buckets);
1139 }
1140 
1141 /**
1142  * Looks up the value for a given string in a hash table
1143  * of type #DBUS_HASH_STRING. Returns %NULL if the value
1144  * is not present. (A not-present entry is indistinguishable
1145  * from an entry with a value of %NULL.)
1146  * @param table the hash table.
1147  * @param key the string to look up.
1148  * @returns the value of the hash entry.
1149  */
1150 void*
_dbus_hash_table_lookup_string(DBusHashTable * table,const char * key)1151 _dbus_hash_table_lookup_string (DBusHashTable *table,
1152                                 const char    *key)
1153 {
1154   DBusHashEntry *entry;
1155 
1156   _dbus_assert (table->key_type == DBUS_HASH_STRING);
1157 
1158   entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
1159 
1160   if (entry)
1161     return entry->value;
1162   else
1163     return NULL;
1164 }
1165 
1166 #ifdef DBUS_BUILD_TESTS
1167 /**
1168  * Looks up the value for a given string in a hash table
1169  * of type #DBUS_HASH_TWO_STRINGS. Returns %NULL if the value
1170  * is not present. (A not-present entry is indistinguishable
1171  * from an entry with a value of %NULL.)
1172  * @param table the hash table.
1173  * @param key the string to look up.
1174  * @returns the value of the hash entry.
1175  */
1176 void*
_dbus_hash_table_lookup_two_strings(DBusHashTable * table,const char * key)1177 _dbus_hash_table_lookup_two_strings (DBusHashTable *table,
1178                                      const char    *key)
1179 {
1180   DBusHashEntry *entry;
1181 
1182   _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
1183 
1184   entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
1185 
1186   if (entry)
1187     return entry->value;
1188   else
1189     return NULL;
1190 }
1191 #endif /* DBUS_BUILD_TESTS */
1192 
1193 /**
1194  * Looks up the value for a given integer in a hash table
1195  * of type #DBUS_HASH_INT. Returns %NULL if the value
1196  * is not present. (A not-present entry is indistinguishable
1197  * from an entry with a value of %NULL.)
1198  * @param table the hash table.
1199  * @param key the integer to look up.
1200  * @returns the value of the hash entry.
1201  */
1202 void*
_dbus_hash_table_lookup_int(DBusHashTable * table,int key)1203 _dbus_hash_table_lookup_int (DBusHashTable *table,
1204                              int            key)
1205 {
1206   DBusHashEntry *entry;
1207 
1208   _dbus_assert (table->key_type == DBUS_HASH_INT);
1209 
1210   entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, NULL, NULL);
1211 
1212   if (entry)
1213     return entry->value;
1214   else
1215     return NULL;
1216 }
1217 
1218 #ifdef DBUS_BUILD_TESTS
1219 /* disabled since it's only used for testing */
1220 /**
1221  * Looks up the value for a given integer in a hash table
1222  * of type #DBUS_HASH_POINTER. Returns %NULL if the value
1223  * is not present. (A not-present entry is indistinguishable
1224  * from an entry with a value of %NULL.)
1225  * @param table the hash table.
1226  * @param key the integer to look up.
1227  * @returns the value of the hash entry.
1228  */
1229 void*
_dbus_hash_table_lookup_pointer(DBusHashTable * table,void * key)1230 _dbus_hash_table_lookup_pointer (DBusHashTable *table,
1231                                  void          *key)
1232 {
1233   DBusHashEntry *entry;
1234 
1235   _dbus_assert (table->key_type == DBUS_HASH_POINTER);
1236 
1237   entry = (* table->find_function) (table, key, FALSE, NULL, NULL);
1238 
1239   if (entry)
1240     return entry->value;
1241   else
1242     return NULL;
1243 }
1244 #endif /* DBUS_BUILD_TESTS */
1245 
1246 /**
1247  * Looks up the value for a given integer in a hash table
1248  * of type #DBUS_HASH_UINTPTR. Returns %NULL if the value
1249  * is not present. (A not-present entry is indistinguishable
1250  * from an entry with a value of %NULL.)
1251  * @param table the hash table.
1252  * @param key the integer to look up.
1253  * @returns the value of the hash entry.
1254  */
1255 void*
_dbus_hash_table_lookup_uintptr(DBusHashTable * table,uintptr_t key)1256 _dbus_hash_table_lookup_uintptr (DBusHashTable *table,
1257                                  uintptr_t      key)
1258 {
1259   DBusHashEntry *entry;
1260 
1261   _dbus_assert (table->key_type == DBUS_HASH_UINTPTR);
1262 
1263   entry = (* table->find_function) (table, (void*) key, FALSE, NULL, NULL);
1264 
1265   if (entry)
1266     return entry->value;
1267   else
1268     return NULL;
1269 }
1270 
1271 /**
1272  * Removes the hash entry for the given key. If no hash entry
1273  * for the key exists, does nothing.
1274  *
1275  * @param table the hash table.
1276  * @param key the hash key.
1277  * @returns #TRUE if the entry existed
1278  */
1279 dbus_bool_t
_dbus_hash_table_remove_string(DBusHashTable * table,const char * key)1280 _dbus_hash_table_remove_string (DBusHashTable *table,
1281                                 const char    *key)
1282 {
1283   DBusHashEntry *entry;
1284   DBusHashEntry **bucket;
1285 
1286   _dbus_assert (table->key_type == DBUS_HASH_STRING);
1287 
1288   entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
1289 
1290   if (entry)
1291     {
1292       remove_entry (table, bucket, entry);
1293       return TRUE;
1294     }
1295   else
1296     return FALSE;
1297 }
1298 
1299 #ifdef DBUS_BUILD_TESTS
1300 /**
1301  * Removes the hash entry for the given key. If no hash entry
1302  * for the key exists, does nothing.
1303  *
1304  * @param table the hash table.
1305  * @param key the hash key.
1306  * @returns #TRUE if the entry existed
1307  */
1308 dbus_bool_t
_dbus_hash_table_remove_two_strings(DBusHashTable * table,const char * key)1309 _dbus_hash_table_remove_two_strings (DBusHashTable *table,
1310                                      const char    *key)
1311 {
1312   DBusHashEntry *entry;
1313   DBusHashEntry **bucket;
1314 
1315   _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
1316 
1317   entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
1318 
1319   if (entry)
1320     {
1321       remove_entry (table, bucket, entry);
1322       return TRUE;
1323     }
1324   else
1325     return FALSE;
1326 }
1327 #endif /* DBUS_BUILD_TESTS */
1328 
1329 /**
1330  * Removes the hash entry for the given key. If no hash entry
1331  * for the key exists, does nothing.
1332  *
1333  * @param table the hash table.
1334  * @param key the hash key.
1335  * @returns #TRUE if the entry existed
1336  */
1337 dbus_bool_t
_dbus_hash_table_remove_int(DBusHashTable * table,int key)1338 _dbus_hash_table_remove_int (DBusHashTable *table,
1339                              int            key)
1340 {
1341   DBusHashEntry *entry;
1342   DBusHashEntry **bucket;
1343 
1344   _dbus_assert (table->key_type == DBUS_HASH_INT);
1345 
1346   entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, &bucket, NULL);
1347 
1348   if (entry)
1349     {
1350       remove_entry (table, bucket, entry);
1351       return TRUE;
1352     }
1353   else
1354     return FALSE;
1355 }
1356 
1357 #ifdef DBUS_BUILD_TESTS
1358 /* disabled since it's only used for testing */
1359 /**
1360  * Removes the hash entry for the given key. If no hash entry
1361  * for the key exists, does nothing.
1362  *
1363  * @param table the hash table.
1364  * @param key the hash key.
1365  * @returns #TRUE if the entry existed
1366  */
1367 dbus_bool_t
_dbus_hash_table_remove_pointer(DBusHashTable * table,void * key)1368 _dbus_hash_table_remove_pointer (DBusHashTable *table,
1369                                  void          *key)
1370 {
1371   DBusHashEntry *entry;
1372   DBusHashEntry **bucket;
1373 
1374   _dbus_assert (table->key_type == DBUS_HASH_POINTER);
1375 
1376   entry = (* table->find_function) (table, key, FALSE, &bucket, NULL);
1377 
1378   if (entry)
1379     {
1380       remove_entry (table, bucket, entry);
1381       return TRUE;
1382     }
1383   else
1384     return FALSE;
1385 }
1386 #endif /* DBUS_BUILD_TESTS */
1387 
1388 /**
1389  * Removes the hash entry for the given key. If no hash entry
1390  * for the key exists, does nothing.
1391  *
1392  * @param table the hash table.
1393  * @param key the hash key.
1394  * @returns #TRUE if the entry existed
1395  */
1396 dbus_bool_t
_dbus_hash_table_remove_uintptr(DBusHashTable * table,uintptr_t key)1397 _dbus_hash_table_remove_uintptr (DBusHashTable *table,
1398                                  uintptr_t      key)
1399 {
1400   DBusHashEntry *entry;
1401   DBusHashEntry **bucket;
1402 
1403   _dbus_assert (table->key_type == DBUS_HASH_UINTPTR);
1404 
1405   entry = (* table->find_function) (table, (void*) key, FALSE, &bucket, NULL);
1406 
1407   if (entry)
1408     {
1409       remove_entry (table, bucket, entry);
1410       return TRUE;
1411     }
1412   else
1413     return FALSE;
1414 }
1415 
1416 /**
1417  * Creates a hash entry with the given key and value.
1418  * The key and value are not copied; they are stored
1419  * in the hash table by reference. If an entry with the
1420  * given key already exists, the previous key and value
1421  * are overwritten (and freed if the hash table has
1422  * a key_free_function and/or value_free_function).
1423  *
1424  * Returns #FALSE if memory for the new hash entry
1425  * can't be allocated.
1426  *
1427  * @param table the hash table.
1428  * @param key the hash entry key.
1429  * @param value the hash entry value.
1430  */
1431 dbus_bool_t
_dbus_hash_table_insert_string(DBusHashTable * table,char * key,void * value)1432 _dbus_hash_table_insert_string (DBusHashTable *table,
1433                                 char          *key,
1434                                 void          *value)
1435 {
1436   DBusPreallocatedHash *preallocated;
1437 
1438   _dbus_assert (table->key_type == DBUS_HASH_STRING);
1439 
1440   preallocated = _dbus_hash_table_preallocate_entry (table);
1441   if (preallocated == NULL)
1442     return FALSE;
1443 
1444   _dbus_hash_table_insert_string_preallocated (table, preallocated,
1445                                                key, value);
1446 
1447   return TRUE;
1448 }
1449 
1450 #ifdef DBUS_BUILD_TESTS
1451 /**
1452  * Creates a hash entry with the given key and value.
1453  * The key and value are not copied; they are stored
1454  * in the hash table by reference. If an entry with the
1455  * given key already exists, the previous key and value
1456  * are overwritten (and freed if the hash table has
1457  * a key_free_function and/or value_free_function).
1458  *
1459  * Returns #FALSE if memory for the new hash entry
1460  * can't be allocated.
1461  *
1462  * @param table the hash table.
1463  * @param key the hash entry key.
1464  * @param value the hash entry value.
1465  */
1466 dbus_bool_t
_dbus_hash_table_insert_two_strings(DBusHashTable * table,char * key,void * value)1467 _dbus_hash_table_insert_two_strings (DBusHashTable *table,
1468                                      char          *key,
1469                                      void          *value)
1470 {
1471   DBusHashEntry *entry;
1472 
1473   _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
1474 
1475   entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
1476 
1477   if (entry == NULL)
1478     return FALSE; /* no memory */
1479 
1480   if (table->free_key_function && entry->key != key)
1481     (* table->free_key_function) (entry->key);
1482 
1483   if (table->free_value_function && entry->value != value)
1484     (* table->free_value_function) (entry->value);
1485 
1486   entry->key = key;
1487   entry->value = value;
1488 
1489   return TRUE;
1490 }
1491 #endif /* DBUS_BUILD_TESTS */
1492 
1493 /**
1494  * Creates a hash entry with the given key and value.
1495  * The key and value are not copied; they are stored
1496  * in the hash table by reference. If an entry with the
1497  * given key already exists, the previous key and value
1498  * are overwritten (and freed if the hash table has
1499  * a key_free_function and/or value_free_function).
1500  *
1501  * Returns #FALSE if memory for the new hash entry
1502  * can't be allocated.
1503  *
1504  * @param table the hash table.
1505  * @param key the hash entry key.
1506  * @param value the hash entry value.
1507  */
1508 dbus_bool_t
_dbus_hash_table_insert_int(DBusHashTable * table,int key,void * value)1509 _dbus_hash_table_insert_int (DBusHashTable *table,
1510                              int            key,
1511                              void          *value)
1512 {
1513   DBusHashEntry *entry;
1514 
1515   _dbus_assert (table->key_type == DBUS_HASH_INT);
1516 
1517   entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), TRUE, NULL, NULL);
1518 
1519   if (entry == NULL)
1520     return FALSE; /* no memory */
1521 
1522   if (table->free_key_function && entry->key != _DBUS_INT_TO_POINTER (key))
1523     (* table->free_key_function) (entry->key);
1524 
1525   if (table->free_value_function && entry->value != value)
1526     (* table->free_value_function) (entry->value);
1527 
1528   entry->key = _DBUS_INT_TO_POINTER (key);
1529   entry->value = value;
1530 
1531   return TRUE;
1532 }
1533 
1534 #ifdef DBUS_BUILD_TESTS
1535 /* disabled since it's only used for testing */
1536 /**
1537  * Creates a hash entry with the given key and value.
1538  * The key and value are not copied; they are stored
1539  * in the hash table by reference. If an entry with the
1540  * given key already exists, the previous key and value
1541  * are overwritten (and freed if the hash table has
1542  * a key_free_function and/or value_free_function).
1543  *
1544  * Returns #FALSE if memory for the new hash entry
1545  * can't be allocated.
1546  *
1547  * @param table the hash table.
1548  * @param key the hash entry key.
1549  * @param value the hash entry value.
1550  */
1551 dbus_bool_t
_dbus_hash_table_insert_pointer(DBusHashTable * table,void * key,void * value)1552 _dbus_hash_table_insert_pointer (DBusHashTable *table,
1553                                  void          *key,
1554                                  void          *value)
1555 {
1556   DBusHashEntry *entry;
1557 
1558   _dbus_assert (table->key_type == DBUS_HASH_POINTER);
1559 
1560   entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
1561 
1562   if (entry == NULL)
1563     return FALSE; /* no memory */
1564 
1565   if (table->free_key_function && entry->key != key)
1566     (* table->free_key_function) (entry->key);
1567 
1568   if (table->free_value_function && entry->value != value)
1569     (* table->free_value_function) (entry->value);
1570 
1571   entry->key = key;
1572   entry->value = value;
1573 
1574   return TRUE;
1575 }
1576 #endif /* DBUS_BUILD_TESTS */
1577 
1578 /**
1579  * Creates a hash entry with the given key and value.
1580  * The key and value are not copied; they are stored
1581  * in the hash table by reference. If an entry with the
1582  * given key already exists, the previous key and value
1583  * are overwritten (and freed if the hash table has
1584  * a key_free_function and/or value_free_function).
1585  *
1586  * Returns #FALSE if memory for the new hash entry
1587  * can't be allocated.
1588  *
1589  * @param table the hash table.
1590  * @param key the hash entry key.
1591  * @param value the hash entry value.
1592  */
1593 dbus_bool_t
_dbus_hash_table_insert_uintptr(DBusHashTable * table,uintptr_t key,void * value)1594 _dbus_hash_table_insert_uintptr (DBusHashTable *table,
1595                                  uintptr_t      key,
1596                                  void          *value)
1597 {
1598   DBusHashEntry *entry;
1599 
1600   _dbus_assert (table->key_type == DBUS_HASH_UINTPTR);
1601 
1602   entry = (* table->find_function) (table, (void*) key, TRUE, NULL, NULL);
1603 
1604   if (entry == NULL)
1605     return FALSE; /* no memory */
1606 
1607   if (table->free_key_function && entry->key != (void*) key)
1608     (* table->free_key_function) (entry->key);
1609 
1610   if (table->free_value_function && entry->value != value)
1611     (* table->free_value_function) (entry->value);
1612 
1613   entry->key = (void*) key;
1614   entry->value = value;
1615 
1616   return TRUE;
1617 }
1618 
1619 /**
1620  * Preallocate an opaque data blob that allows us to insert into the
1621  * hash table at a later time without allocating any memory.
1622  *
1623  * @param table the hash table
1624  * @returns the preallocated data, or #NULL if no memory
1625  */
1626 DBusPreallocatedHash*
_dbus_hash_table_preallocate_entry(DBusHashTable * table)1627 _dbus_hash_table_preallocate_entry (DBusHashTable *table)
1628 {
1629   DBusHashEntry *entry;
1630 
1631   entry = alloc_entry (table);
1632 
1633   return (DBusPreallocatedHash*) entry;
1634 }
1635 
1636 /**
1637  * Frees an opaque DBusPreallocatedHash that was *not* used
1638  * in order to insert into the hash table.
1639  *
1640  * @param table the hash table
1641  * @param preallocated the preallocated data
1642  */
1643 void
_dbus_hash_table_free_preallocated_entry(DBusHashTable * table,DBusPreallocatedHash * preallocated)1644 _dbus_hash_table_free_preallocated_entry (DBusHashTable        *table,
1645                                           DBusPreallocatedHash *preallocated)
1646 {
1647   DBusHashEntry *entry;
1648 
1649   _dbus_assert (preallocated != NULL);
1650 
1651   entry = (DBusHashEntry*) preallocated;
1652 
1653   /* Don't use free_entry(), since this entry has no key/data */
1654   _dbus_mem_pool_dealloc (table->entry_pool, entry);
1655 }
1656 
1657 /**
1658  * Inserts a string-keyed entry into the hash table, using a
1659  * preallocated data block from
1660  * _dbus_hash_table_preallocate_entry(). This function cannot fail due
1661  * to lack of memory. The DBusPreallocatedHash object is consumed and
1662  * should not be reused or freed. Otherwise this function works
1663  * just like _dbus_hash_table_insert_string().
1664  *
1665  * @param table the hash table
1666  * @param preallocated the preallocated data
1667  * @param key the hash key
1668  * @param value the value
1669  */
1670 void
_dbus_hash_table_insert_string_preallocated(DBusHashTable * table,DBusPreallocatedHash * preallocated,char * key,void * value)1671 _dbus_hash_table_insert_string_preallocated (DBusHashTable        *table,
1672                                              DBusPreallocatedHash *preallocated,
1673                                              char                 *key,
1674                                              void                 *value)
1675 {
1676   DBusHashEntry *entry;
1677 
1678   _dbus_assert (table->key_type == DBUS_HASH_STRING);
1679   _dbus_assert (preallocated != NULL);
1680 
1681   entry = (* table->find_function) (table, key, TRUE, NULL, preallocated);
1682 
1683   _dbus_assert (entry != NULL);
1684 
1685   if (table->free_key_function && entry->key != key)
1686     (* table->free_key_function) (entry->key);
1687 
1688   if (table->free_value_function && entry->value != value)
1689     (* table->free_value_function) (entry->value);
1690 
1691   entry->key = key;
1692   entry->value = value;
1693 }
1694 
1695 /**
1696  * Gets the number of hash entries in a hash table.
1697  *
1698  * @param table the hash table.
1699  * @returns the number of entries in the table.
1700  */
1701 int
_dbus_hash_table_get_n_entries(DBusHashTable * table)1702 _dbus_hash_table_get_n_entries (DBusHashTable *table)
1703 {
1704   return table->n_entries;
1705 }
1706 
1707 /** @} */
1708 
1709 #ifdef DBUS_BUILD_TESTS
1710 #include "dbus-test.h"
1711 #include <stdio.h>
1712 
1713 /* If you're wondering why the hash table test takes
1714  * forever to run, it's because we call this function
1715  * in inner loops thus making things quadratic.
1716  */
1717 static int
count_entries(DBusHashTable * table)1718 count_entries (DBusHashTable *table)
1719 {
1720   DBusHashIter iter;
1721   int count;
1722 
1723   count = 0;
1724   _dbus_hash_iter_init (table, &iter);
1725   while (_dbus_hash_iter_next (&iter))
1726     ++count;
1727 
1728   _dbus_assert (count == _dbus_hash_table_get_n_entries (table));
1729 
1730   return count;
1731 }
1732 
1733 /* Copy the foo\0bar\0 double string thing */
1734 static char*
_dbus_strdup2(const char * str)1735 _dbus_strdup2 (const char *str)
1736 {
1737   size_t len;
1738   char *copy;
1739 
1740   if (str == NULL)
1741     return NULL;
1742 
1743   len = strlen (str);
1744   len += strlen ((str + len + 1));
1745 
1746   copy = dbus_malloc (len + 2);
1747   if (copy == NULL)
1748     return NULL;
1749 
1750   memcpy (copy, str, len + 2);
1751 
1752   return copy;
1753 }
1754 
1755 /**
1756  * @ingroup DBusHashTableInternals
1757  * Unit test for DBusHashTable
1758  * @returns #TRUE on success.
1759  */
1760 dbus_bool_t
_dbus_hash_test(void)1761 _dbus_hash_test (void)
1762 {
1763   int i;
1764   DBusHashTable *table1;
1765   DBusHashTable *table2;
1766   DBusHashTable *table3;
1767   DBusHashTable *table4;
1768   DBusHashIter iter;
1769 #define N_HASH_KEYS 5000
1770   char **keys;
1771   dbus_bool_t ret = FALSE;
1772 
1773   keys = dbus_new (char *, N_HASH_KEYS);
1774   if (keys == NULL)
1775     _dbus_assert_not_reached ("no memory");
1776 
1777   for (i = 0; i < N_HASH_KEYS; i++)
1778     {
1779       keys[i] = dbus_malloc (128);
1780 
1781       if (keys[i] == NULL)
1782 	_dbus_assert_not_reached ("no memory");
1783     }
1784 
1785   printf ("Computing test hash keys...\n");
1786   i = 0;
1787   while (i < N_HASH_KEYS)
1788     {
1789       int len;
1790 
1791       /* all the hash keys are TWO_STRINGS, but
1792        * then we can also use those as regular strings.
1793        */
1794 
1795       len = sprintf (keys[i], "Hash key %d", i);
1796       sprintf (keys[i] + len + 1, "Two string %d", i);
1797       _dbus_assert (*(keys[i] + len) == '\0');
1798       _dbus_assert (*(keys[i] + len + 1) != '\0');
1799       ++i;
1800     }
1801   printf ("... done.\n");
1802 
1803   table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
1804                                  dbus_free, dbus_free);
1805   if (table1 == NULL)
1806     goto out;
1807 
1808   table2 = _dbus_hash_table_new (DBUS_HASH_INT,
1809                                  NULL, dbus_free);
1810   if (table2 == NULL)
1811     goto out;
1812 
1813   table3 = _dbus_hash_table_new (DBUS_HASH_UINTPTR,
1814                                  NULL, dbus_free);
1815   if (table3 == NULL)
1816     goto out;
1817 
1818   table4 = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS,
1819                                  dbus_free, dbus_free);
1820   if (table4 == NULL)
1821     goto out;
1822 
1823 
1824   /* Insert and remove a bunch of stuff, counting the table in between
1825    * to be sure it's not broken and that iteration works
1826    */
1827   i = 0;
1828   while (i < 3000)
1829     {
1830       void *value;
1831       char *key;
1832 
1833       key = _dbus_strdup (keys[i]);
1834       if (key == NULL)
1835         goto out;
1836       value = _dbus_strdup ("Value!");
1837       if (value == NULL)
1838         goto out;
1839 
1840       if (!_dbus_hash_table_insert_string (table1,
1841                                            key, value))
1842         goto out;
1843 
1844       value = _dbus_strdup (keys[i]);
1845       if (value == NULL)
1846         goto out;
1847 
1848       if (!_dbus_hash_table_insert_int (table2,
1849                                         i, value))
1850         goto out;
1851 
1852       value = _dbus_strdup (keys[i]);
1853       if (value == NULL)
1854         goto out;
1855 
1856       if (!_dbus_hash_table_insert_uintptr (table3,
1857                                           i, value))
1858         goto out;
1859 
1860       key = _dbus_strdup2 (keys[i]);
1861       if (key == NULL)
1862         goto out;
1863       value = _dbus_strdup ("Value!");
1864       if (value == NULL)
1865         goto out;
1866 
1867       if (!_dbus_hash_table_insert_two_strings (table4,
1868                                                 key, value))
1869         goto out;
1870 
1871       _dbus_assert (count_entries (table1) == i + 1);
1872       _dbus_assert (count_entries (table2) == i + 1);
1873       _dbus_assert (count_entries (table3) == i + 1);
1874       _dbus_assert (count_entries (table4) == i + 1);
1875 
1876       value = _dbus_hash_table_lookup_string (table1, keys[i]);
1877       _dbus_assert (value != NULL);
1878       _dbus_assert (strcmp (value, "Value!") == 0);
1879 
1880       value = _dbus_hash_table_lookup_int (table2, i);
1881       _dbus_assert (value != NULL);
1882       _dbus_assert (strcmp (value, keys[i]) == 0);
1883 
1884       value = _dbus_hash_table_lookup_uintptr (table3, i);
1885       _dbus_assert (value != NULL);
1886       _dbus_assert (strcmp (value, keys[i]) == 0);
1887 
1888       value = _dbus_hash_table_lookup_two_strings (table4, keys[i]);
1889       _dbus_assert (value != NULL);
1890       _dbus_assert (strcmp (value, "Value!") == 0);
1891 
1892       ++i;
1893     }
1894 
1895   --i;
1896   while (i >= 0)
1897     {
1898       _dbus_hash_table_remove_string (table1,
1899                                       keys[i]);
1900 
1901       _dbus_hash_table_remove_int (table2, i);
1902 
1903       _dbus_hash_table_remove_uintptr (table3, i);
1904 
1905       _dbus_hash_table_remove_two_strings (table4,
1906                                            keys[i]);
1907 
1908       _dbus_assert (count_entries (table1) == i);
1909       _dbus_assert (count_entries (table2) == i);
1910       _dbus_assert (count_entries (table3) == i);
1911       _dbus_assert (count_entries (table4) == i);
1912 
1913       --i;
1914     }
1915 
1916   _dbus_hash_table_ref (table1);
1917   _dbus_hash_table_ref (table2);
1918   _dbus_hash_table_ref (table3);
1919   _dbus_hash_table_ref (table4);
1920   _dbus_hash_table_unref (table1);
1921   _dbus_hash_table_unref (table2);
1922   _dbus_hash_table_unref (table3);
1923   _dbus_hash_table_unref (table4);
1924   _dbus_hash_table_unref (table1);
1925   _dbus_hash_table_unref (table2);
1926   _dbus_hash_table_unref (table3);
1927   _dbus_hash_table_unref (table4);
1928   table3 = NULL;
1929 
1930   /* Insert a bunch of stuff then check
1931    * that iteration works correctly (finds the right
1932    * values, iter_set_value works, etc.)
1933    */
1934   table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
1935                                  dbus_free, dbus_free);
1936   if (table1 == NULL)
1937     goto out;
1938 
1939   table2 = _dbus_hash_table_new (DBUS_HASH_INT,
1940                                  NULL, dbus_free);
1941   if (table2 == NULL)
1942     goto out;
1943 
1944   i = 0;
1945   while (i < 5000)
1946     {
1947       char *key;
1948       void *value;
1949 
1950       key = _dbus_strdup (keys[i]);
1951       if (key == NULL)
1952         goto out;
1953       value = _dbus_strdup ("Value!");
1954       if (value == NULL)
1955         goto out;
1956 
1957       if (!_dbus_hash_table_insert_string (table1,
1958                                            key, value))
1959         goto out;
1960 
1961       value = _dbus_strdup (keys[i]);
1962       if (value == NULL)
1963         goto out;
1964 
1965       if (!_dbus_hash_table_insert_int (table2,
1966                                         i, value))
1967         goto out;
1968 
1969       _dbus_assert (count_entries (table1) == i + 1);
1970       _dbus_assert (count_entries (table2) == i + 1);
1971 
1972       ++i;
1973     }
1974 
1975   _dbus_hash_iter_init (table1, &iter);
1976   while (_dbus_hash_iter_next (&iter))
1977     {
1978       const char *key;
1979       void *value;
1980 
1981       key = _dbus_hash_iter_get_string_key (&iter);
1982       value = _dbus_hash_iter_get_value (&iter);
1983 
1984       _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value);
1985 
1986       value = _dbus_strdup ("Different value!");
1987       if (value == NULL)
1988         goto out;
1989 
1990       _dbus_hash_iter_set_value (&iter, value);
1991 
1992       _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value);
1993     }
1994 
1995   _dbus_hash_iter_init (table1, &iter);
1996   while (_dbus_hash_iter_next (&iter))
1997     {
1998       _dbus_hash_iter_remove_entry (&iter);
1999       _dbus_assert (count_entries (table1) == i - 1);
2000       --i;
2001     }
2002 
2003   _dbus_hash_iter_init (table2, &iter);
2004   while (_dbus_hash_iter_next (&iter))
2005     {
2006       int key;
2007       void *value;
2008 
2009       key = _dbus_hash_iter_get_int_key (&iter);
2010       value = _dbus_hash_iter_get_value (&iter);
2011 
2012       _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value);
2013 
2014       value = _dbus_strdup ("Different value!");
2015       if (value == NULL)
2016         goto out;
2017 
2018       _dbus_hash_iter_set_value (&iter, value);
2019 
2020       _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value);
2021     }
2022 
2023   i = count_entries (table2);
2024   _dbus_hash_iter_init (table2, &iter);
2025   while (_dbus_hash_iter_next (&iter))
2026     {
2027       _dbus_hash_iter_remove_entry (&iter);
2028       _dbus_assert (count_entries (table2) + 1 == i);
2029       --i;
2030     }
2031 
2032   /* add/remove interleaved, to check that we grow/shrink the table
2033    * appropriately
2034    */
2035   i = 0;
2036   while (i < 1000)
2037     {
2038       char *key;
2039       void *value;
2040 
2041       key = _dbus_strdup (keys[i]);
2042       if (key == NULL)
2043         goto out;
2044 
2045       value = _dbus_strdup ("Value!");
2046       if (value == NULL)
2047         goto out;
2048 
2049       if (!_dbus_hash_table_insert_string (table1,
2050                                            key, value))
2051         goto out;
2052 
2053       ++i;
2054     }
2055 
2056   --i;
2057   while (i >= 0)
2058     {
2059       char *key;
2060       void *value;
2061 
2062       key = _dbus_strdup (keys[i]);
2063       if (key == NULL)
2064         goto out;
2065       value = _dbus_strdup ("Value!");
2066       if (value == NULL)
2067         goto out;
2068 
2069       if (!_dbus_hash_table_remove_string (table1, keys[i]))
2070         goto out;
2071 
2072       if (!_dbus_hash_table_insert_string (table1,
2073                                            key, value))
2074         goto out;
2075 
2076       if (!_dbus_hash_table_remove_string (table1, keys[i]))
2077         goto out;
2078 
2079       _dbus_assert (_dbus_hash_table_get_n_entries (table1) == i);
2080 
2081       --i;
2082     }
2083 
2084   /* nuke these tables */
2085   _dbus_hash_table_unref (table1);
2086   _dbus_hash_table_unref (table2);
2087 
2088 
2089   /* Now do a bunch of things again using _dbus_hash_iter_lookup() to
2090    * be sure that interface works.
2091    */
2092   table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
2093                                  dbus_free, dbus_free);
2094   if (table1 == NULL)
2095     goto out;
2096 
2097   table2 = _dbus_hash_table_new (DBUS_HASH_INT,
2098                                  NULL, dbus_free);
2099   if (table2 == NULL)
2100     goto out;
2101 
2102   i = 0;
2103   while (i < 3000)
2104     {
2105       void *value;
2106       char *key;
2107 
2108       key = _dbus_strdup (keys[i]);
2109       if (key == NULL)
2110         goto out;
2111       value = _dbus_strdup ("Value!");
2112       if (value == NULL)
2113         goto out;
2114 
2115       if (!_dbus_hash_iter_lookup (table1,
2116                                    key, TRUE, &iter))
2117         goto out;
2118       _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL);
2119       _dbus_hash_iter_set_value (&iter, value);
2120 
2121       value = _dbus_strdup (keys[i]);
2122       if (value == NULL)
2123         goto out;
2124 
2125       if (!_dbus_hash_iter_lookup (table2,
2126                                    _DBUS_INT_TO_POINTER (i), TRUE, &iter))
2127         goto out;
2128       _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL);
2129       _dbus_hash_iter_set_value (&iter, value);
2130 
2131       _dbus_assert (count_entries (table1) == i + 1);
2132       _dbus_assert (count_entries (table2) == i + 1);
2133 
2134       if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter))
2135         goto out;
2136 
2137       value = _dbus_hash_iter_get_value (&iter);
2138       _dbus_assert (value != NULL);
2139       _dbus_assert (strcmp (value, "Value!") == 0);
2140 
2141       /* Iterate just to be sure it works, though
2142        * it's a stupid thing to do
2143        */
2144       while (_dbus_hash_iter_next (&iter))
2145         ;
2146 
2147       if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter))
2148         goto out;
2149 
2150       value = _dbus_hash_iter_get_value (&iter);
2151       _dbus_assert (value != NULL);
2152       _dbus_assert (strcmp (value, keys[i]) == 0);
2153 
2154       /* Iterate just to be sure it works, though
2155        * it's a stupid thing to do
2156        */
2157       while (_dbus_hash_iter_next (&iter))
2158         ;
2159 
2160       ++i;
2161     }
2162 
2163   --i;
2164   while (i >= 0)
2165     {
2166       if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter))
2167         _dbus_assert_not_reached ("hash entry should have existed");
2168       _dbus_hash_iter_remove_entry (&iter);
2169 
2170       if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter))
2171         _dbus_assert_not_reached ("hash entry should have existed");
2172       _dbus_hash_iter_remove_entry (&iter);
2173 
2174       _dbus_assert (count_entries (table1) == i);
2175       _dbus_assert (count_entries (table2) == i);
2176 
2177       --i;
2178     }
2179 
2180   _dbus_hash_table_unref (table1);
2181   _dbus_hash_table_unref (table2);
2182 
2183   ret = TRUE;
2184 
2185  out:
2186   for (i = 0; i < N_HASH_KEYS; i++)
2187     dbus_free (keys[i]);
2188 
2189   dbus_free (keys);
2190 
2191   return ret;
2192 }
2193 
2194 #endif /* DBUS_BUILD_TESTS */
2195