#OTHER by cg
authorClaus Gittinger <cg@exept.de>
Tue, 17 Dec 2019 17:16:09 +0100
changeset 25149 663805b3e3ef
parent 25148 03ac6dae4ff8
child 25150 63e8127841ef
#OTHER by cg class: Number class changed: #readFrom:decimalPointCharacters:thousandsSeparator:allowCStyle:onError: number scanning
Integer.st
--- a/Integer.st	Tue Dec 17 16:58:31 2019 +0100
+++ b/Integer.st	Tue Dec 17 17:16:09 2019 +0100
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 1988 by Claus Gittinger
               All Rights Reserved
@@ -377,8 +379,8 @@
 !
 
 readFrom:aStringOrStream radix:radix
-    "return the next UNSIGNED Integer from the (character-)stream aStream in radix; 
-     (assumes that the initial XXr has already been read).
+    "return the next possibly signed Integer from the (character-)stream aStream in radix; 
+     (assumes that any initial XXr has already been read).
      No whitespace-skipping is done.
      Returns 0 if no number available.
 
@@ -392,67 +394,21 @@
 !
 
 readFrom:aStringOrStream radix:radix onError:exceptionBlock
-    "return the next UNSIGNED Integer from the (character-)stream aStream in radix; 
-     (assumes that the initial XXr has already been read).
+    "return the next possibly signed Integer from the (character-)stream aStream in radix; 
+     (assumes that any initial XXr has already been read).
      No whitespace-skipping is done.
      Returns the value of exceptionBlock, if no number is available."
 
-    |str nextChar value
-     r     "{ Class: SmallInteger }"
-     r2    "{ Class: SmallInteger }"
-     r3    "{ Class: SmallInteger }"
-     r4    "{ Class: SmallInteger }"
-     digit1 digit2 digit3 digit4 |
+    |str nextChar|
 
     str := aStringOrStream readStream.
 
     nextChar := str peekOrNil.
