From 56c48d14ac99f0c7399a09873bd29d2120c48dbe Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Sun, 1 May 2016 14:29:17 +0200 Subject: [PATCH] scm_fill_input can guarantee a minimum fill amount * libguile/ports.h (scm_fill_input): Add "minimum_size" argument. Adapt all callers to pass 0 as this argument. * libguile/ports.c (scm_i_read): Inline into scm_fill_input. (scm_fill_input): "minimum_size" argument ensures that there are a certain number of bytes available, or EOF. Instead of shrinking the read buffer, only fill by the read_buffering amount, or the minimum_size, whichever is larger. * libguile/r6rs-ports.c: * libguile/read.c: Adapt scm_fill_input callers. --- libguile/ports.c | 77 +++++++++++++++++++++++++++---------------- libguile/ports.h | 2 +- libguile/r6rs-ports.c | 2 +- libguile/read.c | 2 +- 4 files changed, 52 insertions(+), 31 deletions(-) diff --git a/libguile/ports.c b/libguile/ports.c index 319b5f5fa..13e28954a 100644 --- a/libguile/ports.c +++ b/libguile/ports.c @@ -1414,7 +1414,7 @@ get_byte_or_eof (SCM port) return ret; } - buf = scm_fill_input (port); + buf = scm_fill_input (port, 0); buf_bv = scm_port_buffer_bytevector (buf); buf_cur = scm_port_buffer_cur (buf); buf_end = scm_port_buffer_end (buf); @@ -1453,7 +1453,7 @@ peek_byte_or_eof (SCM port) return ret; } - buf = scm_fill_input (port); + buf = scm_fill_input (port, 0); buf_bv = scm_port_buffer_bytevector (buf); buf_cur = scm_port_buffer_cur (buf); buf_end = scm_port_buffer_end (buf); @@ -1495,21 +1495,6 @@ scm_i_read_bytes (SCM port, SCM dst, size_t start, size_t count) return filled; } -/* scm_i_read is used internally to add bytes to the given port - buffer. If the number of available bytes in the buffer does not - increase after a call to scm_i_read, that indicates EOF. */ -static void -scm_i_read (SCM port, SCM buf) -{ - size_t count; - - count = scm_i_read_bytes (port, scm_port_buffer_bytevector (buf), - scm_to_size_t (scm_port_buffer_end (buf)), - scm_port_buffer_can_put (buf)); - scm_port_buffer_did_put (buf, count); - scm_port_buffer_set_has_eof_p (buf, scm_from_bool (count == 0)); -} - /* Used by an application to read arbitrary number of bytes from an SCM port. Same semantics as libc read, except that scm_c_read_bytes only returns less than SIZE bytes if at end-of-file. @@ -1548,7 +1533,7 @@ scm_c_read_bytes (SCM port, SCM dst, size_t start, size_t count) buffer directly. */ if (to_read < pt->read_buffering) { - read_buf = scm_fill_input (port); + read_buf = scm_fill_input (port, 0); did_read = scm_port_buffer_take (read_buf, dst_ptr, to_read); dst_ptr += did_read; to_read -= did_read; @@ -1598,7 +1583,7 @@ scm_c_read (SCM port, void *buffer, size_t size) while (copied < size) { size_t count; - read_buf = scm_fill_input (port); + read_buf = scm_fill_input (port, 0); count = scm_port_buffer_take (read_buf, dst + copied, size - copied); copied += count; if (count == 0) @@ -2451,26 +2436,62 @@ scm_flush (SCM port) } SCM -scm_fill_input (SCM port) +scm_fill_input (SCM port, size_t minimum_size) { scm_t_port *pt = SCM_PTAB_ENTRY (port); SCM read_buf = pt->read_buf; + size_t buffered = scm_port_buffer_can_take (read_buf); - if (scm_port_buffer_can_take (read_buf) || - scm_is_true (scm_port_buffer_has_eof_p (read_buf))) + if (minimum_size == 0) + minimum_size = 1; + + if (buffered >= minimum_size + || scm_is_true (scm_port_buffer_has_eof_p (read_buf))) return read_buf; if (pt->rw_random) scm_flush (pt->port); - /* It could be that putback caused us to enlarge the buffer; now that - we've read all the bytes we need to shrink it again. */ - if (scm_port_buffer_size (read_buf) != pt->read_buffering) - read_buf = pt->read_buf = scm_c_make_port_buffer (pt->read_buffering); - else + /* Prepare to read. Make sure there is enough space in the buffer for + minimum_size, and ensure that cur is zero so that we fill towards + the end of the buffer. */ + if (minimum_size > scm_port_buffer_size (read_buf)) + { + /* Grow the read buffer. */ + SCM new_buf = scm_c_make_port_buffer (minimum_size); + scm_port_buffer_reset (new_buf); + scm_port_buffer_put (new_buf, + scm_port_buffer_take_pointer (read_buf), + buffered); + pt->read_buf = read_buf = new_buf; + } + else if (buffered == 0) scm_port_buffer_reset (read_buf); + else + { + const scm_t_uint8 *to_shift = scm_port_buffer_take_pointer (read_buf); + scm_port_buffer_reset (read_buf); + memmove (scm_port_buffer_put_pointer (read_buf), to_shift, buffered); + scm_port_buffer_did_put (read_buf, buffered); + } - scm_i_read (port, read_buf); + while (buffered < minimum_size + && !scm_is_true (scm_port_buffer_has_eof_p (read_buf))) + { + size_t count; + size_t buffering = pt->read_buffering; + size_t to_read; + + if (pt->read_buffering < minimum_size) + buffering = minimum_size; + to_read = buffering - buffered; + + count = scm_i_read_bytes (port, scm_port_buffer_bytevector (read_buf), + buffered, to_read); + buffered += count; + scm_port_buffer_did_put (read_buf, count); + scm_port_buffer_set_has_eof_p (read_buf, scm_from_bool (count == 0)); + } return read_buf; } diff --git a/libguile/ports.h b/libguile/ports.h index 2a6e42c8b..189141fe3 100644 --- a/libguile/ports.h +++ b/libguile/ports.h @@ -310,7 +310,7 @@ SCM_API SCM scm_unread_string (SCM str, SCM port); /* Manipulating the buffers. */ SCM_API SCM scm_setvbuf (SCM port, SCM mode, SCM size); -SCM_API SCM scm_fill_input (SCM port); +SCM_API SCM scm_fill_input (SCM port, size_t minimum_size); SCM_INTERNAL size_t scm_take_from_input_buffers (SCM port, char *dest, size_t read_len); SCM_API SCM scm_drain_input (SCM port); SCM_API void scm_end_input (SCM port); diff --git a/libguile/r6rs-ports.c b/libguile/r6rs-ports.c index 8a7fddd3b..aea1c3aba 100644 --- a/libguile/r6rs-ports.c +++ b/libguile/r6rs-ports.c @@ -474,7 +474,7 @@ SCM_DEFINE (scm_get_bytevector_some, "get-bytevector-some", 1, 0, 0, SCM_VALIDATE_BINARY_INPUT_PORT (1, port); - buf = scm_fill_input (port); + buf = scm_fill_input (port, 0); size = scm_port_buffer_can_take (buf); if (size == 0) { diff --git a/libguile/read.c b/libguile/read.c index 20de0bb9b..cd90b205a 100644 --- a/libguile/read.c +++ b/libguile/read.c @@ -2073,7 +2073,7 @@ scm_i_scan_for_encoding (SCM port) if (scm_port_buffer_can_take (buf) == 0) { /* We can use the read buffer, and thus avoid a seek. */ - buf = scm_fill_input (port); + buf = scm_fill_input (port, 0); bytes_read = scm_port_buffer_can_take (buf); if (bytes_read > SCM_ENCODING_SEARCH_SIZE) bytes_read = SCM_ENCODING_SEARCH_SIZE;