abandon xhash
This commit is contained in:
parent
42794ebbff
commit
9db8b33c61
|
@ -37,7 +37,6 @@ extern "C" {
|
|||
#include "picrin/compat.h"
|
||||
#include "picrin/kvec.h"
|
||||
#include "picrin/khash.h"
|
||||
#include "picrin/xhash.h"
|
||||
|
||||
#include "picrin/value.h"
|
||||
|
||||
|
|
|
@ -1,416 +0,0 @@
|
|||
#ifndef XHASH_H
|
||||
#define XHASH_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2014 by Yuichi Nishiwaki <yuichi.nishiwaki@gmail.com>
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define XHASH_ALLOCATOR pic->allocf
|
||||
|
||||
/* simple object to object hash table */
|
||||
|
||||
#define XHASH_INIT_SIZE 11
|
||||
#define XHASH_RESIZE_RATIO(x) ((x) * 3 / 4)
|
||||
|
||||
#define XHASH_ALIGNMENT 3 /* quad word alignment */
|
||||
#define XHASH_MASK (~(size_t)((1 << XHASH_ALIGNMENT) - 1))
|
||||
#define XHASH_ALIGN(i) ((((i) - 1) & XHASH_MASK) + (1 << XHASH_ALIGNMENT))
|
||||
|
||||
typedef struct xh_entry {
|
||||
struct xh_entry *next;
|
||||
int hash;
|
||||
struct xh_entry *fw, *bw;
|
||||
const void *key;
|
||||
void *val;
|
||||
} xh_entry;
|
||||
|
||||
#define xh_key(e,type) (*(type *)((e)->key))
|
||||
#define xh_val(e,type) (*(type *)((e)->val))
|
||||
|
||||
typedef int (*xh_hashf)(const void *, void *);
|
||||
typedef int (*xh_equalf)(const void *, const void *, void *);
|
||||
typedef void *(*xh_allocf)(void *, size_t);
|
||||
|
||||
typedef struct xhash {
|
||||
xh_allocf allocf;
|
||||
xh_entry **buckets;
|
||||
size_t size, count, kwidth, vwidth;
|
||||
size_t koffset, voffset;
|
||||
xh_hashf hashf;
|
||||
xh_equalf equalf;
|
||||
xh_entry *head, *tail;
|
||||
void *data;
|
||||
} xhash;
|
||||
|
||||
/** Protected Methods:
|
||||
* static inline void xh_init_(xhash *x, size_t, size_t, xh_hashf, xh_equalf, void *);
|
||||
* static inline xh_entry *xh_get_(xhash *x, const void *key);
|
||||
* static inline xh_entry *xh_put_(xhash *x, const void *key, void *val);
|
||||
* static inline void xh_del_(xhash *x, const void *key);
|
||||
*/
|
||||
|
||||
/* string map */
|
||||
PIC_INLINE xh_entry *xh_get_str(xhash *x, const char *key);
|
||||
PIC_INLINE xh_entry *xh_put_str(xhash *x, const char *key, void *);
|
||||
PIC_INLINE void xh_del_str(xhash *x, const char *key);
|
||||
|
||||
/* object map */
|
||||
PIC_INLINE xh_entry *xh_get_ptr(xhash *x, const void *key);
|
||||
PIC_INLINE xh_entry *xh_put_ptr(xhash *x, const void *key, void *);
|
||||
PIC_INLINE void xh_del_ptr(xhash *x, const void *key);
|
||||
|
||||
/* int map */
|
||||
PIC_INLINE xh_entry *xh_get_int(xhash *x, int key);
|
||||
PIC_INLINE xh_entry *xh_put_int(xhash *x, int key, void *);
|
||||
PIC_INLINE void xh_del_int(xhash *x, int key);
|
||||
|
||||
PIC_INLINE size_t xh_size(xhash *x);
|
||||
PIC_INLINE void xh_clear(xhash *x);
|
||||
PIC_INLINE void xh_destroy(xhash *x);
|
||||
|
||||
PIC_INLINE xh_entry *xh_begin(xhash *x);
|
||||
PIC_INLINE xh_entry *xh_next(xh_entry *e);
|
||||
|
||||
|
||||
PIC_INLINE void
|
||||
xh_bucket_alloc(xhash *x, size_t newsize)
|
||||
{
|
||||
x->size = newsize;
|
||||
x->buckets = x->allocf(NULL, (x->size + 1) * sizeof(xh_entry *));
|
||||
memset(x->buckets, 0, (x->size + 1) * sizeof(xh_entry *));
|
||||
}
|
||||
|
||||
PIC_INLINE void
|
||||
xh_init_(xhash *x, xh_allocf allocf, size_t kwidth, size_t vwidth, xh_hashf hashf, xh_equalf equalf, void *data)
|
||||
{
|
||||
x->allocf = allocf;
|
||||
x->size = 0;
|
||||
x->buckets = NULL;
|
||||
x->count = 0;
|
||||
x->kwidth = kwidth;
|
||||
x->vwidth = vwidth;
|
||||
x->koffset = XHASH_ALIGN(sizeof(xh_entry));
|
||||
x->voffset = XHASH_ALIGN(sizeof(xh_entry)) + XHASH_ALIGN(kwidth);
|
||||
x->hashf = hashf;
|
||||
x->equalf = equalf;
|
||||
x->head = NULL;
|
||||
x->tail = NULL;
|
||||
x->data = data;
|
||||
|
||||
xh_bucket_alloc(x, XHASH_INIT_SIZE);
|
||||
}
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_get_(xhash *x, const void *key)
|
||||
{
|
||||
int hash;
|
||||
size_t idx;
|
||||
xh_entry *e;
|
||||
|
||||
hash = x->hashf(key, x->data);
|
||||
idx = ((unsigned)hash) % x->size;
|
||||
for (e = x->buckets[idx]; e; e = e->next) {
|
||||
if (e->hash == hash && x->equalf(key, e->key, x->data))
|
||||
break;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
PIC_INLINE void
|
||||
xh_resize_(xhash *x, size_t newsize)
|
||||
{
|
||||
xhash y;
|
||||
xh_entry *it;
|
||||
size_t idx;
|
||||
|
||||
xh_init_(&y, x->allocf, x->kwidth, x->vwidth, x->hashf, x->equalf, x->data);
|
||||
xh_bucket_alloc(&y, newsize);
|
||||
|
||||
for (it = xh_begin(x); it != NULL; it = xh_next(it)) {
|
||||
idx = ((unsigned)it->hash) % y.size;
|
||||
/* reuse entry object */
|
||||
it->next = y.buckets[idx];
|
||||
y.buckets[idx] = it;
|
||||
y.count++;
|
||||
}
|
||||
|
||||
y.head = x->head;
|
||||
y.tail = x->tail;
|
||||
|
||||
x->allocf(x->buckets, 0);
|
||||
|
||||
/* copy all members from y to x */
|
||||
memcpy(x, &y, sizeof(xhash));
|
||||
}
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_put_(xhash *x, const void *key, void *val)
|
||||
{
|
||||
int hash;
|
||||
size_t idx;
|
||||
xh_entry *e;
|
||||
|
||||
if ((e = xh_get_(x, key))) {
|
||||
memcpy(e->val, val, x->vwidth);
|
||||
return e;
|
||||
}
|
||||
|
||||
if (x->count + 1 > XHASH_RESIZE_RATIO(x->size)) {
|
||||
xh_resize_(x, x->size * 2 + 1);
|
||||
}
|
||||
|
||||
hash = x->hashf(key, x->data);
|
||||
idx = ((unsigned)hash) % x->size;
|
||||
e = x->allocf(NULL, x->voffset + x->vwidth);
|
||||
e->next = x->buckets[idx];
|
||||
e->hash = hash;
|
||||
e->key = ((char *)e) + x->koffset;
|
||||
e->val = ((char *)e) + x->voffset;
|
||||
memcpy((void *)e->key, key, x->kwidth);
|
||||
memcpy(e->val, val, x->vwidth);
|
||||
|
||||
if (x->head == NULL) {
|
||||
x->head = x->tail = e;
|
||||
e->fw = e->bw = NULL;
|
||||
} else {
|
||||
x->tail->bw = e;
|
||||
e->fw = x->tail;
|
||||
e->bw = NULL;
|
||||
x->tail = e;
|
||||
}
|
||||
|
||||
x->count++;
|
||||
|
||||
return x->buckets[idx] = e;
|
||||
}
|
||||
|
||||
PIC_INLINE void
|
||||
xh_del_(xhash *x, const void *key)
|
||||
{
|
||||
int hash;
|
||||
size_t idx;
|
||||
xh_entry *p, *q, *r;
|
||||
|
||||
hash = x->hashf(key, x->data);
|
||||
idx = ((unsigned)hash) % x->size;
|
||||
if (x->buckets[idx]->hash == hash && x->equalf(key, x->buckets[idx]->key, x->data)) {
|
||||
q = x->buckets[idx];
|
||||
if (q->fw == NULL) {
|
||||
x->head = q->bw;
|
||||
} else {
|
||||
q->fw->bw = q->bw;
|
||||
}
|
||||
if (q->bw == NULL) {
|
||||
x->tail = q->fw;
|
||||
} else {
|
||||
q->bw->fw = q->fw;
|
||||
}
|
||||
r = q->next;
|
||||
x->allocf(q, 0);
|
||||
x->buckets[idx] = r;
|
||||
}
|
||||
else {
|
||||
for (p = x->buckets[idx]; ; p = p->next) {
|
||||
if (p->next->hash == hash && x->equalf(key, p->next->key, x->data))
|
||||
break;
|
||||
}
|
||||
q = p->next;
|
||||
if (q->fw == NULL) {
|
||||
x->head = q->bw;
|
||||
} else {
|
||||
q->fw->bw = q->bw;
|
||||
}
|
||||
if (q->bw == NULL) {
|
||||
x->tail = q->fw;
|
||||
} else {
|
||||
q->bw->fw = q->fw;
|
||||
}
|
||||
r = q->next;
|
||||
x->allocf(q, 0);
|
||||
p->next = r;
|
||||
}
|
||||
|
||||
x->count--;
|
||||
}
|
||||
|
||||
PIC_INLINE size_t
|
||||
xh_size(xhash *x)
|
||||
{
|
||||
return x->count;
|
||||
}
|
||||
|
||||
PIC_INLINE void
|
||||
xh_clear(xhash *x)
|
||||
{
|
||||
size_t i;
|
||||
xh_entry *e, *d;
|
||||
|
||||
for (i = 0; i < x->size; ++i) {
|
||||
e = x->buckets[i];
|
||||
while (e) {
|
||||
d = e->next;
|
||||
x->allocf(e, 0);
|
||||
e = d;
|
||||
}
|
||||
x->buckets[i] = NULL;
|
||||
}
|
||||
|
||||
x->head = x->tail = NULL;
|
||||
x->count = 0;
|
||||
}
|
||||
|
||||
PIC_INLINE void
|
||||
xh_destroy(xhash *x)
|
||||
{
|
||||
xh_clear(x);
|
||||
x->allocf(x->buckets, 0);
|
||||
}
|
||||
|
||||
/* string map */
|
||||
|
||||
PIC_INLINE int
|
||||
xh_str_hash(const void *key, void *data)
|
||||
{
|
||||
const char *str = *(const char **)key;
|
||||
int hash = 0;
|
||||
|
||||
(void)data;
|
||||
|
||||
while (*str) {
|
||||
hash = hash * 31 + *str++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
PIC_INLINE int
|
||||
xh_str_equal(const void *key1, const void *key2, void *data)
|
||||
{
|
||||
const char *s1 = *(const char **)key1, *s2 = *(const char **)key2;
|
||||
|
||||
(void)data;
|
||||
|
||||
return strcmp(s1, s2) == 0;
|
||||
}
|
||||
|
||||
#define xh_init_str(x, width) \
|
||||
xh_init_(x, XHASH_ALLOCATOR, sizeof(const char *), width, xh_str_hash, xh_str_equal, NULL);
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_get_str(xhash *x, const char *key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_put_str(xhash *x, const char *key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
PIC_INLINE void
|
||||
xh_del_str(xhash *x, const char *key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
/* object map */
|
||||
|
||||
PIC_INLINE int
|
||||
xh_ptr_hash(const void *key, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return (int)(size_t)*(const void **)key;
|
||||
}
|
||||
|
||||
PIC_INLINE int
|
||||
xh_ptr_equal(const void *key1, const void *key2, void *data)
|
||||
{
|
||||
(void) data;
|
||||
|
||||
return *(const void **)key1 == *(const void **)key2;
|
||||
}
|
||||
|
||||
#define xh_init_ptr(x, width) \
|
||||
xh_init_(x, XHASH_ALLOCATOR, sizeof(const void *), width, xh_ptr_hash, xh_ptr_equal, NULL);
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_get_ptr(xhash *x, const void *key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_put_ptr(xhash *x, const void *key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
PIC_INLINE void
|
||||
xh_del_ptr(xhash *x, const void *key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
/* int map */
|
||||
|
||||
PIC_INLINE int
|
||||
xh_int_hash(const void *key, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return *(int *)key;
|
||||
}
|
||||
|
||||
PIC_INLINE int
|
||||
xh_int_equal(const void *key1, const void *key2, void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
||||
return *(int *)key1 == *(int *)key2;
|
||||
}
|
||||
|
||||
#define xh_init_int(x, width) \
|
||||
xh_init_(x, XHASH_ALLOCATOR, sizeof(int), width, xh_int_hash, xh_int_equal, NULL);
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_get_int(xhash *x, int key)
|
||||
{
|
||||
return xh_get_(x, &key);
|
||||
}
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_put_int(xhash *x, int key, void *val)
|
||||
{
|
||||
return xh_put_(x, &key, val);
|
||||
}
|
||||
|
||||
PIC_INLINE void
|
||||
xh_del_int(xhash *x, int key)
|
||||
{
|
||||
xh_del_(x, &key);
|
||||
}
|
||||
|
||||
/** iteration */
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_begin(xhash *x)
|
||||
{
|
||||
return x->head;
|
||||
}
|
||||
|
||||
PIC_INLINE xh_entry *
|
||||
xh_next(xh_entry *e)
|
||||
{
|
||||
return e->bw;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -36,12 +36,17 @@ is_quasiquote(pic_state *pic, pic_value pair)
|
|||
return is_tagged(pic, pic->sQUASIQUOTE, pair);
|
||||
}
|
||||
|
||||
KHASH_DECLARE(l, void *, int)
|
||||
KHASH_DECLARE(v, void *, int)
|
||||
KHASH_DEFINE2(l, void *, int, 1, kh_ptr_hash_func, kh_ptr_hash_equal)
|
||||
KHASH_DEFINE2(v, void *, int, 0, kh_ptr_hash_func, kh_ptr_hash_equal)
|
||||
|
||||
struct writer_control {
|
||||
pic_state *pic;
|
||||
xFILE *file;
|
||||
int mode;
|
||||
xhash labels; /* object -> int */
|
||||
xhash visited; /* object -> int */
|
||||
khash_t(l) labels; /* object -> int */
|
||||
khash_t(v) visited; /* object -> int */
|
||||
int cnt;
|
||||
};
|
||||
|
||||
|
@ -55,35 +60,36 @@ writer_control_init(struct writer_control *p, pic_state *pic, xFILE *file, int m
|
|||
p->file = file;
|
||||
p->mode = mode;
|
||||
p->cnt = 0;
|
||||
xh_init_ptr(&p->labels, sizeof(int));
|
||||
xh_init_ptr(&p->visited, sizeof(int));
|
||||
kh_init(l, &p->labels);
|
||||
kh_init(v, &p->visited);
|
||||
}
|
||||
|
||||
static void
|
||||
writer_control_destroy(struct writer_control *p)
|
||||
{
|
||||
xh_destroy(&p->labels);
|
||||
xh_destroy(&p->visited);
|
||||
pic_state *pic = p->pic;
|
||||
kh_destroy(l, &p->labels);
|
||||
kh_destroy(v, &p->visited);
|
||||
}
|
||||
|
||||
static void
|
||||
traverse_shared(struct writer_control *p, pic_value obj)
|
||||
{
|
||||
xh_entry *e;
|
||||
pic_state *pic = p->pic;
|
||||
khash_t(l) *h = &p->labels;
|
||||
khiter_t it;
|
||||
size_t i;
|
||||
int c;
|
||||
int ret;
|
||||
|
||||
switch (pic_type(obj)) {
|
||||
case PIC_TT_PAIR:
|
||||
case PIC_TT_VECTOR:
|
||||
e = xh_get_ptr(&p->labels, pic_obj_ptr(obj));
|
||||
if (e == NULL) {
|
||||
c = -1;
|
||||
xh_put_ptr(&p->labels, pic_obj_ptr(obj), &c);
|
||||
it = kh_put(l, h, pic_obj_ptr(obj), &ret);
|
||||
if (ret != 0) {
|
||||
kh_val(h, it) = -1;
|
||||
}
|
||||
else if (xh_val(e, int) == -1) {
|
||||
c = p->cnt++;
|
||||
xh_put_ptr(&p->labels, pic_obj_ptr(obj), &c);
|
||||
else if (kh_val(h, it) == -1) {
|
||||
kh_val(h, it) = p->cnt++;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
|
@ -112,8 +118,10 @@ static void
|
|||
write_pair(struct writer_control *p, struct pic_pair *pair)
|
||||
{
|
||||
pic_state *pic = p->pic;
|
||||
xh_entry *e;
|
||||
int c;
|
||||
khash_t(l) *lh = &p->labels;
|
||||
khash_t(v) *vh = &p->visited;
|
||||
khiter_t it;
|
||||
int ret;
|
||||
|
||||
write_core(p, pair->car);
|
||||
|
||||
|
@ -123,18 +131,15 @@ write_pair(struct writer_control *p, struct pic_pair *pair)
|
|||
else if (pic_pair_p(pair->cdr)) {
|
||||
|
||||
/* shared objects */
|
||||
if ((e = xh_get_ptr(&p->labels, pic_obj_ptr(pair->cdr))) && xh_val(e, int) != -1) {
|
||||
if ((it = kh_get(l, lh, pic_ptr(pair->cdr))) != kh_end(lh) && kh_val(lh, it) != -1) {
|
||||
xfprintf(pic, p->file, " . ");
|
||||
|
||||
if ((xh_get_ptr(&p->visited, pic_obj_ptr(pair->cdr)))) {
|
||||
xfprintf(pic, p->file, "#%d#", xh_val(e, int));
|
||||
kh_put(v, vh, pic_ptr(pair->cdr), &ret);
|
||||
if (ret == 0) { /* if exists */
|
||||
xfprintf(pic, p->file, "#%d#", kh_val(lh, it));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
xfprintf(pic, p->file, "#%d=", xh_val(e, int));
|
||||
c = 1;
|
||||
xh_put_ptr(&p->visited, pic_obj_ptr(pair->cdr), &c);
|
||||
}
|
||||
xfprintf(pic, p->file, "#%d=", kh_val(lh, it));
|
||||
}
|
||||
else {
|
||||
xfprintf(pic, p->file, " ");
|
||||
|
@ -167,29 +172,25 @@ static void
|
|||
write_core(struct writer_control *p, pic_value obj)
|
||||
{
|
||||
pic_state *pic = p->pic;
|
||||
khash_t(l) *lh = &p->labels;
|
||||
khash_t(v) *vh = &p->visited;
|
||||
xFILE *file = p->file;
|
||||
size_t i;
|
||||
pic_sym *sym;
|
||||
xh_entry *e;
|
||||
khiter_t it;
|
||||
int c;
|
||||
int ret;
|
||||
#if PIC_ENABLE_FLOAT
|
||||
double f;
|
||||
#endif
|
||||
|
||||
/* shared objects */
|
||||
if (pic_vtype(obj) == PIC_VTYPE_HEAP
|
||||
&& (e = xh_get_ptr(&p->labels, pic_obj_ptr(obj)))
|
||||
&& xh_val(e, int) != -1) {
|
||||
if ((xh_get_ptr(&p->visited, pic_obj_ptr(obj)))) {
|
||||
xfprintf(pic, file, "#%d#", xh_val(e, int));
|
||||
if (pic_vtype(obj) == PIC_VTYPE_HEAP && ((it = kh_get(l, lh, pic_ptr(obj))) != kh_end(lh)) && kh_val(lh, it) != -1) {
|
||||
kh_put(v, vh, pic_ptr(obj), &ret);
|
||||
if (ret == 0) { /* if exists */
|
||||
xfprintf(pic, file, "#%d#", kh_val(lh, it));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
xfprintf(pic, file, "#%d=", xh_val(e, int));
|
||||
c = 1;
|
||||
xh_put_ptr(&p->visited, pic_obj_ptr(obj), &c);
|
||||
}
|
||||
xfprintf(pic, file, "#%d=", kh_val(lh, it));
|
||||
}
|
||||
|
||||
switch (pic_type(obj)) {
|
||||
|
|
Loading…
Reference in New Issue