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:
parent
8667e8b186
commit
415059abf1
3 changed files with 123 additions and 11 deletions
|
@ -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>
|
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:
|
* enc/iso_8859_14.c, test/ruby/enc/test_case_comprehensive.rb:
|
||||||
|
|
61
io.c
61
io.c
|
@ -3011,11 +3011,16 @@ rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc)
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct getline_arg {
|
||||||
|
VALUE io;
|
||||||
|
VALUE rs;
|
||||||
|
long limit;
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
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;
|
VALUE rs = rb_rs, lim = Qnil;
|
||||||
rb_io_t *fptr;
|
|
||||||
|
|
||||||
rb_check_arity(argc, 0, 2);
|
rb_check_arity(argc, 0, 2);
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
|
@ -3033,6 +3038,16 @@ prepare_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit, VALUE io)
|
||||||
if (!NIL_P(rs))
|
if (!NIL_P(rs))
|
||||||
StringValue(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)) {
|
if (!NIL_P(rs)) {
|
||||||
rb_encoding *enc_rs, *enc_io;
|
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) {
|
if (rs == rb_default_rs) {
|
||||||
rs = rb_enc_str_new(0, 0, enc_io);
|
rs = rb_enc_str_new(0, 0, enc_io);
|
||||||
rb_str_buf_cat_ascii(rs, "\n");
|
rb_str_buf_cat_ascii(rs, "\n");
|
||||||
|
*rsp = rs;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
|
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
|
static VALUE
|
||||||
|
@ -3326,6 +3347,8 @@ rb_io_readline(int argc, VALUE *argv, VALUE io)
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE io_readlines(VALUE rs, long limit, VALUE io);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* ios.readlines(sep=$/) -> array
|
* ios.readlines(sep=$/) -> array
|
||||||
|
@ -3347,10 +3370,18 @@ rb_io_readline(int argc, VALUE *argv, VALUE io)
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_io_readlines(int argc, VALUE *argv, VALUE io)
|
rb_io_readlines(int argc, VALUE *argv, VALUE io)
|
||||||
{
|
{
|
||||||
VALUE line, ary, rs;
|
VALUE rs;
|
||||||
long limit;
|
long limit;
|
||||||
|
|
||||||
prepare_getline_args(argc, argv, &rs, &limit, io);
|
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)
|
if (limit == 0)
|
||||||
rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
|
rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
|
||||||
ary = rb_ary_new();
|
ary = rb_ary_new();
|
||||||
|
@ -9695,13 +9726,15 @@ open_key_args(int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
io_s_foreach(struct foreach_arg *arg)
|
io_s_foreach(struct getline_arg *arg)
|
||||||
{
|
{
|
||||||
VALUE str;
|
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_yield(str);
|
||||||
}
|
}
|
||||||
|
rb_lastline_set(Qnil);
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9737,18 +9770,21 @@ rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
|
||||||
VALUE opt;
|
VALUE opt;
|
||||||
int orig_argc = argc;
|
int orig_argc = argc;
|
||||||
struct foreach_arg arg;
|
struct foreach_arg arg;
|
||||||
|
struct getline_arg garg;
|
||||||
|
|
||||||
argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
|
argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
|
||||||
RETURN_ENUMERATOR(self, orig_argc, argv);
|
RETURN_ENUMERATOR(self, orig_argc, argv);
|
||||||
|
extract_getline_args(argc-1, argv+1, &garg.rs, &garg.limit);
|
||||||
open_key_args(argc, argv, opt, &arg);
|
open_key_args(argc, argv, opt, &arg);
|
||||||
if (NIL_P(arg.io)) return Qnil;
|
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
|
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;
|
VALUE opt;
|
||||||
struct foreach_arg arg;
|
struct foreach_arg arg;
|
||||||
|
struct getline_arg garg;
|
||||||
|
|
||||||
argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
|
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);
|
open_key_args(argc, argv, opt, &arg);
|
||||||
if (NIL_P(arg.io)) return Qnil;
|
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
|
static VALUE
|
||||||
|
|
|
@ -3276,4 +3276,72 @@ End
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end if File::BINARY != 0
|
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
|
end
|
||||||
|
|
Loading…
Reference in a new issue