summaryrefslogtreecommitdiff
path: root/thread.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-05-24 13:48:23 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-05-24 13:48:23 +0000
commit02fb261ec11afc34e0329aa3bbbe146cd1c89e84 (patch)
tree4564444a30a9dc991c8401733228fa37c8a0918f /thread.c
parentb55ff9989153cbe786967d8a1382846059fd2c54 (diff)
* thread.c (rb_exec_recursive_paired): new function for proper
handling of recursive arrays. [EXPERIMENTAL] [ruby-core:23402] * array.c (rb_ary_equal, rb_ary_eql, rb_ary_cmp): use above. * hash.c (hash_equal): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23557 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'thread.c')
-rw-r--r--thread.c87
1 files changed, 69 insertions, 18 deletions
diff --git a/thread.c b/thread.c
index 69b02e3d5e..d2eeca32e6 100644
--- a/thread.c
+++ b/thread.c
@@ -3310,26 +3310,39 @@ rb_barrier_destroy(VALUE self)
static ID recursive_key;
static VALUE
-recursive_check(VALUE hash, VALUE obj)
+recursive_check(VALUE hash, VALUE obj, VALUE paired_obj)
{
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
return Qfalse;
}
else {
- VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_this_func()));
+ VALUE sym = ID2SYM(rb_frame_this_func());
+ VALUE list = rb_hash_aref(hash, sym);
+ VALUE pair_list;
if (NIL_P(list) || TYPE(list) != T_HASH)
return Qfalse;
- if (NIL_P(rb_hash_lookup(list, obj)))
+ pair_list = rb_hash_lookup2(list, obj, Qundef);
+ if (pair_list == Qundef)
return Qfalse;
+ if (paired_obj) {
+ if (TYPE(pair_list) != T_HASH) {
+ if (pair_list != paired_obj)
+ return Qfalse;
+ }
+ else {
+ if (NIL_P(rb_hash_lookup(pair_list, paired_obj)))
+ return Qfalse;
+ }
+ }
return Qtrue;
}
}
static VALUE
-recursive_push(VALUE hash, VALUE obj)
+recursive_push(VALUE hash, VALUE obj, VALUE paired_obj)
{
- VALUE list, sym;
+ VALUE list, sym, pair_list;
sym = ID2SYM(rb_frame_this_func());
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
@@ -3344,61 +3357,99 @@ recursive_push(VALUE hash, VALUE obj)
list = rb_hash_new();
rb_hash_aset(hash, sym, list);
}
- rb_hash_aset(list, obj, Qtrue);
+ if (!paired_obj) {
+ rb_hash_aset(list, obj, Qtrue);
+ }
+ else if ((pair_list = rb_hash_lookup2(list, obj, Qundef)) == Qundef) {
+ rb_hash_aset(list, obj, paired_obj);
+ }
+ else {
+ if (TYPE(pair_list) != T_HASH){
+ VALUE other_paired_obj = pair_list;
+ pair_list = rb_hash_new();
+ rb_hash_aset(pair_list, other_paired_obj, Qtrue);
+ rb_hash_aset(list, obj, pair_list);
+ }
+ rb_hash_aset(pair_list, paired_obj, Qtrue);
+ }
return hash;
}
static void
-recursive_pop(VALUE hash, VALUE obj)
+recursive_pop(VALUE hash, VALUE obj, VALUE paired_obj)
{
- VALUE list, sym;
+ VALUE list, sym, pair_list, symname, thrname;
sym = ID2SYM(rb_frame_this_func());
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
- VALUE symname;
- VALUE thrname;
symname = rb_inspect(sym);
thrname = rb_inspect(rb_thread_current());
-
rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
StringValuePtr(symname), StringValuePtr(thrname));
}
list = rb_hash_aref(hash, sym);
if (NIL_P(list) || TYPE(list) != T_HASH) {
- VALUE symname = rb_inspect(sym);
- VALUE thrname = rb_inspect(rb_thread_current());
+ symname = rb_inspect(sym);
+ thrname = rb_inspect(rb_thread_current());
rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
StringValuePtr(symname), StringValuePtr(thrname));
}
+ if (paired_obj) {
+ pair_list = rb_hash_lookup2(list, obj, Qundef);
+ if (pair_list == Qundef) {
+ symname = rb_inspect(sym);
+ thrname = rb_inspect(rb_thread_current());
+ rb_raise(rb_eTypeError, "invalid inspect_tbl pair_list for %s in %s",
+ StringValuePtr(symname), StringValuePtr(thrname));
+ }
+ if (TYPE(pair_list) == T_HASH) {
+ rb_hash_delete(pair_list, paired_obj);
+ if (!RHASH_EMPTY_P(pair_list)) {
+ return; /* keep hash until is empty */
+ }
+ }
+ }
rb_hash_delete(list, obj);
}
-VALUE
-rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
+static VALUE
+exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE pairid, VALUE arg)
{
volatile VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
VALUE objid = rb_obj_id(obj);
- if (recursive_check(hash, objid)) {
+ if (recursive_check(hash, objid, pairid)) {
return (*func) (obj, arg, Qtrue);
}
else {
VALUE result = Qundef;
int state;
- hash = recursive_push(hash, objid);
+ hash = recursive_push(hash, objid, pairid);
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
result = (*func) (obj, arg, Qfalse);
}
POP_TAG();
- recursive_pop(hash, objid);
+ recursive_pop(hash, objid, pairid);
if (state)
JUMP_TAG(state);
return result;
}
}
+VALUE
+rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
+{
+ return exec_recursive(func, obj, 0, arg);
+}
+
+VALUE
+rb_exec_recursive_paired(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE paired_obj, VALUE arg)
+{
+ return exec_recursive(func, obj, rb_obj_id(paired_obj), arg);
+}
+
/* tracer */
static rb_event_hook_t *