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

ruby-changes:43036

From: naruse <ko1@a...>
Date: Sun, 22 May 2016 11:45:01 +0900 (JST)
Subject: [ruby-changes:43036] naruse:r55110 (trunk): * class.c (rb_scan_args): moved to bottom of the file to make the

naruse	2016-05-22 11:44:54 +0900 (Sun, 22 May 2016)

  New Revision: 55110

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

  Log:
    * class.c (rb_scan_args): moved to bottom of the file to make the
      effect of `#undef rb_scan_args` the minimum.
    
    * include/ruby/ruby.h (rb_scan_args): overwrite only if GCC and
      optimized. Visual C++ 14 or later can compile it but make it
      conservative.

  Modified files:
    trunk/ChangeLog
    trunk/class.c
    trunk/include/ruby/ruby.h
Index: class.c
===================================================================
--- class.c	(revision 55109)
+++ class.c	(revision 55110)
@@ -1754,8 +1754,135 @@ rb_obj_basic_to_s_p(VALUE obj) https://github.com/ruby/ruby/blob/trunk/class.c#L1754
     return 0;
 }
 
-#include <stdarg.h>
+VALUE
+rb_keyword_error_new(const char *error, VALUE keys)
+{
+    const char *msg = "";
+    VALUE error_message;
+
+    if (RARRAY_LEN(keys) == 1) {
+	keys = RARRAY_AREF(keys, 0);
+    }
+    else {
+	keys = rb_ary_join(keys, rb_usascii_str_new2(", "));
+	msg = "s";
+    }
+
+    error_message = rb_sprintf("%s keyword%s: %"PRIsVALUE, error, msg, keys);
+
+    return rb_exc_new_str(rb_eArgError, error_message);
+}
+
+NORETURN(static void rb_keyword_error(const char *error, VALUE keys));
+static void
+rb_keyword_error(const char *error, VALUE keys)
+{
+    rb_exc_raise(rb_keyword_error_new(error, keys));
+}
+
+NORETURN(static void unknown_keyword_error(VALUE hash, const ID *table, int keywords));
+static void
+unknown_keyword_error(VALUE hash, const ID *table, int keywords)
+{
+    st_table *tbl = rb_hash_tbl_raw(hash);
+    VALUE keys;
+    int i;
+    for (i = 0; i < keywords; i++) {
+	st_data_t key = ID2SYM(table[i]);
+	st_delete(tbl, &key, NULL);
+    }
+    keys = rb_funcallv(hash, rb_intern("keys"), 0, 0);
+    if (!RB_TYPE_P(keys, T_ARRAY)) rb_raise(rb_eArgError, "unknown keyword");
+    rb_keyword_error("unknown", keys);
+}
+
+static int
+separate_symbol(st_data_t key, st_data_t value, st_data_t arg)
+{
+    VALUE *kwdhash = (VALUE *)arg;
+
+    if (!SYMBOL_P(key)) kwdhash++;
+    if (!*kwdhash) *kwdhash = rb_hash_new();
+    rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value);
+    return ST_CONTINUE;
+}
+
+VALUE
+rb_extract_keywords(VALUE *orighash)
+{
+    VALUE parthash[2] = {0, 0};
+    VALUE hash = *orighash;
+
+    if (RHASH_EMPTY_P(hash)) {
+	*orighash = 0;
+	return hash;
+    }
+    st_foreach(rb_hash_tbl_raw(hash), separate_symbol, (st_data_t)&parthash);
+    *orighash = parthash[1];
+    return parthash[0];
+}
+
+int
+rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
+{
+    int i = 0, j;
+    int rest = 0;
+    VALUE missing = Qnil;
+    st_data_t key;
+
+#define extract_kwarg(keyword, val) \
+    (key = (st_data_t)(keyword), values ? \
+     st_delete(rb_hash_tbl_raw(keyword_hash), &key, (val)) : \
+     st_lookup(rb_hash_tbl_raw(keyword_hash), key, (val)))
+
+    if (NIL_P(keyword_hash)) keyword_hash = 0;
+
+    if (optional < 0) {
+	rest = 1;
+	optional = -1-optional;
+    }
+    if (values) {
+	for (j = 0; j < required + optional; j++) {
+	    values[j] = Qundef;
+	}
+    }
+    if (required) {
+	for (; i < required; i++) {
+	    VALUE keyword = ID2SYM(table[i]);
+	    if (keyword_hash) {
+		st_data_t val;
+		if (extract_kwarg(keyword, &val)) {
+		    if (values) values[i] = (VALUE)val;
+		    continue;
+		}
+	    }
+	    if (NIL_P(missing)) missing = rb_ary_tmp_new(1);
+	    rb_ary_push(missing, keyword);
+	}
+	if (!NIL_P(missing)) {
+	    rb_keyword_error("missing", missing);
+	}
+    }
+    j = i;
+    if (optional && keyword_hash) {
+	for (i = 0; i < optional; i++) {
+	    st_data_t val;
+	    if (extract_kwarg(ID2SYM(table[required+i]), &val)) {
+		if (values) values[required+i] = (VALUE)val;
+		j++;
+	    }
+	}
+    }
+    if (!rest && keyword_hash) {
+	if (RHASH_SIZE(keyword_hash) > (unsigned int)j) {
+	    unknown_keyword_error(keyword_hash, table, required+optional);
+	}
+    }
+    return j;
+#undef extract_kwarg
+}
 
