mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-io/io.c: change the implementation of read buffers
The original implementations used plain Ruby strings referenced from instance variable (`@buf`) as buffers. We replaced those buffers by C structure (`struct mrb_io_buf`) referenced directly from `fptr`. The result is significant improvement of both performance and memory consumption. Our simple benchmarks (reading `README.md` 10,000 times) runs 5+ times faster, and `mrbtest` test suites consumes 85% less memory. Recent changes on `mruby-io` is preparation for this improvement.
This commit is contained in:
@@ -23,10 +23,19 @@ extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define MRB_IO_BUF_SIZE 4096
|
||||
|
||||
struct mrb_io_buf {
|
||||
short start;
|
||||
short len;
|
||||
char mem[MRB_IO_BUF_SIZE];
|
||||
};
|
||||
|
||||
struct mrb_io {
|
||||
int fd; /* file descriptor, or -1 */
|
||||
int fd2; /* file descriptor to write if it's different from fd, or -1 */
|
||||
int pid; /* child's pid (for pipes) */
|
||||
struct mrb_io_buf *buf;
|
||||
unsigned int readable:1,
|
||||
writable:1,
|
||||
eof:1,
|
||||
|
||||
+189
-149
@@ -301,6 +301,16 @@ io_free(mrb_state *mrb, void *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
io_buf_init(mrb_state *mrb, struct mrb_io *fptr)
|
||||
{
|
||||
if (fptr->readable) {
|
||||
fptr->buf = mrb_malloc(mrb, sizeof(struct mrb_io_buf));
|
||||
fptr->buf->start = 0;
|
||||
fptr->buf->len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct mrb_io *
|
||||
io_alloc(mrb_state *mrb)
|
||||
{
|
||||
@@ -310,6 +320,7 @@ io_alloc(mrb_state *mrb)
|
||||
fptr->fd = -1;
|
||||
fptr->fd2 = -1;
|
||||
fptr->pid = 0;
|
||||
fptr->buf = 0;
|
||||
fptr->readable = 0;
|
||||
fptr->writable = 0;
|
||||
fptr->sync = 0;
|
||||
@@ -443,14 +454,13 @@ io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
pid = pi.dwProcessId;
|
||||
}
|
||||
|
||||
mrb_iv_set(mrb, io, MRB_IVSYM(buf), mrb_str_new_cstr(mrb, ""));
|
||||
|
||||
fptr = io_alloc(mrb);
|
||||
fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0);
|
||||
fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0);
|
||||
fptr->pid = pid;
|
||||
fptr->readable = OPEN_READABLE_P(flags);
|
||||
fptr->writable = OPEN_WRITABLE_P(flags);
|
||||
io_buf_init(mrb, fptr);
|
||||
|
||||
DATA_TYPE(io) = &mrb_io_type;
|
||||
DATA_PTR(io) = fptr;
|
||||
@@ -551,14 +561,13 @@ io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
fd = pw[1];
|
||||
}
|
||||
|
||||
mrb_iv_set(mrb, io, MRB_IVSYM(buf), mrb_str_new_cstr(mrb, ""));
|
||||
|
||||
fptr = io_alloc(mrb);
|
||||
fptr->fd = fd;
|
||||
fptr->fd2 = write_fd;
|
||||
fptr->pid = pid;
|
||||
fptr->readable = OPEN_READABLE_P(flags);
|
||||
fptr->writable = OPEN_WRITABLE_P(flags);
|
||||
io_buf_init(mrb, fptr);
|
||||
|
||||
DATA_TYPE(io) = &mrb_io_type;
|
||||
DATA_PTR(io) = fptr;
|
||||
@@ -598,22 +607,10 @@ symdup(mrb_state *mrb, int fd, mrb_bool *failed)
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
io_buf(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
mrb_value buf = mrb_iv_get(mrb, io, MRB_IVSYM(buf));
|
||||
if (!mrb_string_p(buf)) {
|
||||
buf = mrb_str_new_cstr(mrb, "");
|
||||
mrb_iv_set(mrb, io, MRB_IVSYM(buf), buf);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
io_init_copy(mrb_state *mrb, mrb_value copy)
|
||||
{
|
||||
mrb_value orig = mrb_get_arg1(mrb);
|
||||
mrb_value buf;
|
||||
struct mrb_io *fptr_copy;
|
||||
struct mrb_io *fptr_orig;
|
||||
mrb_bool failed = TRUE;
|
||||
@@ -629,9 +626,7 @@ io_init_copy(mrb_state *mrb, mrb_value copy)
|
||||
|
||||
DATA_TYPE(copy) = &mrb_io_type;
|
||||
DATA_PTR(copy) = fptr_copy;
|
||||
|
||||
buf = io_buf(mrb, orig);
|
||||
mrb_iv_set(mrb, copy, MRB_IVSYM(buf), mrb_str_dup(mrb, buf));
|
||||
io_buf_init(mrb, fptr_copy);
|
||||
|
||||
fptr_copy->fd = symdup(mrb, fptr_orig->fd, &failed);
|
||||
if (failed) {
|
||||
@@ -716,8 +711,6 @@ io_init(mrb_state *mrb, mrb_value io)
|
||||
}
|
||||
flags = io_mode_to_flags(mrb, mode);
|
||||
|
||||
mrb_iv_set(mrb, io, MRB_IVSYM(buf), mrb_str_new_cstr(mrb, ""));
|
||||
|
||||
fptr = (struct mrb_io*)DATA_PTR(io);
|
||||
if (fptr != NULL) {
|
||||
fptr_finalize(mrb, fptr, TRUE);
|
||||
@@ -731,6 +724,7 @@ io_init(mrb_state *mrb, mrb_value io)
|
||||
fptr->fd = (int)fd;
|
||||
fptr->readable = OPEN_READABLE_P(flags);
|
||||
fptr->writable = OPEN_WRITABLE_P(flags);
|
||||
io_buf_init(mrb, fptr);
|
||||
return io;
|
||||
}
|
||||
|
||||
@@ -792,6 +786,11 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
|
||||
/* Note: we don't raise an exception when waitpid(3) fails */
|
||||
}
|
||||
|
||||
if (fptr->buf) {
|
||||
mrb_free(mrb, fptr->buf);
|
||||
fptr->buf = NULL;
|
||||
}
|
||||
|
||||
if (!quiet && saved_errno != 0) {
|
||||
errno = saved_errno;
|
||||
mrb_sys_fail(mrb, "fptr_finalize failed");
|
||||
@@ -819,9 +818,8 @@ io_get_write_fptr(mrb_state *mrb, mrb_value io)
|
||||
}
|
||||
|
||||
static int
|
||||
io_get_write_fd(mrb_state *mrb, mrb_value io)
|
||||
io_get_write_fd(struct mrb_io *fptr)
|
||||
{
|
||||
struct mrb_io *fptr = io_get_write_fptr(mrb, io);
|
||||
if (fptr->fd2 == -1) {
|
||||
return fptr->fd;
|
||||
}
|
||||
@@ -930,9 +928,8 @@ eof_error(mrb_state *mrb)
|
||||
static mrb_value
|
||||
io_read_common(mrb_state *mrb,
|
||||
fssize_t (*readfunc)(int, void*, fsize_t, off_t),
|
||||
mrb_value io, mrb_value buf, mrb_int maxlen, off_t offset, int raise)
|
||||
mrb_value io, mrb_value buf, mrb_int maxlen, off_t offset)
|
||||
{
|
||||
struct mrb_io *fptr;
|
||||
int ret;
|
||||
|
||||
if (maxlen < 0) {
|
||||
@@ -953,7 +950,7 @@ io_read_common(mrb_state *mrb,
|
||||
mrb_str_modify(mrb, RSTRING(buf));
|
||||
}
|
||||
|
||||
fptr = io_get_read_fptr(mrb, io);
|
||||
struct mrb_io *fptr = io_get_read_fptr(mrb, io);
|
||||
ret = readfunc(fptr->fd, RSTRING_PTR(buf), (fsize_t)maxlen, offset);
|
||||
if (ret < 0) {
|
||||
mrb_sys_fail(mrb, "sysread failed");
|
||||
@@ -963,9 +960,7 @@ io_read_common(mrb_state *mrb,
|
||||
}
|
||||
if (ret == 0 && maxlen > 0) {
|
||||
fptr->eof = 1;
|
||||
if (raise) {
|
||||
eof_error(mrb);
|
||||
}
|
||||
eof_error(mrb);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
@@ -984,7 +979,7 @@ io_sysread(mrb_state *mrb, mrb_value io)
|
||||
|
||||
mrb_get_args(mrb, "i|S", &maxlen, &buf);
|
||||
|
||||
return io_read_common(mrb, sysread, io, buf, maxlen, 0, 1);
|
||||
return io_read_common(mrb, sysread, io, buf, maxlen, 0);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
@@ -1015,21 +1010,24 @@ static mrb_value
|
||||
io_seek(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
mrb_value pos = io_sysseek(mrb, io);
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
RSTR_SET_LEN(RSTRING(buf), 0);
|
||||
struct mrb_io *fptr = io_get_open_fptr(mrb, io);
|
||||
if (fptr->buf) {
|
||||
fptr->buf->start = 0;
|
||||
fptr->buf->len = 0;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
io_write_common(mrb_state *mrb,
|
||||
fssize_t (*writefunc)(int, const void*, fsize_t, off_t),
|
||||
mrb_value io, mrb_value buf, off_t offset)
|
||||
struct mrb_io *fptr, const void *buf, fsize_t blen, off_t offset)
|
||||
{
|
||||
int fd;
|
||||
fssize_t length;
|
||||
|
||||
fd = io_get_write_fd(mrb, io);
|
||||
length = writefunc(fd, RSTRING_PTR(buf), (fsize_t)RSTRING_LEN(buf), offset);
|
||||
fd = io_get_write_fd(fptr);
|
||||
length = writefunc(fd, buf, blen, offset);
|
||||
if (length == -1) {
|
||||
mrb_sys_fail(mrb, "syswrite");
|
||||
}
|
||||
@@ -1049,7 +1047,7 @@ io_syswrite(mrb_state *mrb, mrb_value io)
|
||||
|
||||
mrb_get_args(mrb, "S", &buf);
|
||||
|
||||
return io_write_common(mrb, syswrite, io, buf, 0);
|
||||
return io_write_common(mrb, syswrite, io_get_write_fptr(mrb, io), RSTRING_PTR(buf), RSTRING_LEN(buf), 0);
|
||||
}
|
||||
|
||||
/* def write(string) */
|
||||
@@ -1080,20 +1078,20 @@ fd_write(mrb_state *mrb, int fd, mrb_value str)
|
||||
static mrb_value
|
||||
io_write(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
int fd = io_get_write_fd(mrb, io);
|
||||
struct mrb_io *fptr = io_get_write_fptr(mrb, io);
|
||||
int fd = io_get_write_fd(fptr);
|
||||
mrb_int len = 0;
|
||||
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
if (RSTRING_LEN(buf) > 0) {
|
||||
if (fptr->buf && fptr->buf->len > 0) {
|
||||
off_t n;
|
||||
|
||||
/* get current position */
|
||||
n = lseek(fd, 0, SEEK_CUR);
|
||||
if (n == -1) mrb_sys_fail(mrb, "lseek");
|
||||
/* move cursor */
|
||||
n = lseek(fd, n - RSTRING_LEN(buf), SEEK_SET);
|
||||
n = lseek(fd, n - fptr->buf->len, SEEK_SET);
|
||||
if (n == -1) mrb_sys_fail(mrb, "lseek(2)");
|
||||
RSTR_SET_LEN(RSTRING(buf), 0);
|
||||
fptr->buf->start = fptr->buf->len = 0;
|
||||
}
|
||||
|
||||
if (mrb_get_argc(mrb) == 1) {
|
||||
@@ -1150,8 +1148,12 @@ io_pos(mrb_state *mrb, mrb_value io)
|
||||
off_t pos = lseek(fptr->fd, 0, SEEK_CUR);
|
||||
if (pos == -1) mrb_sys_fail(mrb, 0);
|
||||
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
return mrb_int_value(mrb, pos - RSTRING_LEN(buf));
|
||||
if (fptr->buf) {
|
||||
return mrb_int_value(mrb, pos - fptr->buf->len);
|
||||
}
|
||||
else {
|
||||
return mrb_int_value(mrb, pos);
|
||||
}
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
@@ -1192,14 +1194,6 @@ time2timeval(mrb_state *mrb, mrb_value time)
|
||||
return t;
|
||||
}
|
||||
|
||||
static int
|
||||
mrb_io_read_data_pending(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
if (RSTRING_LEN(buf) > 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
|
||||
static mrb_value
|
||||
io_s_pipe(mrb_state *mrb, mrb_value klass)
|
||||
@@ -1215,18 +1209,16 @@ io_s_pipe(mrb_state *mrb, mrb_value klass)
|
||||
}
|
||||
|
||||
r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
|
||||
mrb_iv_set(mrb, r, MRB_IVSYM(buf), mrb_str_new_cstr(mrb, ""));
|
||||
fptr_r = io_alloc(mrb);
|
||||
fptr_r->fd = pipes[0];
|
||||
fptr_r->readable = 1;
|
||||
DATA_TYPE(r) = &mrb_io_type;
|
||||
DATA_PTR(r) = fptr_r;
|
||||
io_buf_init(mrb, fptr_r);
|
||||
|
||||
w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
|
||||
mrb_iv_set(mrb, w, MRB_IVSYM(buf), mrb_str_new_cstr(mrb, ""));
|
||||
fptr_w = io_alloc(mrb);
|
||||
fptr_w->fd = pipes[1];
|
||||
fptr_w->readable = 0;
|
||||
fptr_w->writable = 1;
|
||||
fptr_w->sync = 1;
|
||||
DATA_TYPE(w) = &mrb_io_type;
|
||||
@@ -1236,6 +1228,13 @@ io_s_pipe(mrb_state *mrb, mrb_value klass)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
mrb_io_read_data_pending(mrb_state *mrb, struct mrb_io *fptr)
|
||||
{
|
||||
if (fptr->buf && fptr->buf->len > 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
io_s_select(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
@@ -1286,7 +1285,7 @@ io_s_select(mrb_state *mrb, mrb_value klass)
|
||||
fptr = io_get_open_fptr(mrb, read_io);
|
||||
if (fptr->fd >= FD_SETSIZE) continue;
|
||||
FD_SET(fptr->fd, rp);
|
||||
if (mrb_io_read_data_pending(mrb, read_io)) {
|
||||
if (mrb_io_read_data_pending(mrb, fptr)) {
|
||||
pending++;
|
||||
FD_SET(fptr->fd, &pset);
|
||||
}
|
||||
@@ -1522,7 +1521,7 @@ io_pread(mrb_state *mrb, mrb_value io)
|
||||
|
||||
mrb_get_args(mrb, "io|S!", &maxlen, &off, &buf);
|
||||
|
||||
return io_read_common(mrb, pread, io, buf, maxlen, value2off(mrb, off), 1);
|
||||
return io_read_common(mrb, pread, io, buf, maxlen, value2off(mrb, off));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1536,84 +1535,117 @@ io_pwrite(mrb_state *mrb, mrb_value io)
|
||||
|
||||
mrb_get_args(mrb, "So", &buf, &off);
|
||||
|
||||
return io_write_common(mrb, pwrite, io, buf, value2off(mrb, off));
|
||||
return io_write_common(mrb, pwrite, io_get_write_fptr(mrb, io), RSTRING_PTR(buf), RSTRING_LEN(buf), value2off(mrb, off));
|
||||
}
|
||||
#endif /* MRB_WITH_IO_PREAD_PWRITE */
|
||||
|
||||
static mrb_value
|
||||
io_ungetc(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
mrb_value str, buf;
|
||||
struct mrb_io *fptr = io_get_read_fptr(mrb, io);
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
mrb_value str;
|
||||
mrb_int len;
|
||||
|
||||
io_get_read_fptr(mrb, io);
|
||||
mrb_get_args(mrb, "S", &str);
|
||||
buf = io_buf(mrb, io);
|
||||
str = mrb_str_dup(mrb, str);
|
||||
if (RSTRING_LEN(buf) > 0) {
|
||||
mrb_str_cat_str(mrb, str, buf);
|
||||
len = RSTRING_LEN(str);
|
||||
if (len > MRB_IO_BUF_SIZE - buf->len) {
|
||||
fptr->buf = mrb_realloc(mrb, buf, sizeof(struct mrb_io_buf)+buf->len+len-MRB_IO_BUF_SIZE);
|
||||
buf = fptr->buf;
|
||||
}
|
||||
mrb_iv_set(mrb, io, MRB_IVSYM(buf), str);
|
||||
memmove(buf->mem+len, buf->mem+buf->start, buf->len);
|
||||
memcpy(buf->mem, RSTRING_PTR(str), len);
|
||||
buf->start = 0;
|
||||
buf->len += len;
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static void
|
||||
io_bufshift(mrb_state *mrb, struct RString *s, mrb_int len)
|
||||
io_buf_reset(struct mrb_io *fptr)
|
||||
{
|
||||
mrb_int newlen = RSTR_LEN(s)-len;
|
||||
char *p = RSTR_PTR(s);
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
|
||||
mrb_str_modify(mrb, s);
|
||||
memmove(p, p+len, newlen);
|
||||
p[newlen] = '\0';
|
||||
RSTR_SET_LEN(s, newlen);
|
||||
buf->start = 0;
|
||||
buf->len = 0;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
io_bufread(mrb_state *mrb, mrb_value str, mrb_int len)
|
||||
static void
|
||||
io_buf_shift(struct mrb_io *fptr, mrb_int n)
|
||||
{
|
||||
mrb_value str2;
|
||||
struct RString *s = RSTRING(str);
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
|
||||
str2 = mrb_str_new(mrb, RSTR_PTR(s), len);
|
||||
io_bufshift(mrb, s, len);
|
||||
|
||||
return str2;
|
||||
buf->start += n;
|
||||
buf->len -= n;
|
||||
}
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
static mrb_value
|
||||
io_read_buf(mrb_state *mrb, mrb_value io)
|
||||
#ifdef MRB_UTF8_STRING
|
||||
static void
|
||||
io_buf_fill_comp(mrb_state *mrb, struct mrb_io *fptr)
|
||||
{
|
||||
mrb->c->ci->mid = 0;
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
int keep = buf->len;
|
||||
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
if (RSTRING_LEN(buf) > 0) return buf;
|
||||
return io_read_common(mrb, sysread, io, buf, BUF_SIZE, 0, 0);
|
||||
memmove(buf->mem, buf->mem+buf->start, keep);
|
||||
int n = read(fptr->fd, buf->mem+keep, MRB_IO_BUF_SIZE-keep);
|
||||
if (n < 0) mrb_sys_fail(mrb, 0);
|
||||
if (n == 0) fptr->eof = 1;
|
||||
buf->start = 0;
|
||||
buf->len += (short)n;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
io_buf_fill(mrb_state *mrb, struct mrb_io *fptr)
|
||||
{
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
|
||||
if (buf->len > 0) return;
|
||||
|
||||
int n = read(fptr->fd, buf->mem, MRB_IO_BUF_SIZE);
|
||||
if (n < 0) mrb_sys_fail(mrb, 0);
|
||||
if (n == 0) fptr->eof = 1;
|
||||
buf->start = 0;
|
||||
buf->len = (short)n;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
io_eof(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
struct mrb_io *fptr = io_get_read_fptr(mrb, io);
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
io_read_buf(mrb, io);
|
||||
if (RSTRING_LEN(buf) > 0) return mrb_false_value();
|
||||
|
||||
io_buf_fill(mrb, fptr);
|
||||
if (fptr->buf->len > 0) return mrb_false_value();
|
||||
return mrb_bool_value(fptr->eof);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
io_read_all(mrb_state *mrb, mrb_value io, mrb_value outbuf)
|
||||
static void
|
||||
io_buf_cat(mrb_state *mrb, mrb_value outbuf, struct mrb_io *fptr, mrb_int n)
|
||||
{
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
|
||||
mrb_assert(n <= buf->len);
|
||||
mrb_str_cat(mrb, outbuf, buf->mem+buf->start, n);
|
||||
io_buf_shift(fptr, n);
|
||||
}
|
||||
|
||||
static void
|
||||
io_buf_cat_all(mrb_state *mrb, mrb_value outbuf, struct mrb_io *fptr)
|
||||
{
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
|
||||
mrb_str_cat(mrb, outbuf, buf->mem+buf->start, buf->len);
|
||||
io_buf_reset(fptr);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
io_read_all(mrb_state *mrb, struct mrb_io *fptr, mrb_value outbuf)
|
||||
{
|
||||
struct mrb_io *fptr = io_get_read_fptr(mrb, io);
|
||||
for (;;) {
|
||||
io_read_buf(mrb, io);
|
||||
io_buf_fill(mrb, fptr);
|
||||
if (fptr->eof) {
|
||||
return outbuf;
|
||||
}
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
mrb_str_cat_str(mrb, outbuf, buf);
|
||||
RSTR_SET_LEN(RSTRING(buf), 0);
|
||||
io_buf_cat_all(mrb, outbuf, fptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1643,32 +1675,46 @@ io_read(mrb_state *mrb, mrb_value io)
|
||||
}
|
||||
|
||||
if (mrb_nil_p(outbuf)) {
|
||||
outbuf = mrb_str_new_capa(mrb, BUF_SIZE);
|
||||
outbuf = mrb_str_new_capa(mrb, MRB_IO_BUF_SIZE);
|
||||
}
|
||||
if (!length_given) { /* read as much as possible */
|
||||
return io_read_all(mrb, io, outbuf);
|
||||
return io_read_all(mrb, fptr, outbuf);
|
||||
}
|
||||
for (;;) {
|
||||
io_read_buf(mrb, io);
|
||||
io_buf_fill(mrb, fptr);
|
||||
if (fptr->eof || length == 0) {
|
||||
if (RSTRING_LEN(outbuf) == 0)
|
||||
return mrb_nil_value();
|
||||
return outbuf;
|
||||
}
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
if (RSTRING_LEN(buf) < length) {
|
||||
mrb_str_cat_str(mrb, outbuf, buf);
|
||||
length -= RSTRING_LEN(buf);
|
||||
RSTR_SET_LEN(RSTRING(buf), 0);
|
||||
if (fptr->buf->len < length) {
|
||||
length -= fptr->buf->len;
|
||||
io_buf_cat_all(mrb, outbuf, fptr);
|
||||
}
|
||||
else {
|
||||
mrb_str_cat(mrb, outbuf, RSTRING_PTR(buf), length);
|
||||
io_bufshift(mrb, RSTRING(buf), length);
|
||||
io_buf_cat(mrb, outbuf, fptr, length);
|
||||
return outbuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static mrb_int
|
||||
io_find_index(struct mrb_io *fptr, const char *rs, mrb_int rslen)
|
||||
{
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
|
||||
mrb_assert(rslen > 0);
|
||||
const char c = rs[0];
|
||||
const mrb_int limit = buf->len - rslen;
|
||||
for (mrb_int i=buf->start; i<limit; i++) {
|
||||
if (buf->mem[i] == c) {
|
||||
if (memcmp(buf->mem+i, rs, rslen) == 0)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
io_gets(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
@@ -1677,6 +1723,8 @@ io_gets(mrb_state *mrb, mrb_value io)
|
||||
mrb_bool rs_given = FALSE; /* newline break */
|
||||
mrb_bool limit_given = FALSE; /* no limit */
|
||||
mrb_value outbuf;
|
||||
struct mrb_io *fptr = io_get_read_fptr(mrb, io);
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
|
||||
mrb_get_args(mrb, "|o?i?", &rs, &rs_given, &limit, &limit_given);
|
||||
|
||||
@@ -1710,13 +1758,13 @@ io_gets(mrb_state *mrb, mrb_value io)
|
||||
rs = mrb_str_new_lit(mrb, "\n");
|
||||
rs_given = TRUE;
|
||||
}
|
||||
|
||||
/* from now on rs_given==FALSE means no RS */
|
||||
if (mrb_nil_p(rs) && !limit_given) {
|
||||
return io_read_all(mrb, io, mrb_str_new_capa(mrb, BUF_SIZE));
|
||||
return io_read_all(mrb, fptr, mrb_str_new_capa(mrb, MRB_IO_BUF_SIZE));
|
||||
}
|
||||
|
||||
struct mrb_io *fptr = io_get_read_fptr(mrb, io);
|
||||
io_read_buf(mrb, io);
|
||||
io_buf_fill(mrb, fptr);
|
||||
if (fptr->eof) return mrb_nil_value();
|
||||
|
||||
if (limit_given) {
|
||||
@@ -1727,20 +1775,15 @@ io_gets(mrb_state *mrb, mrb_value io)
|
||||
outbuf = mrb_str_new(mrb, NULL, 0);
|
||||
}
|
||||
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
if (!rs_given) { /* no RS; only limit */
|
||||
mrb_assert(limit_given);
|
||||
for (;;) {
|
||||
if (RSTRING_LEN(buf) >= limit) {
|
||||
mrb_str_cat(mrb, outbuf, RSTRING_PTR(buf), limit);
|
||||
io_bufshift(mrb, RSTRING(buf), limit);
|
||||
if (buf->len >= limit) {
|
||||
io_buf_cat(mrb, outbuf, fptr, limit);
|
||||
return outbuf;
|
||||
}
|
||||
mrb_str_cat(mrb, outbuf, RSTRING_PTR(buf), RSTRING_LEN(buf));
|
||||
limit -= RSTRING_LEN(buf);
|
||||
RSTR_SET_LEN(RSTRING(buf), 0);
|
||||
|
||||
io_read_buf(mrb, io);
|
||||
io_buf_cat_all(mrb, outbuf, fptr);
|
||||
io_buf_fill(mrb, fptr);
|
||||
if (fptr->eof) {
|
||||
if (RSTRING_LEN(outbuf) == 0) return mrb_nil_value();
|
||||
return outbuf;
|
||||
@@ -1749,25 +1792,22 @@ io_gets(mrb_state *mrb, mrb_value io)
|
||||
}
|
||||
|
||||
for (;;) { /* with RS */
|
||||
mrb_int idx = mrb_str_index(mrb, buf, RSTRING_PTR(rs), RSTRING_LEN(rs), 0);
|
||||
int rslen = RSTRING_LEN(rs);
|
||||
mrb_int idx = io_find_index(fptr, RSTRING_PTR(rs), rslen);
|
||||
if (idx >= 0) { /* found */
|
||||
mrb_int n = idx+RSTRING_LEN(rs);
|
||||
mrb_int n = idx+rslen;
|
||||
if (limit_given && limit < n) {
|
||||
n = limit;
|
||||
}
|
||||
mrb_str_cat(mrb, outbuf, RSTRING_PTR(buf), n);
|
||||
io_bufshift(mrb, RSTRING(buf), n);
|
||||
io_buf_cat(mrb, outbuf, fptr, n);
|
||||
return outbuf;
|
||||
}
|
||||
if (limit_given && RSTRING_LEN(buf) < limit) {
|
||||
mrb_str_cat(mrb, outbuf, RSTRING_PTR(buf), limit);
|
||||
io_bufshift(mrb, RSTRING(buf), limit);
|
||||
if (limit_given && buf->len < limit) {
|
||||
io_buf_cat(mrb, outbuf, fptr, limit);
|
||||
return outbuf;
|
||||
}
|
||||
mrb_str_cat(mrb, outbuf, RSTRING_PTR(buf), RSTRING_LEN(buf));
|
||||
RSTR_SET_LEN(RSTRING(buf), 0);
|
||||
|
||||
io_read_buf(mrb, io);
|
||||
io_buf_cat_all(mrb, outbuf, fptr);
|
||||
io_buf_fill(mrb, fptr);
|
||||
if (fptr->eof) {
|
||||
if (RSTRING_LEN(outbuf) == 0) return mrb_nil_value();
|
||||
return outbuf;
|
||||
@@ -1800,25 +1840,26 @@ io_readlines(mrb_state *mrb, mrb_value io)
|
||||
static mrb_value
|
||||
io_getc(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
mrb_value buf;
|
||||
mrb_int len = 1;
|
||||
struct mrb_io *fptr = io_get_read_fptr(mrb, io);
|
||||
|
||||
io_read_buf(mrb, io);
|
||||
buf = io_buf(mrb, io);
|
||||
io_buf_fill(mrb, fptr);
|
||||
if (fptr->eof) return mrb_nil_value();
|
||||
#ifdef MRB_UTF8_STRING
|
||||
unsigned char c = RSTRING_PTR(buf)[0];
|
||||
if (c & 0x80) {
|
||||
len = mrb_utf8len(RSTRING_PTR(buf), RSTRING_END(buf));
|
||||
if (len == 1 && RSTRING_LEN(buf) < 4) { /* partial UTF-8 */
|
||||
io_read_buf(mrb, io);
|
||||
buf = io_buf(mrb, io);
|
||||
len = mrb_utf8len(RSTRING_PTR(buf), RSTRING_END(buf));
|
||||
struct mrb_io_buf *buf = fptr->buf;
|
||||
const char *p = &buf->mem[buf->start];
|
||||
if ((*p) & 0x80) {
|
||||
len = mrb_utf8len(p, p+buf->len);
|
||||
if (len == 1 && buf->len < 4) { /* partial UTF-8 */
|
||||
io_buf_fill_comp(mrb, fptr);
|
||||
p = &buf->mem[buf->start];
|
||||
len = mrb_utf8len(p, p+buf->len);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return io_bufread(mrb, buf, len);
|
||||
mrb_value str = mrb_str_new(mrb, fptr->buf->mem+fptr->buf->start, len);
|
||||
io_buf_shift(fptr, len);
|
||||
return str;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
@@ -1834,14 +1875,13 @@ io_readchar(mrb_state *mrb, mrb_value io)
|
||||
static mrb_value
|
||||
io_getbyte(mrb_state *mrb, mrb_value io)
|
||||
{
|
||||
io_read_buf(mrb, io);
|
||||
if (io_get_read_fptr(mrb, io)->eof) {
|
||||
return mrb_nil_value();
|
||||
}
|
||||
mrb_value buf = io_buf(mrb, io);
|
||||
struct RString *b = RSTRING(buf);
|
||||
unsigned char c = RSTR_PTR(b)[0];
|
||||
io_bufshift(mrb, b, 1);
|
||||
struct mrb_io *fptr = io_get_read_fptr(mrb, io);
|
||||
|
||||
io_buf_fill(mrb, fptr);
|
||||
if (fptr->eof) return mrb_nil_value();
|
||||
|
||||
unsigned char c = fptr->buf->mem[fptr->buf->start];
|
||||
io_buf_shift(fptr, 1);
|
||||
return mrb_int_value(mrb, (mrb_int)c);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user