Module: streams-internals Synopsis: Class, method, and generic function definitions for streams Author: Scott McKay, Eliot Miranda, Toby Weinberg Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Stream constants define constant $input = 1; define constant $output = 2; define constant $input-output = 3; define constant $closed = 4; /// The basic stream class define open abstract primary class () slot outer-stream :: false-or(), init-keyword: outer-stream:; slot private-stream-element-type-value :: = , init-keyword: element-type:; slot private-stream-direction-value :: ; // = $input, // init-keyword: direction:; slot private-stream-lock-value :: false-or() = make(), init-keyword: stream-lock:; end class ; define method initialize (stream :: , #key start: _start, end: _end, direction: _direction = #"input") => () next-method(); unless (slot-initialized?(stream, outer-stream)) stream.outer-stream := stream end; unless (instance?(stream, )) select (_direction) #"input" => #f; #"output", #"input-output" => if (_start | _end) error("START: and END: keywords are not allowed for output streams"); end; otherwise => error("%= is not one of %=, %=, or %=", _direction, #"input", #"output", #"input-output"); end select; stream-direction(stream) := _direction; end unless; end method initialize; define method stream-element-type (the-stream :: ) => (result :: ) the-stream.private-stream-element-type-value end method stream-element-type; define sealed generic stream-element-type-setter (value :: , the-stream :: ) => (result :: ); define method stream-element-type-setter (the-type :: , the-stream :: ) => (result :: ) the-stream.private-stream-element-type-value := the-type; the-type end method stream-element-type-setter; ignore(stream-element-type-setter); define open generic stream-direction (stream :: ) => (direction); define sealed generic stream-direction-setter (direction, the-stream :: ) => (direction); define inline method stream-direction (the-stream :: ) => (result) select (the-stream.private-stream-direction-value) $input-output => #"input-output"; $input => #"input"; $output => #"output"; $closed => #"closed"; end select end method stream-direction; define inline method stream-direction-setter (the-direction, the-stream :: ) => (result) the-stream.private-stream-direction-value := select (the-direction) #"input-output" => $input-output; #"input" => $input; #"output" => $output; #"closed" => $closed; end select; the-direction end method stream-direction-setter; // Change these to use bit fields when everything works again define inline function readable? (the-stream :: ) => (result :: ) logand(the-stream.private-stream-direction-value, $input) ~== 0 end function; define inline function writable? (the-stream :: ) => (result :: ) logand(the-stream.private-stream-direction-value, $output) ~== 0 end function; define inline function closed? (the-stream :: ) => (result :: ) (the-stream.private-stream-direction-value == $closed) end function; define inline function read-only? (the-stream :: ) => (result :: ) (the-stream.private-stream-direction-value == $input) end function; define inline function write-only? (the-stream :: ) => (result :: ) (the-stream.private-stream-direction-value == $output) end function; define inline function read-write? (the-stream :: ) => (result :: ) (the-stream.private-stream-direction-value == $input-output) end function; define open generic stream-lock (stream :: ) => (lock :: false-or()); define sealed generic stream-lock-setter (value, the-stream :: ) => (result :: false-or()); define method stream-lock (the-stream :: ) => (result :: false-or()) the-stream.private-stream-lock-value end method stream-lock; define method stream-lock-setter (value :: false-or(), the-stream :: ) => (result :: false-or()) the-stream.private-stream-lock-value := value; end; /// Stream query functions, common to all streams define method close (stream :: , #rest keys, #key abort? :: , wait? :: , synchronize? :: ) => () ignore(keys, abort?, wait?, synchronize?); stream.outer-stream := #f; stream.private-stream-direction-value := $closed; next-method (); end method close; define method stream-open? (stream :: ) => (open? :: ) ~closed?(stream) end method stream-open?; define method stream-at-end? (stream :: ) => (at-end? :: ) #f end method stream-at-end?; /// Positionable stream protocol define open abstract class (, ) slot initial-position :: = 0; slot current-position :: = 0; slot final-position :: = 0; end class ; /* These are a problem, something in the compiler? define open generic initial-position (stream :: ) => (result :: ); define open generic initial-position-setter (the-position :: , stream :: ) => (result :: ); define open generic current-position (stream :: ) => (result :: ); define open generic current-position-setter (the-position :: , stream :: ) => (result :: ); define open generic final-position (stream :: ) => (result :: ); define open generic final-position-setter (the-position :: , stream :: ) => (result :: ); */ define open generic stream-limit (stream :: ) => (limit :: false-or()); // Most streams have no limit define method stream-limit (stream :: ) => (limit :: singleton(#f)) #f end method stream-limit; define open generic stream-limit-setter (limit :: false-or(), stream :: ) => (limit :: false-or()); /// Positionable stream implementation define method stream-position (stream :: ) => (position :: ) stream.current-position - stream.initial-position end method stream-position; define method stream-position-setter (position :: , stream :: ) => (position :: ) let limit = (stream-direction(stream) == #"input") & stream-limit(stream); let new-position = position + stream.initial-position; if (position < stream.initial-position | (limit & new-position > limit)) error("Invalid position: %=", position); else stream.current-position := new-position end; position end method stream-position-setter; define method stream-position-setter (position == #"start", stream :: ) => (position :: ) stream-position(stream) := 0 end method stream-position-setter; define method stream-position-setter (position == #"end", stream :: ) => (position :: ) stream-position(stream) := stream-limit-or-error(stream) - stream.initial-position end method stream-position-setter; define method adjust-stream-position (stream :: , delta :: , #key from = #"current") => (position :: ) stream-position(stream) := select (from) #"current" => stream-position(stream) + delta; #"start" => delta; #"end" => stream-limit-or-error(stream) + delta; end end method adjust-stream-position; /* define method \< (p1 :: , p2 :: ) => (result :: ) //---*** Implement this end method \<; define method \= (p1 :: , p2 :: ) => (result :: ) //---*** Implement this end method \=; */ /// Readable stream protocol define method stream-input-available? (stream :: ) => (available? :: ) #t end method stream-input-available?; /// Writable stream protocol // Everything about force-output except doesn't wait if the stream is // asynchronous. define generic do-force-output (stream :: ) => (); define method do-force-output (stream :: ) => () ignore(stream); end method; /// Stream contents accessing protocol define generic stream-sequence-class (stream :: ) => (class /* ---*** :: subclass() */); define method stream-sequence-class (stream :: ) => (class /* ---*** :: subclass() */) end method stream-sequence-class; /// Stream locking define open generic stream-locked? (stream :: ) => (locked? :: ); define method stream-locked? (stream :: ) => (locked? :: ) stream-lock(stream) & stream-lock(stream).owned? end method stream-locked?; define open generic lock-stream (stream :: ) => (); define method lock-stream (stream :: ) => () if (stream-lock(stream)) wait-for(stream-lock(stream)); end end method lock-stream; define open generic unlock-stream (stream :: ) => (); define method unlock-stream (stream :: ) => () if (stream-lock(stream)) release(stream-lock(stream)) end end method unlock-stream; define macro with-stream-locked { with-stream-locked (?stream:expression) ?:body end } => { begin let _stream = ?stream; block () lock-stream(_stream); ?body cleanup unlock-stream(_stream) end end } end macro with-stream-locked; /// "High performance" functions define open generic read-skip (stream :: , n :: ) => (); define method read-skip (stream :: , n :: ) => () for (i :: from 0 below n) read-element(stream) end end method read-skip; define open generic write-fill (stream :: , element :: , n :: ) => (); define method write-fill (stream :: , elt :: , n :: ) => () for (i :: from 0 below n) write-element(stream, elt) end end method write-fill;