use weak map to control writer

This commit is contained in:
Yuichi Nishiwaki 2016-02-21 18:01:41 +09:00
parent efa15fd5ce
commit 5bd390aa79
1 changed files with 24 additions and 37 deletions

View File

@ -14,9 +14,9 @@ KHASH_DEFINE2(v, void *, int, 1, kh_ptr_hash_func, kh_ptr_hash_equal)
struct writer_control { struct writer_control {
int mode; int mode;
int op; int op;
khash_t(l) labels; /* object -> int */
khash_t(v) visited; /* is object shared? (yes if >0) */
int cnt; int cnt;
pic_value shared; /* is object shared? (yes if >0) */
pic_value labels; /* object -> int */
}; };
#define WRITE_MODE 1 #define WRITE_MODE 1
@ -27,25 +27,20 @@ struct writer_control {
#define OP_WRITE_SIMPLE 3 #define OP_WRITE_SIMPLE 3
static void static void
writer_control_init(struct writer_control *p, int mode, int op) writer_control_init(pic_state *pic, struct writer_control *p, int mode, int op)
{ {
p->mode = mode; p->mode = mode;
p->op = op; p->op = op;
p->cnt = 0; p->cnt = 0;
kh_init(l, &p->labels); p->shared = pic_make_weak(pic);
kh_init(v, &p->visited); p->labels = pic_make_weak(pic);
}
static void
writer_control_destroy(pic_state *pic, struct writer_control *p)
{
kh_destroy(l, &p->labels);
kh_destroy(v, &p->visited);
} }
static void static void
traverse(pic_state *pic, pic_value obj, struct writer_control *p) traverse(pic_state *pic, pic_value obj, struct writer_control *p)
{ {
pic_value shared = p->shared;
if (p->op == OP_WRITE_SIMPLE) { if (p->op == OP_WRITE_SIMPLE) {
return; return;
} }
@ -54,14 +49,10 @@ traverse(pic_state *pic, pic_value obj, struct writer_control *p)
case PIC_TYPE_PAIR: case PIC_TYPE_PAIR:
case PIC_TYPE_VECTOR: case PIC_TYPE_VECTOR:
case PIC_TYPE_DICT: { case PIC_TYPE_DICT: {
khash_t(v) *h = &p->visited;
int it;
int ret;
it = kh_put(v, h, pic_obj_ptr(obj), &ret); if (! pic_weak_has(pic, shared, obj)) {
if (ret != 0) {
/* first time */ /* first time */
kh_val(h, it) = 0; pic_weak_set(pic, shared, obj, pic_int_value(pic, 0));
if (pic_pair_p(pic, obj)) { if (pic_pair_p(pic, obj)) {
/* pair */ /* pair */
@ -83,14 +74,13 @@ traverse(pic_state *pic, pic_value obj, struct writer_control *p)
} }
if (p->op == OP_WRITE) { if (p->op == OP_WRITE) {
it = kh_get(v, h, pic_obj_ptr(obj)); if (pic_int(pic, pic_weak_ref(pic, shared, obj)) == 0) {
if (kh_val(h, it) == 0) { pic_weak_del(pic, shared, obj);
kh_del(v, h, it);
} }
} }
} else { } else {
/* second time */ /* second time */
kh_val(h, it) = 1; pic_weak_set(pic, shared, obj, pic_int_value(pic, 1));
} }
break; break;
} }
@ -101,17 +91,15 @@ traverse(pic_state *pic, pic_value obj, struct writer_control *p)
static bool static bool
is_shared_object(pic_state *pic, pic_value obj, struct writer_control *p) { is_shared_object(pic_state *pic, pic_value obj, struct writer_control *p) {
khash_t(v) *h = &p->visited; pic_value shared = p->shared;
int it;
if (! pic_obj_p(pic, obj)) { if (! pic_obj_p(pic, obj)) {
return false; return false;
} }
it = kh_get(v, h, pic_obj_ptr(obj)); if (! pic_weak_has(pic, shared, obj)) {
if (it == kh_end(h)) {
return false; return false;
} }
return kh_val(h, it) > 0; return pic_int(pic, pic_weak_ref(pic, shared, obj)) > 0;
} }
static void static void
@ -297,17 +285,18 @@ write_dict(pic_state *pic, pic_value dict, xFILE *file, struct writer_control *p
static void static void
write_core(pic_state *pic, pic_value obj, xFILE *file, struct writer_control *p) write_core(pic_state *pic, pic_value obj, xFILE *file, struct writer_control *p)
{ {
khash_t(l) *lh = &p->labels; pic_value labels = p->labels;
int it, ret; int i;
/* shared objects */ /* shared objects */
if (is_shared_object(pic, obj, p)) { if (is_shared_object(pic, obj, p)) {
it = kh_put(l, lh, pic_obj_ptr(obj), &ret); if (pic_weak_has(pic, labels, obj)) {
if (ret == 0) { /* if exists */ xfprintf(pic, file, "#%d#", pic_int(pic, pic_weak_ref(pic, labels, obj)));
xfprintf(pic, file, "#%d#", kh_val(lh, it));
return; return;
} }
xfprintf(pic, file, "#%d=", (kh_val(lh, it) = p->cnt++)); i = p->cnt++;
xfprintf(pic, file, "#%d=", i);
pic_weak_set(pic, labels, obj, pic_int_value(pic, i));
} }
switch (pic_type(pic, obj)) { switch (pic_type(pic, obj)) {
@ -363,7 +352,7 @@ write_core(pic_state *pic, pic_value obj, xFILE *file, struct writer_control *p)
if (p->op == OP_WRITE) { if (p->op == OP_WRITE) {
if (is_shared_object(pic, obj, p)) { if (is_shared_object(pic, obj, p)) {
kh_del(l, lh, kh_get(l, lh, pic_obj_ptr(obj))); pic_weak_del(pic, labels, obj);
} }
} }
} }
@ -373,13 +362,11 @@ write(pic_state *pic, pic_value obj, xFILE *file, int mode, int op)
{ {
struct writer_control p; struct writer_control p;
writer_control_init(&p, mode, op); writer_control_init(pic, &p, mode, op);
traverse(pic, obj, &p); traverse(pic, obj, &p);
write_core(pic, obj, file, &p); write_core(pic, obj, file, &p);
writer_control_destroy(pic, &p);
} }