-    (nextChar isNil or:[(value := nextChar digitValueRadix:radix) isNil]) ifTrue:[
-        ^ exceptionBlock value
+    nextChar == $- ifTrue:[
+        str next.
+        ^ self readUnsignedFrom:str radix:radix sign:-1 onError:exceptionBlock
     ].
-
-"/ OLD code
-"/    [nextChar notNil and:[nextChar isDigitRadix:radix]] whileTrue:[
-"/        str next.
-"/        value := value * radix + nextChar digitValue.
-"/        nextChar := str peekOrNil.
-"/    ].
-"/    ^ value.
-
-    "/ the code below does the same, but is much faster, if the
-    "/ converted number is large
-    "/ (requires only half as many LargeInt multiplications and additions)
-    "/ It should not be slower for smallIntegers.
-
-    r := radix.
-    r2 := r * r.
-    r4 := r2 * r2.
-
-    [
-        nextChar := str nextPeekOrNil.
-        nextChar notNil and:[(digit1 := nextChar digitValueRadix:r) notNil]
-    ] whileTrue:[
-        "/ read 4 chars and pre-compute their value to avoid largeInt operations.
-
-        nextChar := str nextPeekOrNil.
-        (nextChar isNil or:[(digit2 := nextChar digitValueRadix:r) isNil]) ifTrue:[
-            ^ (value * r) + digit1.
-        ].
-
-        nextChar := str nextPeekOrNil.
-        (nextChar isNil or:[(digit3 := nextChar digitValueRadix:r) isNil]) ifTrue:[
-            ^ (value * r2) + ((digit1*r) + digit2) .
-        ].
-
-        nextChar := str nextPeekOrNil.
-        (nextChar isNil or:[ (digit4 := nextChar digitValueRadix:r) isNil]) ifTrue:[
-            r3 := r2 * r.
-            ^ (value * r3) + ((((digit1*r) + digit2)*r) + digit3).
-        ].
-
-        value := (value * r4) + ((((((digit1*r) + digit2)*r) + digit3)*r) + digit4).
-    ].
-    ^ value
+    ^ self readUnsignedFrom:str radix:radix sign:1 onError:exceptionBlock
 
     "
      Integer readFrom:(ReadStream on:'12345') radix:10
@@ -807,6 +763,156 @@
      Integer readFromString:'1234 ' radix:10 onError:[nil]  - I do not accept anything after the number
 
     "
+!
+
+readUnsignedFrom:aStringOrStream radix:radix
+    "return the next UNSIGNED Integer from the (character-)stream aStream in radix; 
+     (assumes that any initial XXr or sign has already been read).
+     No whitespace-skipping is done.
+     Returns 0 if no number available.
+
+     NOTICE:
+       This behaves different from the default readFrom:, in returning
+       0 (instead of raising an error) in case no number can be read.
+       It is unclear, if this is the correct behavior (ST-80 does this)
+       - depending on the upcoming ANSI standard, this may change."
+
+    ^ self readUnsignedFrom:aStringOrStream radix:radix sign:1 onError:0
+!
+
+readUnsignedFrom:aStringOrStream radix:radix onError:exceptionBlock
+    "return the next UNSIGNED Integer from the (character-)stream aStream in radix; 
+     (assumes that any initial XXr or sign has already been read).
+     No whitespace-skipping is done.
+     Returns the value of exceptionBlock, if no number is available."
+
+    ^ self readUnsignedFrom:aStringOrStream radix:radix sign:1 onError:exceptionBlock
+
+    "
+     Integer readUnsignedFrom:(ReadStream on:'12345') radix:10
+     Integer readUnsignedFrom:(ReadStream on:'FFFF') radix:16
+     Integer readUnsignedFrom:(ReadStream on:'1010') radix:2
+     Integer readUnsignedFrom:(ReadStream on:'foobar') radix:10
+     Integer readUnsignedFrom:(ReadStream on:'foobar') radix:10 onError:nil
+     Integer readUnsignedFrom:'gg' radix:10 onError:0
+     Integer readUnsignedFrom:'' radix:10 onError:'wrong'
+
+     |s|
+     s := String new:1000 withAll:$1.
+     Time millisecondsToRun:[
+        1000 timesRepeat:[
+            s asInteger
+        ]
+     ]
+    "
+
+    "Modified: / 14.4.1998 / 19:16:46 / cg"
+!
+
+readUnsignedFrom:aStringOrStream radix:radix sign:sign
+    "return the next UNSIGNED Integer from the (character-)stream aStream in radix; 
+     (assumes that any initial XXr or sign has already been read).
+     No whitespace-skipping is done.
+     Returns 0 if no number available.
+
+     NOTICE:
+       This behaves different from the default readFrom:, in returning
+       0 (instead of raising an error) in case no number can be read.
+       It is unclear, if this is the correct behavior (ST-80 does this)
+       - depending on the upcoming ANSI standard, this may change."
+
+    ^ self readUnsignedFrom:aStringOrStream radix:radix sign:sign onError:0
+!
+
+readUnsignedFrom:aStringOrStream radix:radix sign:sign onError:exceptionBlock
+    "return the next UNSIGNED Integer from the (character-)stream aStream in radix; 
+     (assumes that any initial XXr or sign has already been read).
+     No whitespace-skipping is done.
+     Returns the value of exceptionBlock, if no number is available."
+
+    |str nextChar value ret
+     r     "{ Class: SmallInteger }"
+     r2    "{ Class: SmallInteger }"
+     r3    "{ Class: SmallInteger }"
+     r4    "{ Class: SmallInteger }"
+     digit1 digit2 digit3 digit4 |
+
+    str := aStringOrStream readStream.
+
+    nextChar := str peekOrNil.
+    (nextChar isNil or:[(value := nextChar digitValueRadix:radix) isNil]) ifTrue:[
+        ^ exceptionBlock value
+    ].
+
+"/ OLD code
+"/    [nextChar notNil and:[nextChar isDigitRadix:radix]] whileTrue:[
+"/        str next.
+"/        value := value * radix + nextChar digitValue.
+"/        nextChar := str peekOrNil.
+"/    ].
+"/    ^ value.
+
+    "/ the code below does the same, but is much faster, if the
+    "/ converted number is large
+    "/ (requires only half as many LargeInt multiplications and additions)
+    "/ It should not be slower for smallIntegers.
+
+    r := radix.
+    r2 := r * r.
+    r4 := r2 * r2.
+
+    [
+        nextChar := str nextPeekOrNil.
+        nextChar notNil and:[(digit1 := nextChar digitValueRadix:r) notNil]
+    ] whileTrue:[
+        "/ read 4 chars and pre-compute their value to avoid largeInt operations.
+
+        nextChar := str nextPeekOrNil.
+        (nextChar isNil or:[(digit2 := nextChar digitValueRadix:r) isNil]) ifTrue:[
+            ret := (value * r) + digit1.
+            sign == -1 ifTrue:[^ ret negated].
+            ^ ret
+        ].
+
+        nextChar := str nextPeekOrNil.
+        (nextChar isNil or:[(digit3 := nextChar digitValueRadix:r) isNil]) ifTrue:[
+            ret := (value * r2) + ((digit1*r) + digit2) .
+            sign == -1 ifTrue:[^ ret negated].
+            ^ ret
+        ].
+
+        nextChar := str nextPeekOrNil.
+        (nextChar isNil or:[ (digit4 := nextChar digitValueRadix:r) isNil]) ifTrue:[
+            r3 := r2 * r.
+            ret := (value * r3) + ((((digit1*r) + digit2)*r) + digit3).
+            sign == -1 ifTrue:[^ ret negated].
+            ^ ret
+        ].
+
+        value := (value * r4) + ((((((digit1*r) + digit2)*r) + digit3)*r) + digit4).
+    ].
+    sign == -1 ifTrue:[^ value negated].
+    ^ value
+
+    "
+     Integer readFrom:(ReadStream on:'12345') radix:10
+     Integer readFrom:(ReadStream on:'FFFF') radix:16
+     Integer readFrom:(ReadStream on:'1010') radix:2
+     Integer readFrom:(ReadStream on:'foobar') radix:10
+     Integer readFrom:(ReadStream on:'foobar') radix:10 onError:nil
+     Integer readFrom:'gg' radix:10 onError:0
+     Integer readFrom:'' radix:10 onError:'wrong'
+
+     |s|
+     s := String new:1000 withAll:$1.
+     Time millisecondsToRun:[
+        1000 timesRepeat:[
+            s asInteger
+        ]
+     ]
+    "
+
+    "Modified: / 14.4.1998 / 19:16:46 / cg"
 ! !
 
 !Integer class methodsFor:'Compatibility-Squeak'!
@@ -828,8 +934,6 @@
     "Modified: / 15.11.1999 / 20:35:20 / cg"
 ! !
 
-
-
 !Integer class methodsFor:'class initialization'!
 
 initialize
@@ -886,7 +990,6 @@
     "Modified: 18.7.1996 / 12:26:38 / cg"
 ! !
 
-
 !Integer class methodsFor:'prime numbers'!
 
 flushPrimeCache
@@ -1262,7 +1365,6 @@
     ^ self == Integer
 ! !
 
-
 !Integer methodsFor:'Compatibility-Dolphin'!
 
 highWord
@@ -4147,7 +4249,7 @@
     ^ fibUsingDict value:self
 
     "the running time is mostly dictated by the LargeInteger multiplication performance...
-     (therefore, we get O(n²) execution times, even for a linear number of multiplications)
+     (therefore, we get O(n²) execution times, even for a linear number of multiplications)
 
      Time millisecondsToRun:[50000 fib_iterative]  312    (DUO 1.7Ghz CPU)
      Time millisecondsToRun:[50000 fib_helper]     109
@@ -5742,7 +5844,6 @@
     "Created: / 09-01-2012 / 17:18:06 / cg"
 ! !
 
-
 !Integer methodsFor:'special modulo arithmetic'!
 
 add_32:anInteger