Simple data structures / objects in plain C Snapshot
|
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