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 size; | ||||
size_t keyoff; | size_t keyoff; | ||||
size_t chainoff; | size_t chainoff; | ||||
float ratio; | |||||
}; | }; | ||||
#define KEYP(tbl, o) ((void *)(o) + (tbl)->keyoff) | #define KEYP(tbl, o) ((void *)(o) + (tbl)->keyoff) | ||||
#define CHAINP(tbl, o) *(struct _any **)((void *)(o) + (tbl)->chainoff) | #define CHAINP(tbl, o) *(struct _any **)((void *)(o) + (tbl)->chainoff) | ||||
struct _htbl * | 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) | uint32_t (*hash)(const void *), size_t keyoff, size_t chainoff) | ||||
{ | { | ||||
struct _htbl *tbl = calloc(1, sizeof(*tbl)); | struct _htbl *tbl = calloc(1, sizeof(*tbl)); | ||||
@@ -25,6 +26,7 @@ _htbl_create(int (*eq)(const void *, const void *), | |||||
return NULL; | return NULL; | ||||
tbl->size = 0; | tbl->size = 0; | ||||
tbl->buckcnt = 1; | tbl->buckcnt = 1; | ||||
tbl->ratio = ratio; | |||||
tbl->keyoff = keyoff; | tbl->keyoff = keyoff; | ||||
tbl->chainoff = chainoff; | tbl->chainoff = chainoff; | ||||
tbl->hash = hash; | tbl->hash = hash; | ||||
@@ -94,7 +96,7 @@ _htbl_insert(struct _htbl *tbl, struct _any *o) | |||||
{ | { | ||||
bucket_insert(tbl, o); | bucket_insert(tbl, o); | ||||
tbl->size++; | tbl->size++; | ||||
if (tbl->size > tbl->buckcnt * 4 / 5) | |||||
if (tbl->size > tbl->buckcnt * tbl->ratio) | |||||
_htbl_grow(tbl); | _htbl_grow(tbl); | ||||
} | } | ||||
@@ -113,23 +115,20 @@ struct _any * | |||||
_htbl_remove(struct _htbl *tbl, const void *key) | _htbl_remove(struct _htbl *tbl, const void *key) | ||||
{ | { | ||||
size_t bi = tbl->hash(key) % tbl->buckcnt; | 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)) { | 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 (o != NULL) { | ||||
if (p == NULL) | |||||
tbl->buckets[bi] = CHAINP(tbl, o); | |||||
else | |||||
CHAINP(tbl, p) = CHAINP(tbl, o); | |||||
*p = CHAINP(tbl, o); | |||||
tbl->size--; | tbl->size--; | ||||
} | } | ||||
return o; | return o; | ||||
} | } | ||||
void | void | ||||
_htbl_tov(struct _htbl *tbl, struct _any **v) | |||||
_htbl_fillv(struct _htbl *tbl, struct _any **v) | |||||
{ | { | ||||
size_t vi = 0; | size_t vi = 0; | ||||
size_t bi = 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 | size_t | ||||
_htbl_size(struct _htbl *tbl) | _htbl_size(struct _htbl *tbl) | ||||
{ | { | ||||
return tbl->size; | 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->tbl = tbl; | ||||
it->cnt = 1; | |||||
it->bi = 0; | it->bi = 0; | ||||
it->cnt = 0; | |||||
it->obj = NULL; | |||||
iter_next_bucket(it); | |||||
return it->obj; | |||||
} | } | ||||
struct _any * | struct _any * | ||||
_htbl_iter_next(struct htbl_iter *it) | _htbl_iter_next(struct htbl_iter *it) | ||||
{ | { | ||||
struct _any *tmp; | |||||
if (it->cnt == it->tbl->size) | if (it->cnt == it->tbl->size) | ||||
return NULL; | 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->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; | return it->obj; | ||||
} | } |
@@ -5,30 +5,34 @@ struct htbl_iter { | |||||
struct _htbl *tbl; | struct _htbl *tbl; | ||||
size_t bi; | size_t bi; | ||||
size_t cnt; | size_t cnt; | ||||
struct _any **ptr; | |||||
struct _any *obj; | 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); | uint32_t (*hash)(const void *), size_t keyoff, size_t chainoff); | ||||
void _htbl_free(struct _htbl *tbl); | void _htbl_free(struct _htbl *tbl); | ||||
void _htbl_insert(struct _htbl *tbl, struct _any *o); | void _htbl_insert(struct _htbl *tbl, struct _any *o); | ||||
struct _any *_htbl_remove(struct _htbl *tbl, const void *key); | struct _any *_htbl_remove(struct _htbl *tbl, const void *key); | ||||
struct _any *_htbl_find(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); | 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_next(struct htbl_iter *it); | ||||
struct _any *_htbl_iter_del(struct htbl_iter *it); | |||||
#define HTBL_ENTRY(name) struct _any *name | #define HTBL_ENTRY(name) struct _any *name | ||||
#define HTBL_TYPE(name, type, ktype, kname, cname) \ | #define HTBL_TYPE(name, type, ktype, kname, cname) \ | ||||
__attribute__((always_inline)) static inline struct name * \ | __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 *)) \ | uint32_t (*hash)(const void *)) \ | ||||
{ \ | { \ | ||||
return (struct name *) \ | 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 * \ | __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); \ | _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 \ | __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 \ | __attribute__((always_inline)) static inline size_t \ | ||||
@@ -66,13 +75,18 @@ name##_size(struct name *tbl) \ | |||||
return _htbl_size((struct _htbl *)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 * \ | __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) \ | name##_iter_next(struct htbl_iter *it) \ | ||||
{ \ | { \ | ||||
return (struct type *)_htbl_iter_next(it); \ | return (struct type *)_htbl_iter_next(it); \ | ||||