[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] 05/21: Add random_access_p port type method

From: Andy Wingo
Subject: [Guile-commits] 05/21: Add random_access_p port type method
Date: Mon, 16 May 2016 07:39:34 +0000 (UTC)

wingo pushed a commit to branch wip-port-refactor
in repository guile.

commit 6ff542ee7138ad6eb837f5a5ac59572a04ef3e45
Author: Andy Wingo <address@hidden>
Date:   Fri May 13 10:05:23 2016 +0200

    Add random_access_p port type method
    * doc/ref/api-io.texi (I/O Extensions): Update documentation on
      implementing port types.  Document get_natural_buffer_sizes.  Document
      the new random_access_p.
    * libguile/fports.c (scm_i_fdes_to_port, fport_random_access_p):
      (scm_make_fptob): Instead of frobbing rw_random manually, implement a
      random_access_p function.
    * libguile/ports.c (default_random_access_p)
      (scm_set_port_random_access_p): New functions.
      scm_make_port_type, scm_c_make_port_with_encoding): Arrange for
      random_access_p to work.
 doc/ref/api-io.texi |  102 +++++++++++++++++++++++----------------------------
 libguile/fports.c   |    8 +++-
 libguile/ports.c    |   19 ++++++++--
 libguile/ports.h    |    3 ++
 4 files changed, 71 insertions(+), 61 deletions(-)

diff --git a/doc/ref/api-io.texi b/doc/ref/api-io.texi
index 78f7cae..1a9c821 100644
--- a/doc/ref/api-io.texi
+++ b/doc/ref/api-io.texi
@@ -2263,72 +2263,20 @@ interface works internally.
 @cindex ptob
 @tindex scm_t_ptob_descriptor
 @tindex scm_t_port
address@hidden scm_t_port_buffer
 @findex SCM_PTOBNUM
 @vindex scm_ptobs
-Guile's port facility consists of three main data structures.  A port
-type object (ptob) is of type @code{scm_t_ptob_descriptor}, and holds
-pointers to the methods that implement the port type.  A port instance
-is of type @code{scm_t_port}, and holds all state for the port.  Finally
-the read and write buffers are the @code{read_buf} and @code{write_buf}
-members of the port instance, and are of type @code{scm_t_port_buffer}.
+Guile's port facility consists of two main data types: port type objects
+and port instances.  A port type object (or @dfn{ptob}) is of type
address@hidden, and holds pointers to the methods that
+implement the port type.  A port instance is of type @code{scm_t_port},
+and holds all state for the port.
 Given an @code{SCM} variable which points to a port, the corresponding C
 port object can be obtained using the @code{SCM_PTAB_ENTRY} macro.  The
 ptob can be obtained by using @code{SCM_PTOBNUM} to give an index into
 the @code{scm_ptobs} global array.
address@hidden Port buffers
-An input port always has a read buffer and an output port always has a
-write buffer.  @xref{Buffering}.  These buffers are represented in C by
address@hidden objects. 
-The port buffer consists of data as a byte array, pointed to by its
address@hidden field.  The valid data in the buffer is between the
address@hidden and @code{end} indices into @code{buf}; @code{cur} must
-always be less than or equal to @code{end}, which in turn must be less
-than or equal to the buffer size @code{size}.  The @code{buf} pointer is
-actually a pointer to the start of a bytevector, stored in the
address@hidden member.  Using bytevectors to back port buffers allows
-Scheme to manipulate these buffers.
-``Valid data'' for a read buffer is data that has been buffered, but not
-yet read by the user.  A port's @code{read} procedure fills a read
-buffer from the @code{end} element.  For a write buffer, the ``valid
-data'' is data which has been written by the user, but not yet flushed
-to the mutable store.  A port's @code{write} procedure will consume the
-data between @code{cur} and @code{end} (not including @code{end}) and
-advance @code{cur}.
-The size of the buffers is controlled by the user, via @code{setvbuf}.
-A port implementation can provide an idea of what the ``natural'' size
-for its buffers are, but it has no guarantee that the buffer will be
-those sizes.  It's also possible for big reads or writes to work on
-auxiliary buffers, and it's possible for @code{unget-bytevector} to
-cause a read buffer to expand temporarily; port implementations can't
-assume that the buffer they have been given to fill or empty corresponds
-to the port's designated read or write buffer.
-Port read buffers also have a flag indicating that the last read did not
-advance @code{end}, which indicates end-of-stream.  It is cleared by
-Guile when Guile gives the user an EOF object.
address@hidden The @code{rw_random} flag
-Special treatment is required for ports which can be seeked at random.
-Before various operations, such as seeking the port or changing from
-input to output on a bidirectional port or vice versa.  Seeking on a
-port with buffered input, or switching to writing after reading, will
-cause the buffered input to be discarded and Guile will seek the port
-back the buffered number of bytes.  Likewise seeking on a port with
-buffered output, or switching to reading after writing, will flush
-pending bytes with a call to the @code{write} procedure.  Indicate to
-Guile that your port needs this behavior by setting the @code{rw_random}
-flag.  This flag is set by default if the port type supplies a seek
 @subsubheading C interface
 A port type object is created by calling @code{scm_make_port_type}.
@@ -2403,6 +2351,46 @@ before hand, as appropriate.  Set using
 @deftypefun void scm_set_port_truncate (scm_t_bits tc, void (*truncate) (SCM 
port, scm_t_off length))
 @end deftypefun
address@hidden random_access_p
+Determine whether this port is a random-access port.
address@hidden random access
+Seeking on a random-access port with buffered input, or switching to
+writing after reading, will cause the buffered input to be discarded and
+Guile will seek the port back the buffered number of bytes.  Likewise
+seeking on a random-access port with buffered output, or switching to
+reading after writing, will flush pending bytes with a call to the
address@hidden procedure.  @xref{Buffering}.
+Indicate to Guile that your port needs this behavior by returning a
+nonzero value from your @code{random_access_p} function.  The default
+implementation of this function returns nonzero if the port type
+supplies a seek implementation.
address@hidden void scm_set_port_random_access_p (scm_t_bits tc, int 
(*random_access_p) (SCM port));
address@hidden deftypefun
address@hidden get_natural_buffer_sizes
+Guile will internally attach buffers to ports.  An input port always has
+a read buffer and an output port always has a write buffer.
address@hidden  A port buffer consists of a bytevector, along with
+some cursors into that bytevector denoting where to get and put data.
+Port implementations generally don't have to be concerned with
+buffering: a port type's @code{read} or @code{write} function will
+receive the buffer's bytevector as an argument, along with an offset and
+a length into that bytevector, and should then either fill or empty that
+bytevector.  However in some cases, port implementations may be able to
+provide an appropriate default buffer size to Guile.
address@hidden void scm_set_port_get_natural_buffer_sizes @
+  (scm_t_bits tc, void (*get_natural_buffer_sizes) (SCM, size_t 
*read_buf_size, size_t *write_buf_size))
+Fill in @var{read_buf_size} and @var{write_buf_size} with an appropriate 
buffer size for this port, if one is known.
address@hidden deftypefun
+File ports implement a @code{get_natural_buffer_sizes} to let the
+operating system inform Guile about the appropriate buffer sizes for the
+particular file opened by the port.
 @end table
 @node BOM Handling
diff --git a/libguile/fports.c b/libguile/fports.c
index c6071fe..aab83c9 100644
--- a/libguile/fports.c
+++ b/libguile/fports.c
@@ -418,7 +418,6 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
   port = scm_c_make_port (scm_tc16_fport, mode_bits, (scm_t_bits)fp);
-  SCM_PTAB_ENTRY (port)->rw_random = SCM_FDES_RANDOM_P (fdes);
   SCM_SET_FILENAME (port, name);
   return port;
@@ -639,6 +638,12 @@ fport_close (SCM port)
     scm_syserror ("fport_close");
+static int
+fport_random_access_p (SCM port)
+  return SCM_FDES_RANDOM_P (SCM_FSTREAM (port)->fdes);
 /* Query the OS to get the natural buffering for FPORT, if available.  */
 static void
 fport_get_natural_buffer_sizes (SCM port, size_t *read_size, size_t 
@@ -663,6 +668,7 @@ scm_make_fptob ()
   scm_set_port_seek                     (tc, fport_seek);
   scm_set_port_truncate                 (tc, fport_truncate);
   scm_set_port_input_waiting            (tc, fport_input_waiting);
+  scm_set_port_random_access_p          (tc, fport_random_access_p);
   scm_set_port_get_natural_buffer_sizes (tc, fport_get_natural_buffer_sizes);
   return tc;
diff --git a/libguile/ports.c b/libguile/ports.c
index 1ad5db0..a2509fb 100644
--- a/libguile/ports.c
+++ b/libguile/ports.c
@@ -196,6 +196,12 @@ scm_c_port_type_add_x (scm_t_ptob_descriptor *desc)
 static SCM trampoline_to_c_read_subr;
 static SCM trampoline_to_c_write_subr;
+static int
+default_random_access_p (SCM port)
+  return SCM_PORT_DESCRIPTOR (port)->seek != NULL;
 scm_make_port_type (char *name,
                     size_t (*read) (SCM port, SCM dst, size_t start,
@@ -215,6 +221,7 @@ scm_make_port_type (char *name,
   desc->c_write = write;
   desc->scm_read = read ? trampoline_to_c_read_subr : SCM_BOOL_F;
   desc->scm_write = write ? trampoline_to_c_write_subr : SCM_BOOL_F;
+  desc->random_access_p = default_random_access_p;
   ptobnum = scm_c_port_type_add_x (desc);
@@ -334,6 +341,13 @@ scm_set_port_input_waiting (scm_t_bits tc, int 
(*input_waiting) (SCM))
+scm_set_port_random_access_p (scm_t_bits tc, int (*random_access_p) (SCM))
+  scm_t_ptob_descriptor *ptob = scm_c_port_type_ref (SCM_TC2PTOBNUM (tc));
+  ptob->random_access_p = random_access_p;
   (scm_t_bits tc, void (*get_natural_buffer_sizes) (SCM, size_t *, size_t *))
@@ -721,9 +735,6 @@ scm_c_make_port_with_encoding (scm_t_bits tag, unsigned 
long mode_bits,
   entry->internal = pti;
   entry->file_name = SCM_BOOL_F;
-  /* By default, any port type with a seek function has random-access
-     ports.  */
-  entry->rw_random = ptob->seek != NULL;
   entry->port = ret;
   entry->stream = stream;
   entry->encoding = encoding;
@@ -743,6 +754,8 @@ scm_c_make_port_with_encoding (scm_t_bits tag, unsigned 
long mode_bits,
   initialize_port_buffers (ret);
+  entry->rw_random = ptob->random_access_p (ret);
   return ret;
diff --git a/libguile/ports.h b/libguile/ports.h
index dc0b30d..f9b6389 100644
--- a/libguile/ports.h
+++ b/libguile/ports.h
@@ -191,6 +191,7 @@ typedef struct scm_t_ptob_descriptor
   void (*get_natural_buffer_sizes) (SCM port, size_t *read_size,
                                     size_t *write_size);
+  int (*random_access_p) (SCM port);
   int (*input_waiting) (SCM port);
@@ -230,6 +231,8 @@ SCM_API void scm_set_port_truncate (scm_t_bits tc,
 SCM_API void scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) 
 SCM_API void scm_set_port_get_natural_buffer_sizes
   (scm_t_bits tc, void (*get_natural_buffer_sizes) (SCM, size_t *, size_t *));
+SCM_API void scm_set_port_random_access_p (scm_t_bits tc,
+                                           int (*random_access_p) (SCM port));
 /* The input, output, error, and load ports.  */
 SCM_API SCM scm_current_input_port (void);

reply via email to

[Prev in Thread] Current Thread [Next in Thread]