Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

hash_table.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- 00002 @COPYRIGHT : 00003 Copyright 1993,1994,1995 David MacDonald, 00004 McConnell Brain Imaging Centre, 00005 Montreal Neurological Institute, McGill University. 00006 Permission to use, copy, modify, and distribute this 00007 software and its documentation for any purpose and without 00008 fee is hereby granted, provided that the above copyright 00009 notice appear in all copies. The author and McGill University 00010 make no representations about the suitability of this 00011 software for any purpose. It is provided "as is" without 00012 express or implied warranty. 00013 ---------------------------------------------------------------------------- */ 00014 00015 #include <volume_io/internal_volume_io.h> 00016 #include <bicpl/data_structures.h> 00017 00018 #ifndef lint 00019 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Data_structures/hash_table.c,v 1.13 2000/02/06 15:30:11 stever Exp $"; 00020 #endif 00021 00022 #define HASH_FUNCTION_CONSTANT 0.6180339887498948482 00023 00024 /* ----------------------------- MNI Header ----------------------------------- 00025 @NAME : initialize_hash_table 00026 @INPUT : 00027 : size 00028 : enlarge_threshold 00029 : new_density 00030 @OUTPUT : hash_table 00031 @RETURNS : Status 00032 @DESCRIPTION: Initializes a hash table to empty, storing the 00033 : initial size, and parameters controlling automatic growth. 00034 @METHOD : 00035 @GLOBALS : 00036 @CALLS : 00037 @CREATED : David MacDonald 00038 @MODIFIED : 00039 ---------------------------------------------------------------------------- */ 00040 00041 public void initialize_hash_table( 00042 hash_table_struct *hash_table, 00043 int size, 00044 int data_size, 00045 Real enlarge_threshold, 00046 Real new_density ) 00047 { 00048 int i; 00049 00050 hash_table->size = size; 00051 hash_table->data_size = data_size; 00052 hash_table->n_entries = 0; 00053 hash_table->enlarge_threshold = enlarge_threshold; 00054 hash_table->new_density = new_density; 00055 00056 ALLOC( hash_table->table, size ); 00057 00058 for( i = 0; i < size; ++i ) 00059 hash_table->table[i] = NULL; 00060 } 00061 00062 /* ----------------------------- MNI Header ----------------------------------- 00063 @NAME : delete_hash_table_list 00064 @INPUT : hash_table 00065 @OUTPUT : 00066 @RETURNS : Status 00067 @DESCRIPTION: Deletes the list of pointers in the hash table. 00068 @METHOD : 00069 @GLOBALS : 00070 @CALLS : 00071 @CREATED : David MacDonald 00072 @MODIFIED : 00073 ---------------------------------------------------------------------------- */ 00074 00075 private void delete_hash_table_list( 00076 hash_table_struct *hash_table ) 00077 { 00078 if( hash_table->size > 0 ) 00079 FREE( hash_table->table ); 00080 } 00081 00082 /* ----------------------------- MNI Header ----------------------------------- 00083 @NAME : delete_hash_table 00084 @INPUT : hash_table 00085 @OUTPUT : 00086 @RETURNS : Status 00087 @DESCRIPTION: Deletes the given hash table. 00088 @METHOD : 00089 @GLOBALS : 00090 @CALLS : 00091 @CREATED : David MacDonald 00092 @MODIFIED : 00093 ---------------------------------------------------------------------------- */ 00094 00095 public void delete_hash_table( 00096 hash_table_struct *hash_table ) 00097 { 00098 int i; 00099 hash_entry_struct *entry, *next; 00100 00101 for( i = 0; i < hash_table->size; ++i ) 00102 { 00103 entry = hash_table->table[i]; 00104 00105 while( entry != NULL ) 00106 { 00107 next = entry->next; 00108 FREE( entry ); 00109 entry = next; 00110 } 00111 } 00112 00113 delete_hash_table_list( hash_table ); 00114 } 00115 00116 /* ----------------------------- MNI Header ----------------------------------- 00117 @NAME : hash_function 00118 @INPUT : hash_table 00119 : key 00120 @OUTPUT : 00121 @RETURNS : an index into the hash table. 00122 @DESCRIPTION: Hashes the key to create an index into the table. Uses 00123 the multiplicative hash method from Corman book on algorithms. 00124 @METHOD : 00125 @GLOBALS : 00126 @CALLS : 00127 @CREATED : David MacDonald 00128 @MODIFIED : 00129 ---------------------------------------------------------------------------- */ 00130 00131 private int hash_function( 00132 hash_table_struct *hash_table, 00133 int key ) 00134 { 00135 int index; 00136 Real v; 00137 00138 v = (Real) key * HASH_FUNCTION_CONSTANT; 00139 00140 index = (int) (FRACTION(v) * (Real) hash_table->size); 00141 00142 return( index ); 00143 } 00144 00145 /* ----------------------------- MNI Header ----------------------------------- 00146 @NAME : lookup 00147 @INPUT : hash_table 00148 : key 00149 @OUTPUT : 00150 @RETURNS : a pointer to a pointer to the hash table entry 00151 @DESCRIPTION: Looks up the given key in the hash table, and returns a pointer 00152 : to a pointer to the entry, suitable for inserting or deleting. 00153 @METHOD : 00154 @GLOBALS : 00155 @CALLS : 00156 @CREATED : David MacDonald 00157 @MODIFIED : 00158 ---------------------------------------------------------------------------- */ 00159 00160 private hash_entry_struct **lookup( 00161 hash_table_struct *hash_table, 00162 int key ) 00163 { 00164 int i; 00165 hash_entry_struct **ptr_to_entry; 00166 00167 i = hash_function( hash_table, key ); 00168 00169 ptr_to_entry = &hash_table->table[i]; 00170 00171 while( *ptr_to_entry != NULL && (*ptr_to_entry)->key != key ) 00172 ptr_to_entry = &(*ptr_to_entry)->next; 00173 00174 return( ptr_to_entry ); 00175 } 00176 00177 /* ----------------------------- MNI Header ----------------------------------- 00178 @NAME : insert_in_hash_table 00179 @INPUT : hash_table 00180 : key 00181 : data_ptr 00182 @OUTPUT : 00183 @RETURNS : Status 00184 @DESCRIPTION: Inserts the data_ptr in the hash table. 00185 @METHOD : 00186 @GLOBALS : 00187 @CALLS : 00188 @CREATED : David MacDonald 00189 @MODIFIED : 00190 ---------------------------------------------------------------------------- */ 00191 00192 public void insert_in_hash_table( 00193 hash_table_struct *hash_table, 00194 int key, 00195 void *data_ptr ) 00196 { 00197 hash_entry_struct **ptr_to_entry; 00198 hash_entry_struct *entry; 00199 00200 ptr_to_entry = lookup( hash_table, key ); 00201 00202 entry = *ptr_to_entry; 00203 00204 if( entry == NULL ) 00205 { 00206 ALLOC_VAR_SIZED_STRUCT( entry, char, hash_table->data_size ); 00207 00208 entry->key = key; 00209 entry->next = *ptr_to_entry; 00210 (void) memcpy( (void *) entry->data, data_ptr, 00211 (size_t) hash_table->data_size ); 00212 00213 *ptr_to_entry = entry; 00214 00215 ++hash_table->n_entries; 00216 00217 if( (Real) hash_table->n_entries / (Real) hash_table->size > 00218 hash_table->enlarge_threshold ) 00219 { 00220 int new_size; 00221 00222 new_size = ROUND( (Real) hash_table->n_entries / 00223 hash_table->new_density ); 00224 increase_hash_table_size( hash_table, new_size ); 00225 } 00226 } 00227 else 00228 { 00229 print_error( "Insert in hash table: entry already present: %d\n", key ); 00230 } 00231 } 00232 00233 /* ----------------------------- MNI Header ----------------------------------- 00234 @NAME : lookup_in_hash_table 00235 @INPUT : hash_table 00236 : key 00237 @OUTPUT : data_ptr 00238 @RETURNS : TRUE if found 00239 @DESCRIPTION: Lookups the given key in the hash table, copying back the 00240 data if found. 00241 @METHOD : 00242 @GLOBALS : 00243 @CALLS : 00244 @CREATED : David MacDonald 00245 @MODIFIED : 00246 ---------------------------------------------------------------------------- */ 00247 00248 public BOOLEAN lookup_in_hash_table( 00249 hash_table_struct *hash_table, 00250 int key, 00251 void *data_ptr ) 00252 { 00253 BOOLEAN found; 00254 hash_entry_struct **ptr_to_entry; 00255 hash_entry_struct *entry; 00256 00257 ptr_to_entry = lookup( hash_table, key ); 00258 00259 entry = *ptr_to_entry; 00260 00261 if( entry == NULL ) 00262 { 00263 found = FALSE; 00264 } 00265 else 00266 { 00267 if( data_ptr != NULL ) 00268 { 00269 (void) memcpy( data_ptr, (void *) entry->data, 00270 (size_t) hash_table->data_size ); 00271 } 00272 00273 found = TRUE; 00274 } 00275 00276 return( found ); 00277 } 00278 00279 /* ----------------------------- MNI Header ----------------------------------- 00280 @NAME : remove_from_hash_table 00281 @INPUT : hash_table 00282 : keys 00283 @OUTPUT : : data_ptr 00284 @RETURNS : TRUE if it existed in the table 00285 @DESCRIPTION: Finds and removes the given data from the hash table, copying 00286 the data back. 00287 @METHOD : 00288 @GLOBALS : 00289 @CALLS : 00290 @CREATED : David MacDonald 00291 @MODIFIED : 00292 ---------------------------------------------------------------------------- */ 00293 00294 public BOOLEAN remove_from_hash_table( 00295 hash_table_struct *hash_table, 00296 int key, 00297 void *data_ptr ) 00298 { 00299 BOOLEAN removed; 00300 hash_entry_struct **ptr_to_entry; 00301 hash_entry_struct *entry; 00302 00303 ptr_to_entry = lookup( hash_table, key ); 00304 00305 entry = *ptr_to_entry; 00306 00307 if( entry == NULL ) 00308 { 00309 removed = FALSE; 00310 } 00311 else 00312 { 00313 if( data_ptr != NULL ) 00314 { 00315 (void) memcpy( data_ptr, (void *) entry->data, 00316 (size_t) hash_table->data_size ); 00317 } 00318 00319 *ptr_to_entry = entry->next; 00320 00321 FREE( entry ); 00322 00323 removed = TRUE; 00324 --hash_table->n_entries; 00325 } 00326 00327 return( removed ); 00328 } 00329 00330 /* ----------------------------- MNI Header ----------------------------------- 00331 @NAME : move_hash_entries_to_new_table 00332 @INPUT : src hash_table 00333 @OUTPUT : dest hash_table 00334 @RETURNS : 00335 @DESCRIPTION: Moves the entries of one hash table to the other, without 00336 : reallocating them. Used when the hash table size is increased. 00337 @METHOD : 00338 @GLOBALS : 00339 @CALLS : 00340 @CREATED : David MacDonald 00341 @MODIFIED : 00342 ---------------------------------------------------------------------------- */ 00343 00344 private void move_hash_entries_to_new_table( 00345 hash_table_struct *dest, 00346 hash_table_struct *src ) 00347 { 00348 int i, hash; 00349 hash_entry_struct *entry, *next; 00350 00351 for( i = 0; i < src->size; ++i ) 00352 { 00353 entry = src->table[i]; 00354 00355 while( entry != NULL ) 00356 { 00357 next = entry->next; 00358 00359 hash = hash_function( dest, entry->key ); 00360 entry->next = dest->table[hash]; 00361 dest->table[hash] = entry; 00362 ++dest->n_entries; 00363 00364 entry = next; 00365 } 00366 00367 src->table[i] = NULL; 00368 } 00369 } 00370 00371 /* ----------------------------- MNI Header ----------------------------------- 00372 @NAME : increase_hash_table_size 00373 @INPUT : hash_table 00374 : new_size 00375 @OUTPUT : 00376 @RETURNS : Status 00377 @DESCRIPTION: Increases the size of the hash table, by creating a new hash 00378 : table, moving over the entries, then assigning the new table to 00379 : the old one. 00380 @METHOD : 00381 @GLOBALS : 00382 @CALLS : 00383 @CREATED : David MacDonald 00384 @MODIFIED : 00385 ---------------------------------------------------------------------------- */ 00386 00387 public void increase_hash_table_size( 00388 hash_table_struct *hash_table, 00389 int new_size ) 00390 { 00391 hash_table_struct new_table; 00392 00393 initialize_hash_table( &new_table, new_size, hash_table->data_size, 00394 hash_table->enlarge_threshold, 00395 hash_table->new_density ); 00396 00397 move_hash_entries_to_new_table( &new_table, hash_table ); 00398 00399 delete_hash_table_list( hash_table ); 00400 00401 *hash_table = new_table; 00402 } 00403 00404 /* ----------------------------- MNI Header ----------------------------------- 00405 @NAME : initialize_hash_pointer 00406 @INPUT : ptr 00407 @OUTPUT : 00408 @RETURNS : 00409 @DESCRIPTION: Initializes a pointer to the beginning of the hash table. This is 00410 : used to step through the hash table to visit every entry. 00411 @METHOD : 00412 @GLOBALS : 00413 @CALLS : 00414 @CREATED : David MacDonald 00415 @MODIFIED : 00416 ---------------------------------------------------------------------------- */ 00417 00418 public void initialize_hash_pointer( 00419 hash_table_pointer *ptr ) 00420 { 00421 ptr->current_index = -1; 00422 ptr->current_entry = NULL; 00423 } 00424 00425 /* ----------------------------- MNI Header ----------------------------------- 00426 @NAME : get_next_hash_entry 00427 @INPUT : hash_table 00428 : ptr 00429 @OUTPUT : data_ptr 00430 @RETURNS : TRUE if one is found 00431 @DESCRIPTION: Steps to the next entry in the hash table, updating the ptr, 00432 : and passing back the data ptr stored in that entry. 00433 @METHOD : 00434 @GLOBALS : 00435 @CALLS : 00436 @CREATED : David MacDonald 00437 @MODIFIED : 00438 ---------------------------------------------------------------------------- */ 00439 00440 public BOOLEAN get_next_hash_entry( 00441 hash_table_struct *hash_table, 00442 hash_table_pointer *ptr, 00443 void *data_ptr ) 00444 { 00445 BOOLEAN found; 00446 00447 if( ptr->current_entry != NULL ) 00448 ptr->current_entry = ptr->current_entry->next; 00449 00450 if( ptr->current_entry == NULL ) 00451 { 00452 do 00453 { 00454 ++ptr->current_index; 00455 } 00456 while( ptr->current_index < hash_table->size && 00457 hash_table->table[ptr->current_index] == NULL ); 00458 00459 if( ptr->current_index < hash_table->size ) 00460 ptr->current_entry = hash_table->table[ptr->current_index]; 00461 } 00462 00463 found = (ptr->current_entry != NULL); 00464 00465 if( found && data_ptr != NULL ) 00466 { 00467 (void) memcpy( data_ptr, (void *) ptr->current_entry->data, 00468 (size_t) hash_table->data_size ); 00469 } 00470 00471 return( found ); 00472 }

Generated on Wed Jul 28 09:10:57 2004 for BICPL by doxygen 1.3.7