1
1

Fixed bug with using string keys and added flag to track whether we need to free the key when removing a value. Added function to remove all values from table. Renamed lam_fh_init_with() to lam_fh_resize().

This commit was SVN r548.
Этот коммит содержится в:
Rob Awles 2004-01-27 17:19:14 +00:00
родитель d5ae55fdcc
Коммит fcc4735f2e
2 изменённых файлов: 154 добавлений и 55 удалений

Просмотреть файл

@ -6,6 +6,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "lam_config.h" #include "lam_config.h"
#include "lam/stdint.h"
#include "lam/constants.h" #include "lam/constants.h"
#include "lam/lfc/hash_table.h" #include "lam/lfc/hash_table.h"
@ -37,7 +38,8 @@ static inline uint32_t lam_hash_value(const unsigned char * key, uint32_t keysiz
} }
static inline void *lam_fh_get_value(lam_fast_hash_t *htbl, void *key, uint32_t keysize) static inline void *lam_fh_get_value(lam_fast_hash_t *htbl, void *key, uint32_t keysize,
bool use_ptr)
{ {
uint32_t hval, i; uint32_t hval, i;
lam_fhnode_t *buckets; lam_fhnode_t *buckets;
@ -50,11 +52,23 @@ static inline void *lam_fh_get_value(lam_fast_hash_t *htbl, void *key, uint32_t
if ( !buckets ) if ( !buckets )
return 0; return 0;
for ( i = 0; i < htbl->fh_bucket_cnt[hval]; i++ ) if ( true == use_ptr )
{ {
if ( (1 == buckets[i].fhn_is_taken) && for ( i = 0; i < htbl->fh_bucket_cnt[hval]; i++ )
(0 == memcmp(&(buckets[i].fhn_key), key, keysize)) ) {
return buckets[i].fhn_value; if ( (true == buckets[i].fhn_is_taken) &&
(0 == memcmp(buckets[i].fhn_key.pval, key, keysize)) )
return buckets[i].fhn_value;
}
}
else
{
for ( i = 0; i < htbl->fh_bucket_cnt[hval]; i++ )
{
if ( (true == buckets[i].fhn_is_taken) &&
(0 == memcmp(&(buckets[i].fhn_key), key, keysize)) )
return buckets[i].fhn_value;
}
} }
return 0; return 0;
@ -76,19 +90,23 @@ static inline void lam_fh_remove_value(lam_fast_hash_t *htbl, void *key, uint32_
for ( i = 0; i < htbl->fh_bucket_cnt[hval]; i++ ) for ( i = 0; i < htbl->fh_bucket_cnt[hval]; i++ )
{ {
if ( (1 == buckets[i].fhn_is_taken) && if ( (true == buckets[i].fhn_is_taken) &&
(0 == memcmp(&(buckets[i].fhn_key), key, keysize)) ) (0 == memcmp(&(buckets[i].fhn_key), key, keysize)) )
{ {
buckets[i].fhn_is_taken = 0; buckets[i].fhn_is_taken = false;
buckets[i].fhn_value = 0; buckets[i].fhn_value = 0;
if ( buckets[i].fhn_using_key_ptr )
{
LAM_FREE(buckets[i].fhn_key.pval);
}
} }
} }
} }
static inline int lam_fh_set_value(lam_fast_hash_t *htbl, void *val, static inline int lam_fh_set_value(lam_fast_hash_t *htbl, void *val,
void *key, uint32_t keysize) void *key, uint32_t keysize, bool should_alloc)
{ {
uint32_t hval, i; uint32_t hval, i, bucket_idx;
lam_fhnode_t *buckets; lam_fhnode_t *buckets;
/* ASSERT: table size is power of 2 and table /* ASSERT: table size is power of 2 and table
@ -100,13 +118,13 @@ static inline int lam_fh_set_value(lam_fast_hash_t *htbl, void *val,
{ {
/* create new array of buckets /* create new array of buckets
for collision */ for collision */
htbl->fh_nodes[hval] = (lam_fhnode_t *)malloc(sizeof(lam_fhnode_t) htbl->fh_nodes[hval] = (lam_fhnode_t *)LAM_MALLOC(sizeof(lam_fhnode_t)
* BUCKET_ALLOC_SZ); * BUCKET_ALLOC_SZ);
if ( !htbl->fh_nodes[hval] ) if ( !htbl->fh_nodes[hval] )
return LAM_ERR_OUT_OF_RESOURCE; return LAM_ERR_OUT_OF_RESOURCE;
bzero(htbl->fh_nodes[hval], sizeof(lam_fhnode_t) memset(htbl->fh_nodes[hval], 0,
* BUCKET_ALLOC_SZ); sizeof(lam_fhnode_t) * BUCKET_ALLOC_SZ);
htbl->fh_bucket_cnt[hval] = BUCKET_ALLOC_SZ; /* keep track of array size. */ htbl->fh_bucket_cnt[hval] = BUCKET_ALLOC_SZ; /* keep track of array size. */
buckets = htbl->fh_nodes[hval]; buckets = htbl->fh_nodes[hval];
} }
@ -115,14 +133,10 @@ static inline int lam_fh_set_value(lam_fast_hash_t *htbl, void *val,
then realloc. */ then realloc. */
for ( i = 0; i < htbl->fh_bucket_cnt[hval]; i++ ) for ( i = 0; i < htbl->fh_bucket_cnt[hval]; i++ )
{ {
if ( 0 == buckets[i].fhn_is_taken ) if ( false == buckets[i].fhn_is_taken )
{ {
/* found empty bucket */ /* found empty bucket */
memcpy(&(buckets[i].fhn_key), key, keysize); bucket_idx = i;
buckets[i].fhn_value = val;
buckets[i].fhn_is_taken = 1;
htbl->fh_count++;
break; break;
} }
} }
@ -139,16 +153,34 @@ static inline int lam_fh_set_value(lam_fast_hash_t *htbl, void *val,
/* get ptr to start of newly alloc buckets */ /* get ptr to start of newly alloc buckets */
buckets = htbl->fh_nodes[hval] + htbl->fh_bucket_cnt[hval]; buckets = htbl->fh_nodes[hval] + htbl->fh_bucket_cnt[hval];
bzero(buckets, sizeof(lam_fhnode_t) memset(buckets, 0,
* BUCKET_ALLOC_SZ); sizeof(lam_fhnode_t) * BUCKET_ALLOC_SZ);
bucket_idx = htbl->fh_bucket_cnt[hval];
memcpy(&(buckets[i].fhn_key), key, keysize);
buckets[0].fhn_value = val;
buckets[0].fhn_is_taken = 1;
htbl->fh_bucket_cnt[hval] += BUCKET_ALLOC_SZ; /* keep track of array size. */ htbl->fh_bucket_cnt[hval] += BUCKET_ALLOC_SZ; /* keep track of array size. */
} }
/* ASSERT: we have an empty bucket */
/* found empty bucket */
if ( should_alloc )
{
buckets[bucket_idx].fhn_key.pval = LAM_MALLOC(keysize);
if ( NULL == buckets[bucket_idx].fhn_key.pval )
{
return LAM_ERR_OUT_OF_RESOURCE;
}
memcpy(buckets[bucket_idx].fhn_key.pval, key, keysize);
}
else
{
memcpy(&(buckets[bucket_idx].fhn_key), key, keysize);
}
buckets[bucket_idx].fhn_using_key_ptr = should_alloc;
buckets[bucket_idx].fhn_value = val;
buckets[bucket_idx].fhn_is_taken = true;
htbl->fh_count++;
return LAM_SUCCESS; return LAM_SUCCESS;
} }
@ -160,6 +192,24 @@ static inline int lam_fh_set_value(lam_fast_hash_t *htbl, void *val,
* *
*/ */
static uint32_t lam_log2(unsigned int n)
{
int overflow;
unsigned int cnt, nn;
cnt = 0;
nn = n;
while (nn >>= 1) {
cnt++;
}
overflow = (~(1 << cnt) & n) > 0;
return cnt + overflow;
}
#define DEFAULT_SIZE 128
void lam_fh_init(lam_fast_hash_t *htbl) void lam_fh_init(lam_fast_hash_t *htbl)
{ {
@ -169,6 +219,7 @@ void lam_fh_init(lam_fast_hash_t *htbl)
htbl->fh_size = 0; htbl->fh_size = 0;
htbl->fh_mask = 0; htbl->fh_mask = 0;
htbl->fh_bucket_cnt = 0; htbl->fh_bucket_cnt = 0;
lam_fh_resize(htbl, DEFAULT_SIZE);
} }
void lam_fh_destroy(lam_fast_hash_t *htbl) void lam_fh_destroy(lam_fast_hash_t *htbl)
@ -177,6 +228,7 @@ void lam_fh_destroy(lam_fast_hash_t *htbl)
if ( htbl->fh_nodes ) if ( htbl->fh_nodes )
{ {
lam_fh_remove_all(htbl);
for ( i = 0; i < htbl->fh_size; i++ ) for ( i = 0; i < htbl->fh_size; i++ )
{ {
if ( htbl->fh_nodes[i] ) if ( htbl->fh_nodes[i] )
@ -191,34 +243,74 @@ void lam_fh_destroy(lam_fast_hash_t *htbl)
/* initialize hash table with fixed size, usually power of 2 or prime */ /* initialize hash table with fixed size, usually power of 2 or prime */
int lam_fh_init_with(lam_fast_hash_t *htbl, uint32_t power2_size) int lam_fh_resize(lam_fast_hash_t *htbl, uint32_t size)
{ {
uint32_t size; uint32_t power2_size;
size = 1 << power2_size; /* round up size to power of 2,
htbl->fh_mask = size - 1; * if passed size is not power of 2.
htbl->fh_nodes = (lam_fhnode_t **)malloc(sizeof(lam_fhnode_t *) * size); */
power2_size = 1 << lam_log2(size);
htbl->fh_mask = power2_size - 1;
htbl->fh_nodes = (lam_fhnode_t **)realloc(htbl->fh_nodes,
sizeof(lam_fhnode_t *) * power2_size);
if ( 0 == htbl->fh_nodes ) if ( 0 == htbl->fh_nodes )
return LAM_ERR_OUT_OF_RESOURCE; return LAM_ERR_OUT_OF_RESOURCE;
htbl->fh_bucket_cnt = (uint32_t *)malloc(sizeof(uint32_t) * size); htbl->fh_bucket_cnt = (uint32_t *)realloc(htbl->fh_bucket_cnt,
sizeof(uint32_t) * power2_size);
if ( 0 == htbl->fh_bucket_cnt ) if ( 0 == htbl->fh_bucket_cnt )
{ {
free(htbl->fh_nodes); LAM_FREE(htbl->fh_nodes);
return LAM_ERR_OUT_OF_RESOURCE; return LAM_ERR_OUT_OF_RESOURCE;
} }
htbl->fh_size = size; if ( power2_size > htbl->fh_size )
bzero(htbl->fh_nodes, sizeof(lam_fhnode_t *)*size); {
bzero(htbl->fh_bucket_cnt, sizeof(uint32_t)*size); /* zero out remaining slots, if adding buckets */
memset(htbl->fh_nodes + htbl->fh_size, 0,
sizeof(lam_fhnode_t *)*(power2_size - htbl->fh_size));
memset(htbl->fh_bucket_cnt + htbl->fh_size, 0,
sizeof(uint32_t)*(power2_size - htbl->fh_size));
}
htbl->fh_size = power2_size;
return LAM_SUCCESS; return LAM_SUCCESS;
} }
void lam_fh_remove_all(lam_fast_hash_t *htbl)
{
uint32_t i, j;
lam_fhnode_t *buckets;
for ( i = 0; i < htbl->fh_size; i++ )
{
/* remove all values in nonempty bucket arrays. */
if ( htbl->fh_nodes[i] )
{
buckets = htbl->fh_nodes[i];
/* process the bucket array. */
for ( j = 0; j < htbl->fh_bucket_cnt[i]; j++ )
{
if ( true == buckets[j].fhn_is_taken )
{
buckets[j].fhn_is_taken = false;
if ( true == buckets[j].fhn_using_key_ptr )
{
LAM_FREE(buckets[j].fhn_key.pval);
}
}
} /* end loop over htbl->fh_bucket_cnt[i]. */
}
} /* end loop over htbl->fh_nodes */
htbl->fh_count = 0;
}
void *lam_fh_get_value_for_ikey(lam_fast_hash_t *htbl, uint32_t key) void *lam_fh_get_value_for_ikey(lam_fast_hash_t *htbl, uint32_t key)
{ {
return lam_fh_get_value(htbl, &key, sizeof(key)); return lam_fh_get_value(htbl, &key, sizeof(key), false);
} }
@ -231,13 +323,13 @@ void lam_fh_remove_value_for_ikey(lam_fast_hash_t *htbl, uint32_t key)
int lam_fh_set_value_for_ikey(lam_fast_hash_t *htbl, void *val, uint32_t key) int lam_fh_set_value_for_ikey(lam_fast_hash_t *htbl, void *val, uint32_t key)
{ {
return lam_fh_set_value(htbl, val, &key, sizeof(key)); return lam_fh_set_value(htbl, val, &key, sizeof(key), false);
} }
void *lam_fh_get_value_for_lkey(lam_fast_hash_t *htbl, uint64_t key) void *lam_fh_get_value_for_lkey(lam_fast_hash_t *htbl, uint64_t key)
{ {
return lam_fh_get_value(htbl, &key, sizeof(key)); return lam_fh_get_value(htbl, &key, sizeof(key), false);
} }
@ -249,22 +341,22 @@ void lam_fh_remove_value_for_lkey(lam_fast_hash_t *htbl, uint64_t key)
int lam_fh_set_value_for_lkey(lam_fast_hash_t *htbl, void *val, uint64_t key) int lam_fh_set_value_for_lkey(lam_fast_hash_t *htbl, void *val, uint64_t key)
{ {
return lam_fh_set_value(htbl, val, &key, sizeof(key)); return lam_fh_set_value(htbl, val, &key, sizeof(key), false);
} }
void *lam_fh_get_value_for_skey(lam_fast_hash_t *htbl, const char *key) void *lam_fh_get_value_for_skey(lam_fast_hash_t *htbl, const char *key)
{ {
return lam_fh_get_value(htbl, (void *)key, strlen(key)); return lam_fh_get_value(htbl, (void *)key, strlen(key)+1, true);
} }
void lam_fh_remove_value_for_skey(lam_fast_hash_t *htbl, const char *key) void lam_fh_remove_value_for_skey(lam_fast_hash_t *htbl, const char *key)
{ {
lam_fh_remove_value(htbl, (void *)key, strlen(key)); lam_fh_remove_value(htbl, (void *)key, strlen(key)+1);
} }
int lam_fh_set_value_for_skey(lam_fast_hash_t *htbl, void *val, const char *key) int lam_fh_set_value_for_skey(lam_fast_hash_t *htbl, void *val, const char *key)
{ {
return lam_fh_set_value(htbl, val, (void *)key, strlen(key)); return lam_fh_set_value(htbl, val, (void *)key, strlen(key)+1, true);
} }

Просмотреть файл

@ -10,15 +10,18 @@
#include "lam/types.h" #include "lam/types.h"
#include "lam/lfc/object.h" #include "lam/lfc/object.h"
typedef struct lam_fhnode struct lam_fhnode_t
{ {
lam_ptr_t fhn_key; lam_ptr_t fhn_key;
void *fhn_value; void *fhn_value;
char fhn_is_taken; /* 1->node is occupied, 0-> not occupied */ bool fhn_using_key_ptr; /* true-> need to free key when removing item. */
} lam_fhnode_t; bool fhn_is_taken; /* true->node is occupied, false-> not occupied */
};
typedef struct lam_fhnode_t lam_fhnode_t;
/* Hash table that only allows integer or string keys. */ /* Hash table that only allows integer or string keys. */
typedef struct lam_fast_hash struct lam_fast_hash_t
{ {
lam_object_t super; lam_object_t super;
lam_fhnode_t **fh_nodes; /* each item is an array of ints */ lam_fhnode_t **fh_nodes; /* each item is an array of ints */
@ -26,7 +29,9 @@ typedef struct lam_fast_hash
uint32_t *fh_bucket_cnt; /* size of each bucket array */ uint32_t *fh_bucket_cnt; /* size of each bucket array */
uint32_t fh_mask; /* used to compute the hash value */ uint32_t fh_mask; /* used to compute the hash value */
uint32_t fh_size; uint32_t fh_size;
} lam_fast_hash_t; };
typedef struct lam_fast_hash_t lam_fast_hash_t;
extern lam_class_info_t lam_fast_hash_cls; extern lam_class_info_t lam_fast_hash_cls;
@ -35,12 +40,17 @@ extern lam_class_info_t lam_fast_hash_cls;
* Fast hash table interface * Fast hash table interface
* *
*/ */
#if defined(c_plusplus) || defined(__cplusplus)
extern "C" {
#endif
void lam_fh_init(lam_fast_hash_t *htbl); void lam_fh_init(lam_fast_hash_t *htbl);
void lam_fh_destroy(lam_fast_hash_t *htbl); void lam_fh_destroy(lam_fast_hash_t *htbl);
/* initialize hash table with fixed size 2 ^ (power2_size) */ /* resize hash table to size */
int lam_fh_init_with(lam_fast_hash_t *htbl, uint32_t power2_size); int lam_fh_resize(lam_fast_hash_t *htbl, uint32_t size);
void lam_fh_remove_all(lam_fast_hash_t *htbl);
void *lam_fh_get_value_for_ikey(lam_fast_hash_t *htbl, uint32_t key); void *lam_fh_get_value_for_ikey(lam_fast_hash_t *htbl, uint32_t key);
void lam_fh_remove_value_for_ikey(lam_fast_hash_t *htbl, uint32_t key); void lam_fh_remove_value_for_ikey(lam_fast_hash_t *htbl, uint32_t key);
@ -50,15 +60,12 @@ void *lam_fh_get_value_for_lkey(lam_fast_hash_t *htbl, uint64_t key);
void lam_fh_remove_value_for_lkey(lam_fast_hash_t *htbl, uint64_t key); void lam_fh_remove_value_for_lkey(lam_fast_hash_t *htbl, uint64_t key);
int lam_fh_set_value_for_lkey(lam_fast_hash_t *htbl, void *val, uint64_t key); int lam_fh_set_value_for_lkey(lam_fast_hash_t *htbl, void *val, uint64_t key);
#if 0
/*
* TSW - This is broken - implementation tried to copy length of string
* into space allocated for a pointer
*/
void *lam_fh_get_value_for_skey(lam_fast_hash_t *htbl, const char *key); void *lam_fh_get_value_for_skey(lam_fast_hash_t *htbl, const char *key);
void lam_fh_remove_value_for_skey(lam_fast_hash_t *htbl, const char *key); void lam_fh_remove_value_for_skey(lam_fast_hash_t *htbl, const char *key);
int lam_fh_set_value_for_skey(lam_fast_hash_t *htbl, void *val, const char *key); int lam_fh_set_value_for_skey(lam_fast_hash_t *htbl, void *val, const char *key);
#if defined(c_plusplus) || defined(__cplusplus)
}
#endif #endif