#REFACTORING by stefan
authorStefan Vogel <sv@exept.de>
Wed, 13 Mar 2019 17:04:15 +0100
changeset 23896 c00000f683b6
parent 23895 d49a46365ed5
child 23897 cb46a48b02b5
#REFACTORING by stefan Refactor for common code. Better documentation class: Stream comment/format in: #copyToEndFrom: #copyToEndInto: #copyToEndInto:bufferSize: changed: #copy:into: (send #bufferSizeForBulkFileCopy instead of #bufferSizeForBulkCopy) #copy:into:bufferSize: category of: #copy:into: #copy:into:bufferSize: #copyToEndFrom: #copyToEndInto: #copyToEndInto:bufferSize: class: Stream class added: #bufferSizeForBulkCopy
Stream.st
--- a/Stream.st	Wed Mar 13 17:01:22 2019 +0100
+++ b/Stream.st	Wed Mar 13 17:04:15 2019 +0100
@@ -216,6 +216,14 @@
     ^ ChunkSeparator
 ! !
 
+!Stream class methodsFor:'defaults'!
+
+bufferSizeForBulkCopy
+    ^ 128 * 1024
+
+    "Created: / 13-03-2019 / 16:50:04 / Stefan Vogel"
+! !
+
 !Stream class methodsFor:'testing'!
 
 isAbstract
@@ -723,181 +731,6 @@
     "Created: 13.9.1996 / 18:33:26 / cg"
 ! !
 
-!Stream methodsFor:'misc functions'!
-
-copy:numberOfBytes into:outStream
-    "read from the receiver, and write numberOfBytes data to another aWriteStream.
-     Return the number of bytes which have been transferred."
-
-    ^ self copy:numberOfBytes into:outStream bufferSize:(128*1024)
-!
-
-copy:numberOfBytes into:aWriteStream bufferSize:bufferSizeArg
-    "read from the receiver, and write numberOfBytes data to another aWriteStream.
-     Return the number of bytes which have been transferred."
-
-    |bufferSpecies bufferSize bytesLeft buffer countWritten freeBuffer|
-
-    countWritten := 0.
-    bufferSpecies := self contentsSpecies.
-    bytesLeft := numberOfBytes.
-    bufferSize := bufferSizeArg min:numberOfBytes.
-
-    bufferSpecies == ByteArray ifTrue:[
-        "an ExternalBytes buffer is faster when writing to a windows ExternalStream"
-        buffer:= ExternalBytes unprotectedNew:bufferSize.
-        freeBuffer := true.
-    ] ifFalse:[
-        buffer := bufferSpecies new:bufferSize.
-        freeBuffer := false.
-    ].
-
-    "read loop: read required bytes"
-    [
-        |readCount writeCount|
-
-        readCount := self nextAvailable:(bytesLeft min:bufferSize) into:buffer startingAt:1.
-        readCount ~~ 0 ifTrue:[
-            bytesLeft := bytesLeft - readCount.
-            writeCount := 0.
-            "write loop: write until all is written"
-            [
-                |count|
-
-                count := aWriteStream
-                            nextPutAll:readCount-writeCount
-                            from:buffer
-                            startingAt:writeCount+1.
-                writeCount := writeCount + count.
-                writeCount < readCount ifTrue:[
-                    aWriteStream writeWait.
-                    true.
-                ] ifFalse:[
-                    false
-                ].
-            ] whileTrue.
-            countWritten := countWritten + writeCount.
-        ].
-        "Note: atEnd will block if reading from an empty pipe or socket.
-         avoid atEnd if possible, because it reads a single byte."
-        (bytesLeft == 0) or:[readCount == 0 and:[self atEnd]]
-    ] whileFalse.
-
-    freeBuffer ifTrue:[ buffer free ].
-    ^ countWritten.
-
-    "
-        |s|
-        s := WriteStream on:(String new:100).
-        '/etc/passwd' asFilename readStream
-            copy:100 into:s bufferSize:10.
-        s contents
-    "
-
-    "Modified: / 13-03-2019 / 12:00:46 / Claus Gittinger"
-    "Modified: / 13-03-2019 / 12:50:48 / Stefan Vogel"
-!
-
-copyToEndFrom:inStream
-    "read from inStream, and write all data up to the end to the receiver.
-     Return the number of bytes which have been transferred.
-     Same functionality as copyToEnd:, but reversed arg and receiver
-     (useful in a cascade message of the writeStream)"
-
-    ^ inStream copyToEndInto:self
-!
-
-copyToEndInto:outStream
-    "read from the receiver, and write all data up to the end to another stream.
-     Return the number of bytes which have been transferred"
-
-    ^ self copyToEndInto:outStream bufferSize:(128*1024)
-
-"/ data rate to USB2.0 stick (Win32):
-"/   120 KB/s       8Kb SingleBuffer
-"/   741 KB/s      64Kb SingleBuffer
-"/  1345 KB/s     128Kb SingleBuffer
-"/  2087 KB/s     256Kb SingleBuffer
-"/  3573 KB/s    1024Kb SingleBuffer
-
-"/|t retVal|
-"/
-"/t := Time millisecondsToRun:[
-"/    retVal := self copyToEndInto:outStream bufferSize:(64*1024).
-"/].
-"/
-"/Transcript showCR:('%1 KB copied in %2s (%3 KB/s)'
-"/        bindWith:((retVal/1024)asFixedPoint:2)
-"/        with:((t/1000)asFixedPoint:2)
-"/        with:((retVal/1024/(t/1000))asFixedPoint:2)).
-"/^ retVal.
-"/
-!
-
-copyToEndInto:outStream bufferSize:bufferSize
-    "read from the receiver, and write all data up to the end to another stream.
-     Return the number of bytes which have been transferred"
-
-    |bufferSpecies buffer countWritten freeBuffer|
-
-    countWritten := 0.
-    bufferSpecies := self contentsSpecies.
-    bufferSpecies == ByteArray ifTrue:[
-        "an ExternalBytes buffer is faster when writing to a windows ExternalStream"
-        buffer:= ExternalBytes unprotectedNew:bufferSize.
-        freeBuffer := true.
-    ] ifFalse:[
-        buffer := bufferSpecies new:bufferSize.
-        freeBuffer := false.
-    ].
-
-    "read loop: read until end of stream"
-    [
-        |readCount|
-
-        readCount := self nextAvailable:bufferSize into:buffer startingAt:1.
-        readCount > 0 ifTrue:[
-            |writeCount|
-
-            writeCount := 0.
-            "write loop: write until all is written"
-            [
-                |count|
-
-                count := outStream
-                            nextPutAll:readCount-writeCount
-                            from:buffer
-                            startingAt:writeCount+1.
-                writeCount := writeCount + count.
-                writeCount < readCount ifTrue:[
-                    outStream writeWait.
-                    true.
-                ] ifFalse:[
-                    false
-                ].
-            ] whileTrue.
-            countWritten := countWritten + writeCount.
-        ].
-        "Note: atEnd will block if reading from an empty pipe or socket.
-         avoid atEnd if possible, because it reads a single byte."
-        readCount ~~ 0 or:[self atEnd not]
-    ] whileTrue.
-
-    freeBuffer ifTrue:[ buffer free ].
-    ^ countWritten
-
-    "
-      'hello world' readStream copyToEndInto:'/tmp/mist' asFilename writeStream.
-      'hello world' readStream copyToEndInto:#[] writeStream.
-      ('/tmp/mist' asFilename readStream binary; yourself) copyToEndInto:#[] writeStream
-      #[1 2 3 4 5 6 7] readStream copyToEndInto:'/tmp/mist' asFilename writeStream.
-      #(1 2 3 a 'b' 6.4 true) readStream next; copyToEndInto:#() writeStream inspect.
-
-    "
-
-    "Modified: / 13-03-2019 / 11:54:17 / Claus Gittinger"
-! !
-
 !Stream methodsFor:'non homogenous reading'!
 
 nextAvailableBytes:numBytes into:aCollection startingAt:initialIndex
