Skip to content

Commit

Permalink
Hashtable tweaks.
Browse files Browse the repository at this point in the history
o Added ability to set the ratio items:buckets.
o One can remove items while iterating.
o _htbl_tov now allocates the result array, _htbl_fillv acts as the old
  _htbl_tov did.
  • Loading branch information
rmn64k committed Feb 6, 2009
1 parent 432be0a commit e5332f1
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 30 deletions.
86 changes: 67 additions & 19 deletions misc/hashtable.c
Expand Up @@ -11,20 +11,22 @@ struct _htbl {
size_t size;
size_t keyoff;
size_t chainoff;
float ratio;
};

#define KEYP(tbl, o) ((void *)(o) + (tbl)->keyoff)
#define CHAINP(tbl, o) *(struct _any **)((void *)(o) + (tbl)->chainoff)

struct _htbl *
_htbl_create(int (*eq)(const void *, const void *),
_htbl_create(float ratio, int (*eq)(const void *, const void *),
uint32_t (*hash)(const void *), size_t keyoff, size_t chainoff)
{
struct _htbl *tbl = calloc(1, sizeof(*tbl));
if (tbl == NULL)
return NULL;
tbl->size = 0;
tbl->buckcnt = 1;
tbl->ratio = ratio;
tbl->keyoff = keyoff;
tbl->chainoff = chainoff;
tbl->hash = hash;
Expand Down Expand Up @@ -94,7 +96,7 @@ _htbl_insert(struct _htbl *tbl, struct _any *o)
{
bucket_insert(tbl, o);
tbl->size++;
if (tbl->size > tbl->buckcnt * 4 / 5)
if (tbl->size > tbl->buckcnt * tbl->ratio)
_htbl_grow(tbl);
}

Expand All @@ -113,23 +115,20 @@ struct _any *
_htbl_remove(struct _htbl *tbl, const void *key)
{
size_t bi = tbl->hash(key) % tbl->buckcnt;
struct _any *p = NULL, *o = tbl->buckets[bi];
struct _any **p = &tbl->buckets[bi], *o = tbl->buckets[bi];
while (o != NULL && !tbl->eq(KEYP(tbl, o), key)) {
p = o;
o = CHAINP(tbl, o);
p = &CHAINP(tbl, o);
o = *p;
}
if (o != NULL) {
if (p == NULL)
tbl->buckets[bi] = CHAINP(tbl, o);
else
CHAINP(tbl, p) = CHAINP(tbl, o);
*p = CHAINP(tbl, o);
tbl->size--;
}
return o;
}

void
_htbl_tov(struct _htbl *tbl, struct _any **v)
_htbl_fillv(struct _htbl *tbl, struct _any **v)
{
size_t vi = 0;
size_t bi = 0;
Expand All @@ -145,32 +144,81 @@ _htbl_tov(struct _htbl *tbl, struct _any **v)
}
}

struct _any **
_htbl_tov(struct _htbl *tbl)
{
struct _any **v = malloc(sizeof(*v));
if (v != NULL)
_htbl_fillv(tbl, v);
return v;
}

size_t
_htbl_size(struct _htbl *tbl)
{
return tbl->size;
}

void
_htbl_iter_init(struct _htbl *tbl, struct htbl_iter *it)
static void
iter_next_bucket(struct htbl_iter *it)
{
while (it->tbl->buckets[it->bi] == NULL)
it->bi++;
it->obj = it->tbl->buckets[it->bi];
it->ptr = &it->tbl->buckets[it->bi];
}

struct _any *
_htbl_iter_first(struct _htbl *tbl, struct htbl_iter *it)
{
if (tbl->size == 0)
return NULL;

it->tbl = tbl;
it->cnt = 1;
it->bi = 0;
it->cnt = 0;
it->obj = NULL;
iter_next_bucket(it);
return it->obj;
}

struct _any *
_htbl_iter_next(struct htbl_iter *it)
{
struct _any *tmp;
if (it->cnt == it->tbl->size)
return NULL;
it->obj = it->cnt == 0 ?
it->tbl->buckets[it->bi] : CHAINP(it->tbl, it->obj);
while (it->obj == NULL) {

it->cnt++;
if ((tmp = CHAINP(it->tbl, it->obj)) != NULL) {
it->ptr = &CHAINP(it->tbl, it->obj);
it->obj = tmp;
} else {
it->bi++;
it->obj = it->tbl->buckets[it->bi];
iter_next_bucket(it);
}
return it->obj;
}

#include <stdio.h>

struct _any *
_htbl_iter_del(struct htbl_iter *it)
{
struct _any *tmp;

it->tbl->size--;
if (it->cnt > it->tbl->size) {
*it->ptr = NULL;
return NULL;
}

if ((tmp = CHAINP(it->tbl, it->obj)) != NULL) {
*it->ptr = tmp;
it->obj = tmp;
} else {
*it->ptr = NULL;
it->bi++;
iter_next_bucket(it);
}
it->cnt++;
return it->obj;
}
36 changes: 25 additions & 11 deletions misc/hashtable.h
Expand Up @@ -5,30 +5,34 @@ struct htbl_iter {
struct _htbl *tbl;
size_t bi;
size_t cnt;
struct _any **ptr;
struct _any *obj;
};

struct _htbl *_htbl_create(int (*equal)(const void *, const void *),
struct _htbl *_htbl_create(float ratio,
int (*equal)(const void *, const void *),
uint32_t (*hash)(const void *), size_t keyoff, size_t chainoff);
void _htbl_free(struct _htbl *tbl);
void _htbl_insert(struct _htbl *tbl, struct _any *o);
struct _any *_htbl_remove(struct _htbl *tbl, const void *key);
struct _any *_htbl_find(struct _htbl *tbl, const void *key);
void _htbl_tov(struct _htbl *tb, struct _any **v);
void _htbl_fillv(struct _htbl *tbl, struct _any **v);
struct _any **_htbl_tov(struct _htbl *tbl);
size_t _htbl_size(struct _htbl *tbl);
void _htbl_iter_init(struct _htbl *tbl, struct htbl_iter *it);
struct _any *_htbl_iter_first(struct _htbl *tbl, struct htbl_iter *it);
struct _any *_htbl_iter_next(struct htbl_iter *it);
struct _any *_htbl_iter_del(struct htbl_iter *it);

#define HTBL_ENTRY(name) struct _any *name

#define HTBL_TYPE(name, type, ktype, kname, cname) \
__attribute__((always_inline)) static inline struct name * \
name##_create(int (*equal)(const void *, const void *), \
name##_create(float ratio, int (*equal)(const void *, const void *), \
uint32_t (*hash)(const void *)) \
{ \
return (struct name *) \
_htbl_create(equal, hash, offsetof(struct type, kname), \
offsetof(struct type, cname)); \
_htbl_create(ratio, equal, hash, offsetof(struct type, kname), \
offsetof(struct type, cname)); \
} \
\
__attribute__((always_inline)) static inline struct type * \
Expand All @@ -54,10 +58,15 @@ name##_insert(struct name *tbl, struct type *o) \
{ \
_htbl_insert((struct _htbl *)tbl, (struct _any *)o); \
} \
__attribute__((always_inline)) static inline struct type ** \
name##_tov(struct name *tbl) \
{ \
return (struct type **) _htbl_tov((struct _htbl *)tbl); \
} \
__attribute__((always_inline)) static inline void \
name##_tov(struct name *tbl, struct type **v) \
name##_fillv(struct name *tbl, struct type **v) \
{ \
_htbl_tov((struct _htbl *)tbl, (struct _any **)v); \
_htbl_fillv((struct _htbl *)tbl, (struct _any **)v); \
} \
\
__attribute__((always_inline)) static inline size_t \
Expand All @@ -66,13 +75,18 @@ name##_size(struct name *tbl) \
return _htbl_size((struct _htbl *)tbl); \
} \
\
__attribute__((always_inline)) static inline void \
name##_iter_init(struct name *tbl, struct htbl_iter *it) \
__attribute__((always_inline)) static inline struct type * \
name##_iter_first(struct name *tbl, struct htbl_iter *it) \
{ \
_htbl_iter_init((struct _htbl *)tbl, it); \
return (struct type *)_htbl_iter_first((struct _htbl *)tbl, it); \
} \
\
__attribute__((always_inline)) static inline struct type * \
name##_iter_del(struct htbl_iter *it) \
{ \
return (struct type *)_htbl_iter_del(it); \
} \
__attribute__((always_inline)) static inline struct type * \
name##_iter_next(struct htbl_iter *it) \
{ \
return (struct type *)_htbl_iter_next(it); \
Expand Down

0 comments on commit e5332f1

Please sign in to comment.