"======================================================================
|
|   PositionableStream Method Definitions
|
|   $Revision: 1.7.5$
|   $Date: 2000/05/28 16:56:52$
|   $Author: pb$
|
 ======================================================================"

"======================================================================
|
| Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.
| Written by Steve Byrne.
|
| This file is part of the GNU Smalltalk class library.
|
| The GNU Smalltalk class library is free software; you can redistribute it
| and/or modify it under the terms of the GNU Lesser General Public License
| as published by the Free Software Foundation; either version 2.1, or (at
| your option) any later version.
| 
| The GNU Smalltalk class library is distributed in the hope that it will be
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
| General Public License for more details.
| 
| You should have received a copy of the GNU Lesser General Public License
| along with the GNU Smalltalk class library; see the file COPYING.LESSER.
| If not, write to the Free Software Foundation, 59 Temple Place - Suite
| 330, Boston, MA 02111-1307, USA.  
|
 ======================================================================"

Stream subclass: #PositionableStream
       instanceVariableNames: 'collection ptr endPtr access'
       classVariableNames: ''
       poolDictionaries: ''
       category: 'Streams-Collections'
!

PositionableStream comment: 
'My instances represent streams where explicit positioning is permitted.
Thus, my streams act in a manner to normal disk files: you can read
or write sequentially, but also position the file to a particular place
whenever you choose.  Generally, you''ll want to use ReadStream, WriteStream
or ReadWriteStream instead of me to create and use streams.' !



!PositionableStream class methodsFor: 'instance creation'!

on: aCollection
    "Answer an instance of the receiver streaming on the
    whole contents of aCollection"
    self subclassResponsiblity
!

on: aCollection from: firstIndex to: lastIndex
    "Answer an instance of the receiver streaming from
     the firstIndex-th item of aCollection to the lastIndex-th"
    ^self on: (aCollection copyFrom: firstIndex to: lastIndex)
! !



!PositionableStream methodsFor: 'accessing-reading'!

next
    "Answer the next item of the receiver"
    | element |
    (access bitAnd: 1) = 0
    	ifTrue: [ ^self shouldNotImplement ].
    self atEnd ifTrue: [ ^self error: 'end of stream reached' ].
    element := collection at: ptr.
    ptr := ptr + 1.
    ^element
!

peek
    "Returns the next element of the stream without moving the pointer.
    Returns nil when at end of stream."
    | peekValue |
    
    self atEnd ifTrue: [ ^nil ].
    peekValue := self next.
    self skip: -1.
    ^peekValue    
!

peekFor: anObject
    "Returns true and gobbles the next element from the stream of it is
    equal to anObject, returns false and doesn't gobble the next element
    if the next element is not equal to anObject."
    self atEnd ifTrue: [ ^false ].
    ^self next = anObject
    	ifTrue: [ true ]
    	ifFalse: [ self skip: -1. false ]
!

copyFrom: start to: end
    "Answer the collection on which the receiver is streaming, from
     the start-th item to the end-th"

    ^collection copyFrom: start to: end
!

contents
    "Returns a collection of the same type that the stream accesses, up to 
    and including the final element."
    ^collection copyFrom: 1 to: endPtr
!

reverseContents
    "Returns a collection of the same type that the stream accesses, up to 
    and including the final element, but in reverse order."
    | newCollection |
    newCollection := self species new: endPtr.
    1 to: endPtr do:
	[ :i | newCollection at: i put: (collection at: endPtr - i + 1) ].
    ^newCollection
! !



!PositionableStream methodsFor: 'testing'!

atEnd
    "Answer whether the objects in the stream have reached an end"
    ^ptr > endPtr
!

basicAtEnd
    "Answer whether the objects in the stream have reached an end.
     This method must NOT be overridden."
    ^ptr > endPtr
!

isEmpty
    "Answer whether the stream has no objects"
    ^endPtr = 0
! !


!PositionableStream methodsFor: 'truncating'!

truncate
    "Truncate the receiver to the current position - only valid
     for writing streams"
    (access bitAnd: 2) = 0
	ifTrue: [ self shouldNotImplement ]
	ifFalse: [ endPtr := ptr - 1 ]
! !

!PositionableStream methodsFor: 'positioning'!

position
    "Answer the current value of the stream pointer"
    ^ptr
!

position: anInteger
    "Move the stream pointer to the anInteger-th object"
    (anInteger between: 1 and: endPtr + 1)
	ifTrue: [ ptr := anInteger ]
	ifFalse: [ endPtr printNl. ^self error: 'position out of range' ]
!

basicPosition: anInteger
    "Move the stream pointer to the anInteger-th object"
    (anInteger between: 1 and: endPtr + 1)
	ifTrue: [ ptr := anInteger ]
	ifFalse: [ ^self error: 'position out of range' ]
!

reset
    "Move the stream back to its first element. For write-only streams,
    the stream is truncated there."
    self position: 1
!

setToEnd
    "Move the current position to the end of the stream."
    ptr := endPtr + 1
!

size
    "Answer the size of data on which we are streaming."
    ^endPtr
!

skip: anInteger
    "Move the current position by anInteger places, either forwards or
    backwards."
    self position: ((ptr + anInteger max: 1) min: endPtr).
! !


!PositionableStream methodsFor: 'private'!

beReadOnly
    access := 1
!

beWriteOnly
    access := 2
!

beReadWrite
    access := 3
!

collection
    ^collection
!

status: aString
    "When working with a stream on strings, this method can be useful!
     Format of the output:
	'ABCDEFG'   aString
	   ^		    "
    Transcript
	print: (collection copyFrom: 1 to: endPtr);
	nextPutAll: '    ';
	nextPutAll: aString;
	nl;
	next: self position put: Character space;
	nextPut: $^;
	nl
! !


!PositionableStream methodsFor: 'class type methods'!

species
    "The collections returned by #upTo: etc. are the same kind as
    those returned by the collection with methods such as #select:"
    ^collection species
! !
