EndOfStream performance cost [was EndOfStream unused]
bonzini at gnu.org
Fri Nov 9 09:30:57 UTC 2007
> - Most String processing loops use atEnd loop (upper level ReadStream
> does not use == nil trick, client code might however uses few).
I found only one that doesn't, in InflateStream>>#atEnd, using this code:
select: [ :m | | s |
s := m getSource asString.
('*next*' match: s ) and: [
('*next == nil*' match: s ) or: [
('*next isNil' match: s ) or: [
'*next notNil' match: s ]]]])
Here is the source code:
"Note: It is possible that we have a few bits left,
representing just the EOB marker. To check for
this we must force decompression of the next
block if at end of data."
super atEnd ifFalse:[^false]. "Primitive test"
(position >= readLimit and:[state = StateNoMoreData])
self next == nil ifTrue:[^true].
position := position - 1.
and in this same class, we have:
state = StateNoMoreData ifTrue:[^nil].
position >= readLimit
ifTrue: [^self pastEndRead]
ifFalse: [^collection at: (position := position + 1)]
So, the "self next == nil" could be written "self pastEndRead == nil".
Or even better, one could simply rewrite "atEnd and next" like this:
position < readLimit ifFalse: [^false].
"for speed, we inline pastEndRead with these changes:"
state = StateNoMoreData ifTrue:[^true].
"position >= readLimit test inlined for speed"
(position >= readLimit and: [self atEnd]) ifTrue: [ ^nil ].
^collection at: (position := position + 1)
Actually, this implementation of #next could be moved up to ReadStream,
so that no override is necessary in InflateStream. So, it looks like
the only explicit usage (in my image) of "self next == nil" ought to be
In some cases, the "self next == nil" test is used implicitly, for example:
('edq' includes: aStream next) ifFalse: [^ nil].
This code however does not seem to be written with speed in mind.
More information about the Squeak-dev