You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.3 KiB
135 lines
3.3 KiB
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "htable.h"
|
|
|
|
//// Generic hash table implementation
|
|
|
|
// Determine the index for a key. On match, it returns the index into
|
|
// the table. On mismatch it returns -i-1 for the first free spot
|
|
// where the keyed element would fit.
|
|
static int htindex(htable *table,unsigned char *key) {
|
|
if ( table->data == 0 ) {
|
|
table->data = calloc( 256, sizeof( unsigned char* ) );
|
|
table->size = 256;
|
|
}
|
|
unsigned int hash = (*table->hashcode)( table, key ) % table->size;
|
|
unsigned int i = hash;
|
|
int hole = -1;
|
|
for ( ;; ) {
|
|
unsigned char *x = table->data[ i++ ];
|
|
if ( x == 0 ) {
|
|
return ( hole >= 0 )? -hole : - (int) i;
|
|
}
|
|
if ( x == (unsigned char *)1 ) {
|
|
if ( hole < 0 ) {
|
|
hole = i;
|
|
}
|
|
} else if ( memcmp( x + table->offset, key, table->esize ) == 0 ) {
|
|
return i-1;
|
|
}
|
|
if ( i >= table->size ) {
|
|
i = 0;
|
|
}
|
|
if ( i == hash ) {
|
|
break;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Find the keyed element, and assign the x pointer, or assign 0.
|
|
// Returns 1 if element is found and 0 otherwise.
|
|
int htfind(htable *table,void *key,unsigned char **x) {
|
|
pthread_mutex_lock( &table->lock );
|
|
int i = htindex( table, key );
|
|
if ( i < 0 ) {
|
|
*x = 0;
|
|
pthread_mutex_unlock( &table->lock );
|
|
return 0;
|
|
}
|
|
*x = table->data[ i ];
|
|
pthread_mutex_unlock( &table->lock );
|
|
return 1;
|
|
}
|
|
|
|
// Forward
|
|
static void htgrow(htable *table);
|
|
|
|
// Add the given element.
|
|
void htadd(htable *table,unsigned char *p) {
|
|
pthread_mutex_lock( &table->lock );
|
|
if ( table->fill >= table->size / 2 ) {
|
|
htgrow( table );
|
|
}
|
|
int i = htindex( table, p + table->offset );
|
|
if ( i < 0 ) {
|
|
i = -i - 1;
|
|
if ( table->data[ i ] != 0 ) {
|
|
table->holes--;
|
|
} else {
|
|
table->fill++;
|
|
}
|
|
} else {
|
|
// There is a match already what to do?
|
|
}
|
|
table->data[ i ] = p;
|
|
pthread_mutex_unlock( &table->lock );
|
|
}
|
|
|
|
// Return the next element starting at i, or 0 if there are no more.
|
|
// Also increment the index to be of the element + 1, or -1 if there
|
|
// are no more elements.
|
|
static unsigned char *htnext(htable *table,int *i) {
|
|
if ( *i < 0 ) {
|
|
return 0;
|
|
}
|
|
unsigned char **p = table->data + *i;
|
|
unsigned char **e = table->data + table->size;
|
|
for ( ; p < e; p++ ) {
|
|
(*i) += 1;
|
|
if ( *p != 0 && *p != (unsigned char*)1 ) {
|
|
return *p;
|
|
}
|
|
}
|
|
(*i) = -1;
|
|
return 0;
|
|
}
|
|
|
|
static void htrehash(htable *table,unsigned int size) {
|
|
htable old = *table;
|
|
table->data = calloc( size, sizeof( unsigned char * ) );
|
|
table->size = size;
|
|
table->fill = 0;
|
|
table->holes = 0;
|
|
int i = 0;
|
|
unsigned char *p;
|
|
while ( ( p = htnext( &old, &i ) ) != 0 ) {
|
|
htadd( table, p );
|
|
}
|
|
free( old.data );
|
|
}
|
|
|
|
static void htgrow(htable *table) {
|
|
if ( table->data == 0 ) {
|
|
table->data = calloc( 256, sizeof( unsigned char * ) );
|
|
table->size = 256;
|
|
table->fill = 0;
|
|
table->holes = 0;
|
|
return;
|
|
}
|
|
htrehash( table, table->size << 8 );
|
|
}
|
|
|
|
// Delete the given element.
|
|
void htdelete(htable *table,unsigned char *p) {
|
|
pthread_mutex_lock( &table->lock );
|
|
int i = htindex( table, p + table->offset );
|
|
if ( i >= 0 ) {
|
|
table->data[ i ] = (unsigned char *)1;
|
|
table->holes += 1;
|
|
if ( table->holes > table->fill / 2 ) {
|
|
htrehash( table, table->size );
|
|
}
|
|
}
|
|
pthread_mutex_unlock( &table->lock );
|
|
}
|
|
|