2 changed files with 1454 additions and 0 deletions
-
491src/include/hash.h
-
963src/misc/hash.c
@ -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 */ |
|||
@ -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() */ |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue