help-smalltalk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Help-smalltalk] [PATCH] Block-level stream input protocol


From: Paolo Bonzini
Subject: [Help-smalltalk] [PATCH] Block-level stream input protocol
Date: Wed, 06 Aug 2008 09:36:55 +0200
User-agent: Thunderbird 2.0.0.16 (Macintosh/20080707)

This patch adds another important set of methods, that allows to eliminate useless creation of collections when stream-to-stream operation is not possible. These are #nextAvailable:into:startingAt: and #next:into:startingAt:.

This patch also cleans up the file code, because #nextAvailable:into:startingAt: can replace the old method #read:from:to:.

Paolo
diff --git a/ChangeLog b/ChangeLog
index 786a934..d896ec0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
 2008-08-05  Paolo Bonzini  <address@hidden>
 
+       * kernel/FileDescr.st: Remove #read:... methods, except
+       #read:from:to: which becomes #nextAvailable:into:startingAt:.
+       Remove #write:... methods except #write:from:to: which becomes
+       #next:putAll:startingAt:.  Remove #next:, #nextAvailable:,
+       #nextHunk, #nextHunkPutAllOn: to use the superclass version,
+       change #next:into: to #next:into:startingAt:.
+       * kernel/FileStream.st: Change calls to #read:form:to:
+       and #write:from:to: to super sends.  Change #nextAvailable:
+       to #nextAvailable:into:startingAt:, #next:into: to
+       #next:into:startingAt:.
+       * kernel/PosStream.st: Add #nextAvailable:into:startingAt:.
+       * kernel/Stream.st: Add #next:into:startingAt: and
+       #nextAvailable:into:startingAt:, use them in #next:,
+       #nextAvailable:, #nextHunk.
+
+2008-08-05  Paolo Bonzini  <address@hidden>
+
        * kernel/Stream.st: Do not use Streams in the default implementation
        of #nextAvailable:.
 
diff --git a/kernel/FileDescr.st b/kernel/FileDescr.st
index 340b6e6..043f204 100644
--- a/kernel/FileDescr.st
+++ b/kernel/FileDescr.st
@@ -342,7 +342,7 @@ do arbitrary processing on the files.'>
                result := 1]
            ifTrue: 
                [data := self species new: 1.
-               result := self read: data from: 1 to: 1.
+               result := self nextAvailable: 1 into: data startingAt: 1.
                data := data at: 1].
        ^result > 0 
            ifTrue: [data]
@@ -368,7 +368,7 @@ do arbitrary processing on the files.'>
        | result data |
        peek isNil ifFalse: [^peek].
        data := self species new: 1.
-       result := self read: data from: 1 to: 1.
+       result := self nextAvailable: 1 into: data startingAt: 1.
        ^result > 0 
            ifTrue: [peek := data at: 1]
            ifFalse: [self pastEnd]
@@ -387,7 +387,7 @@ do arbitrary processing on the files.'>
        "Store aCharacter on the file"
 
        <category: 'basic'>
-       self write: aCharacter numBytes: 1
+       self next: 1 putAll: (String with: aCharacter) startingAt: 1
     ]
 
     nextPutByte: anInteger [
@@ -675,59 +675,17 @@ do arbitrary processing on the files.'>
        bufSize = 0 ifTrue: [ ^self ].
        buf := String new: bufSize.
        [
-           n := self read: buf from: 1 to: bufSize.
+           n := self nextAvailable: bufSize into: buf startingAt: 1.
            aStream next: n putAll: buf startingAt: 1.
            n = 1024
        ] whileTrue
     ]
 
-    next: n putAll: aCollection startingAt: position [
-       "Put the characters in the supplied range of aCollection in the file"
-
-       <category: 'overriding inherited methods'>
-       ^self 
-           write: aCollection
-           from: position
-           to: position + n - 1
-    ]
-
     nextByteArray: anInteger [
         "Return the next 'anInteger' bytes from the stream, as a ByteArray."
 
         <category: 'overriding inherited methods'>
-        ^self next: anInteger into: (ByteArray new: anInteger)
-    ]
-
-    next: anInteger [
-        "Return the next 'anInteger' characters from the stream, as a String."
-
-        <category: 'overriding inherited methods'>
-        ^self next: anInteger into: (self species new: anInteger)
-    ]
-
-    next: anInteger into: result [
-       "Return the next 'anInteger' characters from the stream, as a String."
-
-       <category: 'overriding inherited methods'>
-       | read |
-       read := 0.
-       [ read = anInteger ] whileFalse: [
-            self atEnd ifTrue: [
-                ^SystemExceptions.NotEnoughElements signalOn: anInteger - 
read].
-            read := read + (self read: result from: read + 1 to: anInteger).
-        ].
-       ^result
-    ]
-
-    nextAvailable: anInteger [
-        "Return up to anInteger objects in the receiver, stopping if
-         the end of the stream is reached"
-
-        <category: 'accessing-reading'>
-        | result n |
-       result := self species new: anInteger.
-       n := self read: result.
-       ^n < anInteger ifTrue: [result copyFrom: 1 to: n] ifFalse: [result]
+        ^self next: anInteger into: (ByteArray new: anInteger) startingAt: 1
     ]
 
     atEnd [
@@ -815,28 +773,6 @@ do arbitrary processing on the files.'>
        ^true
     ]
 
-    nextHunkPutAllOn: aStream [
-       "Copy the next buffers worth of stuff from the receiver to aStream."
-
-       <category: 'low-level access'>
-       | count coll |
-       count := self read: (coll := self species new: 1024).
-       count = 0 ifTrue: [^self pastEnd].
-       aStream next: count putAll: coll startingAt: 1
-    ]
-
-    nextHunk [
-       "Answer the next buffers worth of stuff in the Stream represented
-        by the receiver.  Do at most one actual input operation."
-
-       <category: 'low-level access'>
-       | count answer |
-       count := self read: (answer := self species new: 1024).
-       count < answer size ifTrue: [answer := answer copyFrom: 1 to: count].
-       count = 0 ifTrue: [^self pastEnd].
-       ^answer
-    ]
-
     pastEnd [
         "The end of the stream has been reached.  Signal a Notification."
 
@@ -845,115 +781,44 @@ do arbitrary processing on the files.'>
        super pastEnd
     ]
 
-    read: byteArray [
-       "Ignoring any buffering, try to fill byteArray with the
-        contents of the file"
-
-       <category: 'low-level access'>
-       | count available |
-       self ensureReadable.
-       available := peek isNil ifTrue: [0] ifFalse: [1].
-       peek isNil 
-           ifFalse: 
-               [byteArray byteAt: 1 put: peek value.
-               peek := nil].
-       self isOpen ifFalse: [^available].
-       count := self 
-                   fileOp: 3
-                   with: byteArray
-                   with: available + 1
-                   with: byteArray size
-                   ifFail: [self checkError].
-       count := count + available.
-       count = 0 ifTrue: [atEnd := true].
-       ^count
-    ]
-
-    read: byteArray numBytes: anInteger [
-       "Ignoring any buffering, try to fill anInteger bytes of byteArray
+    nextAvailable: n into: aCollection startingAt: position [
+       "Ignoring any buffering, try to fill the given range of aCollection
         with the contents of the file"
 
        <category: 'low-level access'>
        | count available |
+       n = 0 ifTrue: [ ^self ].
        self ensureReadable.
        available := peek isNil ifTrue: [0] ifFalse: [1].
        peek isNil 
            ifFalse: 
-               [byteArray byteAt: 1 put: peek value.
+               [aCollection byteAt: position put: peek value.
                peek := nil].
        self isOpen ifFalse: [^available].
        count := self 
                    fileOp: 3
-                   with: byteArray
-                   with: 1 + available
-                   with: (anInteger min: byteArray size)
-                   ifFail: [self checkError].
-       count := count + available.
-       count = 0 ifTrue: [atEnd := true].
-       ^count
-    ]
-
-    read: byteArray from: position to: end [
-       "Ignoring any buffering, try to fill the given range of byteArray
-        with the contents of the file"
-
-       <category: 'low-level access'>
-       | count available |
-       self ensureReadable.
-       available := peek isNil ifTrue: [0] ifFalse: [1].
-       peek isNil 
-           ifFalse: 
-               [byteArray byteAt: position put: peek value.
-               peek := nil].
-       self isOpen ifFalse: [^available].
-       count := self 
-                   fileOp: 3
-                   with: byteArray
+                   with: aCollection
                    with: position + available
-                   with: (end min: byteArray size)
+                   with: (position + n - 1 min: aCollection size)
                    ifFail: [self checkError].
        count := count + available.
        count = 0 ifTrue: [atEnd := true].
        ^count
     ]
 
-    write: byteArray [
-       "Ignoring any buffering, try to write the contents of byteArray in the
-        file"
-
-       <category: 'low-level access'>
-       ^self 
-           write: byteArray
-           from: 1
-           to: byteArray size
-    ]
-
-    write: byteArray numBytes: anInteger [
-       "Ignoring any buffering, try to write to the file the first anInteger
-        bytes of byteArray"
-
-       <category: 'low-level access'>
-       ^self 
-           write: byteArray
-           from: 1
-           to: anInteger
-    ]
-
-    write: byteArray from: position to: end [
-       "Ignoring any buffering, try to write to the file the given range
-        of byteArray, starting at the position-th element and ending
-        at the end-th."
+    next: n putAll: aCollection startingAt: position [
+       "Put the characters in the supplied range of aCollection in the file"
 
        <category: 'low-level access'>
        | cur last soFar result |
        cur := position.
-       last := end min: byteArray size.
+       last := position + n - 1 min: aCollection size.
        [cur <= last] whileTrue: 
                [self ensureWriteable.
                self isOpen ifFalse: [^cur - position].
                result := self 
                            fileOp: 2
-                           with: byteArray
+                           with: aCollection
                            with: cur
                            with: last
                            ifFail: [self checkError].
diff --git a/kernel/FileStream.st b/kernel/FileStream.st
index 1156e16..827cf5e 100644
--- a/kernel/FileStream.st
+++ b/kernel/FileStream.st
@@ -382,10 +382,10 @@ file object, such as /dev/rmt0 on UNIX or MTA0: on VMS).'>
                    bufferAll: aCollection
                    startingAt: pos + written]
            ifFalse: 
-               [self 
-                   write: aCollection asString
-                   from: pos + written
-                   to: pos + n - 1]
+               [super 
+                   next: n - written
+                   putAll: aCollection asString
+                   startingAt: pos + written]
     ]
 
     upTo: aCharacter [
@@ -477,21 +477,71 @@ file object, such as /dev/rmt0 on UNIX or MTA0: on VMS).'>
        ^resultStream contents
     ]
 
-    nextAvailable: anInteger [
-       "Private - Read up to anInteger bytes from the stream and store them
-        into answer.  Return `answer' itself, or raise an exception if we 
-        could not read the full amount of data."
+    next: anInteger into: answer startingAt: pos [
+       "Read up to anInteger bytes from the stream and store them
+        into answer.  Return the number of bytes that were read, raising
+        an exception if we could not read the full amount of data."
+
+       <category: 'buffering'>
+       | read last |
+       writePtr notNil ifTrue: [self flush].
+       read := 0.
+
+       "Exhaust the remaining contents of the buffer if they cannot satisfy
+        the whole request."
+       ptr + anInteger - 1 > endPtr 
+           ifTrue: 
+               [answer 
+                   replaceFrom: pos
+                   to: endPtr - ptr + pos
+                   with: collection
+                   startingAt: ptr.
+               read := endPtr - ptr + 1.
+               ptr := endPtr + 1].
+
+       "If we did not read everything, but what's left is less than the size of
+        the buffer, try once more filling it..."
+       anInteger - read < collection size 
+           ifTrue: 
+               [ptr > endPtr ifTrue: [self fill].
+               last := read + endPtr - ptr + pos min: answer size.
+               answer 
+                   replaceFrom: read + pos
+                   to: last
+                   with: collection
+                   startingAt: ptr.
+               ptr := ptr + (last - read - pos + 1).
+               read := last - pos + 1].
+
+       "Anything more?  We read it from the file.  We can come here only if the
+        buffer cannot be filled completely, or if we want to read really a
+        lot of data."
+       [ read = anInteger ] whileFalse: [
+            self atEnd ifTrue: [
+                ^SystemExceptions.NotEnoughElements signalOn: anInteger - 
read].
+            read := read + (super
+                               nextAvailable: anInteger - read
+                               into: answer
+                               startingAt: 1)
+        ].
+       ^answer
+    ]
+
+    nextAvailable: anInteger into: aCollection startingAt: pos [
+       "Read up to anInteger bytes from the stream and store them
+        into aCollection.  Return the number of bytes read."
 
        <category: 'buffering'>
-       | answer last |
+       | last n |
        writePtr notNil ifTrue: [self flush].
        ptr > endPtr ifTrue: [self fill].
 
        "Fetch data from the buffer, without doing more than one I/O operation."
        last := endPtr min: ptr + anInteger - 1.
-       answer := collection copyFrom: ptr to: last.
-       ptr := ptr + answer size.
-       ^answer
+       n := last - ptr + 1.
+       aCollection replaceFrom: pos to: pos + n - 1 with: collection 
startingAt: ptr.
+       ptr := ptr + n.
+       ^n
     ]
 
     nextPutAllOn: aStream [
@@ -568,10 +618,10 @@ file object, such as /dev/rmt0 on UNIX or MTA0: on VMS).'>
                    ifTrue: 
                        [(self isPipe or: [writePtr - 1 = endPtr]) 
                            ifFalse: [super skip: writePtr - 1 - endPtr].
-                       self 
-                           write: collection
-                           from: writePtr
-                           to: writeEnd]]
+                       super 
+                           next: writeEnd - writePtr + 1
+                           putAll: collection
+                           startingAt: writePtr]]
            ifFalse: 
                [writePtr notNil 
                    ifTrue: 
@@ -659,63 +709,16 @@ file object, such as /dev/rmt0 on UNIX or MTA0: on VMS).'>
        writeEnd := ptr - 1
     ]
 
-    next: anInteger into: answer [
-       "Private - Read up to anInteger bytes from the stream and store them
-        into answer.  Return `answer' itself, or raise an exception if we 
-        could not read the full amount of data."
-
-       <category: 'buffering'>
-       | read last |
-       writePtr notNil ifTrue: [self flush].
-       read := 0.
-
-       "Exhaust the remaining contents of the buffer if they cannot satisfy
-        the whole request."
-       ptr + anInteger - 1 > endPtr 
-           ifTrue: 
-               [answer 
-                   replaceFrom: 1
-                   to: endPtr - ptr + 1
-                   with: collection
-                   startingAt: ptr.
-               read := endPtr - ptr + 1.
-               ptr := endPtr + 1].
-
-       "If we did not read everything, but what's left is less than the size of
-        the buffer, try once more filling it..."
-       anInteger - read < collection size 
-           ifTrue: 
-               [ptr > endPtr ifTrue: [self fill].
-               last := read + endPtr - ptr + 1 min: answer size.
-               answer 
-                   replaceFrom: read + 1
-                   to: last
-                   with: collection
-                   startingAt: ptr.
-               ptr := ptr + last - read.
-               read := last].
-
-       "Anything more?  We read it from the file.  We can come here only if the
-        buffer cannot be filled completely, or if we want to read really a
-        lot of data."
-       [ read = anInteger ] whileFalse: [
-            self atEnd ifTrue: [
-                ^SystemExceptions.NotEnoughElements signalOn: anInteger - 
read].
-            read := read + (self read: answer from: read + 1 to: anInteger)
-        ].
-       ^answer
-    ]
-
     fill [
        "Private - Fill the input buffer"
 
        <category: 'buffering'>
        (access bitAnd: 1) = 0 ifTrue: [^self shouldNotImplement].
        ptr > endPtr ifTrue: [self flush].
-       endPtr := endPtr + (self 
-                           read: collection
-                           from: endPtr + 1
-                           to: collection size)
+       endPtr := endPtr + (super 
+                           nextAvailable: collection size - endPtr
+                           into: collection
+                           startingAt: endPtr + 1)
     ]
 ]
 
diff --git a/kernel/PosStream.st b/kernel/PosStream.st
index 1f9d78b..1788d69 100644
--- a/kernel/PosStream.st
+++ b/kernel/PosStream.st
@@ -88,6 +88,23 @@ or ReadWriteStream instead of me to create and use streams.'>
        aStream next: endPtr putAll: collection startingAt: 1.
     ]
 
+    nextAvailable: anInteger into: aCollection startingAt: pos [
+        "Place up to anInteger objects from the receiver into
+        aCollection, starting from position pos and stopping if
+         no more data is available."
+
+        <category: 'accessing-reading'>
+       | n |
+       n := anInteger min: endPtr - ptr + 1.
+       aCollection
+           replaceFrom: pos
+           to: pos + n - 1
+           with: collection
+           startingAt: ptr.
+       ptr := ptr + n.
+       ^n
+    ]
+
     peek [
        "Returns the next element of the stream without moving the pointer.
         Returns nil when at end of stream."
diff --git a/kernel/Stream.st b/kernel/Stream.st
index 081cd2b..802aa35 100644
--- a/kernel/Stream.st
+++ b/kernel/Stream.st
@@ -59,16 +59,31 @@ provide for writing collections sequentially.'>
        "Return the next anInteger objects in the receiver"
 
        <category: 'accessing-reading'>
-       | data i item |
-       data := self species new: anInteger.
-       
-       [i := 0.
-       [i < anInteger] whileTrue: 
-               [item := self next.
-               data at: (i := i + 1) put: item]] 
-           on: SystemExceptions.EndOfStream
-           do: [:ex | SystemExceptions.NotEnoughElements signalOn: anInteger - 
i].
-       ^data
+       | answer |
+       self
+           next: anInteger
+           into: (answer := self species new: anInteger)
+           startingAt: 1.
+       ^answer
+    ]
+
+    next: anInteger into: answer startingAt: pos [
+       "Read up to anInteger bytes from the stream and store them
+        into answer.  Return the number of bytes that were read, raising
+        an exception if we could not read the full amount of data."
+
+       <category: 'buffering'>
+       | read |
+       read := 0.
+       [ read = anInteger ] whileFalse: [
+            self atEnd ifTrue: [
+                ^SystemExceptions.NotEnoughElements signalOn: anInteger - 
read].
+            read := read + (self
+                               nextAvailable: anInteger - read
+                               into: answer
+                               startingAt: 1)
+        ].
+       ^answer
     ]
 
     nextAvailable: anInteger [
@@ -79,14 +94,32 @@ provide for writing collections sequentially.'>
         operation."
 
        <category: 'accessing-reading'>
-       | answer |
-       answer := self species new: anInteger.
-       1 to: anInteger do: 
-               [:i | self atEnd ifTrue: [^answer copyFrom: 1 to: i - 1].
-               answer at: i put: self next].
+       | n answer |
+       n := self
+           nextAvailable: anInteger
+           into: (answer := self species new: anInteger)
+           startingAt: 1.
+       n < anInteger ifTrue: [ answer := answer copyFrom: 1 to: n ].
        ^answer
     ]
 
+    nextAvailable: anInteger into: aCollection startingAt: pos [
+       "Place the next anInteger objects from the receiver into aCollection,
+        starting at position pos.  Return the number of items stored.
+        Besides stopping if the end of the stream is reached, this may
+        return less than this number of bytes for various reasons.
+        For example, on files and sockets this operation could be
+        non-blocking, or could do at most one I/O operation."
+
+       <category: 'accessing-reading'>
+       | i |
+       i := -1.
+       [(i := i + 1) = anInteger] whileFalse: [
+               self atEnd ifTrue: [^i].
+               aCollection at: i + pos put: self next].
+       ^anInteger
+    ]
+
     nextMatchFor: anObject [
        "Answer whether the next object is equal to anObject. Even if it does
         not, anObject is lost"
@@ -527,14 +560,7 @@ provide for writing collections sequentially.'>
         Smalltalk (including zlib streams)."
 
        <category: 'positioning'>
-       | s |
-       s := self species new: 1024.
-       1 to: 1024
-           do: 
-               [:i | 
-               self atEnd ifTrue: [^s copyFrom: 1 to: i - 1].
-               s at: i put: self next].
-       ^s
+       ^self nextAvailable: 1024
     ]
 
     prefixTableFor: aCollection [
diff --git a/packages/iconv/ChangeLog b/packages/iconv/ChangeLog
index 9bc08be..5e59995 100644
--- a/packages/iconv/ChangeLog
+++ b/packages/iconv/ChangeLog
@@ -1,5 +1,9 @@
 2008-08-05  Paolo Bonzini  <address@hidden>
 
+       * Sets.st: Use #nextInputAvailable:into:startingAt: instead.
+
+2008-08-05  Paolo Bonzini  <address@hidden>
+
        * Sets.st: Add #nextInputAvailable: and use it to refill the buffer.
 
 2008-01-17  Paolo Bonzini  <address@hidden>
diff --git a/packages/iconv/Sets.st b/packages/iconv/Sets.st
index 35c1cfe..6045b27 100644
--- a/packages/iconv/Sets.st
+++ b/packages/iconv/Sets.st
@@ -379,13 +379,13 @@ encodings.'>
        ^origin next
     ]
 
