00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifndef lint
00031 static const char libbu_hash_RCSid[] = "@(#) $Header: /cvsroot/brlcad/brlcad/src/libbu/hash.c,v 14.11 2006/08/31 05:50:24 lbutler Exp $";
00032 #endif
00033
00034 #include "common.h"
00035
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038 #include <math.h>
00039 #ifdef HAVE_STRING_H
00040 # include <string.h>
00041 #else
00042 # include <strings.h>
00043 #endif
00044 #include "machine.h"
00045 #include "bu.h"
00046
00047
00048
00049
00050
00051 unsigned long
00052 bu_hash(unsigned char *str, int len)
00053 {
00054 unsigned long hash = 5381;
00055 int i, c;
00056
00057 c = *str;
00058 for( i=0 ; i<len ; i++ ) {
00059 c = *str;
00060 hash = ((hash << 5) + hash) + c;
00061 str++;
00062 }
00063
00064 return hash;
00065 }
00066
00067
00068
00069
00070
00071
00072
00073 struct bu_hash_tbl *
00074 bu_create_hash_tbl( unsigned long tbl_size )
00075 {
00076 struct bu_hash_tbl *hsh_tbl;
00077 unsigned long power_of_two=64;
00078 int power=6;
00079 int max_power=(sizeof( unsigned long ) * 8) - 1;
00080
00081
00082 hsh_tbl = (struct bu_hash_tbl *)malloc( sizeof( struct bu_hash_tbl ) );
00083 if( !hsh_tbl ) {
00084 fprintf( stderr, "Failed to allocate hash table\n" );
00085 return( (struct bu_hash_tbl *)NULL );
00086 }
00087
00088
00089 while( power_of_two < tbl_size && power < max_power ) {
00090 power_of_two = power_of_two << 1;
00091 power++;
00092 }
00093
00094 if( power == max_power ) {
00095 int i;
00096
00097 hsh_tbl->mask = 1;
00098 for( i=1 ; i<max_power ; i++ ) {
00099 hsh_tbl->mask = (hsh_tbl->mask << 1) + 1;
00100 }
00101 hsh_tbl->num_lists = hsh_tbl->mask + 1;
00102 } else {
00103 hsh_tbl->num_lists = power_of_two;
00104 hsh_tbl->mask = power_of_two - 1;
00105 }
00106
00107
00108 hsh_tbl->lists = (struct bu_hash_entry **)calloc( hsh_tbl->num_lists, sizeof( struct bu_hash_entry *) );
00109
00110 hsh_tbl->num_entries = 0;
00111 hsh_tbl->magic = BU_HASH_TBL_MAGIC;
00112
00113 return( hsh_tbl );
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 struct bu_hash_entry *
00134 bu_find_hash_entry( struct bu_hash_tbl *hsh_tbl, unsigned char *key, int key_len, struct bu_hash_entry **prev, unsigned long *index )
00135 {
00136 struct bu_hash_entry *hsh_entry=NULL;
00137 int found=0;
00138
00139 BU_CK_HASH_TBL( hsh_tbl );
00140
00141
00142 *index = bu_hash( key, key_len ) & hsh_tbl->mask;
00143 if( *index >= hsh_tbl->num_lists ) {
00144 fprintf( stderr, "hash function returned too large value (%ld), only have %ld lists\n",
00145 *index, hsh_tbl->num_lists );
00146 *prev = NULL;
00147 return( (struct bu_hash_entry *)NULL );
00148 }
00149
00150
00151 *prev = NULL;
00152 if( hsh_tbl->lists[*index] ) {
00153 *prev = NULL;
00154 hsh_entry = hsh_tbl->lists[*index];
00155 while( hsh_entry ) {
00156 unsigned char *c1, *c2;
00157 int i;
00158
00159
00160 if( hsh_entry->key_len != key_len ) {
00161 *prev = hsh_entry;
00162 hsh_entry = hsh_entry->next;
00163 continue;
00164 }
00165
00166
00167 found = 1;
00168 c1 = key;
00169 c2 = hsh_entry->key;
00170 for( i=0 ; i<key_len ; i++ ) {
00171 if( *c1 != *c2 ) {
00172 found = 0;
00173 break;
00174 }
00175 c1++;
00176 c2++;
00177 }
00178
00179
00180 if( found ) break;
00181
00182
00183 *prev = hsh_entry;
00184 hsh_entry = hsh_entry->next;
00185 }
00186 }
00187
00188 if( found ) {
00189
00190 return( hsh_entry );
00191 } else {
00192
00193 return( (struct bu_hash_entry *)NULL );
00194 }
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 void
00206 bu_set_hash_value( struct bu_hash_entry *hsh_entry, unsigned char *value )
00207 {
00208 BU_CK_HASH_ENTRY( hsh_entry );
00209
00210
00211 hsh_entry->value = value;
00212 }
00213
00214
00215
00216
00217
00218 unsigned char *
00219 bu_get_hash_value( struct bu_hash_entry *hsh_entry )
00220 {
00221 BU_CK_HASH_ENTRY( hsh_entry );
00222
00223 return( hsh_entry->value );
00224 }
00225
00226
00227
00228
00229
00230 unsigned char *
00231 bu_get_hash_key( struct bu_hash_entry *hsh_entry )
00232 {
00233 BU_CK_HASH_ENTRY( hsh_entry );
00234
00235 return( hsh_entry->key );
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 struct bu_hash_entry *
00256 bu_hash_add_entry( struct bu_hash_tbl *hsh_tbl, unsigned char *key, int key_len, int *new )
00257 {
00258 struct bu_hash_entry *hsh_entry, *prev;
00259 unsigned long index;
00260
00261 BU_CK_HASH_TBL( hsh_tbl );
00262
00263
00264
00265
00266
00267
00268 hsh_entry = bu_find_hash_entry( hsh_tbl, key, key_len, &prev, &index );
00269
00270 if( hsh_entry ) {
00271
00272 *new = 0;
00273 return( hsh_entry );
00274 }
00275
00276 if( prev ) {
00277
00278 prev->next = (struct bu_hash_entry *)calloc( 1, sizeof( struct bu_hash_entry ) );
00279 hsh_entry = prev->next;
00280 } else {
00281
00282 hsh_entry = (struct bu_hash_entry *)calloc( 1, sizeof( struct bu_hash_entry ) );
00283 hsh_tbl->lists[index] = hsh_entry;
00284 }
00285
00286
00287 hsh_entry->next = NULL;
00288 hsh_entry->value = NULL;
00289 hsh_entry->key_len = key_len;
00290 hsh_entry->magic = BU_HASH_ENTRY_MAGIC;
00291
00292
00293 hsh_entry->key = (unsigned char *)malloc( key_len );
00294 memcpy( hsh_entry->key, key, key_len );
00295
00296
00297 *new = 1;
00298 hsh_tbl->num_entries++;
00299 return( hsh_entry );
00300 }
00301
00302
00303
00304
00305
00306
00307 void
00308 bu_hash_tbl_pr( struct bu_hash_tbl *hsh_tbl, char *str )
00309 {
00310 unsigned long index;
00311 struct bu_hash_entry *hsh_entry;
00312
00313 BU_CK_HASH_TBL( hsh_tbl );
00314
00315 fprintf( stderr, "%s\n", str );
00316 fprintf( stderr, "bu_hash_table (%ld entries):\n", hsh_tbl->num_entries );
00317
00318
00319 for( index=0 ; index<hsh_tbl->num_lists ; index++ ) {
00320 hsh_entry = hsh_tbl->lists[index];
00321 while( hsh_entry ) {
00322 BU_CK_HASH_ENTRY( hsh_entry );
00323 fprintf( stderr, "\tindex=%ld, key=x%lx, value=x%lx\n", index, (unsigned long int)hsh_entry->key, (unsigned long int)hsh_entry->value );
00324 hsh_entry = hsh_entry->next;
00325 }
00326 }
00327 }
00328
00329
00330
00331
00332
00333
00334
00335 void
00336 bu_hash_tbl_free( struct bu_hash_tbl *hsh_tbl )
00337 {
00338 unsigned long index;
00339 struct bu_hash_entry *hsh_entry, *tmp;
00340
00341 BU_CK_HASH_TBL( hsh_tbl );
00342
00343
00344 for( index=0 ; index<hsh_tbl->num_lists ; index++ ) {
00345
00346 hsh_entry = hsh_tbl->lists[index];
00347 while( hsh_entry ) {
00348 BU_CK_HASH_ENTRY( hsh_entry );
00349 tmp = hsh_entry->next;
00350
00351
00352 free( hsh_entry->key );
00353 free( hsh_entry );
00354
00355
00356 hsh_entry = tmp;
00357 }
00358 }
00359
00360
00361 free( hsh_tbl->lists );
00362
00363
00364 free( hsh_tbl );
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 struct bu_hash_entry *
00381 bu_hash_tbl_first( struct bu_hash_tbl *hsh_tbl, struct bu_hash_record *rec )
00382 {
00383 BU_CK_HASH_TBL( hsh_tbl );
00384
00385
00386 rec->magic = BU_HASH_RECORD_MAGIC;
00387 rec->tbl = hsh_tbl;
00388 rec->index = -1;
00389 rec->hsh_entry = (struct bu_hash_entry *)NULL;
00390
00391 if( hsh_tbl->num_entries == 0 ) {
00392
00393 return( (struct bu_hash_entry *)NULL );
00394 }
00395
00396
00397 for( rec->index=0 ; rec->index < hsh_tbl->num_lists ; rec->index++ ) {
00398 rec->hsh_entry = hsh_tbl->lists[rec->index];
00399 if( rec->hsh_entry ) {
00400 return( rec->hsh_entry );
00401 }
00402 }
00403
00404
00405 return( (struct bu_hash_entry *)NULL );
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 struct bu_hash_entry *
00419 bu_hash_tbl_next( struct bu_hash_record *rec )
00420 {
00421 struct bu_hash_tbl *hsh_tbl;
00422
00423 BU_CK_HASH_RECORD( rec );
00424 hsh_tbl = rec->tbl;
00425 BU_CK_HASH_TBL( hsh_tbl );
00426
00427
00428
00429
00430 if( rec->hsh_entry ) {
00431 rec->hsh_entry = rec->hsh_entry->next;
00432 if( rec->hsh_entry ) {
00433 return( rec->hsh_entry );
00434 }
00435 }
00436
00437
00438 for( rec->index++ ; rec->index < hsh_tbl->num_lists ; rec->index++ ) {
00439 rec->hsh_entry = hsh_tbl->lists[rec->index];
00440 if( rec->hsh_entry ) {
00441 return( rec->hsh_entry );
00442 }
00443 }
00444
00445
00446 return( (struct bu_hash_entry *)NULL );
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457