Simple data structures / objects in plain C Snapshot
bhash.c
Go to the documentation of this file.
00001 /* Copyright (c) Michael Moser (2011) . 3-clause BSD License applies */
00002 
00003 #include <cutils/bhash.h>
00004 #include <cutils/util.h>
00005 #include <cutils/hashfunction.h>
00006 
00007 
00008 
00009 #define ADJUST_HASH(hash,buckets) ((hash) & ((buckets) - 1))
00010 
00011 
00012 
00013 int HASH_init(
00014                                         HASH                    *hash,
00015                                         size_t                           buckets, 
00016                                         int                  ismultimap,
00017 
00018                                         HASH_COMPARE_KEY compare_key,
00019                                         HASH_FUNCTION hash_func
00020                                         )
00021 {
00022         size_t i;
00023 
00024         buckets = UTIL_round_to_power_of_n( buckets );
00025 
00026 
00027         hash->elmcount = 0;
00028 
00029         if (!hash_func) {
00030           hash->hash_func = HASHFUNCTION_Bob_Jenkins_one_at_a_time;
00031         } else {
00032           hash->hash_func = hash_func;
00033         }
00034         hash->compare_key = compare_key;
00035 
00036         hash->ismultimap = ismultimap;
00037 
00038         hash->buckets = (SRING *) malloc( sizeof(SRING) * buckets );
00039         if (!hash->buckets) {
00040                 return -1;
00041         }
00042         hash->buckets_size = buckets;
00043         
00044         for(i=0;i<buckets;i++) {
00045           SRING_init(  &hash->buckets[i] );
00046         }
00047 
00048 
00049         hash->mult_load_factor = 2;
00050         hash->div_load_factor = 3;
00051 
00052         hash->resize_threshold = (buckets * hash->mult_load_factor) / hash->div_load_factor;
00053 
00054         return 0;
00055 }
00056 
00057 
00058 
00059 
00060 int HASH_resize(HASH    *hash, size_t buckets)
00061 {
00062         SRING *pbuckets;
00063         size_t i;
00064         HASH_Entry *cur;
00065         size_t elmcount;
00066 
00067         buckets = UTIL_round_to_power_of_n( buckets );
00068 
00069         pbuckets = malloc( sizeof(SRING) * buckets);
00070         if (!pbuckets) {
00071                 return -1;
00072         }
00073         for(i=0;i<buckets;i++) {
00074                 SRING_init( pbuckets + i );
00075         }
00076 
00077         elmcount = hash->elmcount;
00078 
00079         HASH_DELETEALL(cur,hash)
00080                 i = ADJUST_HASH(  cur->hash, buckets);
00081                 SRING_push_front( pbuckets + i, (SRING *) cur);
00082         HASH_DELETEALL_END
00083 
00084         free( hash->buckets );
00085 
00086         hash->buckets = pbuckets;
00087         hash->buckets_size = buckets;
00088         hash->elmcount = elmcount;
00089 
00090 
00091         hash->resize_threshold = (buckets * hash->mult_load_factor) / hash->div_load_factor;
00092 
00093         return 0;
00094 
00095 }
00096 
00097 HASH_Entry *HASH_find_in_bucket(        
00098                                         
00099                                         SRING           *abucket, 
00100                                         HASH_VALUE       hash, 
00101                                         HASH_COMPARE_KEY compare_key,
00102                                         void            *key, 
00103                                         ssize_t          key_size )
00104 {
00105         SRING   *pos;
00106 
00107         SRING_FOREACH(pos, abucket) {
00108                 HASH_Entry *entry = (HASH_Entry *) pos;
00109                 if (entry->hash == hash) 
00110                 {
00111                         if (compare_key( entry, key, key_size ) == 0) {
00112                                 return entry;
00113                         }
00114                 }
00115         }
00116         return 0;
00117 }
00118 
00119 HASH_Entry *HASH_find( HASH *phash, void *key, ssize_t key_size )
00120 {
00121         HASH_VALUE hash = phash->hash_func( key, key_size );
00122         int             bucket =   ADJUST_HASH(hash, phash->buckets_size);
00123         SRING   *abucket = &phash->buckets[ bucket ];   
00124         
00125         return HASH_find_in_bucket( abucket, hash, phash->compare_key, key, key_size );
00126 }
00127 
00128 HASH_Entry *HASH_find_next( HASH *phash, HASH_Entry *prev, void *key, ssize_t key_size )
00129 {
00130         HASH_Entry *next;
00131 
00132         if (!phash->ismultimap) {
00133                 return 0;
00134         }
00135 
00136         next = (HASH_Entry *) prev->entry.next;
00137         if (!next) {
00138                 return 0;
00139         }
00140         if (next->hash != prev->hash) {
00141                 return 0;
00142         }
00143         if (phash->compare_key( next, key, key_size ) != 0) {
00144                 return 0;
00145         }
00146         return next;
00147 }
00148 
00149 int HASH_insert( HASH *phash, HASH_Entry *entry, void *key, ssize_t key_size  )
00150 {
00151         HASH_VALUE hash;
00152         int             bucket;
00153         SRING   *abucket,*fnd;
00154 
00155         if ((phash->elmcount + 1) >= phash->resize_threshold) {
00156 
00157            if (HASH_resize(phash, 2 * phash->buckets_size)) {
00158              return -1;
00159            }
00160         }
00161 
00162         hash = phash->hash_func( key, key_size );       
00163         entry->hash = hash;
00164 
00165         bucket =   ADJUST_HASH(hash, phash->buckets_size);
00166         abucket = &phash->buckets[ bucket ];   
00167         
00168         
00169         fnd = (SRING *) HASH_find_in_bucket( abucket, hash, phash->compare_key, key, key_size );
00170 
00171         /* multimap allows only one entry with the given key */
00172         if (!phash->ismultimap && fnd) {
00173                 return -1;
00174         }
00175 
00176         if (fnd) {
00177                 SRING_insert_after( fnd, &entry->entry );
00178         } else {
00179                 SRING_push_front( abucket,  &entry->entry );
00180         }
00181         phash->elmcount++;
00182 
00183         return 0;
00184 }
00185 
00186 HASH_Entry * HASH_unlink( HASH *phash, void *key, ssize_t key_size )
00187 {
00188         HASH_VALUE hash;
00189         int             bucket;
00190         SRING   *abucket;
00191         SRING   *pos,*prev;
00192         HASH_Entry *ret = 0;
00193 
00194 
00195         hash =  phash->hash_func( key, key_size );      
00196         bucket =   ADJUST_HASH(hash, phash->buckets_size);
00197         abucket = &phash->buckets[ bucket ];   
00198 
00199         prev = abucket;
00200         SRING_FOREACH(pos, abucket) {
00201                 HASH_Entry *entry = (HASH_Entry *) pos;
00202 
00203                 if (entry->hash == hash) {
00204                   
00205                         if (phash->compare_key( entry, key, key_size ) == 0) {
00206                                 ret = (HASH_Entry *) SRING_unlink_after(prev);
00207                                 phash->elmcount--;      
00208                                 return ret;
00209                         }
00210                 }
00211                 prev = pos;
00212         }
00213 
00214         return 0;
00215 }
00216 
00217 
00218