-    nextInputAvailable: n [
-       "Return up to N characters from the origin.  This method is for
+    nextInputAvailable: n into: aCollection startingAt: pos [
+       "Place up to N characters from the origin in aCollection.  This method 
is for
         private use by encoders, calling it outside may corrupt the
         internal state of the encoder."
 
        <category: 'stream operations'>
-       ^origin nextAvailable: n
+       ^origin nextAvailable: n into: aCollection startingAt: pos
     ]
 
     species [
@@ -966,6 +966,22 @@ Iconv is skipped altogether and only Smalltalk converters 
are used.'>
        ^answer
     ]
 
+    nextAvailable: anInteger into: aCollection startingAt: pos [
+       "Answer the next buffer's worth of data from the receiver."
+
+       <category: 'stream operation'>
+       | n |
+       (self atEndOfBuffer and: [self convertMore])
+           ifTrue: [^self pastEnd].
+       n := anInteger min: recodedEnd - recodedPos + 1.
+       aCollection
+           replaceFrom: pos to: pos + n - 1
+           with: recodedBuffer
+           startingAt: recodedPos.
+       recodedPos := recodedPos + n.
+       ^n
+    ]
+
     nextHunkPutAllOn: aStream [
        "Copy the next buffer's worth of data from the receiver onto
         aStream."
@@ -985,12 +1001,7 @@ Iconv is skipped altogether and only Smalltalk converters 
are used.'>
        "Answer the next buffer's worth of data from the receiver."
 
        <category: 'stream operation'>
-       | answer |
-       (self atEndOfBuffer and: [self convertMore])
-           ifTrue: [^self pastEnd].
-       answer := recodedBuffer copyFrom: recodedPos to: recodedEnd.
-       recodedPos := recodedEnd + 1.
-       ^answer
+       ^self nextAvailable: recodedEnd - recodedPos + 1
     ]
 
     release [
@@ -1043,13 +1054,10 @@ Iconv is skipped altogether and only Smalltalk 
converters are used.'>
                readEnd := readEnd - readPos + 1.
                readPos := 1].
 
-       data := self nextInputAvailable: self bufferSize - readEnd.
-       readBuffer
-           replaceFrom: readEnd + 1 to: readEnd + data size 
-           with: data
-           startingAt: 1.
-
-       readEnd := readEnd + data size.
+       readEnd := readEnd + (self
+           nextInputAvailable: self bufferSize - readEnd
+           into: readBuffer
+           startingAt: readEnd + 1).
     ]
 
     initializeFrom: fromEncoding to: toEncoding origin: aStringOrStream [
diff --git a/packages/sockets/Buffers.st b/packages/sockets/Buffers.st
index b822b96..fc2e498 100644
--- a/packages/sockets/Buffers.st
+++ b/packages/sockets/Buffers.st
@@ -124,7 +124,7 @@ evaluates an user defined block to try to get some more 
data.'>
        "Copy a buffer's worth of data from the receiver to aStream, doing
         at most one call to the fill block."
 
-       <category: 'buffer handling'>
+       <category: 'accessing-reading'>
        self atEnd ifTrue: [^super pastEnd].
        aStream next: endPtr - ptr + 1 putAll: self collection startingAt: ptr.
        endPtr := ptr - 1.      "Empty the buffer"
@@ -134,20 +134,27 @@ evaluates an user defined block to try to get some more 
data.'>
        "Answer a buffer's worth of data, doing at most one call
         to the fill block."
 
-       <category: 'buffer handling'>
-       | contents |
-       self atEnd ifTrue: [^super pastEnd].
-       contents := self collection copyFrom: ptr to: endPtr.
-       endPtr := ptr - 1.      "Empty the buffer"
-       ^contents
+       <category: 'accessing-reading'>
+       ^self nextAvailable: endPtr - ptr + 1
     ]
 
     availableBytes [
         "Answer how many bytes are available in the buffer."
 
+       <category: 'buffer handling'>
+       self isEmpty ifTrue: [ self fill ].
        ^endPtr + 1 - ptr
     ]
 
