aboutsummaryrefslogtreecommitdiffstats
path: root/io.c
diff options
context:
space:
mode:
authorJean Boussier <byroot@ruby-lang.org>2022-11-29 10:39:56 +0100
committerJean Boussier <jean.boussier@gmail.com>2022-12-02 09:53:57 +0100
commit7390eb43fe1bfb069af80ba8f73f7dc4999df0fd (patch)
tree4c4a9c984ef196e5edea47afc8c7f9e00ef0abb0 /io.c
parent07ac707758395749611e1028ef18127087d198db (diff)
downloadruby-7390eb43fe1bfb069af80ba8f73f7dc4999df0fd.tar.gz
io.c (read_all): grow the buffer exponentially when size is unknown
[Feature #6047] Currently it's grown by `BUFSIZ` (1024) on every iteration which is bit wasteful. Instead we can double the capacity whenever there is less than `BUFSIZ` capacity left.
Diffstat (limited to 'io.c')
-rw-r--r--io.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/io.c b/io.c
index 3b40950aa0..33226ec7cb 100644
--- a/io.c
+++ b/io.c
@@ -167,6 +167,8 @@ off_t __syscall(quad_t number, ...);
#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
#define IO_WBUF_CAPA_MIN 8192
+#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
+
/* define system APIs */
#ifdef _WIN32
#undef open
@@ -3244,7 +3246,9 @@ io_setstrbuf(VALUE *str, long len)
}
len -= clen;
}
- rb_str_modify_expand(*str, len);
+ if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
+ rb_str_modify_expand(*str, len);
+ }
return FALSE;
}
@@ -3327,7 +3331,17 @@ read_all(rb_io_t *fptr, long siz, VALUE str)
pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
if (bytes < siz) break;
siz += BUFSIZ;
- rb_str_modify_expand(str, BUFSIZ);
+
+ size_t capa = rb_str_capacity(str);
+ if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
+ if (capa < BUFSIZ) {
+ capa = BUFSIZ;
+ }
+ else if (capa > IO_MAX_BUFFER_GROWTH) {
+ capa = IO_MAX_BUFFER_GROWTH;
+ }
+ rb_str_modify_expand(str, capa);
+ }
}
if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
str = io_enc_str(str, fptr);