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

ruby-changes:43028

From: naruse <ko1@a...>
Date: Sat, 21 May 2016 22:24:41 +0900 (JST)
Subject: [ruby-changes:43028] naruse:r55102 (trunk): * include/ruby/ruby.h (rb_scan_args): use __VA_ARGS__ instead of

naruse	2016-05-21 22:24:33 +0900 (Sat, 21 May 2016)

  New Revision: 55102

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=55102

  Log:
    * include/ruby/ruby.h (rb_scan_args): use __VA_ARGS__ instead of
      va_arg to allow compilers optimize more aggressive.
      https://gustedt.wordpress.com/2011/07/10/avoid-writing-va_arg-functions/
      rb_scan_args is now expected to be statically resolved.

  Modified files:
    trunk/ChangeLog
    trunk/class.c
    trunk/include/ruby/ruby.h
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 55101)
+++ include/ruby/ruby.h	(revision 55102)
@@ -1767,7 +1767,6 @@ VALUE rb_funcallv_public(VALUE, ID, int, https://github.com/ruby/ruby/blob/trunk/include/ruby/ruby.h#L1767
 #define rb_funcall3 rb_funcallv_public
 VALUE rb_funcall_passing_block(VALUE, ID, int, const VALUE*);
 VALUE rb_funcall_with_block(VALUE, ID, int, const VALUE*, VALUE);
-int rb_scan_args(int, const VALUE*, const char*, ...);
 VALUE rb_call_super(int, const VALUE*);
 VALUE rb_current_receiver(void);
 int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *);
@@ -2150,6 +2149,144 @@ unsigned long ruby_strtoul(const char *s https://github.com/ruby/ruby/blob/trunk/include/ruby/ruby.h#L2149
 PRINTF_ARGS(int ruby_snprintf(char *str, size_t n, char const *fmt, ...), 3, 4);
 int ruby_vsnprintf(char *str, size_t n, char const *fmt, va_list ap);
 
+#define RB_NARG0(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,...) _19
+#define RB_NARG(...) RB_NARG0(__VA_ARGS__,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
+#define rb_scan_args(argc,argvp,fmt,...) \
+    rb_scan_args0(argc,argv,fmt,RB_NARG(__VA_ARGS__),(VALUE*[]){__VA_ARGS__})
+ALWAYS_INLINE(static inline int
+rb_scan_args0(int argc, const VALUE *argv, const char *fmt, int varc, VALUE *vars[]));
+static inline int
+rb_scan_args0(int argc, const VALUE *argv, const char *fmt, int varc, VALUE *vars[])
+{
+    int i;
+    const char *p = fmt;
+    VALUE *var;
+    int f_var = 0, f_hash = 0, f_block = 0;
+    int n_lead = 0, n_opt = 0, n_trail = 0, n_mand;
+    int argi = 0, vari = 0;
+    VALUE hash = Qnil;
+
+    if (ISDIGIT(*p)) {
+	n_lead = *p - '0';
+	p++;
+	if (ISDIGIT(*p)) {
+	    n_opt = *p - '0';
+	    p++;
+	    if (ISDIGIT(*p)) {
+		n_trail = *p - '0';
+		p++;
+		goto block_arg;
+	    }
+	}
+    }
+    if (*p == '*') {
+	f_var = 1;
+	p++;
+	if (ISDIGIT(*p)) {
+	    n_trail = *p - '0';
+	    p++;
+	}
+    }
+  block_arg:
+    if (*p == ':') {
+	f_hash = 1;
+	p++;
+    }
+    if (*p == '&') {
+	f_block = 1;
+	p++;
+    }
+    if (*p != '\0') {
+	rb_fatal("bad scan arg format: %s", fmt);
+    }
+    n_mand = n_lead + n_trail;
+
+    if (argc < n_mand)
+	goto argc_error;
+
+    /* capture an option hash - phase 1: pop */
+    if (f_hash && n_mand < argc) {
+	VALUE last = argv[argc - 1];
+
+	if (NIL_P(last)) {
+	    /* nil is taken as an empty option hash only if it is not
+	       ambiguous; i.e. '*' is not specified and arguments are
+	       given more than sufficient */
+	    if (!f_var && n_mand + n_opt < argc)
+		argc--;
+	}
+	else {
+	    hash = rb_check_hash_type(last);
+	    if (!NIL_P(hash)) {
+		VALUE opts = rb_extract_keywords(&hash);
+		if (!hash) argc--;
+		hash = opts ? opts : Qnil;
+	    }
+	}
+    }
+    /* capture leading mandatory arguments */
+    for (i = n_lead; i-- > 0; ) {
+	var = vars[vari++];
+	if (var) *var = argv[argi];
+	argi++;
+    }
+    /* capture optional arguments */
+    for (i = n_opt; i-- > 0; ) {
+	var = vars[vari++];
+	if (argi < argc - n_trail) {
+	    if (var) *var = argv[argi];
+	    argi++;
+	}
+	else {
+	    if (var) *var = Qnil;
+	}
+    }
+    /* capture variable length arguments */
+    if (f_var) {
+	int n_var = argc - argi - n_trail;
+
+	var = vars[vari++];
+	if (0 < n_var) {
+	    if (var) *var = rb_ary_new4(n_var, &argv[argi]);
+	    argi += n_var;
+	}
+	else {
+	    if (var) *var = rb_ary_new();
+	}
+    }
+    /* capture trailing mandatory arguments */
+    for (i = n_trail; i-- > 0; ) {
+	var = vars[vari++];
+	if (var) *var = argv[argi];
+	argi++;
+    }
+    /* capture an option hash - phase 2: assignment */
+    if (f_hash) {
+	var = vars[vari++];
+	if (var) *var = hash;
+    }
+    /* capture iterator block */
+    if (f_block) {
+	var = vars[vari++];
+	if (rb_block_given_p()) {
+	    *var = rb_block_proc();
+	}
+	else {
+	    *var = Qnil;
+	}
+    }
+
+    if (argi < argc) {
+      argc_error:
+	rb_error_arity(argc, n_mand, f_var ? UNLIMITED_ARGUMENTS : n_mand + n_opt);
+    }
+    if (vari != varc) {
+	rb_raise(rb_eRuntimeError, "variable argument length doesn't match* %d %d", vari, varc);
+    }
+
+    return argc;
+}
+
 #ifndef RUBY_DONT_SUBST
 #include "ruby/subst.h"
 #endif
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 55101)
+++ ChangeLog	(revision 55102)
@@ -1,3 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat May 21 21:11:56 2016  NARUSE, Yui  <naruse@r...>
+
+	* include/ruby/ruby.h (rb_scan_args): use __VA_ARGS__ instead of
+	  va_arg to allow compilers optimize more aggressive.
+	  https://gustedt.wordpress.com/2011/07/10/avoid-writing-va_arg-functions/
+	  rb_scan_args is now expected to be statically resolved.
+
 Sat May 21 21:07:18 2016  NARUSE, Yui  <naruse@r...>
 
 	* configure.in (ALWAYS_INLINE): force compilers the function inlined.
