Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4764-Change-is-ZnBuffered-are-breaking-something- #5030

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/FileSystem-Core/FileReference.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,13 @@ FileReference >> size [
^ filesystem sizeOf: path
]

{ #category : #streams }
FileReference >> unbufferedBinaryWriteStream [
"Answer a binary read/write stream on the receiver"

^ filesystem binaryWriteStreamOn: self path
]

{ #category : #streams }
FileReference >> writeStream [

Expand Down
10 changes: 6 additions & 4 deletions src/System-Sources/SourceFile.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,16 @@ SourceFile >> tryOpenReadOnly: readOnly [
readOnly ifFalse: [
potentialLocations
do: [ :each |
[ stream := ZnCharacterReadWriteStream
on: (each asFileReference / basename) binaryReadWriteStream
[ stream := SourceFileCharacterReadWriteStream
on: (SourceFileBufferedReadWriteStream on:(each asFileReference / basename) unbufferedBinaryWriteStream)
encoding: 'utf8'.
^ self ] on: Error do: [ ] ] ].

potentialLocations do: [ :each |
[ stream := (each asFileReference / basename) readStream.
^ self ] on: Error do: [ ] ]
[ stream := ZnCharacterReadStream
on: (each asFileReference / basename) binaryReadStream
encoding: 'utf8'.
^ self ] on: Error do: [ ] ]
]

{ #category : #accessing }
Expand Down
343 changes: 343 additions & 0 deletions src/System-Sources/SourceFileBufferedReadWriteStream.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
"
I am Buffered Read Write Stream.
I should only be used in the SourceFile implementation
"
Class {
#name : #SourceFileBufferedReadWriteStream,
#superclass : #Object,
#instVars : [
'innerStream',
'buffer',
'bufferLength',
'streamSize',
'bufferOffset',
'nextPosition',
'isDirty'
],
#category : #'System-Sources-Streams'
}

{ #category : #'instance creation' }
SourceFileBufferedReadWriteStream class >> on: writeStream [
^ self basicNew
on: writeStream;
yourself
]

{ #category : #convenience }
SourceFileBufferedReadWriteStream class >> on: readStream do: block [
"Execute block with as argument a ZnBufferedReadStream on readStream.
Return the value of block."

| stream |

stream := self on: readStream.

^ [block value: stream ] ensure: [ stream flush ]
]

{ #category : #testing }
SourceFileBufferedReadWriteStream >> atEnd [

^ self atEnd: nextPosition
]

{ #category : #private }
SourceFileBufferedReadWriteStream >> atEnd: anInteger [

anInteger < streamSize ifTrue: [ ^ false ].
anInteger <= (bufferOffset + bufferLength) ifTrue: [ ^ false ].

^ true
]

{ #category : #private }
SourceFileBufferedReadWriteStream >> bufferAt: aPosition [

^ buffer at: (aPosition - bufferOffset)


]

{ #category : #private }
SourceFileBufferedReadWriteStream >> bufferAt: aPosition put: anElement [

self checkBufferFor: nextPosition.

bufferLength := (aPosition - bufferOffset) max: bufferLength.
buffer at: (aPosition - bufferOffset) put: anElement

]

{ #category : #private }
SourceFileBufferedReadWriteStream >> checkBufferFor: aPosition [

(self isPositionInBuffer: aPosition)
ifFalse: [ self refreshBufferFrom: aPosition ]
]

{ #category : #closing }
SourceFileBufferedReadWriteStream >> close [

self flush.
innerStream close
]

{ #category : #testing }
SourceFileBufferedReadWriteStream >> closed [

^ innerStream closed
]

{ #category : #'initialize-release' }
SourceFileBufferedReadWriteStream >> collectionSpecies [
^ innerStream isBinary
ifTrue: [ ByteArray ]
ifFalse: [ String ]
]

{ #category : #initialization }
SourceFileBufferedReadWriteStream >> defaultBufferSize [

^ 2 raisedToInteger: 16
]

{ #category : #writing }
SourceFileBufferedReadWriteStream >> flush [

isDirty ifFalse: [ ^ self ].

innerStream position: bufferOffset.
innerStream next: bufferLength putAll: buffer startingAt: 1.

innerStream flush.

streamSize := innerStream size.

isDirty := false
]

{ #category : #testing }
SourceFileBufferedReadWriteStream >> isBinary [

^ innerStream isBinary
]

{ #category : #private }
SourceFileBufferedReadWriteStream >> isPositionInBuffer: aPosition [

^ aPosition between: bufferOffset and: bufferOffset + bufferLength
]

{ #category : #testing }
SourceFileBufferedReadWriteStream >> isReadOnly [

^ false
]

{ #category : #testing }
SourceFileBufferedReadWriteStream >> isStream [

^ true
]

{ #category : #reading }
SourceFileBufferedReadWriteStream >> next [
| value |

self atEnd
ifTrue: [^ nil].

self checkBufferFor:nextPosition.

value := self bufferAt: nextPosition.

nextPosition := nextPosition + 1.

^ value
]

{ #category : #reading }
SourceFileBufferedReadWriteStream >> next: aQuantity [

| read collection |

collection := self collectionSpecies new: aQuantity.

read := self
readInto: collection
startingAt: 1
count: aQuantity.

^ read = aQuantity
ifTrue: [ collection ]
ifFalse: [ collection copyFrom: 1 to: read - 1 ]
]

{ #category : #writing }
SourceFileBufferedReadWriteStream >> next: aQuantity putAll: aCollection startingAt: startingAt [

aCollection readStreamDo: [ :s |
s skip: startingAt - 1.
self nextPutAll: (s next: aQuantity)].
]

{ #category : #writing }
SourceFileBufferedReadWriteStream >> nextPut: anElement [

self checkBufferFor: nextPosition.

self bufferAt: nextPosition put: anElement.

isDirty := true.
nextPosition := nextPosition + 1
]

{ #category : #writing }
SourceFileBufferedReadWriteStream >> nextPutAll: aCollection [

aCollection do: [ :each | self nextPut: each ]
]

{ #category : #'instance creation' }
SourceFileBufferedReadWriteStream >> on: aStream [

innerStream := aStream.
nextPosition := aStream position + 1.
streamSize := aStream size.

bufferOffset := -1.
bufferLength := 0.
isDirty := false.

self sizeBuffer: self defaultBufferSize.


]

{ #category : #reading }
SourceFileBufferedReadWriteStream >> peek [

| value |
value := self next.
"If I have read correctly I reset the position"
value ifNotNil: [ nextPosition := nextPosition - 1 ].

^ value

]

{ #category : #querying }
SourceFileBufferedReadWriteStream >> position [

^ nextPosition - 1

]

{ #category : #querying }
SourceFileBufferedReadWriteStream >> position: aNewPosition [

^ nextPosition := aNewPosition + 1

]

{ #category : #reading }
SourceFileBufferedReadWriteStream >> readInto: aBuffer startingAt: startingAt count: count [

| remainingCount maxPositionInBuffer read countToRead |

remainingCount := count.
read := 0.

[ remainingCount > 0 and: [ self atEnd not ]]
whileTrue: [
self checkBufferFor: nextPosition.

maxPositionInBuffer := bufferOffset + bufferLength.
countToRead := ( maxPositionInBuffer - (nextPosition - 1) ) min: remainingCount.
aBuffer
replaceFrom: startingAt + read
to: startingAt + read + countToRead - 1
with: buffer
startingAt: (nextPosition - bufferOffset).

nextPosition := nextPosition + countToRead.
remainingCount := remainingCount - countToRead.
read := read + countToRead
].

^ read.
]

{ #category : #private }
SourceFileBufferedReadWriteStream >> refreshBufferFrom: aPosition [

| nextBufferPosition |

nextBufferPosition := (((aPosition - 1) max:0) // buffer size) * buffer size.
bufferOffset = nextBufferPosition ifTrue: [ ^ self ].

self flush.

"If the position is outside the real stream I will only flush the buffer if I have to empty it."
(nextBufferPosition >= streamSize)
ifTrue: [
bufferOffset := nextBufferPosition.
bufferLength := 0.
^ self ].

(nextBufferPosition = (bufferOffset + bufferLength))
ifFalse: [ innerStream position: nextBufferPosition ].

bufferLength := innerStream readInto: buffer startingAt: 1 count: buffer size.
bufferOffset := nextBufferPosition.
]

{ #category : #reading }
SourceFileBufferedReadWriteStream >> setToEnd [

nextPosition := (streamSize max: (bufferOffset + bufferLength)) + 1
]

{ #category : #querying }
SourceFileBufferedReadWriteStream >> size [

^ streamSize max: (bufferOffset + bufferLength)
]

{ #category : #'initialize-release' }
SourceFileBufferedReadWriteStream >> sizeBuffer: size [

bufferLength > 0 ifTrue: [ self flush ].
bufferLength := 0.

buffer := self collectionSpecies new: size
]

{ #category : #reading }
SourceFileBufferedReadWriteStream >> skip: aQuantity [

nextPosition := nextPosition + aQuantity
]

{ #category : #reading }
SourceFileBufferedReadWriteStream >> upTo: value [
"Read upto but not including value and return them as a collection.
If value is not found, return the entire contents of the stream.
This could be further optimzed."

^ self collectionSpecies
streamContents: [ :writeStream | | element |
[ self atEnd or: [ (element := self next) = value ] ] whileFalse: [
writeStream nextPut: element ] ]
]

{ #category : #reading }
SourceFileBufferedReadWriteStream >> upToEnd [
"Read elements until the stream is atEnd and return them as a collection."

| toRead |

toRead := (streamSize - (nextPosition - 1)) max: 0.
^ self next: toRead.
]
Loading