+#undef rb_scan_args
 int
 rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
 {
@@ -1889,134 +2016,6 @@ rb_scan_args(int argc, const VALUE *argv https://github.com/ruby/ruby/blob/trunk/class.c#L2016
     return argc;
 }
 
-VALUE
-rb_keyword_error_new(const char *error, VALUE keys)
-{
-    const char *msg = "";
-    VALUE error_message;
-
-    if (RARRAY_LEN(keys) == 1) {
-	keys = RARRAY_AREF(keys, 0);
-    }
-    else {
-	keys = rb_ary_join(keys, rb_usascii_str_new2(", "));
-	msg = "s";
-    }
-
-    error_message = rb_sprintf("%s keyword%s: %"PRIsVALUE, error, msg, keys);
-
-    return rb_exc_new_str(rb_eArgError, error_message);
-}
-
-NORETURN(static void rb_keyword_error(const char *error, VALUE keys));
-static void
-rb_keyword_error(const char *error, VALUE keys)
-{
-    rb_exc_raise(rb_keyword_error_new(error, keys));
-}
-
-NORETURN(static void unknown_keyword_error(VALUE hash, const ID *table, int keywords));
-static void
-unknown_keyword_error(VALUE hash, const ID *table, int keywords)
-{
-    st_table *tbl = rb_hash_tbl_raw(hash);
-    VALUE keys;
-    int i;
-    for (i = 0; i < keywords; i++) {
-	st_data_t key = ID2SYM(table[i]);
-	st_delete(tbl, &key, NULL);
-    }
-    keys = rb_funcallv(hash, rb_intern("keys"), 0, 0);
-    if (!RB_TYPE_P(keys, T_ARRAY)) rb_raise(rb_eArgError, "unknown keyword");
-    rb_keyword_error("unknown", keys);
-}
-
-static int
-separate_symbol(st_data_t key, st_data_t value, st_data_t arg)
-{
-    VALUE *kwdhash = (VALUE *)arg;
-
-    if (!SYMBOL_P(key)) kwdhash++;
-    if (!*kwdhash) *kwdhash = rb_hash_new();
-    rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value);
-    return ST_CONTINUE;
-}
-
-VALUE
-rb_extract_keywords(VALUE *orighash)
-{
-    VALUE parthash[2] = {0, 0};
-    VALUE hash = *orighash;
-
-    if (RHASH_EMPTY_P(hash)) {
-	*orighash = 0;
-	return hash;
-    }
-    st_foreach(rb_hash_tbl_raw(hash), separate_symbol, (st_data_t)&parthash);
-    *orighash = parthash[1];
-    return parthash[0];
-}
-
-int
-rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
-{
-    int i = 0, j;
-    int rest = 0;
-    VALUE missing = Qnil;
-    st_data_t key;
-
-#define extract_kwarg(keyword, val) \
-    (key = (st_data_t)(keyword), values ? \
-     st_delete(rb_hash_tbl_raw(keyword_hash), &key, (val)) : \
-     st_lookup(rb_hash_tbl_raw(keyword_hash), key, (val)))
-
-    if (NIL_P(keyword_hash)) keyword_hash = 0;
-
-    if (optional < 0) {
-	rest = 1;
-	optional = -1-optional;
-    }
-    if (values) {
-	for (j = 0; j < required + optional; j++) {
-	    values[j] = Qundef;
-	}
-    }
-    if (required) {
-	for (; i < required; i++) {
-	    VALUE keyword = ID2SYM(table[i]);
-	    if (keyword_hash) {
-		st_data_t val;
-		if (extract_kwarg(keyword, &val)) {
-		    if (values) values[i] = (VALUE)val;
-		    continue;
-		}
-	    }
-	    if (NIL_P(missing)) missing = rb_ary_tmp_new(1);
-	    rb_ary_push(missing, keyword);
-	}
-	if (!NIL_P(missing)) {
-	    rb_keyword_error("missing", missing);
-	}
-    }
-    j = i;
-    if (optional && keyword_hash) {
-	for (i = 0; i < optional; i++) {
-	    st_data_t val;
-	    if (extract_kwarg(ID2SYM(table[required+i]), &val)) {
-		if (values) values[required+i] = (VALUE)val;
-		j++;
-	    }
-	}
-    }
-    if (!rest && keyword_hash) {
-	if (RHASH_SIZE(keyword_hash) > (unsigned int)j) {
-	    unknown_keyword_error(keyword_hash, table, required+optional);
-	}
-    }
-    return j;
-#undef extract_kwarg
-}
-
 int
 rb_class_has_methods(VALUE c)
 {
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 55109)
+++ include/ruby/ruby.h	(revision 55110)
@@ -2150,6 +2150,144 @@ unsigned long ruby_strtoul(const char *s https://github.com/ruby/ruby/blob/trunk/include/ruby/ruby.h#L2150
 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);
 
