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

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

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