00001 /*! \file chtbl.c 00002 Hash table implementation 00003 */ 00004 00005 #include <stdlib.h> 00006 #include <string.h> 00007 #include "list.h" 00008 #include "chtbl.h" 00009 00010 00011 00012 /*! \brief Initialize the hash table. This function must be called first. 00013 \param htab Pointer to a hash table data structure. 00014 \param conteneurs Number of linked list in the hash table. 00015 \param h Pointer to the function used to hash the input key. 00016 \param corresp Pointer to the function used to compare user's defined data. This function is specific to the type of data stored into 00017 the hash table. This function must return if the user defined data are identical, 0 otherwise. 00018 \param detruire Pointer to the function used to free all allocated memory for the user's defined data. This function is specific to the 00019 type of data stored into the hash table. 00020 \return Upon successful completion the function returns 0, otherwise the function returns 1. 00021 */ 00022 00023 int chtbl_init( 00024 CHTbl *htab, 00025 int conteneurs, 00026 int (*h)(const void *cle), 00027 int (*corresp)(const void *cle1, const void *cle2), 00028 void (*detruire)(void *donnee) 00029 ) 00030 { 00031 int i; 00032 00033 /* ------------------------------------------------------------------------- */ 00034 /* Allocate linked lists for hash table */ 00035 /* ------------------------------------------------------------------------- */ 00036 00037 if ((htab->table = (List *)malloc(conteneurs * sizeof(List))) == NULL) { return -1; } 00038 00039 /* ------------------------------------------------------------------------- */ 00040 /* Initialize the linked lists */ 00041 /* ------------------------------------------------------------------------- */ 00042 00043 htab->conteneurs = conteneurs; 00044 for (i = 0; i < htab->conteneurs; i++) { list_init(&htab->table[i], detruire, corresp); } 00045 00046 /* ------------------------------------------------------------------------- */ 00047 /* Initialize the hash table */ 00048 /* ------------------------------------------------------------------------- */ 00049 00050 htab->h = h; 00051 htab->corresp = corresp; 00052 htab->detruire = detruire; 00053 htab->taille = 0; 00054 00055 return 0; 00056 } 00057 00058 /*! \example test_hash_table.c 00059 This test program shows how to use the hash table's API. 00060 */ 00061 00062 /*! \brief Free all memory allocated for the hash table. 00063 \param htab Pointer to the hash table data structure to destroy. 00064 */ 00065 00066 void chtbl_destroy(CHTbl *htab) 00067 { 00068 int i; 00069 00070 /* ------------------------------------------------------------------------- */ 00071 /* Delete all linked list */ 00072 /* ------------------------------------------------------------------------- */ 00073 00074 for (i = 0; i < htab->conteneurs; i++) { list_destroy(&htab->table[i]); } 00075 00076 /* ------------------------------------------------------------------------- */ 00077 /* Free all memory used by the hash table data structure */ 00078 /* ------------------------------------------------------------------------- */ 00079 00080 free(htab->table); 00081 00082 /* ------------------------------------------------------------------------- */ 00083 /* Clean up the structure (just to look better) */ 00084 /* ------------------------------------------------------------------------- */ 00085 00086 memset(htab, 0, sizeof(CHTbl)); 00087 00088 return; 00089 } 00090 00091 /*! \example test_hash_table.c 00092 This test program shows how to use the hash table's API. 00093 */ 00094 00095 /*! \brief Insert data into the hash table. 00096 \param htab Pointer to the hash table data structure. 00097 \param donnee Pointer to the user defined data to insert. 00098 \return The function may return one of the following value: 00099 <UL> 00100 <li>0: The data was not in the hash table and it has been successfuly inserted. 00101 <li>1: The data already was in the hash table (this is not an error). 00102 <li>-1: An error occured (this means that the program is running out of memory). 00103 </UL> 00104 \warning Data are <B>NOT</B> copied into the hash table. The hash table only contains pointers to user's data. Therefore you should 00105 not free the memory allocated fot the data yourself. 00106 */ 00107 00108 int chtbl_insert(CHTbl *htab, const void *donnee) 00109 { 00110 void *temp; 00111 int conteneur, retval; 00112 00113 /* ------------------------------------------------------------------------- */ 00114 /* Make sure that the data is not already into the hash table */ 00115 /* ------------------------------------------------------------------------- */ 00116 00117 temp = (void *)donnee; 00118 if (chtbl_lookup(htab, &temp) == 0) { return 1; } 00119 00120 /* ------------------------------------------------------------------------- */ 00121 /* Hash the input key */ 00122 /* ------------------------------------------------------------------------- */ 00123 00124 conteneur = htab->h(donnee) % htab->conteneurs; 00125 00126 /* ------------------------------------------------------------------------- */ 00127 /* Insert data into the hash table */ 00128 /* ------------------------------------------------------------------------- */ 00129 00130 if ((retval = list_ins_next(&htab->table[conteneur], NULL, donnee)) == 0) 00131 { htab->taille++; } 00132 00133 return retval; 00134 } 00135 00136 /*! \example test_hash_table.c 00137 This test program shows how to use the hash table's API. 00138 */ 00139 00140 /*! \brief Remove a record from the hash table. 00141 \param htab Pointer to a hash table data structure. 00142 \param donnee Pointer to a data structure pointer that will point to the data of the element that have been removed. Keep in mind that 00143 the user data is <B>NOT</B> freed by the function chtbl_remove(). You must free it yourself. 00144 \return Upon successful completion the function returns 0, otherwise the function returns -1. Please note that the return value -1 00145 is not really an error. It really means that the data was not found in the hash table. 00146 \warning You must keep in mind that the data section of the removed element is <B>NOT</B> freed by the function. A pointer to the 00147 data section is returned (via <i>donnee</i>). This allows you to free it yourself. 00148 */ 00149 00150 int chtbl_remove(CHTbl *htab, void **donnee) 00151 { 00152 ListElmt *element, *prec; 00153 int conteneur; 00154 00155 /* ------------------------------------------------------------------------- */ 00156 /* Hash the input key */ 00157 /* ------------------------------------------------------------------------- */ 00158 00159 conteneur = htab->h(*donnee) % htab->conteneurs; 00160 00161 /* ------------------------------------------------------------------------- */ 00162 /* Search the linked list for the data */ 00163 /* ------------------------------------------------------------------------- */ 00164 00165 element = list_find (&htab->table[conteneur], NULL, *donnee, &prec); 00166 if (element != NULL) 00167 { 00168 /* ----------------------------------------------------------------------- */ 00169 /* Data found, remove it */ 00170 /* Note that 'prec' could be NULL, but that's OK. */ 00171 /* ----------------------------------------------------------------------- */ 00172 00173 if (list_rem_next(&htab->table[conteneur], prec, donnee) == 0) 00174 { 00175 htab->taille--; 00176 return 0; 00177 } 00178 } 00179 00180 /* ------------------------------------------------------------------------- */ 00181 /* The data was not found */ 00182 /* ------------------------------------------------------------------------- */ 00183 00184 return -1; 00185 00186 } 00187 00188 /*! \example test_hash_table.c 00189 This test program shows how to use the hash table's API. 00190 */ 00191 00192 /*! \brief Searh the hash table for a given data. 00193 \param htab Pointer to a hash table structure. 00194 \param donnee Pointer to a user defined data. This pointer will be used: 00195 <UL> 00196 <li>To specify the data to search for. 00197 <li>To point to the element's data (that has been found). 00198 </UL> 00199 \return If the element was in the hash table, that the function returns 0 and <i>donnee</i> points to the element's data. Otherwise, 00200 the function return -1. 00201 */ 00202 00203 int chtbl_lookup(const CHTbl *htab, void **donnee) 00204 { 00205 ListElmt *element; 00206 int conteneur; 00207 00208 /* ------------------------------------------------------------------------- */ 00209 /* Hash the input key */ 00210 /* ------------------------------------------------------------------------- */ 00211 00212 conteneur = htab->h(*donnee) % htab->conteneurs; 00213 00214 /* ------------------------------------------------------------------------- */ 00215 /* Search for the jey in the linked list */ 00216 /* ------------------------------------------------------------------------- */ 00217 00218 for (element = list_head(&htab->table[conteneur]); element != NULL; element = list_next(element)) 00219 { 00220 if (htab->corresp(*donnee, list_data(element))) 00221 { 00222 /* --------------------------------------------------------------------- */ 00223 /* The record has been found */ 00224 /* Assign 'donnee' to the element's data. */ 00225 /* --------------------------------------------------------------------- */ 00226 00227 *donnee = list_data(element); 00228 return 0; 00229 } 00230 } 00231 00232 /* ------------------------------------------------------------------------- */ 00233 /* The data was not found */ 00234 /* ------------------------------------------------------------------------- */ 00235 00236 return -1; 00237 } 00238 00239 /*! \example test_hash_table.c 00240 This test program shows how to use the hash table's API. 00241 */ 00242 00243 /*! \brief Cover the entire hash table in search for an given element. 00244 \param htab Pointer to a hash table structure. 00245 \param donnee Pointer to a user defined data. This pointer will be used: 00246 <UL> 00247 <li>To specify the data to search for. 00248 <li>To point to the element's data (that has been found). 00249 </UL> 00250 \return If the element was in the hash table, that the function returns 0 and <i>donnee</i> points to the element's data. Otherwise, the function return -1. 00251 \warning This function lookup compare each element in the hash table with a given element (<i>donnee</i>). 00252 It may take long ... do not use it if you don't have to! 00253 */ 00254 00255 int chtbl_find (const CHTbl *htab, void **donnee) 00256 { 00257 int ht; 00258 List *linked_list; 00259 ListElmt *element; 00260 00261 /* ------------------------------------------------------------------------- */ 00262 /* For each linked list, look for the data */ 00263 /* ------------------------------------------------------------------------- */ 00264 00265 for (ht=0; ht<htab->conteneurs; ht++) 00266 { 00267 linked_list = &(htab->table[ht]); 00268 element = list_head (linked_list); 00269 00270 while (element != NULL) 00271 { 00272 if (htab->corresp(list_data(element), *donnee)) 00273 { 00274 *donnee = list_data(element); 00275 return 0; 00276 } 00277 element = list_next(element); 00278 } 00279 } 00280 00281 return -1; 00282 } 00283 00284 /*! \example test_hash_table.c 00285 This test program shows how to use the hash table's API. 00286 */ 00287 00288 /*! \brief Returns the next element of a given linked list. 00289 \param htab Pointer to a hash table structure. 00290 \param rewind Flag used to set the hash pointer to the first element of the hash. The value of this 00291 parameter can be: 00292 <UL> 00293 <LI>REWIND_HASH: Set the hash pointer to the first element of the hash. 00294 <LI>CURRENT_HASH: Set the hash pointer to the current element in the hash. 00295 </UL> 00296 \return The function returns a pointer to the current element in the hash, or NULL if the current element 00297 is the last one. 00298 \warning Each time you call the function, it returns the next element in the hash (until the last one where 00299 the function returns NULL). 00300 <UL> 00301 <LI>When you <B>start walking</B> through a hash table, you <B>must</B> set the parameter 00302 <I>rewind</I> to the value REWIND_HASH !. If you don't do that, the baheviour of the function 00303 is unpredictable. You may generate a segmentation fault. 00304 <LI>Do <B>NOT</B> modify (add or remove elements) the hash while you are walking 00305 through it! If you don't do that, the baheviour of the function is unpredictable. 00306 You may generate a segmentation fault. 00307 </UL> 00308 */ 00309 00310 void* chtbl_next (CHTbl *htab, int rewind) 00311 { 00312 List *linked_list; 00313 ListElmt *element; 00314 00315 /* ------------------------------------------------------------------------- */ 00316 /* Set the hash pointer to the first element if necessary */ 00317 /* ------------------------------------------------------------------------- */ 00318 00319 if (rewind == REWIND_HASH) 00320 { 00321 linked_list = &(htab->table[0]); 00322 (htab->pointer).current_list = 0; 00323 (htab->pointer).current_element = list_head(linked_list); 00324 } 00325 else 00326 { 00327 linked_list = &(htab->table[(htab->pointer).current_list]); 00328 } 00329 00330 /* ------------------------------------------------------------------------- */ 00331 /* Find the next element */ 00332 /* ------------------------------------------------------------------------- */ 00333 00334 while ((htab->pointer).current_element == NULL) 00335 { 00336 /* ----------------------------------------------------------------------- */ 00337 /* Go to the next linked list */ 00338 /* ----------------------------------------------------------------------- */ 00339 00340 (htab->pointer).current_list += 1; 00341 if ((htab->pointer).current_list >= htab->conteneurs) { return NULL; } 00342 00343 linked_list = &(htab->table[(htab->pointer).current_list]); 00344 (htab->pointer).current_element = list_head(linked_list); 00345 } 00346 00347 element = (htab->pointer).current_element; 00348 00349 (htab->pointer).current_element = list_next(element); 00350 00351 return list_data(element); 00352 } 00353 00354 /*! \example test_hash_table.c 00355 This test program shows how to use the hash table's API. 00356 */ 00357 00358