From a6c47565819cd334e37dc105cc3cb87633992b9a Mon Sep 17 00:00:00 2001 From: h_vogt Date: Thu, 25 Feb 2010 22:09:23 +0000 Subject: [PATCH] new files --- src/include/hash.h | 491 +++++++++++++++++++++++ src/misc/hash.c | 963 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1454 insertions(+) create mode 100644 src/include/hash.h create mode 100644 src/misc/hash.c diff --git a/src/include/hash.h b/src/include/hash.h new file mode 100644 index 000000000..810cc976e --- /dev/null +++ b/src/include/hash.h @@ -0,0 +1,491 @@ +/* ----------------------------------------------------------------- +FILE: nghash.h +DESCRIPTION:Insert file for threaded hash routines. + This code was donated from TimberWolf. +CONTENTS: +DATE: Jul 17, 1988 - original coding +REVISIONS: Aug 21, 2009 - adapted for ngspice +----------------------------------------------------------------- */ +#ifndef NGHASH_H +#define NGHASH_H + +#include + +#define _NGMALLOC(size_xz) tmalloc((size_xz)) +#define NGMALLOC(n, els) (els *) tmalloc((n)*sizeof(els)) +#define NGREALLOC(ar,n,els) (els *) trealloc(ar,(n)*sizeof(els)) +#define NGFREE(els) txfree(els) + + + +/* ********************** TYPE DEFINITIONS ************************* */ +typedef void (*ngdelete)(void *) ; + + + +typedef struct ngtable_rec { + void *key ; + void *data ; + struct ngtable_rec *next ; /* collision list */ + struct ngtable_rec *thread_next ; /* thread thru entire table */ + struct ngtable_rec *thread_prev ; /* thread thru entire table */ +} NGTABLEBOX, *NGTABLEPTR ; + +typedef struct nghashbox { + NGTABLEPTR *hash_table ; + NGTABLEPTR thread ; /* thread of hash table */ + NGTABLEPTR last_entry ; /* last entry into hash table */ + NGTABLEPTR enumeratePtr ; /* used to enumerate hash table */ + NGTABLEPTR searchPtr ; /* used for find again mechanism */ + void *compare_func ; /* the comparison function */ + void *hash_func ; /* the hash function */ + int size ; /* the size of the table */ + int max_density ; /* maximum number of entries before growth */ + int num_entries ; /* current number of entries in table */ + int need_resize ; /* amount before we need a resize */ + float growth_factor ; /* how much to grow table by */ + long access ; /* used for statistics */ + long collision ; /* collision times */ + unsigned int power_of_two : 8 ; /* build table as a power of two */ + unsigned int call_from_free : 8 ;/* true if in a free calling sequence */ + unsigned int unique : 16 ; /* true if only one unique item in col. list */ +} NGHASHBOX, *NGHASHPTR ; + +typedef enum { + NGHASH_NONUNIQUE = 0, + NGHASH_UNIQUE = 1L, + NGHASH_POWER_OF_TWO = (1L<<1) +} NGHASHFLAGS_T ; + +typedef unsigned int (*nghash_func)(NGHASHPTR,void *) ; + +/* the default hashing functions */ +typedef enum { + NGHASH_FUNC_STR = 0, + NGHASH_FUNC_PTR = -1, + NGHASH_FUNC_NUM = -2 +} NGHASH_FUNC_T ; + +typedef struct nghash_iter_rec { + struct ngtable_rec *position ; +} NGHASHITER, *NGHASHITERPTR ; +/* ----------------------------------------------------------------- + * macro definition for enumeration. Strange looking but compiler + * will optimize. x_yz->position = 0 and x_yz will be returned. +----------------------------------------------------------------- */ +#define NGHASH_FIRST(x_yz) ( ((x_yz)->position = NULL) ? (x_yz) : (x_yz) ) +#define NGHASH_ITER_EQUAL(x_yz,y_yz) ( (x_yz)->position == (y_yz)->position ) + +#define NGHASH_DEF_HASH_STR NGHASH_FUNC_STR +#define NGHASH_DEF_HASH_PTR (void *) NGHASH_FUNC_PTR +#define NGHASH_DEF_HASH_NUM (void *) NGHASH_FUNC_NUM + +/* the default comparison functions */ +#define NGHASH_DEF_CMP_STR NGHASH_FUNC_STR +#define NGHASH_DEF_CMP_PTR (void *) NGHASH_FUNC_PTR +#define NGHASH_DEF_CMP_NUM (void *) NGHASH_FUNC_PTR + +/* defines for unique flag */ + +/* misc definitions */ +#define NGHASH_DEF_GROW_FACTOR 2.0 +#define NGHASH_DEF_MAX_DENSITY 4 +#define NGHASH_MIN_SIZE 4 +#define nghash_tablesize( htable_xz ) ( (htable_xz)->size ) + +/* ----------------------------------------------------------------- + * Here are three hash functions in order of increasingly better + * behaviour. Remember hsum must be unsigned int. The best one + * is taken from tcl. +----------------------------------------------------------------- */ + +#define NGHASH_STR_TO_HASH( str, hsum, size ) \ + do { \ + char *name ; \ + int shift ; \ + for( name=str,shift=1,hsum=0 ;*name; name++){ \ + hsum = hsum + ((*name)<> 24); \ + hsum = hsum^g; \ + } \ + } \ + hsum = hsum & (size-1); \ + } while(0); + +#undef NGHASH_STR_TO_HASH +#define NGHASH_STR_TO_HASH( str, hsum, size ) \ + do { \ + int c ; \ + char *string ; \ + hsum = 0 ; \ + string = (char *) str ; \ + while(1) { \ + c = *string ; \ + string++ ; \ + if( c == 0) { \ + break ; \ + } \ + hsum += (hsum<<3) + c; \ + } \ + hsum %= (size) ; \ + } while(0); + +#define NGHASH_NUM_TO_HASH( num, hsum, size ) \ + do { \ + int c, len ; \ + unsigned long temp; \ + char cptr[80] ; \ + sprintf( cptr, "%lx", (UNSIGNED_LONG) num) ; \ + len = strlen(cptr) ; \ + temp = (unsigned long) cptr[0] ; \ + for( c = 1 ; c < len ; c++ ){ \ + temp += (temp<<3) + (unsigned long) cptr[c] ; \ + } \ + temp %= (size) ; \ + hsum = temp ; \ + } while(0); + +#undef NGHASH_NUM_TO_HASH + +/* ----------------------------------------------------------------- + * Replace the old num to hash with a new algorithm which is simple + * and is 5 times faster. Variance was even less on generated data. + * To use this hash table power of 2 table size must be enforced. +----------------------------------------------------------------- */ +#define NGHASH_NUM_TO_HASH( ptr, hsum, size ) \ + do { \ + unsigned int temp ; \ + long value = (long) ptr ; \ + temp = value ; \ + hsum = temp & (size - 1) ; \ + } while(0); + + +#define NGHASH_PTR_TO_HASH( ptr, hsum, size ) \ + do { \ + unsigned long temp; \ + temp = (unsigned long) (ptr); \ + temp %= (size) ; \ + hsum = temp ; \ + } while(0); + +#undef NGHASH_PTR_TO_HASH +/* ----------------------------------------------------------------- + * We use strlen instead of looking at the return value of sprintf + * because it is not standard. Actually no machine have 80 byte pointers + * but just being cautious. +----------------------------------------------------------------- */ + +#define NGHASH_PTR_TO_HASH( ptr, hsum, size ) \ + do { \ + int c, len ; \ + unsigned long temp; \ + char cptr[80] ; \ + sprintf( cptr, "%lx", (UNSIGNED_LONG) ptr) ; \ + len = strlen(cptr) ; \ + temp = (UNSIGNED_LONG) cptr[0] ; \ + for( c = 1 ; c < len ; c++ ){ \ + temp += (temp<<3) + (UNSIGNED_LONG) cptr[c] ; \ + } \ + temp %= (size) ; \ + hsum = temp ; \ + } while(0); + +#undef NGHASH_PTR_TO_HASH +/* ----------------------------------------------------------------- + * Replace the old ptr to hash with a new algorithm which is simple + * and is 5 times faster. Variance was even less on generated data. + * To use this hash table power of 2 table size must be enforced. +----------------------------------------------------------------- */ +#define NGHASH_PTR_TO_HASH( ptr, hsum, size ) \ + do { \ + unsigned int temp ; \ + long value = (long) ptr ; \ + temp = value >> 4 ; \ + hsum = temp & (size - 1) ; \ + } while(0); + +#define NGHASH_PTR_COMPARE_FUNC( p1 , p2 ) ( (p1) != (p2) ) + + +#define nghash_unique( htable_xz, flag_xz ) ((htable_xz)->unique = flag_xz) + +extern NGHASHPTR nghash_init( int numentries ) ; +/* +Function: + Returns a hash table with the given number of entries. + More that one hash table can coexist at the same time. + The default key type is string. The default comparison function + is strcmp. +*/ + +extern NGHASHPTR nghash_init_integer( int numentries ) ; +/* +Function: + Returns a hash table with the given number of entries. + More that one hash table can coexist at the same time. + The default key type is an integer. The default comparison function + is integer comparison. +*/ + +extern NGHASHPTR nghash_init_pointer( int numentries ) ; +/* +Function: + Returns a hash table with the given number of entries. + More that one hash table can coexist at the same time. + The default key type is a pointer. The default comparison function + is pointer comparison. +*/ + +extern NGHASHPTR nghash_init_with_parms( void *comp_func, + nghash_func hash_func, int numentries, int max_density, + double growth, NGHASHFLAGS_T flags ) ; +/* +Function: + Returns a hash table with the given number of entries. + More that one hash table can coexist at the same time. + Tables may be given their own hash and compare functions. If your keys + are pointers, numbers or strings, it is recommended that you use the + functions: + * HASH_DEF_HASH_PTR and HASH_DEF_CMP_PTR for pointers, + * HASH_DEF_HASH_NUM and HASH_DEF_CMP_NUM for numbers, and + * HASH_DEF_HASH_STR and HASH_DEF_CMP_STR for strings. + The hash package will recognize these and run faster as a result. + + You may use your own hash and compare functions provided they look like + * INT hash(void * key) and + * UNSIGNED_INT compare(void * key1, void * key2). + The hash function's return value should be in the interval [0, UINT_MAX]. + The compare should return zero if the two keys are equal and a non-zero + value otherwise. + + Whenever + number of entries in hash table >= size of table * max_density, + the table is grown at a the specified by growth. Unique if TRUE only allows + one entry which matches comparison function. Otherwise, multiple items + which are not unique relative to the comparison function can exist in + collision list. +*/ + +extern int nghash_max_density(NGHASHPTR hashtable,int max_density) ; +/* +Function: + Changes the max_density limit in the hash table if max_density > 1. + This function returns the current value of max_density. +*/ + + +extern int nghash_table_get( NGHASHPTR hashtable ) ; +/* +Function: + Returns the current size of hash table set by nghash_table_create +*/ + +extern int nghash_table_size( int num ) ; +/* +Function: + Returns the closest prime number to given size. +*/ + +extern int nghash_table_size2( int num ) ; +/* +Function: + Returns the table size to the closest power of 2. +*/ + +extern void *_nghash_find(NGHASHPTR hashtable, void * user_key,BOOL *status) ; +extern void *nghash_find(NGHASHPTR hashtable, void * user_key) ; +extern void *nghash_find_again(NGHASHPTR hashtable, void * user_key) ; +extern void *_nghash_find_again(NGHASHPTR hashtable, void * user_key,BOOL *status) ; +extern void *nghash_delete(NGHASHPTR hashtable, void * user_key) ; +extern void *nghash_insert(NGHASHPTR hashtable, void * user_key, void * data) ; +/* +The four functions above replace the old nghash_search function. The same +functionality but now four functions. +Function: + Hash table search routine. Given a hashtable and a key, perform + the following operations: + HASH_ENTER:if key is in table it, returns a pointer to the item. + if key is not in table, add it to the table. returns NULL. + HASH_FIND:if key is in table, it returns data pointer. + if key is not in the table, it returns NULL. + HASH_FIND_AGAIN:if additional keys are in table, returns data pointer. + if no more keys are in the table, it returns NULL. + HASH_DELETE:if key is in table, it returns -1 + if key is not in table, it return NULL. + Memory is not freed in the delete case, but marked dirty. + Data is a pointer to the information to be store with the given key. + A new operation is available for using pointers are arguments. + Just pass the pointer in as a key. Make sure to call the + nghash_init_pointer function first. +*/ + +/* ----------------------------------------------------------------- + * Convenience functions. +----------------------------------------------------------------- */ +typedef void * (*nghash)(void *) ; + +extern void nghash_free(NGHASHPTR htabl,void (*del_data)(void *),void (*del_key)(void *) ); +/* +Function: + Frees the memory associated with a hash table. The user make supply a + function which deletes the memory associated with the data field. + In addition, the user may free the memory stored at the key. + This function must have the data pointer supplied by the hash add routines + as an argument,ie. + nghash_table_delete( my_hash_table, my_free_func, my_key_free ) ; + my_free_func( data ) + void * data ; + { + } + my_key_free( key ) + void * key ; + { + } + Note: for the default hash types: STR, PTR, and NUM, the free key + operation is ignored. +*/ + +extern void nghash_free_string_func(char *str) ; +/* +Function: + Just a wrapper for YFREE(string) +*/ + +extern void nghash_free_string_hashtable(NGHASHPTR htable) ; +/* +Function: + Frees the memory associated with a hash table. This version is + a convenience function as it is equivalent to the function: + nghash_free( htable, (ngdelete) nghash_free_string_func, NULL ) ; +*/ + +extern void nghash_empty(NGHASHPTR htabl,void (*del_data)(void *),void (*del_key)(void *) ) ; +/* +Function: + Similar to nghash_free except table structure is not delete. However, + all entries have been deleted. +*/ + +extern NGHASHPTR nghash_merge( NGHASHPTR master_htable, NGHASHPTR merge_htable ) ; +/* +Function: + Merge items in merge_htable into master_htable. Create master_htable + if master_htable is NULL. Returns the merged hash table. +*/ + +extern int nghash_get_size( NGHASHPTR hashtable ) ; +/* +Function: + Since this is a threaded hash table we can find the size of + all the valid entries in the table in O(n) where n is the + number of valid entries. Returns the number of valid entries. + One may enumerate the hash table by writing the following loop. + TABLEPTR ptr ; + for( ptr = mytable->thread; ptr ; ptr= ptr->threadNext ){ + ... + } +*/ + +extern void *nghash_enumeratek(NGHASHPTR hashtable,void **key_ret,BOOL flag) ; +/* +Function: + Since this is a threaded hash table, we can enumerate the elements of + the hash table in O(n) time where n is the number of valid entries. + Returns the data and key associated with each entry. The flag is similar + to the rbtree enumerate function. This eliminates the need for writing + the following: + TABLEPTR ptr ; + for( ptr = mytable->thread; ptr ; ptr= ptr->threadNext ){ + ... + } + Instead write: + for( data = nghash_enumerate(hashtable,&key,TRUE) ; data ; + data = nghash_enumerate(hashtable,&key,TRUE) ){ + ... + } + The order returned is guaranteed to be the same as the order entered. +*/ + +extern void *nghash_enumeratekRE(NGHASHPTR hashtable,void **key_ret,NGHASHITERPTR iter_p) ; +/* +Function: + Same as nghash_enumeratekRE but this is a reentrant version. Use as + void * key_ret ; + for( i_p= nghash_enumeratekRE(htable_p,&key_ret,YHASH_FIRST(&iter) ) ; i_p ; + i_p= nghash_enumeratekRE(htable_p,&key_ret,&iter) ) ){ + data_p = (data_cast) key_ret ; + } +*/ + +extern void *nghash_enumerate(NGHASHPTR hashtable,BOOL flag) ; +/* +Function: + Like above but we don't return the key. +*/ + +extern void *nghash_enumerateRE(NGHASHPTR hashtable,NGHASHITERPTR iter_p) ; +/* +Function: + Like nghash_enumerate but this is a reentrant version. + for( i_p= nghash_enumerateRE(htable_p,YHASH_FIRST(&iter) ) ; i_p ; + i_p= nghash_enumerateRE(htable_p,&iter) ) ){ + data_p = (data_cast) key_ret ; + } + +*/ + +extern BOOL nghash_deleteItem( NGHASHPTR hashtable, void *key, void *data ) ; +/* +Function: + Delete a specific item in the hash table. Returns true if the item was + found and deleted. +*/ + +/* + * This function has been removed because we now support reentrant versions. +extern VOID nghash_enumeratePush( P1(YHASHPTR hashtable)); +Function: + Push the current enumeration pointer onto a stack. This is useful + for recursive enumeration. +*/ + +/* + * This function has been removed because we now support reentrant versions. +extern VOID nghash_enumeratePop( P1(YHASHPTR hashtable)); +Function: + Pops the current enumeration pointer from the stack. This is useful + for recursive enumeration. +*/ + +extern void nghash_dump( NGHASHPTR hashtable,void (*print_func)(void *) ) ; +/* +Function: + Prints the contents of the hash table. +*/ + +extern void nghash_reset_stat( NGHASHPTR hashtable ) ; +extern void nghash_resize( NGHASHPTR hashtable, int num ) ; + +extern void nghash_distribution( NGHASHPTR hashtable ) ; +/* +Function: + Returns information about hash table distribution to message system. +*/ + + +#endif /* NGHASH_H */ diff --git a/src/misc/hash.c b/src/misc/hash.c new file mode 100644 index 000000000..3eadd50bf --- /dev/null +++ b/src/misc/hash.c @@ -0,0 +1,963 @@ +/* ----------------------------------------------------------------- +FILE: hash.c +DESCRIPTION:This file contains the routines for building and + maintaining a hash table. + Abstract : Contains routines for managing hash tables. Tables + may be given their own hash and compare functions. If your keys + are pointers, numbers or strings, it is recommended that you + use the functions + * HASH_DEF_HASH_PTR and HASH_DEF_CMP_PTR for pointers, + * HASH_DEF_HASH_NUM and HASH_DEF_CMP_NUM for numbers, and + * HASH_DEF_HASH_STR and HASH_DEF_CMP_STR for strings. + The hash package will recognize these and run faster as + a result. + + You may use your own hash and compare functions provided they + look like + * int hash(void * key) and + * int compare(void * key1, void * key2). + The hash function's return value should be in the interval + [0, Uint_MAX]. The compare should return zero if the two + keys are equal and a non-zero value otherwise. +CONTENTS: +DATE: Jul 7, 1988 - original coding. + 1988 - 2009 many updates... +REVISIONS: +----------------------------------------------------------------- */ +#include "ngspice.h" +#include "hash.h" + +/* definitions local to this file only */ + +/* ********************** TYPE DEFINITIONS ************************* */ +#define PRIMECOUNT 200 +#define MINPRIMESIZE 7 +typedef int (*COMPARE_FUNC)(void *,void *) ; + +/* ********************** STATIC DEFINITIONS ************************* */ +static NGTABLEPTR _nghash_find_item(NGHASHPTR hhtable,void *user_key,void *data) ; + + +NGHASHPTR nghash_init_with_parms(void *comp_func, nghash_func hash_func, int num, + int max, double growth, NGHASHFLAGS_T flags) +{ + BOOL unique ; /* entries are to be unique */ + BOOL power_of_two ; /* want hash table power of 2 */ + NGHASHPTR hashtable ; + + unique = flags & NGHASH_UNIQUE ; + power_of_two = flags & NGHASH_POWER_OF_TWO ; + + hashtable = NGMALLOC( 1, NGHASHBOX ) ; + if( power_of_two ){ + hashtable->size = nghash_table_size2( num ) ; + } else { + /* prime size */ + hashtable->size = nghash_table_size( num ) ; + } + hashtable->compare_func = (void *) comp_func ; + hashtable->hash_func = (void *) hash_func ; + + hashtable->hash_table = NGMALLOC( hashtable->size, NGTABLEPTR ) ; + hashtable->max_density = max ; + hashtable->need_resize = hashtable->size * hashtable->max_density ; + hashtable->growth_factor = growth ; + hashtable->unique = unique ; + hashtable->power_of_two = power_of_two ; + hashtable->thread = NULL ; /* initialize list */ + hashtable->last_entry = NULL ; /* end of list */ + hashtable->num_entries = 0 ; + hashtable->call_from_free = FALSE ; + hashtable->access = 0; + hashtable->collision = 0; + hashtable->enumeratePtr = NULL ; + return(hashtable) ; +} /* end nghash_init_with_parms() */ + + +void nghash_resize(NGHASHPTR hashtable, int num) +{ + NGTABLEPTR *oldtable, hptr, zapptr ; + NGTABLEPTR new_hptr ; /* new hash table entry */ + int i, oldsize ; + + oldsize = hashtable->size ; + oldtable = hashtable->hash_table; + + if( hashtable->power_of_two ){ + hashtable->size = nghash_table_size2( num - 1 ) ; + } else { + hashtable->size = nghash_table_size( num ) ; + } + hashtable->num_entries = 0 ; + hashtable->thread = NULL ; + hashtable->last_entry = NULL ; /* end of list */ + hashtable->need_resize = hashtable->size * hashtable->max_density ; + + hashtable->hash_table = NGMALLOC( hashtable->size, NGTABLEPTR); + for( i = 0 ; i < oldsize ; i++ ) { + for( hptr = oldtable[i]; hptr; ) { + zapptr = hptr ; + nghash_insert( hashtable, hptr->key, hptr->data ) ; + if( hashtable->searchPtr && hashtable->searchPtr == hptr ){ + new_hptr = _nghash_find_item(hashtable, hptr->key, hptr->data ) ; + hashtable->searchPtr = new_hptr ; + } + if( hashtable->enumeratePtr && hashtable->enumeratePtr == hptr ){ + new_hptr = _nghash_find_item(hashtable, hptr->key, hptr->data ) ; + hashtable->enumeratePtr = new_hptr ; + } + /* Now safe to free */ + if( hashtable->hash_func == (void *) NGHASH_DEF_HASH_STR){ + NGFREE( hptr->key); + } + hptr = hptr->next ; + NGFREE( zapptr ) ; + } + } + + NGFREE( oldtable ); +} /* end nghash_resize() */ + + +void nghash_reset_stat(NGHASHPTR hashtable) +{ + hashtable->collision = 0 ; + hashtable->access = 0 ; +} + +NGHASHPTR nghash_init(int num_entries) +{ + return( nghash_init_with_parms( NGHASH_DEF_CMP_STR, NGHASH_DEF_HASH_STR, + num_entries, NGHASH_DEF_MAX_DENSITY, + NGHASH_DEF_GROW_FACTOR, NGHASH_UNIQUE) ) ; +} /* end nghash_init() */ + +NGHASHPTR nghash_init_pointer(int num_entries) +{ + return( nghash_init_with_parms( NGHASH_DEF_CMP_PTR, NGHASH_DEF_HASH_PTR, + num_entries, NGHASH_DEF_MAX_DENSITY, + NGHASH_DEF_GROW_FACTOR, + NGHASH_UNIQUE|NGHASH_POWER_OF_TWO) ) ; +} /* end nghash_init_pointer() */ + +NGHASHPTR nghash_init_integer(int num_entries) +{ + return( nghash_init_with_parms( NGHASH_DEF_CMP_NUM, NGHASH_DEF_HASH_NUM, + num_entries, NGHASH_DEF_MAX_DENSITY, + NGHASH_DEF_GROW_FACTOR, + NGHASH_UNIQUE|NGHASH_POWER_OF_TWO) ) ; +} /* end nghash_init_integer() */ + +int nghash_table_get(NGHASHPTR hashtable) +{ + return(hashtable->size) ; +} + +int nghash_max_density(NGHASHPTR hashtable,int max_density) +{ + if( max_density > 0 ){ + hashtable->max_density = max_density ; + hashtable->need_resize = hashtable->size * hashtable->max_density ; + } + return(hashtable->max_density) ; +} + +void nghash_empty(NGHASHPTR hashtable, void (*delete_data) (void *), + void (*delete_key) (void *)) +{ + long old_size ; /* old size of hash table */ + long new_size ; /* new size of hash table */ + NGTABLEPTR *table, hptr , zapptr ; + + nghash_reset_stat(hashtable); + + old_size = MAX( NGHASH_MIN_SIZE, hashtable->num_entries ) ; + if( hashtable->power_of_two ){ + new_size = nghash_table_size2( old_size ) ; + } else { + /* prime size */ + new_size = nghash_table_size( old_size ) ; + } + + table = hashtable->hash_table ; + if( table ){ + for( hptr = hashtable->thread ; hptr ; ){ + zapptr = hptr ; + hptr = hptr->thread_next ; + + /* execute user define delete function if requested */ + if( delete_data ){ + (*delete_data)(zapptr->data) ; + } + if( hashtable->hash_func == (void *) NGHASH_DEF_HASH_STR ) { + /* we allocated this ourselves we can delete it */ + NGFREE( zapptr->key ) ; + } else if( delete_key ){ + (*delete_key)(zapptr->key) ; + } + NGFREE( zapptr ) ; + } + memset( (char *)table, 0, (size_t) hashtable->size*sizeof(NGTABLEPTR)) ; + } + /* free decks associated with tree if they exist */ + hashtable->thread = NULL ; /* initialize list */ + hashtable->last_entry = NULL ; /* initialize list */ + hashtable->num_entries = 0 ; +} /* end nghash_empty() */ + + +void nghash_free(NGHASHPTR hashtable, void (*delete_data) (void *), + void (*delete_key) (void *)) +{ + hashtable->call_from_free = TRUE; + nghash_empty(hashtable, delete_data, delete_key ) ; + hashtable->call_from_free = FALSE ; + NGFREE( hashtable->hash_table ) ; + NGFREE( hashtable ) ; +} /* end nghash_free() */ + +void nghash_free_string_func( char *str ) +{ + NGFREE( str ) ; +} /* end nghash_free_string_func() */ + +void nghash_free_string_hashtable(NGHASHPTR hashtable) +{ + hashtable->call_from_free = TRUE; + nghash_empty(hashtable, (ngdelete) nghash_free_string_func, NULL ) ; + hashtable->call_from_free = FALSE ; + NGFREE( hashtable->hash_table ) ; + NGFREE( hashtable ) ; +} /* end nghash_free_string_hashtable() */ + +/* ----------------------------------------------------------------- + * Now nghash_search is broken into four routines: nghash_find, + * nghash_find_again, nghash_delete, and nghash_insert. +----------------------------------------------------------------- */ +void * _nghash_find(NGHASHPTR hashtable, void * user_key,BOOL *status) +{ + int ret_code ; + long hfunc ; + unsigned int hsum ; + COMPARE_FUNC compare_func ; + NGTABLEPTR curPtr ; + NGTABLEPTR *table ; + + /* initialization */ + table = hashtable->hash_table ; + DS(hashtable->access++;) ; + + /* ----------------------------------------------------------------- + * Process the hash function. + ----------------------------------------------------------------- */ + hfunc = (long) hashtable->hash_func ; + switch( hfunc ){ + case NGHASH_FUNC_STR: + NGHASH_STR_TO_HASH( user_key, hsum, hashtable->size); + break ; + case NGHASH_FUNC_PTR: + NGHASH_PTR_TO_HASH( user_key, hsum, hashtable->size); + break ; + case NGHASH_FUNC_NUM: + NGHASH_NUM_TO_HASH( user_key, hsum, hashtable->size); + break ; + default: + hsum = (*((nghash_func)hashtable->hash_func))(hashtable,user_key) ; + } + + curPtr = table[hsum] ; + if( curPtr ){ + /* list started at this hash */ + for( ; curPtr ; curPtr=curPtr->next ) { + if( hashtable->compare_func == (void *) NGHASH_DEF_CMP_STR ) { + ret_code = strcmp((char *)curPtr->key, user_key ) ; + } else if ( hashtable->compare_func == (void *) NGHASH_DEF_CMP_PTR|| + hashtable->compare_func == (void *) NGHASH_DEF_CMP_NUM ){ + ret_code = NGHASH_PTR_COMPARE_FUNC( curPtr->key, user_key ); + } else { + compare_func = (COMPARE_FUNC) hashtable->compare_func ; + ret_code = (*(compare_func))(curPtr->key, user_key ) ; + } + if( ret_code == STRINGEQ ){ + /* ---------------------------------------------------- + * Operation find or enter with unique items, we + * return item. On a nonunique enter, add item below. + ------------------------------------------------------- */ + hashtable->searchPtr = curPtr ; + if( status ){ + *status = TRUE ; + } + return( curPtr->data ) ; + } + } + } + /* cant find anything on a find operation */ + hashtable->searchPtr = NULL ; + if( status ){ + *status = FALSE ; + } + return( NULL ) ; + +} /* end nghash_find() */ + +/* ----------------------------------------------------------------- + * This find does not understand 0 or NULL data items. Use _nghash_find + * instead. + * ----------------------------------------------------------------- */ +void * nghash_find(NGHASHPTR hashtable, void * user_key) +{ + return( _nghash_find( hashtable, user_key, NULL ) ) ; +} /* end nghash_find() */ + + +void * _nghash_find_again(NGHASHPTR hashtable, void * user_key,BOOL *status) +{ + int ret_code ; /* comparison return code */ + NGTABLEPTR curPtr ; /* current hashtable entry */ + COMPARE_FUNC compare_func ; /* user defined comparison function */ + NGTABLEPTR *table ; /* hash table array */ + + /* initialization */ + table = hashtable->hash_table ; + DS(hashtable->access++;) ; + + if( hashtable->searchPtr ){ + for(curPtr=hashtable->searchPtr->next; curPtr ; curPtr=curPtr->next ) { + if( hashtable->compare_func == (void *) NGHASH_DEF_CMP_STR ) { + ret_code = strcmp((char *)curPtr->key, user_key ) ; + } else if ( hashtable->compare_func == (void *) NGHASH_DEF_CMP_PTR|| + hashtable->compare_func == (void *) NGHASH_DEF_CMP_NUM ){ + ret_code = NGHASH_PTR_COMPARE_FUNC( curPtr->key, user_key ); + } else { + compare_func = (COMPARE_FUNC) hashtable->compare_func ; + ret_code = (*(compare_func))(curPtr->key, user_key ) ; + } + if( ret_code == STRINGEQ ){ + hashtable->searchPtr = curPtr ; + if( status ){ + *status = TRUE ; + } + return( curPtr->data ) ; + } + } + } + if( status ){ + *status = FALSE ; + } + return(NULL) ; +} /* end _nghash_find_again() */ + +void * nghash_find_again(NGHASHPTR hashtable, void * user_key) +{ + return( _nghash_find_again( hashtable, user_key, NULL ) ) ; +} /* end nghash_find_again() */ + + +void * nghash_delete(NGHASHPTR hashtable, void * user_key) +{ + int ret_code ; + long hfunc ; + unsigned int hsum ; + void * user_data_p ; + COMPARE_FUNC compare_func ; + NGTABLEPTR curPtr, *prevPtr ; + NGTABLEPTR *table ; + + /* initialization */ + table = hashtable->hash_table ; + DS(hashtable->access++;) ; + + /* ----------------------------------------------------------------- + * Process the hash function. + ----------------------------------------------------------------- */ + hfunc = (long) hashtable->hash_func ; + switch( hfunc ){ + case NGHASH_FUNC_STR: + NGHASH_STR_TO_HASH( user_key, hsum, hashtable->size); + break ; + case NGHASH_FUNC_PTR: + NGHASH_PTR_TO_HASH( user_key, hsum, hashtable->size); + break ; + case NGHASH_FUNC_NUM: + NGHASH_NUM_TO_HASH( user_key, hsum, hashtable->size); + break ; + default: + hsum = (*((nghash_func)hashtable->hash_func))(hashtable,user_key) ; + } + + /* insert into table only if distinct number */ + curPtr = table[hsum] ; + if( curPtr ){ + /* list started at this hash */ + prevPtr = table + hsum ; + for( ; curPtr ; prevPtr = &(curPtr->next), curPtr=curPtr->next ) { + if( hashtable->compare_func == (void *) NGHASH_DEF_CMP_STR ) { + ret_code = strcmp((char *)curPtr->key, user_key ) ; + } else if ( hashtable->compare_func == (void *) NGHASH_DEF_CMP_PTR|| + hashtable->compare_func == (void *) NGHASH_DEF_CMP_NUM ){ + ret_code = NGHASH_PTR_COMPARE_FUNC( curPtr->key, user_key ); + } else { + compare_func = (COMPARE_FUNC) hashtable->compare_func ; + ret_code = (*(compare_func))(curPtr->key, user_key ) ; + } + if( ret_code == STRINGEQ ){ + if( curPtr->thread_prev ){ /* no sentinel */ + curPtr->thread_prev->thread_next = curPtr->thread_next; + } else { + hashtable->thread = curPtr->thread_next ; + } + if( curPtr->thread_next ){ /* no sentinel */ + curPtr->thread_next->thread_prev = curPtr->thread_prev ; + } else { + hashtable->last_entry = curPtr->thread_prev ; + } + *prevPtr = curPtr->next ; + if( hashtable->hash_func == (void *) NGHASH_DEF_HASH_STR ) { + /* we allocated this ourselves we can delete it */ + NGFREE( curPtr->key ) ; + } + user_data_p = curPtr->data ; + NGFREE(curPtr); + hashtable->num_entries-- ; + return( user_data_p ) ; + } + } + } + return( NULL ) ; /* didn't find anything to delete */ + +} /* end nghash_delete() */ + +void * nghash_insert(NGHASHPTR hashtable, void * user_key, void * data) +{ + int ret_code ; + long hfunc ; + unsigned int hsum ; + COMPARE_FUNC compare_func ; + NGTABLEPTR curPtr, temptr, curTable ; + NGTABLEPTR *table ; + + /* initialization */ + table = hashtable->hash_table ; + DS(hashtable->access++;) + + /* ----------------------------------------------------------------- + * Process the hash function. + ----------------------------------------------------------------- */ + hfunc = (long) hashtable->hash_func ; + switch( hfunc ){ + case NGHASH_FUNC_STR: + NGHASH_STR_TO_HASH( user_key, hsum, hashtable->size); + break ; + case NGHASH_FUNC_PTR: + NGHASH_PTR_TO_HASH( user_key, hsum, hashtable->size); + break ; + case NGHASH_FUNC_NUM: + NGHASH_NUM_TO_HASH( user_key, hsum, hashtable->size); + break ; + default: + hsum = (*((nghash_func)hashtable->hash_func))(hashtable,user_key) ; + } + + /* insert into table only if distinct number */ + temptr = table[hsum] ; + if( temptr ){ + /* list started at this hash */ + for( curPtr = temptr ; curPtr ; curPtr=curPtr->next ) { + DS(hashtable->collision++;) ; + if( hashtable->compare_func == (void *) NGHASH_DEF_CMP_STR ) { + ret_code = strcmp((char *)curPtr->key, user_key ) ; + } else if ( hashtable->compare_func == (void *) NGHASH_DEF_CMP_PTR|| + hashtable->compare_func == (void *) NGHASH_DEF_CMP_NUM ){ + ret_code = NGHASH_PTR_COMPARE_FUNC( curPtr->key, user_key ); + } else { + compare_func = (COMPARE_FUNC) hashtable->compare_func ; + ret_code = (*(compare_func))(curPtr->key, user_key ) ; + } + if( ret_code == STRINGEQ ){ + if( hashtable->unique ){ + /* ---------------------------------------------------- + * Operation enter with unique items, we + * return item. On a nonunique enter, add item below. + ------------------------------------------------------- */ + hashtable->searchPtr = curPtr ; + return( curPtr->data ) ; + } else { + break ; /* avoid some work for nonunique hash_enter */ + } + } + } + } + + /* now save data */ + hashtable->num_entries++ ; + table[hsum] = curTable = NGMALLOC(1,NGTABLEBOX); + curTable->data = data ; + if( hashtable->hash_func == (void *) NGHASH_DEF_HASH_STR ){ + curTable->key = copy( user_key); + } else { + curTable->key = user_key ; + } + curTable->next = temptr ; + /* now fix thread which goes through hash table */ + if( hashtable->last_entry ){ + hashtable->last_entry->thread_next = curTable ; + curTable->thread_prev = hashtable->last_entry ; + hashtable->last_entry = curTable ; + } else { + hashtable->thread = hashtable->last_entry = curTable ; + curTable->thread_prev = NULL ; + } + curTable->thread_next = NULL ; + + if( hashtable->num_entries >= hashtable->need_resize ){ + int newsize ; /* new size of table */ + newsize = hashtable->size * hashtable->growth_factor ; + nghash_resize(hashtable, newsize ) ; + } + + return( NULL ) ; /* no conflict on a enter */ + +} /* end nghash_insert() */ + +/* returns the pointer with the item */ +static NGTABLEPTR _nghash_find_item(NGHASHPTR htable,void * user_key,void * data) +{ + int ret_code ; + long hfunc ; + unsigned int hsum ; + COMPARE_FUNC compare_func ; + NGTABLEPTR curPtr, temptr ; + NGTABLEPTR *table ; + + /* initialization */ + table = htable->hash_table ; + + /* ----------------------------------------------------------------- + * Process the hash function. + ----------------------------------------------------------------- */ + hfunc = (long) htable->hash_func ; + switch( hfunc ){ + case NGHASH_FUNC_STR: + NGHASH_STR_TO_HASH( user_key, hsum, htable->size); + break ; + case NGHASH_FUNC_PTR: + NGHASH_PTR_TO_HASH( user_key, hsum, htable->size); + break ; + case NGHASH_FUNC_NUM: + NGHASH_NUM_TO_HASH( user_key, hsum, htable->size); + break ; + default: + hsum = (*((nghash_func)htable->hash_func))(htable,user_key) ; + } + + /* insert into table only if distinct number */ + if( (temptr = table[hsum]) ){ + /* list started at this hash */ + for(curPtr=temptr ; curPtr ; curPtr=curPtr->next ) { + if( htable->compare_func == (void *) NGHASH_DEF_CMP_STR ) { + ret_code = strcmp((char *)curPtr->key, user_key ) ; + } else if ( htable->compare_func == (void *) NGHASH_DEF_CMP_PTR|| + htable->compare_func == (void *) NGHASH_DEF_CMP_NUM ){ + ret_code = NGHASH_PTR_COMPARE_FUNC( curPtr->key, user_key ); + } else { + compare_func = (COMPARE_FUNC) htable->compare_func ; + ret_code = (*(compare_func))(curPtr->key, user_key ) ; + } + if( ret_code == STRINGEQ ){ + if( data ){ + if( curPtr->data == data ){ + return( curPtr ) ; + } + } else { + return( curPtr ) ; + } + } + } + } + return( NULL ) ; /* no matching item */ + +} /* end _nghash_find_item() */ + + + +void * nghash_enumeratek(NGHASHPTR htable, void * *key_return, BOOL start_flag) +{ + NGTABLEPTR current_spot ; /* current place in threaded list */ + + if( start_flag ){ + if( (htable->enumeratePtr = htable->thread) ){ + current_spot = htable->enumeratePtr ; + *key_return = current_spot->key ; + return( current_spot->data ) ; + } + } else { + if( htable->enumeratePtr && + (htable->enumeratePtr = htable->enumeratePtr->thread_next) ){ + current_spot = htable->enumeratePtr ; + *key_return = current_spot->key ; + return( current_spot->data ) ; + } + } + *key_return = NULL ; + return( NULL ) ; + +} /* end nghash_enumeratek() */ + +void * nghash_enumerate(NGHASHPTR htable,BOOL start_flag) +{ + NGTABLEPTR current_spot ; /* current place in threaded list */ + + if( start_flag ){ + if( (htable->enumeratePtr = htable->thread) ){ + current_spot = htable->enumeratePtr ; + return( current_spot->data ) ; + } + } else { + if( htable->enumeratePtr && + (htable->enumeratePtr = htable->enumeratePtr->thread_next) ){ + current_spot = htable->enumeratePtr ; + return( current_spot->data ) ; + } + } + return( NULL ) ; + +} /* end nghash_enumerate() */ + +/* ----------------------------------------------------------------- + * This is the reentrant version which uses an iterator. + * ----------------------------------------------------------------- */ +void * nghash_enumeratekRE(NGHASHPTR htable, void * *key_return, NGHASHITERPTR iter_p) +{ + NGTABLEPTR current_spot ; /* current place in threaded list */ + FUNC_NAME("nghash_enumeratekRE") ; + + if(!(iter_p)){ + fprintf( stderr, "ERROR[%s]:Null iterator pointer.\n", routine ) ; + return(NULL) ; + } + if(!(iter_p->position)){ + if( (iter_p->position = htable->thread) ){ + current_spot = iter_p->position ; + *key_return = current_spot->key ; + return( current_spot->data ) ; + } + } else { + if( iter_p->position && + (iter_p->position = iter_p->position->thread_next) ){ + current_spot = iter_p->position ; + *key_return = current_spot->key ; + return( current_spot->data ) ; + } + } + *key_return = NULL ; + return( NULL ) ; + +} /* end nghash_enumeratekRE() */ + +/* ----------------------------------------------------------------- + * This is the reentrant version which uses an iterator. + * ----------------------------------------------------------------- */ +void * nghash_enumerateRE(NGHASHPTR htable, NGHASHITERPTR iter_p) +{ + NGTABLEPTR current_spot ; /* current place in threaded list */ + FUNC_NAME("nghash_enumerateRE") ; + + if(!(iter_p)){ + fprintf( stderr, "ERROR[%s]:Null iterator pointer.\n", routine ) ; + return(NULL) ; + } + if(!(iter_p->position)){ + if( (iter_p->position = htable->thread) ){ + current_spot = iter_p->position ; + return( current_spot->data ) ; + } + } else { + if( iter_p->position && + (iter_p->position = iter_p->position->thread_next) ){ + current_spot = iter_p->position ; + return( current_spot->data ) ; + } + } + return( NULL ) ; + +} /* end nghash_enumerateRE() */ + +/* ----------------------------------------------------------------- + * Merge items in merge_htable into master_htable. Create master_htable + * if master_htable is NULL. Returns the merged hash table. + * ----------------------------------------------------------------- */ +NGHASHPTR nghash_merge( NGHASHPTR master_htable, NGHASHPTR merge_htable ) +{ + NGTABLEPTR ptr ; /* traverse hash table */ + + if(!(master_htable)){ + master_htable = NGMALLOC( 1, NGHASHBOX ) ; + *master_htable = *merge_htable ; + master_htable->hash_table = NGMALLOC( master_htable->size, NGTABLEPTR ) ; + master_htable->thread = NULL ; + master_htable->last_entry = NULL ; + master_htable->num_entries = 0 ; + master_htable->enumeratePtr = NULL ; + master_htable->searchPtr = NULL ; + master_htable->access = 0 ; + master_htable->collision = 0 ; + } + for( ptr = merge_htable->thread ; ptr ; ptr = ptr->thread_next ){ + nghash_insert( master_htable, ptr->key, ptr->data ) ; + } + return( master_htable ) ; +} /* end nghash_merge() */ + + +int nghash_get_size(NGHASHPTR hashtable) +{ + return( hashtable->num_entries ) ; +} + +void nghash_dump(NGHASHPTR htable, void (*print_key) (void *)) +{ + int i ; /* counter */ + int count ; /* counter */ + NGTABLEPTR *table ; /* hash table */ + NGTABLEPTR hptr ; /* hash table element */ + + table = htable->hash_table ; + fprintf( stderr, "Dump of hashtable containing %d entries...\n", + htable->num_entries ) ; + fprintf( stderr, "Table is %4.2f%% full\n", + 100.0 * (double) htable->num_entries / (double) htable->size ) ; + for( i = 0 ; i < htable->size ; i++ ) { + if( (hptr = table[i]) ){ + fprintf( stderr, " [%5d]:", i ) ; + count = 0 ; + for( ; hptr ; hptr=hptr->next ){ + if( ++count == 3 ){ + fprintf( stderr, "\n\t" ) ; + count = 0 ; + } + if( htable->hash_func == (void *) NGHASH_DEF_HASH_STR ){ + fprintf( stderr, " key:%s ", (char *) hptr->key ) ; + } else { + fprintf( stderr, " key:%0lx ", (unsigned long) hptr->key ) ; + } + if( print_key) { + (*print_key)(hptr->data) ; + } else { + fprintf( stderr, " data:%0lx ", (unsigned long) hptr->data ) ; + } + } + fprintf( stderr, "\n" ) ; + } + } /* end for( i = 0... */ + +} /* end nghash_enumerate() */ + +/* ----------------------------------------------------------------- + * nghash_deleteItem - deletes a specified item out of the hash table. + * To be useful, unique flag should be off. Otherwise just use nghash_delete. + * Returns true if item was deleted. +----------------------------------------------------------------- */ +BOOL nghash_deleteItem(NGHASHPTR hashtable, void * user_key, void * data) +{ + int ret_code ; + long hfunc ; + unsigned long hsum ; + COMPARE_FUNC compare_func ; + NGTABLEPTR curPtr, temptr, *prevPtr ; + NGTABLEPTR *table ; + + /* initialization */ + table = hashtable->hash_table ; + + /* ----------------------------------------------------------------- + * Process the hash function. + ----------------------------------------------------------------- */ + hfunc = (long) hashtable->hash_func ; + switch( hfunc ){ + case NGHASH_FUNC_STR: + NGHASH_STR_TO_HASH( user_key, hsum, hashtable->size); + break ; + case NGHASH_FUNC_PTR: + NGHASH_PTR_TO_HASH( user_key, hsum, hashtable->size); + break ; + case NGHASH_FUNC_NUM: + NGHASH_NUM_TO_HASH( user_key, hsum, hashtable->size); + break ; + default: + hsum = (*((nghash_func)hashtable->hash_func))(hashtable,user_key) ; + } + + /* insert into table only if distinct number */ + temptr = table[hsum] ; + if( temptr ){ + /* list started at this hash */ + prevPtr = table + hsum ; + for(curPtr=temptr;curPtr;prevPtr = &(curPtr->next), curPtr=curPtr->next ) { + /* ----------------------------------------------------------------- + * Look for match. + ----------------------------------------------------------------- */ + if( hashtable->compare_func == (void *) NGHASH_DEF_CMP_STR ) { + ret_code = strcmp((char *)curPtr->key, user_key ) ; + } else if ( hashtable->compare_func == (void *) NGHASH_DEF_CMP_PTR|| + hashtable->compare_func == (void *) NGHASH_DEF_CMP_NUM ){ + ret_code = NGHASH_PTR_COMPARE_FUNC( curPtr->key, user_key ); + } else { + compare_func = (COMPARE_FUNC) hashtable->compare_func ; + ret_code = (*(compare_func))(curPtr->key, user_key ) ; + } + if( ret_code == STRINGEQ ){ + if( curPtr->data == data ){ + if( curPtr->thread_prev ){ /* no sentinel */ + curPtr->thread_prev->thread_next = curPtr->thread_next; + } else { + hashtable->thread = curPtr->thread_next ; + } + if( curPtr->thread_next ){ /* no sentinel */ + curPtr->thread_next->thread_prev = curPtr->thread_prev ; + } else { + hashtable->last_entry = curPtr->thread_prev ; + } + *prevPtr = curPtr->next; + if( hashtable->hash_func == (void *) NGHASH_DEF_HASH_STR ) { + /* we allocated this ourselves we can delete it */ + NGFREE( curPtr->key ) ; + } + NGFREE(curPtr); + hashtable->num_entries-- ; + return( TRUE ) ; + } + } + } /* end for(curPtr=temptr... */ + } /* end if( temptr... */ + + return( FALSE ) ; /* could not find item */ + +} /* end nghash_deleteItem() */ + +/*---------------------------- hash_table_size -------------------------*/ +int nghash_table_size(int minEntries) +{ + int i; + BOOL isPrime; + int prime; + int testPrime; + static int primes[PRIMECOUNT] = + { 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, + 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, + 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, + 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, + 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, + 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, + 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, + 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, + 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, + 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, + 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, + 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, + 881, 883, 887, 907, 991, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997,1009,1013,1019, + 1021,1031,1033,1039,1049,1051,1061,1063,1069,1087, + 1091,1093,1097,1103,1109,1117,1123,1129,1151,1153, + 1163,1171,1181,1187,1193,1201,1213,1217,1223,1229 }; + + if (minEntries <= MINPRIMESIZE){ + return(MINPRIMESIZE); + } else { + testPrime = minEntries; + /* test to see if even */ + if ((testPrime % 2) == 0){ + testPrime = testPrime + 1; + } + do { + testPrime = testPrime + 2; + isPrime = TRUE; + for (i=0;i < PRIMECOUNT;i++){ + prime = primes[i]; + if (testPrime < prime*prime){ + break; + } + if ((testPrime % prime) == 0){ + isPrime = FALSE; + break; + } + } + } while (!(isPrime)); + + return(testPrime); + } + +} /* FUNCTION nghash_table_size */ + +int nghash_table_size2(int minEntries) +{ + int power ; + int table_size ; + power = 0 ; + while( minEntries > 0 ){ + minEntries = minEntries >> 1 ; + power++ ; + } + power = MIN( power, 32 ) ; + table_size = 1 << power ; + table_size = MAX( NGHASH_MIN_SIZE, table_size ) ; + return( table_size ) ; + +} /* end nghash_table_size2() */ + + +void nghash_distribution(NGHASHPTR hashtable) +{ + int i ; /* counter */ + long min ; /* min count */ + long max ; /* max count */ + long nzero_cnt ; /* non zero count */ + long this_count ; /* count items at this list */ + long tablesize ; /* table size */ + double avg ; /* average */ + double sum2 ; /* squared sum */ + double diff ; /* difference */ + double diff2 ; /* difference squared */ + double nzavg ; /* non zero average */ + double variance ; /* variance of table */ + NGTABLEPTR *table ; /* hash table */ + NGTABLEPTR hptr ; /* hash table pointer */ + FUNC_NAME("nghash_distribution" ) ; + + tablesize = nghash_tablesize(hashtable) ; + table = hashtable->hash_table ; + avg = hashtable->num_entries / (double) tablesize ; + sum2 = 0.0 ; + min = max = 0 ; + nzero_cnt = 0 ; + for( i = 0 ; i < tablesize ; i++ ) { + this_count = 0 ; + for( hptr = table[i]; hptr; hptr = hptr->next ) { + this_count++ ; + } + if( i == 0 ){ + min = max = this_count ; + } else { + if( this_count < min ){ + min = this_count ; + } + if( this_count > max ){ + max = this_count ; + } + } + if( this_count > 0 ){ + nzero_cnt++ ; + } + diff = this_count - avg ; + diff2 = diff * diff ; + sum2 += diff2 ; + } + variance = sum2 / hashtable->num_entries ; + nzavg = hashtable->num_entries / (double) nzero_cnt ; + fprintf( stderr, "[%s]:min:%ld max:%ld nonzero avg:%f\n", routine, min, max, nzavg ) ; + fprintf( stderr, " variance:%f std dev:%f target:%f nonzero entries:%ld / %ld\n", + variance, sqrt(variance), avg, nzero_cnt, tablesize ) ; +} /* end nghash_distribution() */