+    nextAvailable: anInteger into: aCollection startingAt: pos [
+       "Place the next anInteger objects from the receiver into aCollection,
+        starting at position pos.  Return the number of items stored."
+
+       <category: 'accessing-reading'>
+       self isEmpty ifTrue: [ self fill ].
+       ^super nextAvailable: anInteger into: aCollection startingAt: pos
+    ]
+
     fill [
        "Fill the buffer with more data if it is empty, and answer
         true if the fill block was able to read more data."
diff --git a/packages/sockets/ChangeLog b/packages/sockets/ChangeLog
index f7450dc..f10dbb5 100644
--- a/packages/sockets/ChangeLog
+++ b/packages/sockets/ChangeLog
@@ -1,5 +1,12 @@
 2008-08-05  Paolo Bonzini  <address@hidden>
 
+       * Buffers.st: Add #nextAvailable:into:startingAt:.
+       * Sockets.st: Change #nextAvailable: into
+       #nextAvailable:into:startingAt:.  Change the fill
+       blocks to not use #read:from:to: and #write:from:to:.
+
+2008-08-05  Paolo Bonzini  <address@hidden>
+
        * Buffers.st: Add #nextHunk and #nextHunkPutAllOn:.
        * Sockets.st: Remove the lookahead instance variable.  Delegate
        more stuff to the readBuffer, including #nextHunk.  Implement
diff --git a/packages/sockets/Sockets.st b/packages/sockets/Sockets.st
index b2c11f2..11de715 100644
--- a/packages/sockets/Sockets.st
+++ b/packages/sockets/Sockets.st
@@ -1164,7 +1164,6 @@ This class adds a read buffer to the basic model of 
AbstractSocket.'>
 
        <category: 'stream protocol'>
        self canRead ifFalse: [ ^0 ].
-       self readBuffer isEmpty ifTrue: [ self readBuffer fill ].
        ^self readBuffer availableBytes
     ]
 
@@ -1208,30 +1207,24 @@ This class adds a read buffer to the basic model of 
AbstractSocket.'>
        ^self readBuffer next
     ]
        
-    nextAvailable: anInteger [
-        "Return up to anInteger objects in the receiver, stopping if
-         the end of the stream is reached"
+    nextAvailable: anInteger into: aCollection startingAt: pos [
+        "Place up to anInteger objects from the receiver into
+        aCollection, starting from position pos and stopping if
+         no more data is available."
 
         <category: 'accessing-reading'>
-       | buffer available stream |
+       | available read |
        readBuffer isNil ifTrue: [ ^self pastEnd ].
-
        self ensureReadable.
-       available := self availableBytes.
-       available >= anInteger ifTrue: [ ^self next: anInteger ].
-
-       "Try filling the first buffer."
-       buffer := self next: available.
-       available := self availableBytes min: anInteger - available.
-       available = 0 ifTrue: [ ^buffer ].
 
-       "Streams have extra costs because of copying, use them only if
-        needed."
-       stream := WriteStream with: buffer.
-       [ (available := self availableBytes min: anInteger - stream size) > 0 ]
-           whileTrue: [ stream nextPutAll: (self readBuffer next: available) ].
+       read := 0.
+       [ (available := self availableBytes) > 0 ] whileTrue: [
+           read := read + (self readBuffer
+               nextAvailable: available
+               into: aCollection
+               startingAt: pos + read) ].
 
-       ^stream contents
+       ^read
     ]
 
     nextHunkPutAllOn: aStream [
@@ -1256,16 +1249,6 @@ This class adds a read buffer to the basic model of 
AbstractSocket.'>
        ^self readBuffer nextHunk
     ]
 
-    next: count [
-       "Read `count' bytes from the socket.  This might yield control to other
-        Smalltalk Processes."
-
-       <category: 'stream protocol'>
-       | result |
-       readBuffer isNil ifTrue: [ ^self pastEnd ].
-       ^self readBuffer next: count
-    ]
-
     peek [
        "Read a byte from the socket, without advancing the buffer; answer
         nil if no more data is available.  This might yield control to other
@@ -1329,7 +1312,7 @@ This class adds a read buffer to the basic model of 
AbstractSocket.'>
                [:data :size | 
                self implementation ensureReadable.
                self implementation isOpen 
-                   ifTrue: [self implementation read: data numBytes: size]
+                   ifTrue: [self implementation nextAvailable: size into: data 
startingAt: 1]
                    ifFalse: 
                        [self deleteBuffers.
                        0]]
@@ -1470,7 +1453,7 @@ This class adds read and write buffers to the basic model 
of AbstractSocket.'>
                | alive |
                self implementation ensureWriteable.
                alive := self implementation isOpen 
-                           and: [(self implementation write: data numBytes: 
size) > -1].
+                           and: [(self implementation next: size putAll: data 
startingAt: 1) > -1].
                alive ifFalse: [self deleteBuffers]]
     ]
 
