[前][次][番号順一覧][スレッド一覧]

ruby-changes:43530

From: nobu <ko1@a...>
Date: Thu, 7 Jul 2016 16:31:16 +0900 (JST)
Subject: [ruby-changes:43530] nobu:r55603 (trunk): io.c: convert arguments just once

nobu	2016-07-07 16:31:09 +0900 (Thu, 07 Jul 2016)

  New Revision: 55603

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=55603

  Log:
    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.

  Modified files:
    trunk/ChangeLog
    trunk/io.c
    trunk/test/ruby/test_io.rb
Index: test/ruby/test_io.rb
===================================================================
--- test/ruby/test_io.rb	(revision 55602)
+++ test/ruby/test_io.rb	(revision 55603)
@@ -3276,4 +3276,72 @@ End https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L3276
       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
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 55602)
+++ ChangeLog	(revision 55603)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Jul  7 16:31:07 2016  Nobuyoshi Nakada  <nobu@r...>
+
+	* 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@i...>
 
 	* enc/iso_8859_14.c, test/ruby/enc/test_case_comprehensive.rb:
Index: io.c
===================================================================
--- io.c	(revision 55602)
+++ io.c	(revision 55603)
@@ -3011,11 +3011,16 @@ rb_io_getline_fast(rb_io_t *fptr, rb_enc https://github.com/ruby/ruby/blob/trunk/io.c#L3011
     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 *ar https://github.com/ruby/ruby/blob/trunk/io.c#L3038
         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 *ar https://github.com/ruby/ruby/blob/trunk/io.c#L3060
             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 *ar https://github.com/ruby/ruby/blob/trunk/io.c#L3069
             }
 	}
     }
-    *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, VA https://github.com/ruby/ruby/blob/trunk/io.c#L3347
     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, VA https://github.com/ruby/ruby/blob/trunk/io.c#L3370
 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, VAL https://github.com/ruby/ruby/blob/trunk/io.c#L9726
 }
 
 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, V https://github.com/ruby/ruby/blob/trunk/io.c#L9770
     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, https://github.com/ruby/ruby/blob/trunk/io.c#L9810
 {
     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

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]