Changeset 1385 for trunk/psLib/src/sysUtils/psHash.c
- Timestamp:
- Aug 4, 2004, 1:37:39 PM (22 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/sysUtils/psHash.c (modified) (13 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/sysUtils/psHash.c
r1375 r1385 10 10 * @author George Gusciora, MHPCC 11 11 * 12 * @version $Revision: 1.1 3$ $Name: not supported by cvs2svn $13 * @date $Date: 2004-08-04 01:21:33$12 * @version $Revision: 1.14 $ $Name: not supported by cvs2svn $ 13 * @date $Date: 2004-08-04 23:37:39 $ 14 14 * 15 15 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 28 28 static void hashBucketFree( psHashBucket *bucket ); 29 29 static void *doHashWork( psHash* table, const char* key, void* data, bool remove 30 )31 ;30 ) 31 ; 32 32 static void hashFree( psHash *table ); 33 33 … … 45 45 psList *myLinkList = NULL; // The output data structure 46 46 psHashBucket *ptr = NULL; // Used to step thru linked list. 47 47 48 48 if ( table == NULL ) { 49 return NULL;50 }51 49 return NULL; 50 } 51 52 52 // Create the linked list 53 53 myLinkList = psListAlloc( NULL ); 54 54 55 55 // Loop through every bucket in the hash table. If that bucket is not 56 56 // NULL, then add the bucket's key to the linked list. 57 57 for ( i = 0;i < table->nbucket;i++ ) { 58 if ( table->buckets[ i ] != NULL ) { 59 // Since a bucket contains a linked list of keys/data, we must 60 // step trough each key in that linked list: 61 62 ptr = table->buckets[ i ]; 63 while ( ptr != NULL ) { 64 psListAdd( myLinkList, ptr->key, PS_LIST_HEAD ); 65 ptr = ptr->next; 66 } 67 } 58 if ( table->buckets[ i ] != NULL ) { 59 // Since a bucket contains a linked list of keys/data, we must 60 // step trough each key in that linked list: 61 62 ptr = table->buckets[ i ]; 63 while ( ptr != NULL ) { 64 psListAdd( myLinkList, ptr->key, PS_LIST_HEAD ); 65 ptr = ptr->next; 66 } 68 67 } 69 68 } 69 70 70 // Return the linked list 71 71 return ( myLinkList ); … … 89 89 { 90 90 if ( key == NULL ) { 91 psAbort( __func__, "psHashBucket() called with NULL key." );92 }93 91 psAbort( __func__, "psHashBucket() called with NULL key." ); 92 } 93 94 94 // Allocate memory for the new hash bucket. 95 95 psHashBucket *bucket = psAlloc( sizeof( psHashBucket ) ); 96 96 p_psMemSetDeallocator( bucket, ( psFreeFcn ) hashBucketFree ); 97 97 98 98 // Initialize the bucket. 99 99 bucket->key = psStringCopy( key ); 100 100 101 101 if ( data == NULL ) { 102 // NOTE: Should we flag a warning message?103 bucket->data = NULL;104 } else {105 bucket->data = psMemIncrRefCounter( data );106 }107 102 // NOTE: Should we flag a warning message? 103 bucket->data = NULL; 104 } else { 105 bucket->data = psMemIncrRefCounter( data ); 106 } 107 108 108 bucket->next = next; 109 109 110 110 return bucket; 111 111 } … … 123 123 { 124 124 if ( bucket == NULL ) { 125 return ;126 }127 125 return ; 126 } 127 128 128 // A bucket is actually a linked list of buckets. We recursively step 129 129 // through that linked list, free each bucket. 130 130 psFree( bucket->next ); 131 131 132 132 psFree( bucket->key ); 133 133 134 134 psFree( bucket->data ); 135 135 } … … 150 150 psHash *table = psAlloc( sizeof( psHash ) ); 151 151 p_psMemSetDeallocator( table, ( psFreeFcn ) hashFree ); 152 152 153 153 // Allocate memory for the buckets. 154 154 table->buckets = psAlloc( nbucket * sizeof( psHashBucket * ) ); 155 155 table->nbucket = nbucket; 156 156 157 157 psTrace( "utils.hash", 1, "Creating %d-element hash table\n", nbucket ); 158 158 159 159 // Initialize all buckets to NULL. 160 160 for ( i = 0; i < nbucket; i++ ) 161 {162 table->buckets[ i ] = NULL;163 }164 161 { 162 table->buckets[ i ] = NULL; 163 } 164 165 165 // Return the new hash table. 166 166 return table; … … 182 182 { 183 183 int i = 0; // Loop index variable. 184 184 185 185 if ( table == NULL ) { 186 return ;187 }188 186 return ; 187 } 188 189 189 // Loop through each bucket in the hash table. If that bucket is not 190 190 // NULL, then free the bucket via a function call to hashBucketFree(); 191 191 for ( i = 0; i < table->nbucket; i++ ) { 192 193 // A bucket is composed of a linked list of buckets. 194 if ( table->buckets[ i ] != NULL ) { 195 psFree( table->buckets[ i ] ); 196 } 192 193 // A bucket is composed of a linked list of buckets. 194 if ( table->buckets[ i ] != NULL ) { 195 psFree( table->buckets[ i ] ); 197 196 } 198 197 } 198 199 199 // Free the bucket structure, then the hash table. 200 200 psFree( table->buckets ); … … 221 221 *****************************************************************************/ 222 222 static void *doHashWork( psHash *table, const char *key, void *data, bool remove 223 )223 ) 224 224 { 225 225 long int hash = 1; // This will contain an integer value … … 229 229 psHashBucket *optr = NULL; // "original pointer": used to step 230 230 // thru the linked list for a bucket. 231 231 232 232 // The following condition should never be true, since this is a private 233 233 // function, but I'm checking it anyway since future coders might change 234 234 // the way this procedure is called. 235 235 if ( ( table == NULL ) || ( key == NULL ) ) { 236 237 psAbort( __func__, "psHashRemove() called with NULL key or table." );238 }239 236 237 psAbort( __func__, "psHashRemove() called with NULL key or table." ); 238 } 239 240 240 // NOTE: This is the originally supplied hash function. 241 241 // for (int i = 0, len = strlen(key); i < len; i++) { … … 243 243 // } 244 244 // hash &= (table->nbucket - 1); 245 245 246 246 // This hash algorithm is from Sedgewick. NOTE: must reread to ensure that 247 247 // the size of the hash table is not required to be a prime number. 248 248 tmpchar = ( char * ) key; 249 249 for ( hash = 0; *tmpchar != '\0'; tmpchar++ ) { 250 hash = ( 64 * hash + *tmpchar ) % ( table->nbucket );251 }252 250 hash = ( 64 * hash + *tmpchar ) % ( table->nbucket ); 251 } 252 253 253 // NOTE: This should not be necessary, but for now, I'm checking bounds 254 254 // anyway. 255 255 if ( ( hash < 0 ) || ( hash >= table->nbucket ) ) { 256 psAbort( __func__, "Internal hash function out of range (%d)", hash );257 }258 256 psAbort( __func__, "Internal hash function out of range (%d)", hash ); 257 } 258 259 259 // ptr will have the correct hash bucket. 260 260 ptr = table->buckets[ hash ]; 261 261 262 262 // We know the correct hash bucket, now we need to know what to do. 263 263 // If the data parameter is NULL, then, by definition, this is a retrieve 264 264 // or a remove operation on the hash table. 265 265 266 266 if ( data == NULL ) { 267 if ( remove267 if ( remove 268 268 ) { 269 // We search through the linked list for this bucket in 270 // the hash table and look for an entry for this key. 271 269 // We search through the linked list for this bucket in 270 // the hash table and look for an entry for this key. 271 272 optr = ptr; 273 while ( ptr != NULL ) { 274 // Dtermine if this entry holds the correct key. 275 if ( strcmp( key, ptr->key ) == 0 ) { 276 // The following lines of code are fairly standard ways 277 // of removing an item from a single-linked list. 278 279 void * data = ptr->data; 280 optr->next = ptr->next; 281 if ( ptr == table->buckets[ hash ] ) { 282 table->buckets[ hash ] = ptr->next; 283 } 284 285 psFree( ptr ); 286 287 // By definition, the data associated with that key 288 // must be returned, not freed. 289 return data; 290 } 272 291 optr = ptr; 273 while ( ptr != NULL ) {274 // Dtermine if this entry holds the correct key.275 if ( strcmp( key, ptr->key ) == 0 ) {276 // The following lines of code are fairly standard ways277 // of removing an item from a single-linked list.278 279 void * data = ptr->data;280 optr->next = ptr->next;281 if ( ptr == table->buckets[ hash ] ) {282 table->buckets[ hash ] = ptr->next;283 }284 285 psFree( ptr );286 287 // By definition, the data associated with that key288 // must be returned, not freed.289 return data;290 }291 optr = ptr;292 ptr = ptr->next;293 }294 return NULL; // not in hash295 }296 else {297 // If we get here, then a retrieve operation is requested. So,298 // we step trough the linked list at this bucket, and return the299 // data once we find it, or return NULL if we don't.300 while ( ptr != NULL ) {301 if ( strcmp( key, ptr->key ) == 0 ) {302 return ptr->data;303 }304 ptr = ptr->next;305 }306 return NULL; // not in hash307 }308 } else {309 // We get here if this procedure was called with non-NULL data.310 // Therefore, we should insert that data into the hash table.311 // First, we search through the linked list for this bucket in312 // the hash table and look for a duplicate entry for this key.313 314 while ( ptr != NULL ) {315 if ( strcmp( key, ptr->key ) == 0 ) {316 // We have found this key in the hash table.317 318 psTrace( "utils.hash.insert", 3, "Replacing data for %s\n",319 key );320 321 // NOTE: I have changed this behavior from the originally322 // supplied code. Formerly, if itemFree was NULL, then323 // the new data was not inserted into the hash table.324 325 psFree( ptr->data );326 327 ptr->data = psMemIncrRefCounter( data );328 return data;329 }330 292 ptr = ptr->next; 331 293 } 332 // We did not found key in the linked list for this bucket of the hash 333 // table. So, we insert this data at the head of that linked list. 334 335 table->buckets[ hash ] = hashBucketAlloc( key, 336 data, 337 table->buckets[ hash ] ); 338 return data; 294 return NULL; // not in hash 295 } 296 else { 297 // If we get here, then a retrieve operation is requested. So, 298 // we step trough the linked list at this bucket, and return the 299 // data once we find it, or return NULL if we don't. 300 while ( ptr != NULL ) { 301 if ( strcmp( key, ptr->key ) == 0 ) { 302 return ptr->data; 303 } 304 ptr = ptr->next; 305 } 306 return NULL; // not in hash 339 307 } 308 } else { 309 // We get here if this procedure was called with non-NULL data. 310 // Therefore, we should insert that data into the hash table. 311 // First, we search through the linked list for this bucket in 312 // the hash table and look for a duplicate entry for this key. 313 314 while ( ptr != NULL ) { 315 if ( strcmp( key, ptr->key ) == 0 ) { 316 // We have found this key in the hash table. 317 318 psTrace( "utils.hash.insert", 3, "Replacing data for %s\n", 319 key ); 320 321 // NOTE: I have changed this behavior from the originally 322 // supplied code. Formerly, if itemFree was NULL, then 323 // the new data was not inserted into the hash table. 324 325 psFree( ptr->data ); 326 327 ptr->data = psMemIncrRefCounter( data ); 328 return data; 329 } 330 ptr = ptr->next; 331 } 332 // We did not found key in the linked list for this bucket of the hash 333 // table. So, we insert this data at the head of that linked list. 334 335 table->buckets[ hash ] = hashBucketAlloc( key, 336 data, 337 table->buckets[ hash ] ); 338 return data; 339 } 340 340 } 341 341 … … 354 354 { 355 355 if ( table == NULL ) { 356 psAbort( __func__, "psHashInsert() called with NULL hash table." );357 }356 psAbort( __func__, "psHashInsert() called with NULL hash table." ); 357 } 358 358 if ( key == NULL ) { 359 psAbort( __func__, "psHashInsert() called with NULL key." );360 }359 psAbort( __func__, "psHashInsert() called with NULL key." ); 360 } 361 361 if ( data == NULL ) { 362 psAbort( __func__, "psHashLookup() called with NULL data." );363 }364 362 psAbort( __func__, "psHashLookup() called with NULL data." ); 363 } 364 365 365 return ( doHashWork( table, key, data, 0 ) != NULL ); 366 366 } … … 381 381 { 382 382 if ( table == NULL ) { 383 psAbort( __func__, "psHashLookup() called with NULL hash table." );384 }383 psAbort( __func__, "psHashLookup() called with NULL hash table." ); 384 } 385 385 if ( key == NULL ) { 386 psAbort( __func__, "psHashLookup() called with NULL key." );387 }388 389 386 psAbort( __func__, "psHashLookup() called with NULL key." ); 387 } 388 389 390 390 return doHashWork( table, key, NULL, 0 ); 391 391 } … … 405 405 void * data = NULL; 406 406 bool retVal = false; 407 407 408 408 if ( table == NULL ) { 409 psAbort( __func__, "psHashRemove() called with NULL hash table." );410 }409 psAbort( __func__, "psHashRemove() called with NULL hash table." ); 410 } 411 411 if ( key == NULL ) { 412 psAbort( __func__, "psHashRemove() called with NULL key." );413 }414 412 psAbort( __func__, "psHashRemove() called with NULL key." ); 413 } 414 415 415 data = doHashWork( table, key, NULL, 1 ); 416 416 if ( data != NULL ) { 417 psFree( data );418 retVal = true;419 } else {420 retVal = false;421 }417 psFree( data ); 418 retVal = true; 419 } else { 420 retVal = false; 421 } 422 422 return retVal; 423 423 }
Note:
See TracChangeset
for help on using the changeset viewer.