diff --git a/packages/sport/ChangeLog b/packages/sport/ChangeLog
index 3599bbb..ba15e8d 100644
--- a/packages/sport/ChangeLog
+++ b/packages/sport/ChangeLog
@@ -1,3 +1,8 @@
+2008-08-05  Paolo Bonzini  <address@hidden>
+
+       * sport.st: At last use native Socket methods for #read: and
+       #readInto:startingAt:for:.
+
 2008-08-04  Paolo Bonzini  <address@hidden>
 
        * sport.st: Use StreamSocket>>#nextAvailable:.
diff --git a/packages/sport/sport.st b/packages/sport/sport.st
index 6ed8633..957f5f3 100644
--- a/packages/sport/sport.st
+++ b/packages/sport/sport.st
@@ -1205,10 +1205,11 @@ Object subclass: SpSocket [
         If the targetNumberOfBytes     are not available, I return what I can 
get."
 
        <category: 'services-io'>
-       "FIXME: this needs #nextAvailable:into: to avoid a copy in #asByteArray"
-       ^(self underlyingSocket
-           ensureReadable;
-           nextAvailable: targetNumberOfBytes) asByteArray
+       | answer n |
+       answer := ByteArray new: targetNumberOfBytes.
+       n := self underlyingSocket nextAvailable: targetNumberOfBytes into: 
answer startingAt: 1.
+       n < targetNumberOfBytes ifTrue: [ answer := answer copyFrom: 1 to: n ].
+       ^answer
     ]
 
     readInto: aByteArray startingAt: startIndex for: aNumberOfBytes [
@@ -1217,13 +1218,7 @@ Object subclass: SpSocket [
         number of bytes to be read.    We get what its there no matter how 
much their is!!"
 
        <category: 'services-io'>
-       | buffer |
-       buffer := self underlyingSocket
-           ensureReadable;
-           nextAvailable: aNumberOfBytes.
-       aByteArray replaceFrom: startIndex to: startIndex + buffer size - 1
-                    with: buffer startingAt: 1.
-       ^buffer size
+       ^self underlyingSocket nextAvailable: aNumberOfBytes into: aByteArray 
startingAt: startIndex
     ]
 
     readyForRead [
diff --git a/packages/zlib/ChangeLog b/packages/zlib/ChangeLog
index a9c3914..9e8bfb5 100644
--- a/packages/zlib/ChangeLog
+++ b/packages/zlib/ChangeLog
@@ -1,5 +1,9 @@
 2008-08-05  Paolo Bonzini  <address@hidden>
 
+       * ZLibReadStream.st: Add #nextAvailable:into:startingAt:.
+
+2008-08-05  Paolo Bonzini  <address@hidden>
+
        * ZLibReadStream.st: Add #nextHunkPutAllOn:.
        * zlibtests.st: Test it.
 
diff --git a/packages/zlib/ZLibReadStream.st b/packages/zlib/ZLibReadStream.st
index 17fbea5..8684ab5 100644
--- a/packages/zlib/ZLibReadStream.st
+++ b/packages/zlib/ZLibReadStream.st
@@ -89,11 +89,24 @@ used for communication with zlib.'>
         operation."
 
        <category: 'streaming'>
-       | result |
-       self atEnd ifTrue: [^self pastEnd].
-       result := outBytes copyFrom: ptr + 1 to: endPtr.
-       ptr := endPtr.
-       ^result
+       ^self nextAvailable: endPtr - ptr
+    ]
+
+    nextAvailable: anInteger into: aCollection startingAt: pos [
+        "Place up to anInteger objects from the receiver into
+         aCollection, starting from position pos and stopping if
+         no more data is available."
+
+        <category: 'accessing-reading'>
+        | n |
+        n := anInteger min: endPtr - ptr.
+        aCollection
+            replaceFrom: pos
+            to: pos + n - 1
+            with: outBytes
+            startingAt: ptr + 1.
+        ptr := ptr + n.
+        ^n
     ]
 
     peek [

reply via email to

[Prev in Thread] Current Thread [Next in Thread]