mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Revert r50102
This reverts "* include/ruby/ruby.h (rb_scan_args): don't use ALWAYS_INLINE with" This rb_scan_args macro is GCCism. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55104 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
3caa177668
commit
8becb1e465
3 changed files with 136 additions and 150 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,15 +1,3 @@
|
|||
Sat May 21 22:45:50 2016 NAKAMURA Usaku <usa@ruby-lang.org>
|
||||
|
||||
* 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@ruby-lang.org>
|
||||
|
||||
* 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@ruby-lang.org>
|
||||
|
||||
* configure.in (ALWAYS_INLINE): force compilers the function inlined.
|
||||
|
|
135
class.c
135
class.c
|
@ -1754,6 +1754,141 @@ rb_obj_basic_to_s_p(VALUE obj)
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -1767,6 +1767,7 @@ VALUE rb_funcallv_public(VALUE, ID, int, const VALUE*);
|
|||
#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 *);
|
||||
|
@ -2149,144 +2150,6 @@ unsigned long ruby_strtoul(const char *str, char **endptr, int base);
|
|||
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 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
|
||||
|
|
Loading…
Reference in a new issue