diff options
author | yugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-06-20 09:06:35 +0000 |
---|---|---|
committer | yugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-06-20 09:06:35 +0000 |
commit | 0ddc8305736610337d6c26b3cec2c767cc5a054c (patch) | |
tree | e3a9880f73be06acc8e852899f6caa3ac8575c5f /thread.c | |
parent | 7340277cfb06305590a62a505c49e63a491be20c (diff) |
merges r23557 and r23563 from trunk into ruby_1_9_1.
--
* 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.
--
* test/ruby/test_hash.rb (TestHash::test_equal2): recursive hashes
are handled properly now. ref: [ruby-core:23402]
* test/ruby/test_m17n.rb (TestM17N#test_sprintf_p): test fixed
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_1@23759 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'thread.c')
-rw-r--r-- | thread.c | 87 |
1 files changed, 69 insertions, 18 deletions
@@ -3279,26 +3279,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) { @@ -3313,61 +3326,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) { 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 * |