Share argument parsing in Regexp#initialize and Regexp.linear_time?

This commit is contained in:
Nobuyoshi Nakada 2022-12-21 23:17:37 +09:00
parent bb4cbd0803
commit 454c00723a
Notes: git 2022-12-22 06:51:19 +00:00
2 changed files with 45 additions and 21 deletions

63
re.c
View File

@ -3750,6 +3750,15 @@ set_timeout(rb_hrtime_t *hrt, VALUE timeout)
double2hrtime(hrt, timeout_d); double2hrtime(hrt, timeout_d);
} }
struct reg_init_args {
VALUE src, str, timeout;
rb_encoding *enc;
int flags;
};
static void reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args);
static VALUE reg_init_args(VALUE self, VALUE str, rb_encoding *enc, int flags);
/* /*
* call-seq: * call-seq:
* Regexp.new(string, options = 0, n_flag = nil, timeout: nil) -> regexp * Regexp.new(string, options = 0, n_flag = nil, timeout: nil) -> regexp
@ -3813,26 +3822,38 @@ set_timeout(rb_hrtime_t *hrt, VALUE timeout)
static VALUE static VALUE
rb_reg_initialize_m(int argc, VALUE *argv, VALUE self) rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
{ {
int flags = 0; struct reg_init_args args;
VALUE str;
rb_encoding *enc = 0;
VALUE src, opts = Qundef, n_flag = Qundef, kwargs, timeout = Qnil; reg_extract_args(argc, argv, &args);
reg_init_args(self, args.str, args.enc, args.flags);
set_timeout(&RREGEXP_PTR(self)->timelimit, args.timeout);
return self;
}
static void
reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args)
{
int flags = 0;
rb_encoding *enc = 0;
VALUE str, src, opts = Qundef, n_flag = Qundef, kwargs;
rb_scan_args(argc, argv, "12:", &src, &opts, &n_flag, &kwargs); rb_scan_args(argc, argv, "12:", &src, &opts, &n_flag, &kwargs);
args->timeout = Qnil;
if (!NIL_P(kwargs)) { if (!NIL_P(kwargs)) {
static ID keywords[1]; static ID keywords[1];
if (!keywords[0]) { if (!keywords[0]) {
keywords[0] = rb_intern_const("timeout"); keywords[0] = rb_intern_const("timeout");
} }
rb_get_kwargs(kwargs, keywords, 0, 1, &timeout); rb_get_kwargs(kwargs, keywords, 0, 1, &args->timeout);
} }
if (RB_TYPE_P(src, T_REGEXP)) { if (RB_TYPE_P(src, T_REGEXP)) {
VALUE re = src; VALUE re = src;
if (opts != Qnil) { if (!NIL_P(opts)) {
rb_warn("flags ignored"); rb_warn("flags ignored");
} }
rb_reg_check(re); rb_reg_check(re);
@ -3847,7 +3868,7 @@ rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
else if (!NIL_P(opts) && rb_bool_expected(opts, "ignorecase", FALSE)) else if (!NIL_P(opts) && rb_bool_expected(opts, "ignorecase", FALSE))
flags = ONIG_OPTION_IGNORECASE; flags = ONIG_OPTION_IGNORECASE;
} }
if (!UNDEF_P(n_flag) && !NIL_P(n_flag)) { if (!NIL_OR_UNDEF_P(n_flag)) {
char *kcode = StringValuePtr(n_flag); char *kcode = StringValuePtr(n_flag);
if (kcode[0] == 'n' || kcode[0] == 'N') { if (kcode[0] == 'n' || kcode[0] == 'N') {
enc = rb_ascii8bit_encoding(); enc = rb_ascii8bit_encoding();
@ -3859,15 +3880,19 @@ rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
} }
str = StringValue(src); str = StringValue(src);
} }
args->src = src;
args->str = str;
args->enc = enc;
args->flags = flags;
}
static VALUE
reg_init_args(VALUE self, VALUE str, rb_encoding *enc, int flags)
{
if (enc && rb_enc_get(str) != enc) if (enc && rb_enc_get(str) != enc)
rb_reg_init_str_enc(self, str, enc, flags); rb_reg_init_str_enc(self, str, enc, flags);
else else
rb_reg_init_str(self, str, flags); rb_reg_init_str(self, str, flags);
regex_t *reg = RREGEXP_PTR(self);
set_timeout(&reg->timelimit, timeout);
return self; return self;
} }
@ -4219,21 +4244,17 @@ static VALUE
rb_reg_s_linear_time_p(int argc, VALUE *argv, VALUE self) rb_reg_s_linear_time_p(int argc, VALUE *argv, VALUE self)
{ {
VALUE re; VALUE re;
VALUE src, opts = Qundef, n_flag = Qundef, kwargs; struct reg_init_args args;
rb_scan_args(argc, argv, "12:", &src, &opts, &n_flag, &kwargs); reg_extract_args(argc, argv, &args);
if (RB_TYPE_P(src, T_REGEXP)) { if (RB_TYPE_P(args.src, T_REGEXP)) {
re = src; re = args.src;
if (opts != Qnil) {
rb_warn("flags ignored");
}
} }
else { else {
re = rb_class_new_instance(argc, argv, rb_cRegexp); re = reg_init_args(rb_reg_alloc(), args.str, args.enc, args.flags);
} }
rb_reg_check(re);
return RBOOL(onig_check_linear_time(RREGEXP_PTR(re))); return RBOOL(onig_check_linear_time(RREGEXP_PTR(re)));
} }

View File

@ -1703,5 +1703,8 @@ class TestRegexp < Test::Unit::TestCase
assert_send [Regexp, :linear_time?, 'a', Regexp::IGNORECASE] assert_send [Regexp, :linear_time?, 'a', Regexp::IGNORECASE]
assert_not_send [Regexp, :linear_time?, /(a)\1/] assert_not_send [Regexp, :linear_time?, /(a)\1/]
assert_not_send [Regexp, :linear_time?, "(a)\\1"] assert_not_send [Regexp, :linear_time?, "(a)\\1"]
assert_raise(TypeError) {Regexp.linear_time?(nil)}
assert_raise(TypeError) {Regexp.linear_time?(Regexp.allocate)}
end end
end end