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.master
@@ -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 <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; | |||
} |
@@ -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); \ | |||