new files

This commit is contained in:
h_vogt 2010-02-25 22:09:23 +00:00
parent 76feebbbfa
commit a6c4756581
2 changed files with 1454 additions and 0 deletions

491
src/include/hash.h Normal file
View File

@ -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 <bool.h>
#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)<<shift); \
shift = (shift + 1) & 0x0007; \
} \
hsum %= (size) ; \
} while(0);
#undef NGHASH_STR_TO_HASH
#define NGHASH_STR_TO_HASH( str, hsum, size ) \
do { \
char *name ; \
unsigned long g ; \
for( name=str,hsum=0 ;*name; name++){ \
hsum = (hsum << 4) + (*name); \
g = hsum & 0xF0000000 ; \
if (g) { \
hsum = hsum^(g >> 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 */

963
src/misc/hash.c Normal file
View File

@ -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() */