Index: class.c
===================================================================
--- class.c	(revision 55101)
+++ class.c	(revision 55102)
@@ -1754,141 +1754,6 @@ rb_obj_basic_to_s_p(VALUE obj) https://github.com/ruby/ruby/blob/trunk/class.c#L1754
     return 0;
 }
 
-#include <stdarg.h>
-
-int
-rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
-{
-    int i;
-    const char *p = fmt;
-    VALUE *var;
-    va_list vargs;
-    int f_var = 0, f_hash = 0, f_block = 0;
-    int n_lead = 0, n_opt = 0, n_trail = 0, n_mand;
-    int argi = 0;
-    VALUE hash = Qnil;
-
-    if (ISDIGIT(*p)) {
-	n_lead = *p - '0';
-	p++;
-	if (ISDIGIT(*p)) {
-	    n_opt = *p - '0';
-	    p++;
-	    if (ISDIGIT(*p)) {
-		n_trail = *p - '0';
-		p++;
-		goto block_arg;
-	    }
-	}
-    }
-    if (*p == '*') {
-	f_var = 1;
-	p++;
-	if (ISDIGIT(*p)) {
-	    n_trail = *p - '0';
-	    p++;
-	}
-    }
-  block_arg:
-    if (*p == ':') {
-	f_hash = 1;
-	p++;
-    }
-    if (*p == '&') {
-	f_block = 1;
-	p++;
-    }
-    if (*p != '\0') {
-	rb_fatal("bad scan arg format: %s", fmt);
-    }
-    n_mand = n_lead + n_trail;
-
-    if (argc < n_mand)
-	goto argc_error;
-
-    va_start(vargs, fmt);
-
-    /* capture an option hash - phase 1: pop */
-    if (f_hash && n_mand < argc) {
-	VALUE last = argv[argc - 1];
-
-	if (NIL_P(last)) {
-	    /* nil is taken as an empty option hash only if it is not
-	       ambiguous; i.e. '*' is not specified and arguments are
-	       given more than sufficient */
-	    if (!f_var && n_mand + n_opt < argc)
-		argc--;
-	}
-	else {
-	    hash = rb_check_hash_type(last);
-	    if (!NIL_P(hash)) {
-		VALUE opts = rb_extract_keywords(&hash);
-		if (!hash) argc--;
-		hash = opts ? opts : Qnil;
-	    }
-	}
-    }
-    /* capture leading mandatory arguments */
-    for (i = n_lead; i-- > 0; ) {
-	var = va_arg(vargs, VALUE *);
-	if (var) *var = argv[argi];
-	argi++;
-    }
-    /* capture optional arguments */
-    for (i = n_opt; i-- > 0; ) {
-	var = va_arg(vargs, VALUE *);
-	if (argi < argc - n_trail) {
-	    if (var) *var = argv[argi];
-	    argi++;
-	}
-	else {
-	    if (var) *var = Qnil;
-	}
-    }
-    /* capture variable length arguments */
-    if (f_var) {
-	int n_var = argc - argi - n_trail;
-
-	var = va_arg(vargs, VALUE *);
-	if (0 < n_var) {
-	    if (var) *var = rb_ary_new4(n_var, &argv[argi]);
-	    argi += n_var;
-	}
-	else {
-	    if (var) *var = rb_ary_new();
-	}
-    }
-    /* capture trailing mandatory arguments */
-    for (i = n_trail; i-- > 0; ) {
-	var = va_arg(vargs, VALUE *);
-	if (var) *var = argv[argi];
-	argi++;
-    }
-    /* capture an option hash - phase 2: assignment */
-    if (f_hash) {
-	var = va_arg(vargs, VALUE *);
-	if (var) *var = hash;
-    }
-    /* capture iterator block */
-    if (f_block) {
-	var = va_arg(vargs, VALUE *);
-	if (rb_block_given_p()) {
-	    *var = rb_block_proc();
-	}
-	else {
-	    *var = Qnil;
-	}
-    }
-    va_end(vargs);
-
-    if (argi < argc) {
-      argc_error:
-	rb_error_arity(argc, n_mand, f_var ? UNLIMITED_ARGUMENTS : n_mand + n_opt);
-    }
-
-    return argc;
-}
-
 VALUE
 rb_keyword_error_new(const char *error, VALUE keys)
 {

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

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