1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

io.c: convert arguments just once

* io.c (rb_io_s_foreach, rb_io_s_readlines): convert arguments
  just once before reading, instead of conversions for each lines.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55603 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2016-07-07 07:31:09 +00:00
parent 8667e8b186
commit 415059abf1
3 changed files with 123 additions and 11 deletions

View file

@ -1,3 +1,8 @@
Thu Jul 7 16:31:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* io.c (rb_io_s_foreach, rb_io_s_readlines): convert arguments
just once before reading, instead of conversions for each lines.
Wed Jul 6 19:54:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
* enc/iso_8859_14.c, test/ruby/enc/test_case_comprehensive.rb:

61
io.c
View file

@ -3011,11 +3011,16 @@ rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc)
return str;
}
struct getline_arg {
VALUE io;
VALUE rs;
long limit;
};
static void
prepare_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit, VALUE io)
extract_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit)
{
VALUE rs = rb_rs, lim = Qnil;
rb_io_t *fptr;
rb_check_arity(argc, 0, 2);
if (argc == 1) {
@ -3033,6 +3038,16 @@ prepare_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit, VALUE io)
if (!NIL_P(rs))
StringValue(rs);
}
*rsp = rs;
*limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
}
static void
check_getline_args(VALUE *rsp, long *limit, VALUE io)
{
rb_io_t *fptr;
VALUE rs = *rsp;
if (!NIL_P(rs)) {
rb_encoding *enc_rs, *enc_io;
@ -3045,6 +3060,7 @@ prepare_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit, VALUE io)
if (rs == rb_default_rs) {
rs = rb_enc_str_new(0, 0, enc_io);
rb_str_buf_cat_ascii(rs, "\n");
*rsp = rs;
}
else {
rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
@ -3053,8 +3069,13 @@ prepare_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit, VALUE io)
}
}
}
*rsp = rs;
*limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
}
static void
prepare_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit, VALUE io)
{
extract_getline_args(argc, argv, rsp, limit);
check_getline_args(rsp, limit, io);
}
static VALUE
@ -3326,6 +3347,8 @@ rb_io_readline(int argc, VALUE *argv, VALUE io)
return line;
}
static VALUE io_readlines(VALUE rs, long limit, VALUE io);
/*
* call-seq:
* ios.readlines(sep=$/) -> array
@ -3347,10 +3370,18 @@ rb_io_readline(int argc, VALUE *argv, VALUE io)
static VALUE
rb_io_readlines(int argc, VALUE *argv, VALUE io)
{
VALUE line, ary, rs;
VALUE rs;
long limit;
prepare_getline_args(argc, argv, &rs, &limit, io);
return io_readlines(rs, limit, io);
}
static VALUE
io_readlines(VALUE rs, long limit, VALUE io)
{
VALUE line, ary;
if (limit == 0)
rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
ary = rb_ary_new();
@ -9695,13 +9726,15 @@ open_key_args(int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
}
static VALUE
io_s_foreach(struct foreach_arg *arg)
io_s_foreach(struct getline_arg *arg)
{
VALUE str;
while (!NIL_P(str = rb_io_gets_m(arg->argc, arg->argv, arg->io))) {
while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->io))) {
rb_lastline_set(str);
rb_yield(str);
}
rb_lastline_set(Qnil);
return Qnil;
}
@ -9737,18 +9770,21 @@ rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
VALUE opt;
int orig_argc = argc;
struct foreach_arg arg;
struct getline_arg garg;
argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
RETURN_ENUMERATOR(self, orig_argc, argv);
extract_getline_args(argc-1, argv+1, &garg.rs, &garg.limit);
open_key_args(argc, argv, opt, &arg);
if (NIL_P(arg.io)) return Qnil;
return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
}
static VALUE
io_s_readlines(struct foreach_arg *arg)
io_s_readlines(struct getline_arg *arg)
{
return rb_io_readlines(arg->argc, arg->argv, arg->io);
return io_readlines(arg->rs, arg->limit, arg->io);
}
/*
@ -9774,11 +9810,14 @@ rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
{
VALUE opt;
struct foreach_arg arg;
struct getline_arg garg;
argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
extract_getline_args(argc-1, argv+1, &garg.rs, &garg.limit);
open_key_args(argc, argv, opt, &arg);
if (NIL_P(arg.io)) return Qnil;
return rb_ensure(io_s_readlines, (VALUE)&arg, rb_io_close, arg.io);
check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
}
static VALUE

View file

@ -3276,4 +3276,72 @@ End
end
end
end if File::BINARY != 0
if RUBY_ENGINE == "ruby" # implementation details
def test_foreach_rs_conversion
make_tempfile {|t|
a = []
rs = Struct.new(:count).new(0)
def rs.to_str; self.count += 1; "\n"; end
IO.foreach(t.path, rs) {|x| a << x }
assert_equal(["foo\n", "bar\n", "baz\n"], a)
assert_equal(1, rs.count)
}
end
def test_foreach_rs_invalid
make_tempfile {|t|
rs = Object.new
def rs.to_str; raise "invalid rs"; end
assert_raise(RuntimeError) do
IO.foreach(t.path, rs, mode:"w") {}
end
assert_equal(["foo\n", "bar\n", "baz\n"], IO.foreach(t.path).to_a)
}
end
def test_foreach_limit_conversion
make_tempfile {|t|
a = []
lim = Struct.new(:count).new(0)
def lim.to_int; self.count += 1; -1; end
IO.foreach(t.path, lim) {|x| a << x }
assert_equal(["foo\n", "bar\n", "baz\n"], a)
assert_equal(1, lim.count)
}
end
def test_foreach_limit_invalid
make_tempfile {|t|
lim = Object.new
def lim.to_int; raise "invalid limit"; end
assert_raise(RuntimeError) do
IO.foreach(t.path, lim, mode:"w") {}
end
assert_equal(["foo\n", "bar\n", "baz\n"], IO.foreach(t.path).to_a)
}
end
def test_readlines_rs_invalid
make_tempfile {|t|
rs = Object.new
def rs.to_str; raise "invalid rs"; end
assert_raise(RuntimeError) do
IO.readlines(t.path, rs, mode:"w")
end
assert_equal(["foo\n", "bar\n", "baz\n"], IO.readlines(t.path))
}
end
def test_readlines_limit_invalid
make_tempfile {|t|
lim = Object.new
def lim.to_int; raise "invalid limit"; end
assert_raise(RuntimeError) do
IO.readlines(t.path, lim, mode:"w")
end
assert_equal(["foo\n", "bar\n", "baz\n"], IO.readlines(t.path))
}
end
end
end