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>
|
||||
|
||||
* 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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue