Top Banner
FRANZ INC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002
45

F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

Dec 23, 2015

Download

Documents

Kerry Nicholson
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

An In-Depth Look at Simple Streams

By Duane Rettig

October, 2002

Page 2: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

What is a Lisp Stream?

Lisp

stream

stream

externaldevice

internal device

Page 3: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

An In-Depth Look at Simple Streams

• Simple Streams Design Goals• What is a Simple Stream?• Simple-stream Concepts

– Opening, closing, blocking, reading, writing

• Character Strategies• Common Windows Rewrite• Further changes in next version (references

distributed throughout presentation)

Page 4: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Design Goals

• CL compliance• Bivalence• Thin Strategy layer that is uniform• Extensibility via specializations/mixins and

encapsulations• Minimal decision points in critical strategy code• Minimal calls to generic-functions• External-format ready for 8 and 16 bit lisps

Page 5: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Gray vs. Simple Stream

Object functionality

buffer

API call

Strategy

Gray Stream

Simple Stream

Device interface

Page 6: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Dual-channel stream

• Two octet buffers• External-format character translation

Ext. format

Device methods

Out buffer

API

In buffer

External device

Page 7: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Single-channel stream

• One octet buffer• External-format character translation

Ext. format

Device methods

buffer

API

direction

Internal or External device

Page 8: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

String stream

• Zero, one, or two string buffers• No external-format translations• Plugable character/buffer strategies

Device methods

Out buffer

API

In buffer

Internal device

Page 9: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Opening a Stream

• Creates or reuses a stream object

• Makes or retains a connection to a device

• Initializes character strategies

• Marks the stream as open

Page 10: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Open

open make-instance (gf) ... shared-initialize (gf) shared-initialize :after [Method] device-open [Method]

Page 11: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

(Open): Simple encapsulation

(setq bun (open "sesame"))

(setq big-mac (make-instance 'all-beef :input-handle bun ...))

bunbig-mac

all-beef sesame

Page 12: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

(Open): shared-initialize

(defmethod shared-initialize :after ((stream simple-stream) slots

&rest initargs) (declare (ignore slots)) (unless (device-open stream initargs) (device-close stream t)) stream)

Page 13: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

(Open): device-open

• At device-open time:– All instance slots have been initialized– connection has been made or will be made by

device-open

• When device-open returns:– If non-nil, the stream is ready for appropriate

actions – If nil, then the open has failed.

Page 14: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

(Open): device-open

• device-open must:– Ensure a connection before returning– Ensure buffers are in place– Initialize/reinitialize pointers– Return nil for failure, or non-nil after success

• device-open must not:– Assume that the stream was closed– close the stream

Page 15: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

(Open): subclass example

(defclass file-with-header (file-simple-stream) ((header :initform nil :accessor file-header-info)))

(defmethod device-open ((stream file-with-header) options) (declare (ignore options)) (let ((success (call-next-method))) (when success (setf (file-header-info stream) (read-file-header stream)) t)))

Page 16: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

(Open): device-open :before methods

• In future releases, for string-simple-streams:– A catch-all primary method returns true for an

open stream.– Strategy installation functions are directional and

do not override.• install-string-character-strategy deprecated, replaced

by install-string-{input,output}-character-strategy

– All :before methods fire according to CPL, and may shadow default actions.

Page 17: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

(Open): device-open: string-input (future)

(defmethod device-open :before ((stream string-input-simple-stream) options) (with-stream-class (string-input-simple-stream stream) (let ((string (getf options :string))) (when (and string (null (sm buffer stream))) (let ((start (getf options :start)) (end (or (getf options :end) (length string)))) (setf (sm buffer stream) string (sm buffpos stream) start (sm buffer-ptr stream) end))))) (install-string-input-character-strategy stream) (add-stream-instance-flags stream :string :input :simple))

Page 18: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

(Open): device-open: string-output (future)(defmethod device-open :before ((stream string-output-simple-stream) options) (with-stream-class (string-output-simple-stream stream) (unless (sm out-buffer stream) (let ((string (getf options :string))) (if string (setf (sm out-buffer stream) string (sm max-out-pos stream) (length string)) (let ((buflen (max (device-buffer-length stream) 16))) (setf (sm out-buffer stream) (make-string buflen) (sm max-out-pos stream) buflen))))) (unless (sm control-out stream) (setf (sm control-out stream) *std-control-out-table*))) (install-string-output-character-strategy stream) (add-stream-instance-flags stream :string :output :simple))

Page 19: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Closing a Stream

• Flushes output if any.• Breaks connection to device.• Secures against accidental future operations.• Does not change-class.

(defmethod close ((stream simple-stream) &key abort) (device-close stream abort))

Page 20: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Close(defmethod device-close :around ((stream simple-stream) abort) (let (res) (when (pseudo::open-stream-p stream) (unwind-protect (progn (when (output-stream-p stream) (ignore-errors (if abort (clear-output stream) (force-output stream)))) (setq res (call-next-method))) (without-interrupts (pseudo::unset-open-flags stream) (setf (stream-input-handle stream) nil (stream-output-handle stream) nil)) (setf (stream-external-format stream) (find-external-format :void)) res))))

Page 21: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

(Close): device-close

• device-close should:– flush all data (unless aborting)– disconnect handles of any encapsulated streams– call lower-levels to close as necessary

• device-close should not:– operate on a closed stream– close an encapsulated stream

Page 22: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Blocking

• Issues with listen– read direction only– covers character availability and not blocking– assumes character as the basic data unit

• stream-listen (carried over from Gray streams)

• read-no-hang-p and write-no-hang-p

Page 23: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Blocking styles

• Non-blocking

• Blocking

• B/NB (blocking, then non-blocking)

Character: One element

Octet: One element

Page 24: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Reading and Writing

• Mostly symmetrical

• Device methods obey B/NB discipline

Page 25: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Basic read strategy

(block read (when (>= buffpos buffer-ptr) (let ((res (device-read stream nil 0 buffpos blocking))) (when (< res 0) (pseudo::do-error-handling)) (when (= res 0) (if blocking (pseudo::do-eof-handling) (return-from read nil))) (setq buffer-ptr res buffpos 0))) (prog1 (aref buffer buffpos) (incf buffpos)))))

