瀏覽代碼

Pointers to different things need not be represented in the same way.

Use the fact that we only can store structs in the table to make the
complex pointer use safe. Unfortunately the equal and hash functions
need to take void * arguments.
master
Richard Nyberg 19 年之前
父節點
當前提交
8695ecdf18
共有 2 個檔案被更改,包括 35 行新增33 行删除
  1. +21
    -20
      misc/hashtable.c
  2. +14
    -13
      misc/hashtable.h

+ 21
- 20
misc/hashtable.c 查看文件

@@ -3,19 +3,19 @@


#include "hashtable.h" #include "hashtable.h"


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

struct _htbl { struct _htbl {
int (*eq)(const void *, const void *); int (*eq)(const void *, const void *);
uint32_t (*hash)(const void *); uint32_t (*hash)(const void *);
void **buckets;
struct _any **buckets;
size_t buckcnt; size_t buckcnt;
size_t size; size_t size;
size_t keyoff; size_t keyoff;
size_t chainoff; size_t chainoff;
}; };


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

struct _htbl * struct _htbl *
_htbl_create(int (*eq)(const void *, const void *), _htbl_create(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)
@@ -44,11 +44,11 @@ _htbl_free(struct _htbl *tbl)
free(tbl); free(tbl);
} }


static void *
bucket_rev(struct _htbl *tbl, void *p, void *n)
static struct _any *
bucket_rev(struct _htbl *tbl, struct _any *p, struct _any *n)
{ {
while (n != NULL) { while (n != NULL) {
void *s = CHAINP(tbl, n);
struct _any *s = CHAINP(tbl, n);
CHAINP(tbl, n) = p; CHAINP(tbl, n) = p;
p = n; p = n;
n = s; n = s;
@@ -57,7 +57,7 @@ bucket_rev(struct _htbl *tbl, void *p, void *n)
} }


static void static void
bucket_insert(struct _htbl *tbl, void *o)
bucket_insert(struct _htbl *tbl, struct _any *o)
{ {
size_t bi = tbl->hash(KEYP(tbl, o)) % tbl->buckcnt; size_t bi = tbl->hash(KEYP(tbl, o)) % tbl->buckcnt;
CHAINP(tbl, o) = tbl->buckets[bi]; CHAINP(tbl, o) = tbl->buckets[bi];
@@ -69,8 +69,8 @@ _htbl_grow(struct _htbl *tbl)
{ {
size_t ncnt = 2 * tbl->buckcnt + 1; size_t ncnt = 2 * tbl->buckcnt + 1;
size_t ocnt = tbl->buckcnt; size_t ocnt = tbl->buckcnt;
void **obuckets = tbl->buckets;
void **nbuckets = calloc(ncnt, sizeof(*nbuckets));
struct _any **obuckets = tbl->buckets;
struct _any **nbuckets = calloc(ncnt, sizeof(*nbuckets));
if (nbuckets == NULL) if (nbuckets == NULL)
return; return;


@@ -78,9 +78,9 @@ _htbl_grow(struct _htbl *tbl)
tbl->buckets = nbuckets; tbl->buckets = nbuckets;


for (size_t i = 0; i < ocnt; i++) { for (size_t i = 0; i < ocnt; i++) {
void *o = bucket_rev(tbl, NULL, obuckets[i]);
struct _any *o = bucket_rev(tbl, NULL, obuckets[i]);
while (o != NULL) { while (o != NULL) {
void *s = CHAINP(tbl, o);
struct _any *s = CHAINP(tbl, o);
bucket_insert(tbl, o); bucket_insert(tbl, o);
o = s; o = s;
} }
@@ -90,7 +90,7 @@ _htbl_grow(struct _htbl *tbl)
} }


void void
_htbl_insert(struct _htbl *tbl, void *o)
_htbl_insert(struct _htbl *tbl, struct _any *o)
{ {
bucket_insert(tbl, o); bucket_insert(tbl, o);
tbl->size++; tbl->size++;
@@ -98,21 +98,22 @@ _htbl_insert(struct _htbl *tbl, void *o)
_htbl_grow(tbl); _htbl_grow(tbl);
} }


void *
struct _any *
_htbl_find(struct _htbl *tbl, const void *key) _htbl_find(struct _htbl *tbl, const void *key)
{ {
struct _any *ret;
size_t bi = tbl->hash(key) % tbl->buckcnt; size_t bi = tbl->hash(key) % tbl->buckcnt;
for (void *ret = tbl->buckets[bi]; ret != NULL; ret = CHAINP(tbl, ret))
for (ret = tbl->buckets[bi]; ret != NULL; ret = CHAINP(tbl, ret))
if (tbl->eq(KEYP(tbl, ret), key)) if (tbl->eq(KEYP(tbl, ret), key))
return ret; return ret;
return NULL; return NULL;
} }


void *
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;
void *p = NULL, *o = tbl->buckets[bi];
struct _any *p = NULL, *o = tbl->buckets[bi];
while (o != NULL && !tbl->eq(KEYP(tbl, o), key)) { while (o != NULL && !tbl->eq(KEYP(tbl, o), key)) {
p = o; p = o;
o = CHAINP(tbl, o); o = CHAINP(tbl, o);
@@ -128,11 +129,11 @@ _htbl_remove(struct _htbl *tbl, const void *key)
} }


void void
_htbl_tov(struct _htbl *tbl, void **v)
_htbl_tov(struct _htbl *tbl, struct _any **v)
{ {
size_t vi = 0; size_t vi = 0;
size_t bi = 0; size_t bi = 0;
void *o = tbl->buckets[bi];
struct _any *o = tbl->buckets[bi];
while (vi < tbl->size) { while (vi < tbl->size) {
while (o == NULL) { while (o == NULL) {
bi++; bi++;
@@ -159,7 +160,7 @@ _htbl_iter_init(struct _htbl *tbl, struct htbl_iter *it)
it->obj = NULL; it->obj = NULL;
} }


void *
struct _any *
_htbl_iter_next(struct htbl_iter *it) _htbl_iter_next(struct htbl_iter *it)
{ {
if (it->cnt == it->tbl->size) if (it->cnt == it->tbl->size)


+ 14
- 13
misc/hashtable.h 查看文件

@@ -5,28 +5,29 @@ struct htbl_iter {
struct _htbl *tbl; struct _htbl *tbl;
size_t bi; size_t bi;
size_t cnt; size_t cnt;
void *obj;
struct _any *obj;
}; };


struct _htbl *_htbl_create(int (*equal)(const void *, const void *), struct _htbl *_htbl_create(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, void *o);
void *_htbl_remove(struct _htbl *tbl, const void *key);
void *_htbl_find(struct _htbl *tbl, const void *key);
void _htbl_tov(struct _htbl *tb, void **v);
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);
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); void _htbl_iter_init(struct _htbl *tbl, struct htbl_iter *it);
void *_htbl_iter_next(struct htbl_iter *it);
struct _any *_htbl_iter_next(struct htbl_iter *it);


#define HTBLTYPE(name, type, ktype, kname, cname) \
#define HTBL_ENTRY(name) struct _any *name

#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 ktype *, const ktype *), \
uint32_t (*hash)(const ktype *)) \
name##_create(int (*equal)(const void *, const void *), \
uint32_t (*hash)(const void *)) \
{ \ { \
return (struct name *) \ return (struct name *) \
_htbl_create((int (*)(const void *, const void *))equal, \
(uint32_t (*)(const void *))hash, offsetof(struct type, kname), \
_htbl_create(equal, hash, offsetof(struct type, kname), \
offsetof(struct type, cname)); \ offsetof(struct type, cname)); \
} \ } \
\ \
@@ -51,12 +52,12 @@ name##_free(struct name *tbl) \
__attribute__((always_inline)) static inline void \ __attribute__((always_inline)) static inline void \
name##_insert(struct name *tbl, struct type *o) \ name##_insert(struct name *tbl, struct type *o) \
{ \ { \
_htbl_insert((struct _htbl *)tbl, o); \
_htbl_insert((struct _htbl *)tbl, (struct _any *)o); \
} \ } \
__attribute__((always_inline)) static inline void \ __attribute__((always_inline)) static inline void \
name##_tov(struct name *tbl, struct type **v) \ name##_tov(struct name *tbl, struct type **v) \
{ \ { \
_htbl_tov((struct _htbl *)tbl, (void **)v); \
_htbl_tov((struct _htbl *)tbl, (struct _any **)v); \
} \ } \
\ \
__attribute__((always_inline)) static inline size_t \ __attribute__((always_inline)) static inline size_t \


Loading…
取消
儲存