new files
This commit is contained in:
parent
76feebbbfa
commit
a6c4756581
|
|
@ -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() */
|
||||
Loading…
Reference in New Issue