Page 26: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Basic write strategy

(block write (when (>= out-pos max-out-pos) (when (> out-pos 0) (erroring-device-write-whole stream nil 0 out-pos t)) (setq out-pos 0)) (setf (aref buffer out-pos) value) (incf out-pos))

Page 27: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Implementing force-output, finish-output

• Both are implemented using device-write

• blocking argument determines whether force (nil) or finish (t)

• device-write buffer argument is :flush (future)

Page 28: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Reading and Writing Sequences

• read-sequence and write-sequence– are width sensitive and by-element– require blocking semantics– do not return a count

• read-vector and write-vector– are octet-based– employ B/NB semantics– return a count, 0, or error code

Page 29: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Deprecated generic function: device-extend

• History and relationship to device-read and device-write– structural differences– purity of reference

• Problems– one generic-function for two directions– inconsistent interface

Page 30: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Replacement of device-extend

• Actions :input and :input-check become blocking argument to device-read

• Actions :output and :output-check become blocking argument to device-write

• Extra actions come through via device-read and device-write buffer argument

Page 31: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Record orientation

• Via device-finish-record gf– dual-channel input– string output

Page 32: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Other generic-functions

• device-buffer-length

• device-clear-input

• device-clear-output

• device-file-length

• device-file-position

Page 33: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Strategies

• What is a strategy’s purpose?– To satisfy the high-level requirements of a

specified behavior in a uniform manner.

• Octet strategies are non-programmable.– read-byte, write-byte are cast in concrete.

• Character strategies are programmable...

Page 34: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Character strategies

• Programmable, replaceable.

• External-formats use template functions for dual-channel and single-channel streams.

• String-streams use simple strategy functions.

• (future): Subclassed strategy functions can shadow more general ones.

• Occupy “joint” slots in the stream.

Page 35: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Example strategy set for *terminal-io*

cl-user(5): :iterminal-simple-stream @ #x711e057a = #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x711e057a> 0 Class --------> #<standard-class terminal-simple-stream> 1 j-unread-char -> #<Function dual-channel-unread-char> 2 j-write-chars -> #<Function (:efft dc-write-chars :latin1-base)> 3 j-write-char -> #<Function (:efft dc-write-char :latin1-base)> 4 j-read-chars -> #<Function (:efft dc-read-chars :latin1-base)> 5 j-read-char --> #<Function (:efft dc-read-char :latin1-base)> 6 j-listen -----> #<Function (:efft dc-listen :latin1-base)> ... 34 src-position-table -> The symbol nilcl-user(6):

Page 36: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Example strategy set for string-output

cl-user(9): :istring-output-simple-stream @ #x719cb5e2 = #<string-output-simple-stream "" pos 0 @ #x719cb5e2> 0 Class --------> #<standard-class string-output-simple-stream> 1 j-unread-char -> The symbol nil 2 j-write-chars -> #<Function string-output-write-chars> 3 j-write-char -> #<Function string-output-write-char> 4 j-read-chars -> The symbol nil 5 j-read-char --> The symbol nil 6 j-listen -----> The symbol nil ... 33 out-buffer ---> A simple-string (4096) that starts "xxxxxxxxxxxxxxxx”cl-user(10):

Page 37: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Example strategy set for string-input

cl-user(14): :istring-input-simple-stream @ #x719e74aa = #<string-input-simple-stream "abc" pos 0 @ #x719e74aa> 0 Class --------> #<standard-class string-input-simple-stream> 1 j-unread-char -> #<Function string-input-unread-char> 2 j-write-chars -> The symbol nil 3 j-write-char -> The symbol nil 4 j-read-chars -> #<Function string-input-read-chars> 5 j-read-char --> #<Function string-input-read-char> 6 j-listen -----> #<Function string-listen> ... 31 src-position-table -> The symbol nilcl-user(15):

Page 38: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

j-read-char

• Args: stream eof-error-p eof-value blocking

• Implements read-char and read-char-no-hang functionality directly (after argument resolution)

• blocking argument is nil/true dichotomy

Page 39: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

j-write-char

• Args: character stream

• Implements write-char directly (after argument resolution)

• Writing nil as the character argument will flush an external-format’s output state.

Page 40: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

j-read-chars

• Args: stream string search start end blocking

• Implements read-sequence, read-line

• blocking argument is nil, :bnb, or true

Page 41: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

j-write-chars

• Args: stream string start end

• Implements write-sequence, write-string

• Always blocks (for now)

Page 42: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

j-listen

• Args: stream

• Implements stream-listen directly

• Must have a complete character or an error condition in order to return true.

Page 43: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

j-unread-char

• Args: stream relaxed

• May need to unread multiple characters as part of a composing or encapsulating character.

• relaxed allows non-error unreads beyond the first unread.

Page 44: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Taking strategies beyond ANS

• Other strategies can be created for operations that don’t fit into CL standard functionalities.

• Example: one-buffer ring fifo queue

Page 45: F RANZ I NC. An In-Depth Look at Simple Streams By Duane Rettig October, 2002.

FRANZ INC.

Common Windows low-level rewrite

• Source code comparison between Gray and simple streams

• Demo