00001 #ifndef _CP_HASHTABLE_H 00002 #define _CP_HASHTABLE_H 00003 00004 /* 00005 * hash table implementation 00006 */ 00007 00008 /** 00009 * @addtogroup cp_hashtable 00010 * @ingroup collection 00011 * @copydoc collection 00012 * 00013 */ 00014 /** @{ */ 00015 /** 00016 * @file 00017 * generic synchronized hashtable. 00018 * 00019 * Here is an example of using a cp_hashtable to create a lookup for 'bar' 00020 * items using 'foo' keys: 00021 * 00022 * <code><pre> 00023 * unsigned long foo_hash_code(void *fooptr) 00024 * { 00025 * return ((foo *) fooptr)->id; 00026 * } 00027 * 00028 * // compare function 00029 * int foo_compare(void *f1, void *f2) 00030 * { 00031 * return ((foo *) f1)->id != ((foo *) f2)->id; 00032 * } 00033 * 00034 * ... 00035 * 00036 * cp_hashtable *t; 00037 * foo *foo1, *f; 00038 * bar *bar1, *bar2; 00039 * 00040 * t = cp_hashtable_create(10, foo_hash_code, foo_compare); 00041 * if (t == NULL) 00042 * { 00043 * perror("can\'t create cp_hashtable"); 00044 * exit(1); 00045 * } 00046 * 00047 * cp_hashtable_put(foo1, bar1, t); 00048 * 00049 * ... 00050 * f = foo_create(...); 00051 * ... 00052 * 00053 * if ((bar2 = (bar *) cp_hashtable_get(f, t))) 00054 * printf("%s maps to %s\n", foo_get_name(f), bar_get_name(bar2)); 00055 * else 00056 * printf("%s is not mapped\n", foo_get_name(f)); 00057 * 00058 * ... 00059 * 00060 * cp_hashtable_destroy(t); 00061 * </pre></code> 00062 * 00063 * Note the strcmp like semantics of the compare function. The comparison 00064 * should return 0 for identical keys. 00065 * <p> 00066 * @see hash.h (util.collection) for function prototypes 00067 * and convenience functions. 00068 * @see cp_hashtable_create, cp_hashtable_destroy, cp_hashtable_destroy_deep, cp_hashtable_put, 00069 * cp_hashtable_get, cp_hashtable_contains, cp_hashtable_remove_deep 00070 */ 00071 00072 #include "common.h" 00073 00074 __BEGIN_DECLS 00075 00076 #include "collection.h" 00077 00078 /* 00079 * cp_hashtable interface for members of mapping collections. 00080 */ 00081 00082 #include "config.h" 00083 00084 /** 00085 * 1000000001 is a prime. HASH_SEED is used by cp_hash_string(). 00086 */ 00087 #define HASH_SEED 1000000001L 00088 00089 #ifndef CP_HASHTABLE_DEFAULT_MIN_FILL_FACTOR 00090 #define CP_HASHTABLE_DEFAULT_MIN_FILL_FACTOR 5 00091 #endif 00092 00093 #ifndef CP_HASHTABLE_DEFAULT_MAX_FILL_FACTOR 00094 #define CP_HASHTABLE_DEFAULT_MAX_FILL_FACTOR 70 00095 #endif 00096 00097 /* ----------------------------------------------------------------- 00098 * Function prototypes 00099 * ----------------------------------------------------------------- */ 00100 /** 00101 * the hash function takes (void *) and returns unsigned long. 00102 * 00103 * Create a function with the name <class_name>_hash_code() 00104 */ 00105 typedef unsigned long (*cp_hashfunction)(void *); 00106 00107 00108 /* ------------------------------------------------------------------------ 00109 * hash function prototypes for primitives and cp_strings 00110 * ------------------------------------------------------------------------ */ 00111 00112 00113 /** 00114 * hash function for int keys 00115 * @param key pointer to the int 00116 * @return hash code of the key 00117 */ 00118 CPROPS_DLL 00119 unsigned long cp_hash_int(void *key); 00120 00121 00122 /** 00123 * comparator for int keys 00124 * @param key1 pointer the first int 00125 * @param key2 pointer the second int 00126 * @retval 0 if key1 equals key2; 00127 * @retval <0 if key1 is less than key2; 00128 * @retval >0 if key1 is greater than key2 00129 00130 */ 00131 CPROPS_DLL 00132 int cp_hash_compare_int(void *key1, void *key2); 00133 00134 /** 00135 * hash function for long keys 00136 */ 00137 CPROPS_DLL 00138 unsigned long cp_hash_long(void *key); 00139 00140 /** 00141 * comparator for long keys 00142 * 00143 * @param key1 pointer the first long 00144 * @param key2 pointer the second long 00145 * @retval 0 if key1 equals key2; 00146 * @retval <0 if key1 is less than key2; 00147 * @retval >0 if key1 is greater than key2 00148 */ 00149 CPROPS_DLL 00150 int cp_hash_compare_long(void *key1, void *key2); 00151 00152 /** 00153 * hash function for pointer keys 00154 */ 00155 CPROPS_DLL 00156 unsigned long cp_hash_addr(void *addr); 00157 00158 /** 00159 * comparator for pointer keys 00160 * 00161 * @param key1 pointer the first pointer 00162 * @param key2 pointer the second pointer 00163 * @retval 0 if key1 equals key2; 00164 * @retval <0 if key1 is less than key2; 00165 * @retval >0 if key1 is greater than key2 00166 */ 00167 CPROPS_DLL 00168 int cp_hash_compare_addr(void *key1, void *key2); 00169 00170 /** 00171 * hash function for (char *) keys 00172 * @param key pointer to the cp_string 00173 * @return hash code of the key 00174 */ 00175 CPROPS_DLL 00176 unsigned long cp_hash_string(void *key); 00177 00178 /** 00179 * case insensitive hash function for (char *) keys 00180 * @param key pointer to the cp_string 00181 * @return hash code of the key 00182 */ 00183 CPROPS_DLL 00184 unsigned long cp_hash_istring(void *key); 00185 00186 00187 /** 00188 * copy function for cp_string copy tables 00189 */ 00190 CPROPS_DLL 00191 void *cp_hash_copy_string(void *element); 00192 00193 /** 00194 * comparator for (char *) keys 00195 * 00196 * @param key1 pointer to the first cp_string 00197 * @param key2 pointer to the second cp_string 00198 * @retval 0 if key1 equals key2 00199 * @retval <>0 otherwise 00200 */ 00201 CPROPS_DLL 00202 int cp_hash_compare_string(void *key1, void *key2); 00203 00204 00205 /** 00206 * comparator for (char *) keys 00207 * 00208 * @param key1 pointer to the first cp_string 00209 * @param key2 pointer to the second cp_string 00210 * @retval 0 if key1 equals key2 00211 * @retval <>0 otherwise 00212 */ 00213 CPROPS_DLL 00214 int cp_hash_compare_istring(void *key1, void *key2); 00215 00216 00217 00218 /** 00219 * Internal object that implements a key, value pair plus linked list. 00220 * 00221 * Entries which are stored under the same index in the hashtable are stored 00222 * in a linked list. The algorithm of the hashtable has to ensure that the lists 00223 * do not get too long. 00224 */ 00225 typedef CPROPS_DLL struct _cp_hashtable_entry 00226 { 00227 void *key; /**< key (original) needed for comparisons */ 00228 void *value; /**< the item value being stored */ 00229 unsigned long hashcode; /**< save calculated hash-code of the key */ 00230 struct _cp_hashtable_entry *next; /**< link to next entry */ 00231 } cp_hashtable_entry; 00232 00233 /** 00234 * data structure of generic synchronized cp_hashtable 00235 */ 00236 typedef CPROPS_DLL struct _cp_hashtable 00237 { 00238 cp_hashtable_entry **table; /**< array of pointers to entries */ 00239 long table_size; /**< size of the table */ 00240 00241 unsigned long items; /**< number of items in the table */ 00242 int mode; /**< collection mode @see collection.h */ 00243 cp_hashfunction hash_fn; /**< pointer to hash function */ 00244 cp_compare_fn compare_fn; /**< pointer to compare function */ 00245 cp_copy_fn copy_key; /**< pointer to key copy function */ 00246 cp_copy_fn copy_value; /**< pointer to value copy function */ 00247 cp_destructor_fn free_key; 00248 cp_destructor_fn free_value; 00249 00250 cp_lock *lock; /**< lock */ 00251 cp_thread txowner; /**< lock owner */ 00252 int txtype; /**< lock type */ 00253 00254 int min_size; /**< table resize lower limit */ 00255 int fill_factor_min; /**< minimal fill factor in percent */ 00256 int fill_factor_max; /**< maximal fill factor in percent */ 00257 00258 cp_hashtable_entry **resize_table; /**< temp table for resizing */ 00259 int resizing; /**< resize running flag */ 00260 unsigned long resize_len; /**< resize table length */ 00261 cp_thread resize_thread; /**< run resize in a separate thread */ 00262 cp_mutex *resize_lock; /**< for synchronizing resize operation */ 00263 } cp_hashtable; 00264 00265 00266 /** 00267 * creates a new cp_hashtable. 00268 * 00269 * by default there is no memory management for table content; insertion, 00270 * removal and retrieval operations are synchronized; and the table will 00271 * automatically resize when the fill factor goes over 70% or under 5%. 00272 * @param size_hint an estimate for the initial storage requirements. The table 00273 * 00274 * handles the storage appropriately when items become too tight. 00275 * @param hashfn a hash code function. This should ideally produce different 00276 * results for different keys. 00277 * @param compare_fn the comparator for your key type. 00278 * 00279 * @return a pointer to the newly created cp_hashtable. 00280 */ 00281 CPROPS_DLL 00282 cp_hashtable * 00283 cp_hashtable_create(unsigned long size_hint, 00284 cp_hashfunction hashfn, 00285 cp_compare_fn compare_fn); 00286 00287 /** 00288 * creates a new cp_hashtable with the specified mode. 00289 */ 00290 #define cp_hashtable_create_by_mode(mode, size_hint, cp_hashfn, compare_fn) \ 00291 cp_hashtable_create_by_option((mode), (size_hint), (cp_hashfn), (compare_fn), NULL, NULL, NULL, NULL) 00292 00293 /** 00294 * creates a new cp_hashtable with COLLECTION_MODE_DEEP | COLLECTION_MODE_COPY. 00295 * @param size_hint an estimate for the initial storage requirements. The table 00296 * handles the storage appropriately when items become too tight. 00297 * @param hashfn a hash code function. This should ideally produce different 00298 * results for different keys. 00299 * @param compare_fn the comparator for your key type. 00300 * 00301 * @return a pointer to the newly created cp_hashtable. 00302 */ 00303 CPROPS_DLL 00304 cp_hashtable * 00305 cp_hashtable_create_copy_mode(unsigned long size_hint, 00306 cp_hashfunction hash_fn, 00307 cp_compare_fn compare_fn, 00308 cp_copy_fn copy_key, 00309 cp_destructor_fn free_key, 00310 cp_copy_fn copy_value, 00311 cp_destructor_fn free_value); 00312 00313 /** 00314 * create a new table, fully specifying all parameters. 00315 * @param size_hint initial capacity 00316 * @param hash_fn hash function 00317 * @param compare_fn key comparison function 00318 * @param copy_key function to return new copies of keys 00319 * @param copy_value function to return new copies of values 00320 * @param mode mode flags 00321 * 00322 * @return new created cp_hashtable. Returns NULL case of error. 00323 */ 00324 CPROPS_DLL 00325 cp_hashtable * 00326 cp_hashtable_create_by_option(int mode, unsigned long size_hint, 00327 cp_hashfunction hash_fn, 00328 cp_compare_fn compare_fn, 00329 cp_copy_fn copy_key, 00330 cp_destructor_fn free_key, 00331 cp_copy_fn copy_value, 00332 cp_destructor_fn free_value); 00333 00334 /** 00335 * deletes a cp_hashtable according to the current mode settings 00336 * @param table object to delete 00337 */ 00338 CPROPS_DLL 00339 void cp_hashtable_destroy(cp_hashtable *table); 00340 00341 /** 00342 * deletes a cp_hashtable. Pointers to the keys and values are not released. Use 00343 * table if the keys and values you entered in the table should not be released 00344 * by the cp_hashtable. 00345 * @param table object to delete 00346 */ 00347 CPROPS_DLL 00348 void cp_hashtable_destroy_shallow(cp_hashtable *table); 00349 00350 /** 00351 * deletes a cp_hashtable. Keys and values entered in the cp_hashtable are released. 00352 * @param table object to delete 00353 */ 00354 CPROPS_DLL 00355 void cp_hashtable_destroy_deep(cp_hashtable *table); 00356 00357 00358 /** 00359 * Deep destroy with custom destructors for keys and values. NULL function 00360 * pointers are not invoked. 00361 */ 00362 CPROPS_DLL 00363 void cp_hashtable_destroy_custom(cp_hashtable *table, cp_destructor_fn dk, cp_destructor_fn dv); 00364 00365 /** 00366 * by default the get, put and remove functions as well as set and unset mode 00367 * perform their own locking. Other functions do not synchronize, since it is 00368 * assumed they would be called in a single cp_thread context - the initialization * and deletion functions in particular. You can of course set 00369 * COLLECTION_MODE_NOSYNC and perform your own synchronization.<p> 00370 * 00371 * The current implementation uses a queued read/write lock where blocked 00372 * cp_threads are guaranteed to be woken by the order in which they attempted 00373 * 00374 * the following macros are defined for convenience:<p> 00375 * <ul> 00376 * <li> cp_hashtable_rdlock(table) - get a read lock on the table </li> 00377 * <li> cp_hashtable_wrlock(table) - get a write lock on the table </li> 00378 * </ul> 00379 * @param table cp_hashtable to lock 00380 * @param type COLLECTION_LOCK_READ or COLLECTION_LOCK_WRITE 00381 */ 00382 CPROPS_DLL 00383 int cp_hashtable_lock(cp_hashtable *table, int type); 00384 00385 /** unlock the table */ 00386 CPROPS_DLL 00387 int cp_hashtable_unlock(cp_hashtable *table); 00388 00389 /** macro to get a read lock on the table 00390 */ 00391 #define cp_hashtable_rdlock(table) cp_hashtable_lock((table), COLLECTION_LOCK_READ) 00392 00393 /** macro to get a write lock on the table */ 00394 #define cp_hashtable_wrlock(table) cp_hashtable_lock((table), COLLECTION_LOCK_WRITE) 00395 00396 /** 00397 * returns the current operation mode. See cp_hashtable_set_mode for a list of 00398 * mode bits and their effects. 00399 */ 00400 CPROPS_DLL 00401 int cp_hashtable_get_mode(cp_hashtable *table); 00402 00403 /** 00404 * set the operation mode as a bit set of the following options: 00405 * <ul> 00406 * <li> COLLECTION_MODE_DEEP - release memory when removing references from table </li> 00407 * <li> COLLECTION_MODE_MULTIPLE_PUT - allow multiple values for a key </li> 00408 * <li> COLLECTION_MODE_COPY - keep copies rather than references </li> 00409 * <li> COLLECTION_MODE_NOSYNC - the table will not perform its own synchronization. </li> 00410 * <li> COLLECTION_MODE_NORESIZE - the table will not resize automatically. </li> 00411 * </ul> 00412 * 00413 * The parameter bits are flipped on. If the current mode is 00414 * COLLECTION_MODE_DEEP and you want to change it, call 00415 * cp_hashtable_unset_mode(table, COLLECTION_MODE_DEEP). 00416 */ 00417 CPROPS_DLL 00418 int cp_hashtable_set_mode(cp_hashtable *table, int mode); 00419 00420 00421 /** 00422 * unset the mode bits defined by mode 00423 */ 00424 CPROPS_DLL 00425 int cp_hashtable_unset_mode(cp_hashtable *table, int mode); 00426 00427 00428 /** 00429 * the internal table will not be resized to less than min_size 00430 */ 00431 CPROPS_DLL 00432 int cp_hashtable_set_min_size(cp_hashtable *table, int min_size); 00433 00434 /** 00435 * a resize is triggered when the table contains more items than 00436 * table_size * fill_factor / 100 00437 */ 00438 CPROPS_DLL 00439 int cp_hashtable_set_max_fill_factor(cp_hashtable *table, int fill_factor); 00440 00441 /** 00442 * a resize is triggered when the table contains less items than 00443 * table_size * fill_factor / 100 00444 */ 00445 CPROPS_DLL 00446 int cp_hashtable_set_min_fill_factor(cp_hashtable *table, int fill_factor); 00447 00448 /** 00449 * attempts to retrieve the value assigned to the key 'key'. To return 00450 * multiple values the table mode must be set to COLLECTION_MODE_MULTIPLE_VALUES, 00451 * otherwise the only first value for the given key will be returned. 00452 * @retval (void*)value to the value if found 00453 * @retval NULL otherwise 00454 */ 00455 CPROPS_DLL 00456 void *cp_hashtable_get(cp_hashtable *table, void *key); 00457 00458 /** 00459 * retrieve the value or values for key 'key'. the 'mode' parameter sets the 00460 * mode for the current operation. 00461 */ 00462 CPROPS_DLL 00463 void *cp_hashtable_get_by_option(cp_hashtable *table, void *key, int mode); 00464 00465 /** 00466 * Internal put method. 00467 */ 00468 CPROPS_DLL 00469 void *cp_hashtable_put_by_option(cp_hashtable *table, void *key, void *value, int mode); 00470 00471 /** 00472 * the key 'key' will be assigned to the value 'value'. The new value will 00473 * override an old value if one exists. The old value will not be deallocated. 00474 * If you would need the old value to be released call cp_hashtable_put_safe instead. 00475 */ 00476 CPROPS_DLL 00477 void *cp_hashtable_put(cp_hashtable *table, void *key, void *value); 00478 00479 /** 00480 * same as cp_hashtable_put(table, key, value) except that an old value is released if it 00481 * exists. 00482 */ 00483 CPROPS_DLL 00484 void *cp_hashtable_put_safe(cp_hashtable *table, void *key, void *value); 00485 00486 /** 00487 * same as cp_hashtable_put(table, key, value) except that it inserts a copy 00488 * of the key and the value object. 00489 */ 00490 CPROPS_DLL 00491 void *cp_hashtable_put_copy(cp_hashtable *table, void *key, void *value); 00492 00493 /** 00494 * Attempts to remove the mapping for key from the table. 00495 * 00496 * @param table the object 00497 * @param key Key to search for. 00498 * @retval value retrieved by the key (that was removed) 00499 * @retval NULL if the table does not contain the requested key. 00500 */ 00501 CPROPS_DLL 00502 void *cp_hashtable_remove(cp_hashtable *table, void *key); 00503 00504 /** remove all entries with current mode */ 00505 CPROPS_DLL 00506 int cp_hashtable_remove_all(cp_hashtable *table); 00507 00508 /** 00509 * removes a mapping from the table, and deallocates the memory for the mapped 00510 * key and value. 00511 * 00512 * @param table the object 00513 * @param key Key to search for. 00514 * @return 1 if the operation was successful, 0 otherwise 00515 */ 00516 CPROPS_DLL 00517 int cp_hashtable_remove_deep(cp_hashtable *table, void *key); 00518 00519 /** 00520 * Check if there is an entry with matching key. 00521 * 00522 * @param table the object 00523 * @param key Key to search for. 00524 * @return 1 if table contains key, 0 otherwise 00525 */ 00526 CPROPS_DLL 00527 int cp_hashtable_contains(cp_hashtable *table, void *key); 00528 00529 /** 00530 * get an array containing all keys mapped in table table. 00531 * @note It is the responsibility of the caller to free the returned array. 00532 * @note The keys themselves must not be changed or deleted (read-only). 00533 */ 00534 CPROPS_DLL 00535 void **cp_hashtable_get_keys(cp_hashtable *table); 00536 00537 /** 00538 * get an array containing all values in the table. 00539 * @note It is the responsibility of the caller to free the returned array. 00540 * @note The values themselves must not be changed or deleted (read-only). 00541 */ 00542 CPROPS_DLL 00543 void **cp_hashtable_get_values(cp_hashtable *table); 00544 00545 /** 00546 * Get the number of entries in the collection. 00547 * @return the number of key mappings currently in the table. 00548 */ 00549 CPROPS_DLL 00550 unsigned long cp_hashtable_count(cp_hashtable *table); 00551 00552 /** 00553 * Check if the collection is empty. 00554 * @retval true/1 if the collection is empty 00555 * @retval false/0 if the collection has entries 00556 */ 00557 #define cp_hashtable_is_empty(table) (cp_hashtable_count(table) == 0) 00558 00559 /** 00560 * @return a prime greater than <code>size_request</code> 00561 */ 00562 CPROPS_DLL 00563 unsigned long cp_hashtable_choose_size(unsigned long size_request); 00564 00565 __END_DECLS 00566 /** @} */ 00567 #endif 00568