@@ -3785,6 +3618,159 @@
 ! !
 
 
+!Stream methodsFor:'stream-to-stream copy'!
+
+copy:numberOfElementsOrNil into:outStream
+    "read from the receiver, and write numberOfElements elements to outStream, a WriteStream.
+     Return the number of elements which have been transferred.
+     If numberOfElementsOrNil is nil, copy until the end of myself."
+
+    ^ self copy:numberOfElementsOrNil into:outStream bufferSize:(self class bufferSizeForBulkCopy)
+
+    "Modified (comment): / 13-03-2019 / 17:03:47 / Stefan Vogel"
+!
+
+copy:numberOfElementsOrNil into:aWriteStream bufferSize:bufferSizeArg
+    "read from the receiver, and write numberOfElementsOrNil elements to outStream, a WriteStream.
+     Return the number of elements which have been transferred.
+     If numberOfElementsOrNil is nil, copy until the end of myself."
+
+    |bufferSpecies bufferSize elementsLeft buffer countWritten freeBuffer|
+
+    countWritten := 0.
+    numberOfElementsOrNil isNil ifTrue:[
+        "read to end..."
+        elementsLeft := -1.
+        bufferSize := bufferSizeArg.
+    ] ifFalse:[
+        elementsLeft := numberOfElementsOrNil.
+        bufferSize := bufferSizeArg min:numberOfElementsOrNil.
+    ].
+
+    bufferSpecies := self contentsSpecies.
+    bufferSpecies == ByteArray ifTrue:[
+        "an ExternalBytes buffer is faster when writing to a windows ExternalStream"
+        buffer:= ExternalBytes unprotectedNew:bufferSize.
+        freeBuffer := true.
+    ] ifFalse:[
+        buffer := bufferSpecies new:bufferSize.
+        freeBuffer := false.
+    ].
+
+    "read loop: read required bytes"
+    [
+        |readCount writeCount|
+
+        readCount := self nextAvailable:bufferSize into:buffer startingAt:1.
+        readCount ~~ 0 ifTrue:[
+            elementsLeft := elementsLeft - readCount.
+            writeCount := 0.
+            "write loop: write until all is written"
+            [
+                |count|
+
+                count := aWriteStream
+                            nextPutAll:readCount-writeCount
+                            from:buffer
+                            startingAt:writeCount+1.
+                writeCount := writeCount + count.
+                writeCount < readCount ifTrue:[
+                    aWriteStream writeWait.
+                    true.
+                ] ifFalse:[
+                    false
+                ].
+            ] whileTrue.
+            countWritten := countWritten + writeCount.
+        ].
+        "Note: atEnd will block if reading from an empty pipe or socket.
+               avoid atEnd if possible, because it reads a single byte.
+         If we read until end, bytesLeft is negative and will never become 0!!"
+        (elementsLeft == 0) or:[readCount == 0 and:[self atEnd]]
+    ] whileFalse.
+
+    freeBuffer ifTrue:[ buffer free ].
+    ^ countWritten.
+
+    "
+        |s|
+        s := WriteStream on:(String new:100).
+        '/etc/passwd' asFilename readStream
+            copy:nil into:s bufferSize:10.
+        s contents
+
+        |s|
+        s := WriteStream on:(String new:100).
+        '/etc/passwd' asFilename readStream
+            copy:100 into:s bufferSize:10.
+        s contents
+    "
+
+    "Modified: / 13-03-2019 / 12:00:46 / Claus Gittinger"
+    "Modified (comment): / 13-03-2019 / 17:03:20 / Stefan Vogel"
+!
+
+copyToEndFrom:inStream
+    "read from inStream, and write all elements up to the end to the receiver.
+     Return the number of elements which have been transferred.
+     Same functionality as #copyToEndInto:, but reversed arg and receiver
+     (useful in a cascade message of the writeStream)"
+
+    ^ inStream copy:nil into:self
+
+    "Modified (comment): / 13-03-2019 / 17:02:19 / Stefan Vogel"
+!
+
+copyToEndInto:outStream
+    "read from the receiver, and write all elements up to the end to outStream, a WriteStream.
+     Return the number of elements which have been transferred"
+
+    ^ self copy:nil into:outStream bufferSize:(self class bufferSizeForBulkCopy)
+
+"/ data rate to USB2.0 stick (Win32):
+"/   120 KB/s       8Kb SingleBuffer
+"/   741 KB/s      64Kb SingleBuffer
+"/  1345 KB/s     128Kb SingleBuffer
+"/  2087 KB/s     256Kb SingleBuffer
+"/  3573 KB/s    1024Kb SingleBuffer
+
+"/|t retVal|
+"/
+"/t := Time millisecondsToRun:[
+"/    retVal := self copyToEndInto:outStream bufferSize:(64*1024).
+"/].
+"/
+"/Transcript showCR:('%1 KB copied in %2s (%3 KB/s)'
+"/        bindWith:((retVal/1024)asFixedPoint:2)
+"/        with:((t/1000)asFixedPoint:2)
+"/        with:((retVal/1024/(t/1000))asFixedPoint:2)).
+"/^ retVal.
+"/
+
+    "Modified (comment): / 13-03-2019 / 17:03:04 / Stefan Vogel"
+!
+
+copyToEndInto:outStream bufferSize:bufferSize
+    "read from the receiver, and write all elements up to the end to outStream, aWriteStream.
+     Return the number of elements which have been transferred"
+
+    ^ self copy:nil into:outStream bufferSize:bufferSize
+
+    "
+      'hello world' readStream copyToEndInto:'/tmp/mist' asFilename writeStream.
+      'hello world' readStream copyToEndInto:'' writeStream.
+      ('/tmp/mist' asFilename readStream binary; yourself) copyToEndInto:#[] writeStream
+      #[1 2 3 4 5 6 7] readStream copyToEndInto:'/tmp/mist' asFilename writeStream binary; yourself.
+
+      |s|
+      s := #() writeStream.
+      #(1 2 3 a 'b' 6.4 true) readStream next; copyToEndInto:s. s inspect.
+    "
+
+    "Modified: / 13-03-2019 / 11:54:17 / Claus Gittinger"
+    "Modified (comment): / 13-03-2019 / 17:02:51 / Stefan Vogel"
+! !
+
 !Stream methodsFor:'testing'!
 
 atEnd