-/* Copyright (C) 1995,1996,1998,1999,2000,2001,2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1998,1999,2000,2001,2002, 2003, 2005, 2006 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
\f
-#if HAVE_CONFIG_H
+#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
has been written to, but this is only updated after a flush.
read_pos and write_pos in principle should be equal, but this is only true
when rw_active is SCM_PORT_NEITHER.
-*/
+
+ ENHANCE-ME - output blocks:
+
+ The current code keeps an output string as a single block. That means
+ when the size is increased the entire old contents must be copied. It'd
+ be more efficient to begin a new block when the old one is full, so
+ there's no re-copying of previous data.
+
+ To make seeking efficient, keeping the pieces in a vector might be best,
+ though appending is probably the most common operation. The size of each
+ block could be progressively increased, so the bigger the string the
+ bigger the blocks.
+
+ When `get-output-string' is called the blocks have to be coalesced into a
+ string, the result could be kept as a single big block. If blocks were
+ strings then `get-output-string' could notice when there's just one and
+ return that with a copy-on-write (though repeated calls to
+ `get-output-string' are probably unlikely).
+
+ Another possibility would be to extend the port mechanism to let SCM
+ strings come through directly from `display' and friends. That way if a
+ big string is written it can be kept as a copy-on-write, saving time
+ copying and maybe saving some space. */
+
scm_t_bits scm_tc16_strport;
/* reset buffer. */
{
pt->stream = SCM_UNPACK (new_stream);
- pt->read_buf = pt->write_buf = dst;
+ pt->read_buf = pt->write_buf = (unsigned char *)dst;
pt->read_pos = pt->write_pos = pt->write_buf + index;
pt->write_end = pt->write_buf + pt->write_buf_size;
pt->read_end = pt->read_buf + pt->read_buf_size;
#define SCM_WRITE_BLOCK 80
/* ensure that write_pos < write_end by enlarging the buffer when
- necessary. update read_buf to account for written chars. */
+ necessary. update read_buf to account for written chars.
+
+ The buffer is enlarged by 1.5 times, plus SCM_WRITE_BLOCK. Adding just a
+ fixed amount is no good, because there's a block copy for each increment,
+ and that copying would take quadratic time. In the past it was found to
+ be very slow just adding 80 bytes each time (eg. about 10 seconds for
+ writing a 100kbyte string). */
+
static void
st_flush (SCM port)
{
if (pt->write_pos == pt->write_end)
{
- st_resize_port (pt, pt->write_buf_size + SCM_WRITE_BLOCK);
+ st_resize_port (pt, pt->write_buf_size * 3 / 2 + SCM_WRITE_BLOCK);
}
pt->read_pos = pt->write_pos;
if (pt->read_pos > pt->read_end)
else
str = scm_c_substring (str, 0, str_len);
- scm_pthread_mutex_lock (&scm_i_port_table_mutex);
+ scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
z = scm_new_port_table_entry (scm_tc16_strport);
pt = SCM_PTAB_ENTRY(z);
SCM_SETSTREAM (z, SCM_UNPACK (str));
SCM_SET_CELL_TYPE(z, scm_tc16_strport|modes);
/* see above why we can use scm_i_string_chars here. */
- pt->write_buf = pt->read_buf = (char *)scm_i_string_chars (str);
+ pt->write_buf = pt->read_buf = (unsigned char *) scm_i_string_chars (str);
pt->read_pos = pt->write_pos = pt->read_buf + c_pos;
pt->write_buf_size = pt->read_buf_size = str_len;
pt->write_end = pt->read_end = pt->read_buf + pt->read_buf_size;
pt->rw_random = 1;
- pthread_mutex_unlock (&scm_i_port_table_mutex);
+ scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
/* ensure write_pos is writable. */
if ((modes & SCM_WRTNG) && pt->write_pos == pt->write_end)