diff --git a/src/bool.c b/src/bool.c index 904a21d6..8ed9cc02 100644 --- a/src/bool.c +++ b/src/bool.c @@ -10,33 +10,87 @@ #include "picrin/blob.h" #include "picrin/string.h" -bool -pic_equal_p(pic_state *pic, pic_value x, pic_value y) +bool pic_string_equal_p(struct pic_string *str1, struct pic_string *str2) { + return pic_strcmp(str1, str2) == 0; +} + +bool pic_blob_equal_p(struct pic_blob *blob1, struct pic_blob *blob2) +{ + if(blob1->len != blob2->len){ + return false; + } + size_t i; + for(i = 0; i < blob1->len; ++i){ + if(blob1->data[i] != blob2->data[i]) + return false; + } + return true; +} + +bool +pic_internal_equal_p(pic_state *pic, pic_value x, pic_value y, size_t depth, xhash *ht) +{ + + if (depth > 10){ + if(depth > 200){ + pic_errorf(pic, "Stack overflow in equal\n"); + } + if (NULL == ht){ + xh_init_ptr(ht, sizeof(void *)); + } + switch(pic_type(x)){ + case PIC_TT_PAIR: + case PIC_TT_VECTOR:{ + xh_entry *e = xh_get(ht, pic_obj_ptr(x)); + if(e){ + /* `x' was seen already. */ + return true; + }else{ + xh_put(ht, pic_obj_ptr(x), NULL); + } + } + default:; + } + } + enum pic_tt type; + pic_value local = pic_nil_value(); + size_t rapid_count = 0; + + LOOP: if (pic_eqv_p(x, y)) return true; - + type = pic_type(x); - if (type != pic_type(y)) - return false; + + if (type != pic_type(y)){ + return false; + } + switch (type) { case PIC_TT_PAIR: - return pic_equal_p(pic, pic_car(pic, x), pic_car(pic, y)) - && pic_equal_p(pic, pic_cdr(pic, x), pic_cdr(pic, y)); - case PIC_TT_BLOB: { - int i; - struct pic_blob *v1 = pic_blob_ptr(x), *v2 = pic_blob_ptr(y); - if(v1->len != v2->len){ + if(pic_nil_p(local)){ + local = x; + } + if(pic_internal_equal_p(pic, pic_car(pic, x), pic_car(pic, y), depth + 1, ht)){ + x = pic_cdr(pic, x); + y = pic_cdr(pic, y); + ++rapid_count; + + if(rapid_count == 2){ + rapid_count = 0; + local = pic_cdr(pic, local); + if (pic_eq_p(local, x)) { + return true; + } + } + goto LOOP; + }else{ return false; } - for(i = 0; i < v1->len; ++i){ - if(v1->data[i] != v2->data[i]) - return false; - } - return true; - } + case PIC_TT_VECTOR:{ size_t i; struct pic_vector *v1 = pic_vec_ptr(x), *v2 = pic_vec_ptr(y); @@ -45,18 +99,28 @@ pic_equal_p(pic_state *pic, pic_value x, pic_value y) return false; } for(i = 0; i < v1->len; ++i){ - if(! pic_equal_p(pic, v1->data[i], v2->data[i])) - return false; + if(! pic_internal_equal_p(pic, v1->data[i], v2->data[i], depth + 1, ht)){ + return false; + } } return true; } + case PIC_TT_BLOB: + return pic_blob_equal_p(pic_blob_ptr(x), pic_blob_ptr(y)); case PIC_TT_STRING: - return pic_strcmp(pic_str_ptr(x), pic_str_ptr(y)) == 0; + return pic_string_equal_p(pic_str_ptr(x), pic_str_ptr(y)); default: return false; } } +bool +pic_equal_p(pic_state *pic, pic_value x, pic_value y){ + xhash ht; + xh_init_ptr(&ht, 0); + return pic_internal_equal_p(pic, x, y, 0, &ht); +} + static pic_value pic_bool_eq_p(pic_state *pic) {