[PATCH] Block-level stream input protocol

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] Block-level stream input protocol

Paolo Bonzini-2
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  <[hidden email]>
 
+ * 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  <[hidden email]>
+
  * 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  <[hidden email]>
 
+ * Sets.st: Use #nextInputAvailable:into:startingAt: instead.
+
+2008-08-05  Paolo Bonzini  <[hidden email]>
+
  * Sets.st: Add #nextInputAvailable: and use it to refill the buffer.
 
 2008-01-17  Paolo Bonzini  <[hidden email]>
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  <[hidden email]>
 
+ * 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  <[hidden email]>
+
  * 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  <[hidden email]>
+
+ * sport.st: At last use native Socket methods for #read: and
+ #readInto:startingAt:for:.
+
 2008-08-04  Paolo Bonzini  <[hidden email]>
 
  * 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  <[hidden email]>
 
+ * ZLibReadStream.st: Add #nextAvailable:into:startingAt:.
+
+2008-08-05  Paolo Bonzini  <[hidden email]>
+
  * 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 [

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk