00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 
00077 #include "dbus-hash.h"
00078 #include "dbus-internals.h"
00079 #include "dbus-mempool.h"
00080 
00103 #define REBUILD_MULTIPLIER  3
00104 
00121 #define RANDOM_INDEX(table, i) \
00122     (((((long) (i))*1103515245) >> (table)->down_shift) & (table)->mask)
00123 
00129 #define DBUS_SMALL_HASH_TABLE 4
00130 
00134 typedef struct DBusHashEntry DBusHashEntry;
00135 
00142 struct DBusHashEntry
00143 {
00144   DBusHashEntry *next;    
00148   void *key;              
00149   void *value;            
00150 };
00151 
00155 typedef DBusHashEntry* (* DBusFindEntryFunction) (DBusHashTable        *table,
00156                                                   void                 *key,
00157                                                   dbus_bool_t           create_if_not_found,
00158                                                   DBusHashEntry      ***bucket,
00159                                                   DBusPreallocatedHash *preallocated);
00160 
00167 struct DBusHashTable {
00168   int refcount;                       
00170   DBusHashEntry **buckets;            
00174   DBusHashEntry *static_buckets[DBUS_SMALL_HASH_TABLE];
00178   int n_buckets;                       
00181   int n_entries;                       
00184   int hi_rebuild_size;                 
00187   int lo_rebuild_size;                 
00190   int down_shift;                      
00194   int mask;                            
00197   DBusHashType key_type;               
00200   DBusFindEntryFunction find_function; 
00202   DBusFreeFunction free_key_function;   
00203   DBusFreeFunction free_value_function; 
00205   DBusMemPool *entry_pool;              
00206 };
00207 
00211 typedef struct
00212 {
00213   DBusHashTable *table;     
00214   DBusHashEntry **bucket;   
00218   DBusHashEntry *entry;      
00219   DBusHashEntry *next_entry; 
00220   int next_bucket;           
00221   int n_entries_on_init;     
00222 } DBusRealHashIter;
00223 
00224 static DBusHashEntry* find_direct_function      (DBusHashTable          *table,
00225                                                  void                   *key,
00226                                                  dbus_bool_t             create_if_not_found,
00227                                                  DBusHashEntry        ***bucket,
00228                                                  DBusPreallocatedHash   *preallocated);
00229 static DBusHashEntry* find_string_function      (DBusHashTable          *table,
00230                                                  void                   *key,
00231                                                  dbus_bool_t             create_if_not_found,
00232                                                  DBusHashEntry        ***bucket,
00233                                                  DBusPreallocatedHash   *preallocated);
00234 #ifdef DBUS_BUILD_TESTS
00235 static DBusHashEntry* find_two_strings_function (DBusHashTable          *table,
00236                                                  void                   *key,
00237                                                  dbus_bool_t             create_if_not_found,
00238                                                  DBusHashEntry        ***bucket,
00239                                                  DBusPreallocatedHash   *preallocated);
00240 #endif
00241 static unsigned int   string_hash               (const char             *str);
00242 #ifdef DBUS_BUILD_TESTS
00243 static unsigned int   two_strings_hash          (const char             *str);
00244 #endif
00245 static void           rebuild_table             (DBusHashTable          *table);
00246 static DBusHashEntry* alloc_entry               (DBusHashTable          *table);
00247 static void           remove_entry              (DBusHashTable          *table,
00248                                                  DBusHashEntry         **bucket,
00249                                                  DBusHashEntry          *entry);
00250 static void           free_entry                (DBusHashTable          *table,
00251                                                  DBusHashEntry          *entry);
00252 static void           free_entry_data           (DBusHashTable          *table,
00253                                                  DBusHashEntry          *entry);
00254 
00255 
00291 DBusHashTable*
00292 _dbus_hash_table_new (DBusHashType     type,
00293                       DBusFreeFunction key_free_function,
00294                       DBusFreeFunction value_free_function)
00295 {
00296   DBusHashTable *table;
00297   DBusMemPool *entry_pool;
00298   
00299   table = dbus_new0 (DBusHashTable, 1);
00300   if (table == NULL)
00301     return NULL;
00302 
00303   entry_pool = _dbus_mem_pool_new (sizeof (DBusHashEntry), TRUE);
00304   if (entry_pool == NULL)
00305     {
00306       dbus_free (table);
00307       return NULL;
00308     }
00309   
00310   table->refcount = 1;
00311   table->entry_pool = entry_pool;
00312   
00313   _dbus_assert (DBUS_SMALL_HASH_TABLE == _DBUS_N_ELEMENTS (table->static_buckets));
00314   
00315   table->buckets = table->static_buckets;  
00316   table->n_buckets = DBUS_SMALL_HASH_TABLE;
00317   table->n_entries = 0;
00318   table->hi_rebuild_size = DBUS_SMALL_HASH_TABLE * REBUILD_MULTIPLIER;
00319   table->lo_rebuild_size = 0;
00320   table->down_shift = 28;
00321   table->mask = 3;
00322   table->key_type = type;
00323 
00324   _dbus_assert (table->mask < table->n_buckets);
00325   
00326   switch (table->key_type)
00327     {
00328     case DBUS_HASH_INT:
00329     case DBUS_HASH_POINTER:
00330     case DBUS_HASH_ULONG:
00331       table->find_function = find_direct_function;
00332       break;
00333     case DBUS_HASH_STRING:
00334       table->find_function = find_string_function;
00335       break;
00336     case DBUS_HASH_TWO_STRINGS:
00337 #ifdef DBUS_BUILD_TESTS
00338       table->find_function = find_two_strings_function;
00339 #endif
00340       break;
00341     default:
00342       _dbus_assert_not_reached ("Unknown hash table type");
00343       break;
00344     }
00345 
00346   table->free_key_function = key_free_function;
00347   table->free_value_function = value_free_function;
00348 
00349   return table;
00350 }
00351 
00352 
00359 DBusHashTable *
00360 _dbus_hash_table_ref (DBusHashTable *table)
00361 {
00362   table->refcount += 1;
00363   
00364   return table;
00365 }
00366 
00373 void
00374 _dbus_hash_table_unref (DBusHashTable *table)
00375 {
00376   table->refcount -= 1;
00377 
00378   if (table->refcount == 0)
00379     {
00380 #if 0
00381       DBusHashEntry *entry;
00382       DBusHashEntry *next;
00383       int i;
00384 
00385       
00386       for (i = 0; i < table->n_buckets; i++)
00387         {
00388           entry = table->buckets[i];
00389           while (entry != NULL)
00390             {
00391               next = entry->next;
00392 
00393               free_entry (table, entry);
00394               
00395               entry = next;
00396             }
00397         }
00398 #else
00399       DBusHashEntry *entry;
00400       int i;
00401 
00402       
00403       for (i = 0; i < table->n_buckets; i++)
00404         {
00405           entry = table->buckets[i];
00406           while (entry != NULL)
00407             {
00408               free_entry_data (table, entry);
00409               
00410               entry = entry->next;
00411             }
00412         }
00413       
00414       _dbus_mem_pool_free (table->entry_pool);
00415 #endif
00416       
00417       
00418       if (table->buckets != table->static_buckets)
00419         dbus_free (table->buckets);
00420 
00421       dbus_free (table);
00422     }
00423 }
00424 
00430 void
00431 _dbus_hash_table_remove_all (DBusHashTable *table)
00432 {
00433   DBusHashIter iter;
00434   _dbus_hash_iter_init (table, &iter);
00435   while (_dbus_hash_iter_next (&iter))
00436     {
00437       _dbus_hash_iter_remove_entry(&iter);
00438     }
00439 }
00440 
00441 static DBusHashEntry*
00442 alloc_entry (DBusHashTable *table)
00443 {
00444   DBusHashEntry *entry;
00445 
00446   entry = _dbus_mem_pool_alloc (table->entry_pool);
00447   
00448   return entry;
00449 }
00450 
00451 static void
00452 free_entry_data (DBusHashTable  *table,
00453                  DBusHashEntry  *entry)
00454 {
00455   if (table->free_key_function)
00456     (* table->free_key_function) (entry->key);
00457   if (table->free_value_function)
00458     (* table->free_value_function) (entry->value);
00459 }
00460 
00461 static void
00462 free_entry (DBusHashTable  *table,
00463             DBusHashEntry  *entry)
00464 {
00465   free_entry_data (table, entry);
00466   _dbus_mem_pool_dealloc (table->entry_pool, entry);
00467 }
00468 
00469 static void
00470 remove_entry (DBusHashTable  *table,
00471               DBusHashEntry **bucket,
00472               DBusHashEntry  *entry)
00473 {
00474   _dbus_assert (table != NULL);
00475   _dbus_assert (bucket != NULL);
00476   _dbus_assert (*bucket != NULL);  
00477   _dbus_assert (entry != NULL);
00478   
00479   if (*bucket == entry)
00480     *bucket = entry->next;
00481   else
00482     {
00483       DBusHashEntry *prev;
00484       prev = *bucket;
00485 
00486       while (prev->next != entry)
00487         prev = prev->next;      
00488       
00489       _dbus_assert (prev != NULL);
00490 
00491       prev->next = entry->next;
00492     }
00493   
00494   table->n_entries -= 1;
00495   free_entry (table, entry);
00496 }
00497 
00529 void
00530 _dbus_hash_iter_init (DBusHashTable *table,
00531                       DBusHashIter  *iter)
00532 {
00533   DBusRealHashIter *real;
00534   
00535   _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
00536   
00537   real = (DBusRealHashIter*) iter;
00538 
00539   real->table = table;
00540   real->bucket = NULL;
00541   real->entry = NULL;
00542   real->next_entry = NULL;
00543   real->next_bucket = 0;
00544   real->n_entries_on_init = table->n_entries;
00545 }
00546 
00555 dbus_bool_t
00556 _dbus_hash_iter_next (DBusHashIter  *iter)
00557 {
00558   DBusRealHashIter *real;
00559   
00560   _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
00561   
00562   real = (DBusRealHashIter*) iter;
00563 
00564   
00565 
00566 
00567   _dbus_assert (real->n_entries_on_init >= real->table->n_entries);
00568   
00569   
00570   
00571   while (real->next_entry == NULL)
00572     {
00573       if (real->next_bucket >= real->table->n_buckets)
00574         {
00575           
00576           real->entry = NULL;
00577           real->table = NULL;
00578           real->bucket = NULL;
00579           return FALSE;
00580         }
00581 
00582       real->bucket = &(real->table->buckets[real->next_bucket]);
00583       real->next_entry = *(real->bucket);
00584       real->next_bucket += 1;
00585     }
00586 
00587   _dbus_assert (real->next_entry != NULL);
00588   _dbus_assert (real->bucket != NULL);
00589   
00590   real->entry = real->next_entry;
00591   real->next_entry = real->entry->next;
00592   
00593   return TRUE;
00594 }
00595 
00604 void
00605 _dbus_hash_iter_remove_entry (DBusHashIter *iter)
00606 {
00607   DBusRealHashIter *real;
00608 
00609   real = (DBusRealHashIter*) iter;
00610 
00611   _dbus_assert (real->table != NULL);
00612   _dbus_assert (real->entry != NULL);
00613   _dbus_assert (real->bucket != NULL);
00614   
00615   remove_entry (real->table, real->bucket, real->entry);
00616 
00617   real->entry = NULL; 
00618 }
00619 
00625 void*
00626 _dbus_hash_iter_get_value (DBusHashIter *iter)
00627 {
00628   DBusRealHashIter *real;
00629 
00630   real = (DBusRealHashIter*) iter;
00631 
00632   _dbus_assert (real->table != NULL);
00633   _dbus_assert (real->entry != NULL);
00634 
00635   return real->entry->value;
00636 }
00637 
00648 void
00649 _dbus_hash_iter_set_value (DBusHashIter *iter,
00650                            void         *value)
00651 {
00652   DBusRealHashIter *real;
00653 
00654   real = (DBusRealHashIter*) iter;
00655 
00656   _dbus_assert (real->table != NULL);
00657   _dbus_assert (real->entry != NULL);
00658 
00659   if (real->table->free_value_function && value != real->entry->value)    
00660     (* real->table->free_value_function) (real->entry->value);
00661   
00662   real->entry->value = value;
00663 }
00664 
00671 int
00672 _dbus_hash_iter_get_int_key (DBusHashIter *iter)
00673 {
00674   DBusRealHashIter *real;
00675 
00676   real = (DBusRealHashIter*) iter;
00677 
00678   _dbus_assert (real->table != NULL);
00679   _dbus_assert (real->entry != NULL);
00680 
00681   return _DBUS_POINTER_TO_INT (real->entry->key);
00682 }
00683 
00690 unsigned long
00691 _dbus_hash_iter_get_ulong_key (DBusHashIter *iter)
00692 {
00693   DBusRealHashIter *real;
00694 
00695   real = (DBusRealHashIter*) iter;
00696 
00697   _dbus_assert (real->table != NULL);
00698   _dbus_assert (real->entry != NULL);
00699 
00700   return (unsigned long) real->entry->key;
00701 }
00702 
00708 const char*
00709 _dbus_hash_iter_get_string_key (DBusHashIter *iter)
00710 {
00711   DBusRealHashIter *real;
00712 
00713   real = (DBusRealHashIter*) iter;
00714 
00715   _dbus_assert (real->table != NULL);
00716   _dbus_assert (real->entry != NULL);
00717 
00718   return real->entry->key;
00719 }
00720 
00721 #ifdef DBUS_BUILD_TESTS
00722 
00727 const char*
00728 _dbus_hash_iter_get_two_strings_key (DBusHashIter *iter)
00729 {
00730   DBusRealHashIter *real;
00731 
00732   real = (DBusRealHashIter*) iter;
00733 
00734   _dbus_assert (real->table != NULL);
00735   _dbus_assert (real->entry != NULL);
00736 
00737   return real->entry->key;
00738 }
00739 #endif 
00740 
00772 dbus_bool_t
00773 _dbus_hash_iter_lookup (DBusHashTable *table,
00774                         void          *key,
00775                         dbus_bool_t    create_if_not_found,
00776                         DBusHashIter  *iter)
00777 {
00778   DBusRealHashIter *real;
00779   DBusHashEntry *entry;
00780   DBusHashEntry **bucket;
00781   
00782   _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter));
00783   
00784   real = (DBusRealHashIter*) iter;
00785 
00786   entry = (* table->find_function) (table, key, create_if_not_found, &bucket, NULL);
00787 
00788   if (entry == NULL)
00789     return FALSE;
00790   
00791   real->table = table;
00792   real->bucket = bucket;
00793   real->entry = entry;
00794   real->next_entry = entry->next;
00795   real->next_bucket = (bucket - table->buckets) + 1;
00796   real->n_entries_on_init = table->n_entries; 
00797 
00798   _dbus_assert (&(table->buckets[real->next_bucket-1]) == real->bucket);
00799   
00800   return TRUE;
00801 }
00802 
00803 static void
00804 add_allocated_entry (DBusHashTable   *table,
00805                      DBusHashEntry   *entry,
00806                      unsigned int     idx,
00807                      void            *key,
00808                      DBusHashEntry ***bucket)
00809 {
00810   DBusHashEntry **b;  
00811   
00812   entry->key = key;
00813   
00814   b = &(table->buckets[idx]);
00815   entry->next = *b;
00816   *b = entry;
00817 
00818   if (bucket)
00819     *bucket = b;
00820   
00821   table->n_entries += 1;
00822 
00823   
00824 
00825 
00826   if (table->n_entries >= table->hi_rebuild_size ||
00827       table->n_entries < table->lo_rebuild_size)
00828     rebuild_table (table);
00829 }
00830 
00831 static DBusHashEntry*
00832 add_entry (DBusHashTable        *table, 
00833            unsigned int          idx,
00834            void                 *key,
00835            DBusHashEntry      ***bucket,
00836            DBusPreallocatedHash *preallocated)
00837 {
00838   DBusHashEntry  *entry;
00839 
00840   if (preallocated == NULL)
00841     {
00842       entry = alloc_entry (table);
00843       if (entry == NULL)
00844         {
00845           if (bucket)
00846             *bucket = NULL;
00847           return NULL;
00848         }
00849     }
00850   else
00851     {
00852       entry = (DBusHashEntry*) preallocated;
00853     }
00854 
00855   add_allocated_entry (table, entry, idx, key, bucket);
00856 
00857   return entry;
00858 }
00859 
00860 
00861 
00862 
00863 static unsigned int
00864 string_hash (const char *str)
00865 {
00866   const char *p = str;
00867   unsigned int h = *p;
00868 
00869   if (h)
00870     for (p += 1; *p != '\0'; p++)
00871       h = (h << 5) - h + *p;
00872 
00873   return h;
00874 }
00875 
00876 #ifdef DBUS_BUILD_TESTS
00877 
00878 
00879 
00880 static unsigned int
00881 two_strings_hash (const char *str)
00882 {
00883   const char *p = str;
00884   unsigned int h = *p;
00885 
00886   if (h)
00887     for (p += 1; *p != '\0'; p++)
00888       h = (h << 5) - h + *p;
00889 
00890   for (p += 1; *p != '\0'; p++)
00891     h = (h << 5) - h + *p;
00892   
00893   return h;
00894 }
00895 #endif 
00896 
00898 typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b);
00899 
00900 static DBusHashEntry*
00901 find_generic_function (DBusHashTable        *table,
00902                        void                 *key,
00903                        unsigned int          idx,
00904                        KeyCompareFunc        compare_func,
00905                        dbus_bool_t           create_if_not_found,
00906                        DBusHashEntry      ***bucket,
00907                        DBusPreallocatedHash *preallocated)
00908 {
00909   DBusHashEntry *entry;
00910 
00911   if (bucket)
00912     *bucket = NULL;
00913 
00914   
00915   entry = table->buckets[idx];
00916   while (entry != NULL)
00917     {
00918       if ((compare_func == NULL && key == entry->key) ||
00919           (compare_func != NULL && (* compare_func) (key, entry->key) == 0))
00920         {
00921           if (bucket)
00922             *bucket = &(table->buckets[idx]);
00923 
00924           if (preallocated)
00925             _dbus_hash_table_free_preallocated_entry (table, preallocated);
00926           
00927           return entry;
00928         }
00929       
00930       entry = entry->next;
00931     }
00932 
00933   if (create_if_not_found)
00934     entry = add_entry (table, idx, key, bucket, preallocated);
00935   else if (preallocated)
00936     _dbus_hash_table_free_preallocated_entry (table, preallocated);
00937   
00938   return entry;
00939 }
00940 
00941 static DBusHashEntry*
00942 find_string_function (DBusHashTable        *table,
00943                       void                 *key,
00944                       dbus_bool_t           create_if_not_found,
00945                       DBusHashEntry      ***bucket,
00946                       DBusPreallocatedHash *preallocated)
00947 {
00948   unsigned int idx;
00949   
00950   idx = string_hash (key) & table->mask;
00951 
00952   return find_generic_function (table, key, idx,
00953                                 (KeyCompareFunc) strcmp, create_if_not_found, bucket,
00954                                 preallocated);
00955 }
00956 
00957 #ifdef DBUS_BUILD_TESTS
00958 static int
00959 two_strings_cmp (const char *a,
00960                  const char *b)
00961 {
00962   size_t len_a;
00963   size_t len_b;
00964   int res;
00965   
00966   res = strcmp (a, b);
00967   if (res != 0)
00968     return res;
00969 
00970   len_a = strlen (a);
00971   len_b = strlen (b);
00972 
00973   return strcmp (a + len_a + 1, b + len_b + 1);
00974 }
00975 #endif
00976 
00977 #ifdef DBUS_BUILD_TESTS
00978 static DBusHashEntry*
00979 find_two_strings_function (DBusHashTable        *table,
00980                            void                 *key,
00981                            dbus_bool_t           create_if_not_found,
00982                            DBusHashEntry      ***bucket,
00983                            DBusPreallocatedHash *preallocated)
00984 {
00985   unsigned int idx;
00986   
00987   idx = two_strings_hash (key) & table->mask;
00988 
00989   return find_generic_function (table, key, idx,
00990                                 (KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket,
00991                                 preallocated);
00992 }
00993 #endif 
00994 
00995 static DBusHashEntry*
00996 find_direct_function (DBusHashTable        *table,
00997                       void                 *key,
00998                       dbus_bool_t           create_if_not_found,
00999                       DBusHashEntry      ***bucket,
01000                       DBusPreallocatedHash *preallocated)
01001 {
01002   unsigned int idx;
01003   
01004   idx = RANDOM_INDEX (table, key) & table->mask;
01005 
01006 
01007   return find_generic_function (table, key, idx,
01008                                 NULL, create_if_not_found, bucket,
01009                                 preallocated);
01010 }
01011 
01012 static void
01013 rebuild_table (DBusHashTable *table)
01014 {
01015   int old_size;
01016   int new_buckets;
01017   DBusHashEntry **old_buckets;
01018   DBusHashEntry **old_chain;
01019   DBusHashEntry *entry;
01020   dbus_bool_t growing;
01021   
01022   
01023 
01024 
01025 
01026 
01027   growing = table->n_entries >= table->hi_rebuild_size;
01028   
01029   old_size = table->n_buckets;
01030   old_buckets = table->buckets;
01031 
01032   if (growing)
01033     {
01034       
01035       if (table->n_buckets < _DBUS_INT_MAX / 4 &&
01036           table->down_shift >= 0)
01037         new_buckets = table->n_buckets * 4;
01038       else
01039         return; 
01040     }
01041   else
01042     {
01043       new_buckets = table->n_buckets / 4;
01044       if (new_buckets < DBUS_SMALL_HASH_TABLE)
01045         return; 
01046     }
01047 
01048   table->buckets = dbus_new0 (DBusHashEntry*, new_buckets);
01049   if (table->buckets == NULL)
01050     {
01051       
01052 
01053 
01054       table->buckets = old_buckets;
01055       return;
01056     }
01057 
01058   table->n_buckets = new_buckets;
01059   
01060   if (growing)
01061     {
01062       table->lo_rebuild_size = table->hi_rebuild_size;
01063       table->hi_rebuild_size *= 4;
01064       
01065       table->down_shift -= 2;               
01066       table->mask = (table->mask << 2) + 3; 
01067     }
01068   else
01069     {
01070       table->hi_rebuild_size = table->lo_rebuild_size;
01071       table->lo_rebuild_size /= 4;
01072 
01073       table->down_shift += 2;         
01074       table->mask = table->mask >> 2; 
01075     }
01076 
01077 #if 0
01078   printf ("%s table to lo = %d hi = %d downshift = %d mask = 0x%x\n",
01079           growing ? "GROW" : "SHRINK",
01080           table->lo_rebuild_size,
01081           table->hi_rebuild_size,
01082           table->down_shift,
01083           table->mask);
01084 #endif
01085   
01086   _dbus_assert (table->lo_rebuild_size >= 0);
01087   _dbus_assert (table->hi_rebuild_size > table->lo_rebuild_size);
01088   _dbus_assert (table->mask != 0);
01089   
01090   _dbus_assert (table->mask < table->n_buckets);
01091   
01092   
01093 
01094 
01095 
01096   for (old_chain = old_buckets; old_size > 0; old_size--, old_chain++)
01097     {
01098       for (entry = *old_chain; entry != NULL; entry = *old_chain)
01099         {
01100           unsigned int idx;
01101           DBusHashEntry **bucket;
01102           
01103           *old_chain = entry->next;
01104           switch (table->key_type)
01105             {
01106             case DBUS_HASH_STRING:
01107               idx = string_hash (entry->key) & table->mask;
01108               break;
01109             case DBUS_HASH_TWO_STRINGS:
01110 #ifdef DBUS_BUILD_TESTS
01111               idx = two_strings_hash (entry->key) & table->mask;
01112 #else
01113               idx = 0;
01114               _dbus_assert_not_reached ("two-strings is not enabled");
01115 #endif
01116               break;
01117             case DBUS_HASH_INT:
01118             case DBUS_HASH_ULONG:
01119             case DBUS_HASH_POINTER:
01120               idx = RANDOM_INDEX (table, entry->key);
01121               break;
01122             default:
01123               idx = 0;
01124               _dbus_assert_not_reached ("Unknown hash table type");
01125               break;
01126             }
01127           
01128           bucket = &(table->buckets[idx]);
01129           entry->next = *bucket;
01130           *bucket = entry;
01131         }
01132     }
01133   
01134   
01135 
01136   if (old_buckets != table->static_buckets)
01137     dbus_free (old_buckets);
01138 }
01139 
01149 void*
01150 _dbus_hash_table_lookup_string (DBusHashTable *table,
01151                                 const char    *key)
01152 {
01153   DBusHashEntry *entry;
01154 
01155   _dbus_assert (table->key_type == DBUS_HASH_STRING);
01156   
01157   entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
01158 
01159   if (entry)
01160     return entry->value;
01161   else
01162     return NULL;
01163 }
01164 
01165 #ifdef DBUS_BUILD_TESTS
01166 
01175 void*
01176 _dbus_hash_table_lookup_two_strings (DBusHashTable *table,
01177                                      const char    *key)
01178 {
01179   DBusHashEntry *entry;
01180 
01181   _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
01182   
01183   entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
01184 
01185   if (entry)
01186     return entry->value;
01187   else
01188     return NULL;
01189 }
01190 #endif 
01191 
01201 void*
01202 _dbus_hash_table_lookup_int (DBusHashTable *table,
01203                              int            key)
01204 {
01205   DBusHashEntry *entry;
01206 
01207   _dbus_assert (table->key_type == DBUS_HASH_INT);
01208   
01209   entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, NULL, NULL);
01210 
01211   if (entry)
01212     return entry->value;
01213   else
01214     return NULL;
01215 }
01216 
01217 #ifdef DBUS_BUILD_TESTS
01218 
01228 void*
01229 _dbus_hash_table_lookup_pointer (DBusHashTable *table,
01230                                  void          *key)
01231 {
01232   DBusHashEntry *entry;
01233 
01234   _dbus_assert (table->key_type == DBUS_HASH_POINTER);
01235   
01236   entry = (* table->find_function) (table, key, FALSE, NULL, NULL);
01237 
01238   if (entry)
01239     return entry->value;
01240   else
01241     return NULL;
01242 }
01243 #endif 
01244 
01254 void*
01255 _dbus_hash_table_lookup_ulong (DBusHashTable *table,
01256                                unsigned long  key)
01257 {
01258   DBusHashEntry *entry;
01259 
01260   _dbus_assert (table->key_type == DBUS_HASH_ULONG);
01261   
01262   entry = (* table->find_function) (table, (void*) key, FALSE, NULL, NULL);
01263 
01264   if (entry)
01265     return entry->value;
01266   else
01267     return NULL;
01268 }
01269 
01278 dbus_bool_t
01279 _dbus_hash_table_remove_string (DBusHashTable *table,
01280                                 const char    *key)
01281 {
01282   DBusHashEntry *entry;
01283   DBusHashEntry **bucket;
01284   
01285   _dbus_assert (table->key_type == DBUS_HASH_STRING);
01286   
01287   entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
01288 
01289   if (entry)
01290     {
01291       remove_entry (table, bucket, entry);
01292       return TRUE;
01293     }
01294   else
01295     return FALSE;
01296 }
01297 
01298 #ifdef DBUS_BUILD_TESTS
01299 
01307 dbus_bool_t
01308 _dbus_hash_table_remove_two_strings (DBusHashTable *table,
01309                                      const char    *key)
01310 {
01311   DBusHashEntry *entry;
01312   DBusHashEntry **bucket;
01313   
01314   _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
01315   
01316   entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
01317 
01318   if (entry)
01319     {
01320       remove_entry (table, bucket, entry);
01321       return TRUE;
01322     }
01323   else
01324     return FALSE;
01325 }
01326 #endif 
01327 
01336 dbus_bool_t
01337 _dbus_hash_table_remove_int (DBusHashTable *table,
01338                              int            key)
01339 {
01340   DBusHashEntry *entry;
01341   DBusHashEntry **bucket;
01342   
01343   _dbus_assert (table->key_type == DBUS_HASH_INT);
01344   
01345   entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, &bucket, NULL);
01346   
01347   if (entry)
01348     {
01349       remove_entry (table, bucket, entry);
01350       return TRUE;
01351     }
01352   else
01353     return FALSE;
01354 }
01355 
01356 #ifdef DBUS_BUILD_TESTS
01357 
01366 dbus_bool_t
01367 _dbus_hash_table_remove_pointer (DBusHashTable *table,
01368                                  void          *key)
01369 {
01370   DBusHashEntry *entry;
01371   DBusHashEntry **bucket;
01372   
01373   _dbus_assert (table->key_type == DBUS_HASH_POINTER);
01374   
01375   entry = (* table->find_function) (table, key, FALSE, &bucket, NULL);
01376   
01377   if (entry)
01378     {
01379       remove_entry (table, bucket, entry);
01380       return TRUE;
01381     }
01382   else
01383     return FALSE;
01384 }
01385 #endif 
01386 
01395 dbus_bool_t
01396 _dbus_hash_table_remove_ulong (DBusHashTable *table,
01397                                unsigned long  key)
01398 {
01399   DBusHashEntry *entry;
01400   DBusHashEntry **bucket;
01401   
01402   _dbus_assert (table->key_type == DBUS_HASH_ULONG);
01403   
01404   entry = (* table->find_function) (table, (void*) key, FALSE, &bucket, NULL);
01405   
01406   if (entry)
01407     {
01408       remove_entry (table, bucket, entry);
01409       return TRUE;
01410     }
01411   else
01412     return FALSE;
01413 }
01414 
01430 dbus_bool_t
01431 _dbus_hash_table_insert_string (DBusHashTable *table,
01432                                 char          *key,
01433                                 void          *value)
01434 {
01435   DBusPreallocatedHash *preallocated;
01436 
01437   _dbus_assert (table->key_type == DBUS_HASH_STRING);
01438 
01439   preallocated = _dbus_hash_table_preallocate_entry (table);
01440   if (preallocated == NULL)
01441     return FALSE;
01442 
01443   _dbus_hash_table_insert_string_preallocated (table, preallocated,
01444                                                key, value);
01445   
01446   return TRUE;
01447 }
01448 
01449 #ifdef DBUS_BUILD_TESTS
01450 
01465 dbus_bool_t
01466 _dbus_hash_table_insert_two_strings (DBusHashTable *table,
01467                                      char          *key,
01468                                      void          *value)
01469 {
01470   DBusHashEntry *entry;
01471   
01472   _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
01473   
01474   entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
01475 
01476   if (entry == NULL)
01477     return FALSE; 
01478 
01479   if (table->free_key_function && entry->key != key)
01480     (* table->free_key_function) (entry->key);
01481   
01482   if (table->free_value_function && entry->value != value)
01483     (* table->free_value_function) (entry->value);
01484   
01485   entry->key = key;
01486   entry->value = value;
01487 
01488   return TRUE;
01489 }
01490 #endif 
01491 
01507 dbus_bool_t
01508 _dbus_hash_table_insert_int (DBusHashTable *table,
01509                              int            key,
01510                              void          *value)
01511 {
01512   DBusHashEntry *entry;
01513 
01514   _dbus_assert (table->key_type == DBUS_HASH_INT);
01515   
01516   entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), TRUE, NULL, NULL);
01517 
01518   if (entry == NULL)
01519     return FALSE; 
01520 
01521   if (table->free_key_function && entry->key != _DBUS_INT_TO_POINTER (key))
01522     (* table->free_key_function) (entry->key);
01523   
01524   if (table->free_value_function && entry->value != value)
01525     (* table->free_value_function) (entry->value);
01526   
01527   entry->key = _DBUS_INT_TO_POINTER (key);
01528   entry->value = value;
01529 
01530   return TRUE;
01531 }
01532 
01533 #ifdef DBUS_BUILD_TESTS
01534 
01550 dbus_bool_t
01551 _dbus_hash_table_insert_pointer (DBusHashTable *table,
01552                                  void          *key,
01553                                  void          *value)
01554 {
01555   DBusHashEntry *entry;
01556 
01557   _dbus_assert (table->key_type == DBUS_HASH_POINTER);
01558   
01559   entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
01560 
01561   if (entry == NULL)
01562     return FALSE; 
01563 
01564   if (table->free_key_function && entry->key != key)
01565     (* table->free_key_function) (entry->key);
01566   
01567   if (table->free_value_function && entry->value != value)
01568     (* table->free_value_function) (entry->value);
01569   
01570   entry->key = key;
01571   entry->value = value;
01572 
01573   return TRUE;
01574 }
01575 #endif 
01576 
01592 dbus_bool_t
01593 _dbus_hash_table_insert_ulong (DBusHashTable *table,
01594                                unsigned long  key,
01595                                void          *value)
01596 {
01597   DBusHashEntry *entry;
01598 
01599   _dbus_assert (table->key_type == DBUS_HASH_ULONG);
01600   
01601   entry = (* table->find_function) (table, (void*) key, TRUE, NULL, NULL);
01602 
01603   if (entry == NULL)
01604     return FALSE; 
01605 
01606   if (table->free_key_function && entry->key != (void*) key)
01607     (* table->free_key_function) (entry->key);
01608   
01609   if (table->free_value_function && entry->value != value)
01610     (* table->free_value_function) (entry->value);
01611   
01612   entry->key = (void*) key;
01613   entry->value = value;
01614 
01615   return TRUE;
01616 }
01617 
01625 DBusPreallocatedHash*
01626 _dbus_hash_table_preallocate_entry (DBusHashTable *table)
01627 {
01628   DBusHashEntry *entry;
01629   
01630   entry = alloc_entry (table);
01631 
01632   return (DBusPreallocatedHash*) entry;
01633 }
01634 
01642 void
01643 _dbus_hash_table_free_preallocated_entry (DBusHashTable        *table,
01644                                           DBusPreallocatedHash *preallocated)
01645 {
01646   DBusHashEntry *entry;
01647 
01648   _dbus_assert (preallocated != NULL);
01649   
01650   entry = (DBusHashEntry*) preallocated;
01651   
01652   
01653   _dbus_mem_pool_dealloc (table->entry_pool, entry);
01654 }
01655 
01669 void
01670 _dbus_hash_table_insert_string_preallocated (DBusHashTable        *table,
01671                                              DBusPreallocatedHash *preallocated,
01672                                              char                 *key,
01673                                              void                 *value)
01674 {
01675   DBusHashEntry *entry;
01676 
01677   _dbus_assert (table->key_type == DBUS_HASH_STRING);
01678   _dbus_assert (preallocated != NULL);
01679   
01680   entry = (* table->find_function) (table, key, TRUE, NULL, preallocated);
01681 
01682   _dbus_assert (entry != NULL);
01683   
01684   if (table->free_key_function && entry->key != key)
01685     (* table->free_key_function) (entry->key);
01686 
01687   if (table->free_value_function && entry->value != value)
01688     (* table->free_value_function) (entry->value);
01689       
01690   entry->key = key;
01691   entry->value = value;
01692 }
01693 
01700 int
01701 _dbus_hash_table_get_n_entries (DBusHashTable *table)
01702 {
01703   return table->n_entries;
01704 }
01705 
01708 #ifdef DBUS_BUILD_TESTS
01709 #include "dbus-test.h"
01710 #include <stdio.h>
01711 
01712 
01713 
01714 
01715 
01716 static int
01717 count_entries (DBusHashTable *table)
01718 {
01719   DBusHashIter iter;
01720   int count;
01721 
01722   count = 0;
01723   _dbus_hash_iter_init (table, &iter);
01724   while (_dbus_hash_iter_next (&iter))
01725     ++count;
01726 
01727   _dbus_assert (count == _dbus_hash_table_get_n_entries (table));
01728   
01729   return count;
01730 }
01731 
01732 
01733 static char*
01734 _dbus_strdup2 (const char *str)
01735 {
01736   size_t len;
01737   char *copy;
01738   
01739   if (str == NULL)
01740     return NULL;
01741   
01742   len = strlen (str);
01743   len += strlen ((str + len + 1));
01744 
01745   copy = dbus_malloc (len + 2);
01746   if (copy == NULL)
01747     return NULL;
01748 
01749   memcpy (copy, str, len + 2);
01750   
01751   return copy;
01752 }
01753 
01759 dbus_bool_t
01760 _dbus_hash_test (void)
01761 {
01762   int i;
01763   DBusHashTable *table1;
01764   DBusHashTable *table2;
01765   DBusHashTable *table3;
01766   DBusHashTable *table4;
01767   DBusHashIter iter;
01768 #define N_HASH_KEYS 5000
01769   char **keys;
01770   dbus_bool_t ret = FALSE;
01771 
01772   keys = dbus_new (char *, N_HASH_KEYS);
01773   if (keys == NULL)
01774     _dbus_assert_not_reached ("no memory");
01775 
01776   for (i = 0; i < N_HASH_KEYS; i++)
01777     {
01778       keys[i] = dbus_malloc (128);
01779 
01780       if (keys[i] == NULL)
01781         _dbus_assert_not_reached ("no memory");
01782     }
01783 
01784   printf ("Computing test hash keys...\n");
01785   i = 0;
01786   while (i < N_HASH_KEYS)
01787     {
01788       int len;
01789 
01790       
01791 
01792 
01793       
01794       len = sprintf (keys[i], "Hash key %d", i);
01795       sprintf (keys[i] + len + 1, "Two string %d", i);
01796       _dbus_assert (*(keys[i] + len) == '\0');
01797       _dbus_assert (*(keys[i] + len + 1) != '\0');
01798       ++i;
01799     }
01800   printf ("... done.\n");
01801   
01802   table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
01803                                  dbus_free, dbus_free);
01804   if (table1 == NULL)
01805     goto out;
01806 
01807   table2 = _dbus_hash_table_new (DBUS_HASH_INT,
01808                                  NULL, dbus_free);
01809   if (table2 == NULL)
01810     goto out;
01811 
01812   table3 = _dbus_hash_table_new (DBUS_HASH_ULONG,
01813                                  NULL, dbus_free);
01814   if (table3 == NULL)
01815     goto out;
01816 
01817   table4 = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS,
01818                                  dbus_free, dbus_free);
01819   if (table4 == NULL)
01820     goto out;
01821 
01822   
01823   
01824 
01825 
01826   i = 0;
01827   while (i < 3000)
01828     {
01829       void *value;
01830       char *key;
01831 
01832       key = _dbus_strdup (keys[i]);
01833       if (key == NULL)
01834         goto out;
01835       value = _dbus_strdup ("Value!");
01836       if (value == NULL)
01837         goto out;
01838       
01839       if (!_dbus_hash_table_insert_string (table1,
01840                                            key, value))
01841         goto out;
01842 
01843       value = _dbus_strdup (keys[i]);
01844       if (value == NULL)
01845         goto out;
01846       
01847       if (!_dbus_hash_table_insert_int (table2,
01848                                         i, value))
01849         goto out;
01850 
01851       value = _dbus_strdup (keys[i]);
01852       if (value == NULL)
01853         goto out;
01854       
01855       if (!_dbus_hash_table_insert_ulong (table3,
01856                                           i, value))
01857         goto out;
01858 
01859       key = _dbus_strdup2 (keys[i]);
01860       if (key == NULL)
01861         goto out;
01862       value = _dbus_strdup ("Value!");
01863       if (value == NULL)
01864         goto out;
01865       
01866       if (!_dbus_hash_table_insert_two_strings (table4,
01867                                                 key, value))
01868         goto out;
01869       
01870       _dbus_assert (count_entries (table1) == i + 1);
01871       _dbus_assert (count_entries (table2) == i + 1);
01872       _dbus_assert (count_entries (table3) == i + 1);
01873       _dbus_assert (count_entries (table4) == i + 1);
01874 
01875       value = _dbus_hash_table_lookup_string (table1, keys[i]);
01876       _dbus_assert (value != NULL);
01877       _dbus_assert (strcmp (value, "Value!") == 0);
01878 
01879       value = _dbus_hash_table_lookup_int (table2, i);
01880       _dbus_assert (value != NULL);
01881       _dbus_assert (strcmp (value, keys[i]) == 0);
01882 
01883       value = _dbus_hash_table_lookup_ulong (table3, i);
01884       _dbus_assert (value != NULL);
01885       _dbus_assert (strcmp (value, keys[i]) == 0);
01886 
01887       value = _dbus_hash_table_lookup_two_strings (table4, keys[i]);
01888       _dbus_assert (value != NULL);
01889       _dbus_assert (strcmp (value, "Value!") == 0);
01890       
01891       ++i;
01892     }
01893 
01894   --i;
01895   while (i >= 0)
01896     {
01897       _dbus_hash_table_remove_string (table1,
01898                                       keys[i]);
01899 
01900       _dbus_hash_table_remove_int (table2, i);
01901 
01902       _dbus_hash_table_remove_ulong (table3, i); 
01903 
01904       _dbus_hash_table_remove_two_strings (table4,
01905                                            keys[i]);
01906       
01907       _dbus_assert (count_entries (table1) == i);
01908       _dbus_assert (count_entries (table2) == i);
01909       _dbus_assert (count_entries (table3) == i);
01910       _dbus_assert (count_entries (table4) == i);
01911 
01912       --i;
01913     }
01914 
01915   _dbus_hash_table_ref (table1);
01916   _dbus_hash_table_ref (table2);
01917   _dbus_hash_table_ref (table3);
01918   _dbus_hash_table_ref (table4);
01919   _dbus_hash_table_unref (table1);
01920   _dbus_hash_table_unref (table2);
01921   _dbus_hash_table_unref (table3);
01922   _dbus_hash_table_unref (table4);
01923   _dbus_hash_table_unref (table1);
01924   _dbus_hash_table_unref (table2);
01925   _dbus_hash_table_unref (table3);
01926   _dbus_hash_table_unref (table4);
01927   table3 = NULL;
01928 
01929   
01930 
01931 
01932 
01933   table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
01934                                  dbus_free, dbus_free);
01935   if (table1 == NULL)
01936     goto out;
01937   
01938   table2 = _dbus_hash_table_new (DBUS_HASH_INT,
01939                                  NULL, dbus_free);
01940   if (table2 == NULL)
01941     goto out;
01942   
01943   i = 0;
01944   while (i < 5000)
01945     {
01946       char *key;
01947       void *value;      
01948       
01949       key = _dbus_strdup (keys[i]);
01950       if (key == NULL)
01951         goto out;
01952       value = _dbus_strdup ("Value!");
01953       if (value == NULL)
01954         goto out;
01955       
01956       if (!_dbus_hash_table_insert_string (table1,
01957                                            key, value))
01958         goto out;
01959 
01960       value = _dbus_strdup (keys[i]);
01961       if (value == NULL)
01962         goto out;
01963       
01964       if (!_dbus_hash_table_insert_int (table2,
01965                                         i, value))
01966         goto out;
01967       
01968       _dbus_assert (count_entries (table1) == i + 1);
01969       _dbus_assert (count_entries (table2) == i + 1);
01970       
01971       ++i;
01972     }
01973 
01974   _dbus_hash_iter_init (table1, &iter);
01975   while (_dbus_hash_iter_next (&iter))
01976     {
01977       const char *key;
01978       void *value;
01979 
01980       key = _dbus_hash_iter_get_string_key (&iter);
01981       value = _dbus_hash_iter_get_value (&iter);
01982 
01983       _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value);
01984 
01985       value = _dbus_strdup ("Different value!");
01986       if (value == NULL)
01987         goto out;
01988       
01989       _dbus_hash_iter_set_value (&iter, value);
01990 
01991       _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value);
01992     }
01993   
01994   _dbus_hash_iter_init (table1, &iter);
01995   while (_dbus_hash_iter_next (&iter))
01996     {
01997       _dbus_hash_iter_remove_entry (&iter);
01998       _dbus_assert (count_entries (table1) == i - 1);
01999       --i;
02000     }
02001 
02002   _dbus_hash_iter_init (table2, &iter);
02003   while (_dbus_hash_iter_next (&iter))
02004     {
02005       int key;
02006       void *value;
02007 
02008       key = _dbus_hash_iter_get_int_key (&iter);
02009       value = _dbus_hash_iter_get_value (&iter);
02010 
02011       _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value);
02012 
02013       value = _dbus_strdup ("Different value!");
02014       if (value == NULL)
02015         goto out;
02016       
02017       _dbus_hash_iter_set_value (&iter, value);
02018 
02019       _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value);
02020     }
02021 
02022   i = count_entries (table2);
02023   _dbus_hash_iter_init (table2, &iter);
02024   while (_dbus_hash_iter_next (&iter))
02025     {
02026       _dbus_hash_iter_remove_entry (&iter);
02027       _dbus_assert (count_entries (table2) + 1 == i);
02028       --i;
02029     }
02030 
02031   
02032 
02033 
02034   i = 0;
02035   while (i < 1000)
02036     {
02037       char *key;
02038       void *value;
02039             
02040       key = _dbus_strdup (keys[i]);
02041       if (key == NULL)
02042         goto out;
02043 
02044       value = _dbus_strdup ("Value!");
02045       if (value == NULL)
02046         goto out;
02047       
02048       if (!_dbus_hash_table_insert_string (table1,
02049                                            key, value))
02050         goto out;
02051       
02052       ++i;
02053     }
02054 
02055   --i;
02056   while (i >= 0)
02057     {
02058       char *key;
02059       void *value;      
02060       
02061       key = _dbus_strdup (keys[i]);
02062       if (key == NULL)
02063         goto out;
02064       value = _dbus_strdup ("Value!");
02065       if (value == NULL)
02066         goto out;
02067 
02068       if (!_dbus_hash_table_remove_string (table1, keys[i]))
02069         goto out;
02070       
02071       if (!_dbus_hash_table_insert_string (table1,
02072                                            key, value))
02073         goto out;
02074 
02075       if (!_dbus_hash_table_remove_string (table1, keys[i]))
02076         goto out;
02077       
02078       _dbus_assert (_dbus_hash_table_get_n_entries (table1) == i);
02079       
02080       --i;
02081     }
02082 
02083   
02084   _dbus_hash_table_unref (table1);
02085   _dbus_hash_table_unref (table2);
02086 
02087 
02088   
02089 
02090 
02091   table1 = _dbus_hash_table_new (DBUS_HASH_STRING,
02092                                  dbus_free, dbus_free);
02093   if (table1 == NULL)
02094     goto out;
02095   
02096   table2 = _dbus_hash_table_new (DBUS_HASH_INT,
02097                                  NULL, dbus_free);
02098   if (table2 == NULL)
02099     goto out;
02100   
02101   i = 0;
02102   while (i < 3000)
02103     {
02104       void *value;
02105       char *key;
02106 
02107       key = _dbus_strdup (keys[i]);
02108       if (key == NULL)
02109         goto out;
02110       value = _dbus_strdup ("Value!");
02111       if (value == NULL)
02112         goto out;
02113       
02114       if (!_dbus_hash_iter_lookup (table1,
02115                                    key, TRUE, &iter))
02116         goto out;
02117       _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL);
02118       _dbus_hash_iter_set_value (&iter, value);
02119 
02120       value = _dbus_strdup (keys[i]);
02121       if (value == NULL)
02122         goto out;
02123 
02124       if (!_dbus_hash_iter_lookup (table2,
02125                                    _DBUS_INT_TO_POINTER (i), TRUE, &iter))
02126         goto out;
02127       _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL);
02128       _dbus_hash_iter_set_value (&iter, value); 
02129       
02130       _dbus_assert (count_entries (table1) == i + 1);
02131       _dbus_assert (count_entries (table2) == i + 1);
02132 
02133       if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter))
02134         goto out;
02135       
02136       value = _dbus_hash_iter_get_value (&iter);
02137       _dbus_assert (value != NULL);
02138       _dbus_assert (strcmp (value, "Value!") == 0);
02139 
02140       
02141 
02142 
02143       while (_dbus_hash_iter_next (&iter))
02144         ;
02145       
02146       if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter))
02147         goto out;
02148 
02149       value = _dbus_hash_iter_get_value (&iter);
02150       _dbus_assert (value != NULL);
02151       _dbus_assert (strcmp (value, keys[i]) == 0);
02152 
02153       
02154 
02155 
02156       while (_dbus_hash_iter_next (&iter))
02157         ;
02158       
02159       ++i;
02160     }
02161 
02162   --i;
02163   while (i >= 0)
02164     {
02165       if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter))
02166         _dbus_assert_not_reached ("hash entry should have existed");
02167       _dbus_hash_iter_remove_entry (&iter);
02168       
02169       if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter))
02170         _dbus_assert_not_reached ("hash entry should have existed");
02171       _dbus_hash_iter_remove_entry (&iter);
02172 
02173       _dbus_assert (count_entries (table1) == i);
02174       _dbus_assert (count_entries (table2) == i);
02175 
02176       --i;
02177     }
02178 
02179   _dbus_hash_table_unref (table1);
02180   _dbus_hash_table_unref (table2);
02181 
02182   ret = TRUE;
02183 
02184  out:
02185   for (i = 0; i < N_HASH_KEYS; i++)
02186     dbus_free (keys[i]);
02187 
02188   dbus_free (keys);
02189   
02190   return ret;
02191 }
02192 
02193 #endif