From e5332f1aa9226a0934ae616828e1dbf603d50d91 Mon Sep 17 00:00:00 2001 From: Richard Nyberg Date: Fri, 6 Feb 2009 20:03:56 +0100 Subject: [PATCH] Hashtable tweaks. 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. --- misc/hashtable.c | 86 +++++++++++++++++++++++++++++++++++++----------- misc/hashtable.h | 36 +++++++++++++------- 2 files changed, 92 insertions(+), 30 deletions(-) diff --git a/misc/hashtable.c b/misc/hashtable.c index b124749..519af5f 100644 --- a/misc/hashtable.c +++ b/misc/hashtable.c @@ -11,13 +11,14 @@ 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)); @@ -25,6 +26,7 @@ _htbl_create(int (*eq)(const void *, const void *), return NULL; tbl->size = 0; tbl->buckcnt = 1; + tbl->ratio = ratio; tbl->keyoff = keyoff; tbl->chainoff = chainoff; tbl->hash = hash; @@ -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); } @@ -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; @@ -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 + +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; } diff --git a/misc/hashtable.h b/misc/hashtable.h index 84a8e0b..adc4229 100644 --- a/misc/hashtable.h +++ b/misc/hashtable.h @@ -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 * \ @@ -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 \ @@ -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); \