[前][次][番号順一覧][スレッド一覧]

ruby-changes:4586

From: ko1@a...
Date: Sat, 19 Apr 2008 19:30:14 +0900 (JST)
Subject: [ruby-changes:4586] knu - Ruby:r16080 (ruby_1_8): * eval.c (rb_exec_recursive): New internal function to help

knu	2008-04-19 19:29:59 +0900 (Sat, 19 Apr 2008)

  New Revision: 16080

  Modified files:
    branches/ruby_1_8/ChangeLog
    branches/ruby_1_8/eval.c
    branches/ruby_1_8/intern.h

  Log:
    * eval.c (rb_exec_recursive): New internal function to help
      perform recursive operation; backported from 1.9.


  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/intern.h?r1=16080&r2=16079&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=16080&r2=16079&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/eval.c?r1=16080&r2=16079&diff_format=u

Index: ruby_1_8/intern.h
===================================================================
--- ruby_1_8/intern.h	(revision 16079)
+++ ruby_1_8/intern.h	(revision 16080)
@@ -233,6 +233,7 @@
 VALUE rb_thread_local_aref _((VALUE, ID));
 VALUE rb_thread_local_aset _((VALUE, ID, VALUE));
 void rb_thread_atfork _((void));
+VALUE rb_exec_recursive _((VALUE(*)(VALUE, VALUE, int),VALUE,VALUE));
 VALUE rb_funcall_rescue __((VALUE, ID, int, ...));
 /* file.c */
 VALUE rb_file_s_expand_path _((int, VALUE *));
Index: ruby_1_8/ChangeLog
===================================================================
--- ruby_1_8/ChangeLog	(revision 16079)
+++ ruby_1_8/ChangeLog	(revision 16080)
@@ -1,3 +1,8 @@
+Sat Apr 19 19:26:09 2008  Akinori MUSHA  <knu@i...>
+
+	* intern.h, eval.c (rb_exec_recursive): New internal function to
+	  help perform recursive operation; backported from 1.9.
+
 Sat Apr 19 18:42:04 2008  Akinori MUSHA  <knu@i...>
 
 	* intern.h, hash.c (rb_hash_lookup): New internal function to
Index: ruby_1_8/eval.c
===================================================================
--- ruby_1_8/eval.c	(revision 16079)
+++ ruby_1_8/eval.c	(revision 16080)
@@ -13043,6 +13043,109 @@
 }
 
 
+/* variables for recursive traversals */
+static ID recursive_key;
+
+static VALUE
+recursive_check(hash, obj)
+    VALUE hash;
+    VALUE obj;
+{
+    if (NIL_P(hash) || TYPE(hash) != T_HASH) {
+	return Qfalse;
+    }
+    else {
+	VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_last_func()));
+
+	if (NIL_P(list) || TYPE(list) != T_HASH)
+	    return Qfalse;
+	if (NIL_P(rb_hash_lookup(list, obj)))
+	    return Qfalse;
+	return Qtrue;
+    }
+}
+
+static VALUE
+recursive_push(hash, obj)
+    VALUE hash;
+    VALUE obj;
+{
+    VALUE list, sym;
+
+    sym = ID2SYM(rb_frame_last_func());
+    if (NIL_P(hash) || TYPE(hash) != T_HASH) {
+	hash = rb_hash_new();
+	rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
+	list = Qnil;
+    }
+    else {
+	list = rb_hash_aref(hash, sym);
+    }
+    if (NIL_P(list) || TYPE(list) != T_HASH) {
+	list = rb_hash_new();
+	rb_hash_aset(hash, sym, list);
+    }
+    rb_hash_aset(list, obj, Qtrue);
+    return hash;
+}
+
+static void
+recursive_pop(hash, obj)
+    VALUE hash;
+    VALUE obj;
+{
+    VALUE list, sym;
+
+    sym = ID2SYM(rb_frame_last_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());
+	rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
+		 StringValuePtr(symname), StringValuePtr(thrname));
+    }
+    rb_hash_delete(list, obj);
+}
+
+VALUE
+rb_exec_recursive(func, obj, arg)
+    VALUE (*func) _((VALUE, VALUE, int));
+    VALUE obj;
+    VALUE arg;
+{
+    VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
+    VALUE objid = rb_obj_id(obj);
+
+    if (recursive_check(hash, objid)) {
+	return (*func) (obj, arg, Qtrue);
+    }
+    else {
+	VALUE result = Qundef;
+	int state;
+
+	hash = recursive_push(hash, objid);
+	PUSH_TAG(PROT_NONE);
+	if ((state = EXEC_TAG()) == 0) {
+	    result = (*func) (obj, arg, Qfalse);
+	}
+	POP_TAG();
+	recursive_pop(hash, objid);
+	if (state)
+	    JUMP_TAG(state);
+	return result;
+    }
+}
+
+
 /*
  *  +Thread+ encapsulates the behavior of a thread of
  *  execution, including the main thread of the Ruby script.

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]