mruby-io/io.c: implement `_read_buf` in C
MODIFY
mrbgems/mruby-io/mrblib/io.rb
mrbgems/mruby-io/mrblib/io.rb
@@ -9,8 +9,6 @@ class IO
SEEK_CUR = 1
SEEK_END = 2
- BUF_SIZE = 4096
-
def self.open(*args, &block)
io = self.new(*args)
@@ -144,11 +142,6 @@ class IO
0
end
- def _read_buf
- return @buf if @buf && @buf.bytesize > 0
- sysread(BUF_SIZE, @buf)
- end
-
def ungetc(substr)
raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String)
if @buf.empty?

MODIFY
mrbgems/mruby-io/src/io.c
mrbgems/mruby-io/src/io.c
@@ -1492,6 +1492,20 @@ mrb_io_bufread(mrb_state *mrb, mrb_value self)
return io_bufread(mrb, str, len);
}
+#define BUF_SIZE 4096
+
+static mrb_value
+mrb_io_read_buf(mrb_state *mrb, mrb_value self)
+{
+ mrb_value buf = mrb_iv_get(mrb, self, MRB_IVSYM(buf));
+ if (!mrb_nil_p(buf)) {
+ mrb_ensure_string_type(mrb, buf);
+ if (RSTRING_LEN(buf) > 0) return buf;
+ }
+ mrb_str_modify(mrb, RSTRING(buf));
+ return mrb_io_sysread_common(mrb, sysread, self, buf, BUF_SIZE, 0);
+}
+
static mrb_value
mrb_io_readchar(mrb_state *mrb, mrb_value self)
{
@@ -1564,6 +1578,7 @@ mrb_init_io(mrb_state *mrb)
mrb_define_method(mrb, io, "pread", mrb_io_pread, MRB_ARGS_ANY()); /* ruby 2.5 feature */
mrb_define_method(mrb, io, "pwrite", mrb_io_pwrite, MRB_ARGS_ANY()); /* ruby 2.5 feature */
+ mrb_define_method(mrb, io, "_read_buf", mrb_io_read_buf, MRB_ARGS_NONE());
mrb_define_method(mrb, io, "_readchar", mrb_io_readchar, MRB_ARGS_NONE());
mrb_define_class_method(mrb, io, "_bufread", mrb_io_bufread, MRB_ARGS_REQ(2));
}

MODIFY
mrbgems/mruby-io/test/io.rb
mrbgems/mruby-io/test/io.rb
@@ -140,9 +140,10 @@ assert('IO#read', '15.2.20.5.14') do
end
assert "IO#read(n) with n > IO::BUF_SIZE" do
+ buf_size = 4096 # copied from io.c
skip "pipe is not supported on this platform" if MRubyIOTestUtil.win?
IO.pipe do |r,w|
- n = IO::BUF_SIZE+1
+ n = buf_size+1
w.write 'a'*n
assert_equal 'a'*n, r.read(n)
end

mruby-io/io.c: implement `_read_buf` in C