+#if defined(__GNUC__) && defined(__OPTIMIZE__)
+# define rb_scan_args(argc,argvp,fmt,...) \
+    rb_scan_args0(argc,argv,fmt,(sizeof((VALUE*[]){__VA_ARGS__})/sizeof(VALUE*)),(VALUE*[]){__VA_ARGS__})
+ALWAYS_INLINE(static int
+rb_scan_args0(int argc, const VALUE *argv, const char *fmt, int varc, VALUE *vars[]));
+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;
+}
+#endif
+
 #ifndef RUBY_DONT_SUBST
 #include "ruby/subst.h"
 #endif
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 55109)
+++ ChangeLog	(revision 55110)
@@ -1,3 +1,24 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sun May 22 11:41:12 2016  NARUSE, Yui  <naruse@r...>
+
+	* class.c (rb_scan_args): moved to bottom of the file to make the
+	  effect of `#undef rb_scan_args` the minimum.
+
+	* include/ruby/ruby.h (rb_scan_args): overwrite only if GCC and
+	  optimized. Visual C++ 14 or later can compile it but make it
+	  conservative.
+
+Sat May 21 22:45:50 2016  NAKAMURA Usaku  <usa@r...>
+
+	* include/ruby/ruby.h (rb_scan_args): don't use ALWAYS_INLINE with
+	  `inline`.  if gcc needs this duplication, do in ALWAYS_INLINE macro.
+
+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.
+
 Sun May 22 02:41:52 2016  NARUSE, Yui  <naruse@r...>
 
 	* ext/zlib/zlib.c: remove hacky macro introduced at r30437.

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

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