<div dir="ltr"><div><div>Just a side note: nextFloat is broken in the sense that it will fail to answer the nearest floating point value to the specified decimal value.<br><br></div>OK, it's reasonably fast, but the comments should mention the trade offs.<br><br></div><div>Also in 32 bits VM, nextFloat might be slower than NumberParser when numbers are specified with many decimal digits.<br></div><div><br></div>Nicolas<br></div><div class="gmail_extra"><br><div class="gmail_quote">2015-04-02 0:08 GMT+02:00 <span dir="ltr"><<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Levente Uzonyi uploaded a new version of Collections to project The Trunk:<br>
<a href="http://source.squeak.org/trunk/Collections-ul.607.mcz" target="_blank">http://source.squeak.org/trunk/Collections-ul.607.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: Collections-ul.607<br>
Author: ul<br>
Time: 2 April 2015, 12:07:14.622 am<br>
UUID: 607c7a3f-c462-454c-8e18-02c49e4ae91a<br>
Ancestors: Collections-ul.606<br>
<br>
Simplified CharacterSet class>>separators.<br>
Fixed ReadStream >> #nextFloat, when collection is not a ByteString.<br>
<br>
=============== Diff against Collections-ul.606 ===============<br>
<br>
Item was changed:<br>
----- Method: CharacterSet class>>separators (in category 'accessing') -----<br>
separators<br>
"return a set containing just the whitespace characters"<br>
<br>
+ ^Separators ifNil: [ Separators := self newFrom: Character separators ]!<br>
- ^Separators ifNil: [<br>
- Separators := self new<br>
- addAll: Character separators;<br>
- yourself ]!<br>
<br>
Item was changed:<br>
----- Method: ReadStream>>nextFloat (in category 'accessing') -----<br>
nextFloat<br>
"Read a floating point value from the receiver. This method is highly optimized for cases<br>
where many floating point values need to be read subsequently. And if this needs to go<br>
even faster, look at the inner loops fetching the characters - moving those into a plugin<br>
would speed things up even more."<br>
| buffer count sign index cc value digit fraction exp startIndex anyDigit digitNeeded |<br>
buffer := collection.<br>
count := readLimit.<br>
index := position+1.<br>
<br>
"Skip separators"<br>
+ index := ByteString findFirstInString: buffer inSet: CharacterSet nonSeparators byteArrayMap startingAt: index.<br>
- index := buffer indexOfAnyOf: CharacterSet nonSeparators startingAt: index.<br>
index = 0 ifTrue:[self setToEnd. ^nil].<br>
<br>
"check for sign"<br>
digitNeeded := false.<br>
sign := 1. cc := buffer byteAt: index.<br>
cc = 45 "$- asciiValue"<br>
ifTrue:[sign := -1. index := index+1. digitNeeded := true]<br>
ifFalse:[cc = 43 "$+ asciiValue" ifTrue:[index := index+1. digitNeeded := true]].<br>
<br>
"Read integer part"<br>
startIndex := index.<br>
value := 0.<br>
[index <= count and:[<br>
digit := (buffer byteAt: index) - 48. "$0 asciiValue"<br>
digit >= 0 and:[digit <= 9]]] whileTrue:[<br>
value := value * 10 + digit.<br>
index := index + 1.<br>
].<br>
anyDigit := index > startIndex.<br>
index > count ifTrue:[<br>
(digitNeeded and:[anyDigit not]) ifTrue:[^self error: 'At least one digit expected'].<br>
self setToEnd. ^value asFloat * sign].<br>
<br>
(buffer byteAt: index) = 46 "$. asciiValue" ifTrue:["<integer>.<fraction>"<br>
index := index+1.<br>
startIndex := index.<br>
"NOTE: fraction and exp below can overflow into LargeInteger range. If they do, then things slow down horribly due to the relatively slow LargeInt -> Float conversion. This can be avoided by changing fraction and exp to use floats to begin with (0.0 and 1.0 respectively), however, this will give different results to Float>>readFrom: and it is not clear if that is acceptable here."<br>
fraction := 0. exp := 1.<br>
[index <= count and:[<br>
digit := (buffer byteAt: index) - 48. "$0 asciiValue"<br>
digit >= 0 and:[digit <= 9]]] whileTrue:[<br>
fraction := fraction * 10 + digit.<br>
exp := exp * 10.<br>
index := index + 1.<br>
].<br>
value := value + (fraction asFloat / exp asFloat).<br>
anyDigit := anyDigit or:[index > startIndex].<br>
].<br>
value := value asFloat * sign.<br>
<br>
"At this point we require at least one digit to avoid allowing:<br>
- . ('0.0' without leading digits)<br>
- e32 ('0e32' without leading digits)<br>
- .e32 ('0.0e32' without leading digits)<br>
but these are currently allowed:<br>
- .5 (0.5)<br>
- 1. ('1.0')<br>
- 1e32 ('1.0e32')<br>
- 1.e32 ('1.0e32')<br>
- .5e32 ('0.5e32')<br>
"<br>
anyDigit ifFalse:["Check for NaN/Infinity first"<br>
(count - index >= 2 and:[(buffer copyFrom: index to: index+2) = 'NaN'])<br>
ifTrue:[position := index+2. ^Float nan * sign].<br>
(count - index >= 7 and:[(buffer copyFrom: index to: index+7) = 'Infinity'])<br>
ifTrue:[position := index+7. ^Float infinity * sign].<br>
^self error: 'At least one digit expected'<br>
].<br>
<br>
index > count ifTrue:[self setToEnd. ^value asFloat].<br>
<br>
(buffer byteAt: index) = 101 "$e asciiValue" ifTrue:["<number>e[+|-]<exponent>"<br>
index := index+1. "skip e"<br>
sign := 1. cc := buffer byteAt: index.<br>
cc = 45 "$- asciiValue"<br>
ifTrue:[sign := -1. index := index+1]<br>
ifFalse:[cc = 43 "$+ asciiValue" ifTrue:[index := index+1]].<br>
startIndex := index.<br>
exp := 0. anyDigit := false.<br>
[index <= count and:[<br>
digit := (buffer byteAt: index) - 48. "$0 asciiValue"<br>
digit >= 0 and:[digit <= 9]]] whileTrue:[<br>
exp := exp * 10 + digit.<br>
index := index + 1.<br>
].<br>
index> startIndex ifFalse:[^self error: 'Exponent expected'].<br>
value := value * (10.0 raisedToInteger: exp * sign).<br>
].<br>
<br>
position := index-1.<br>
^value!<br>
<br>
<br>
</blockquote></div><br></div>