2002-08-21 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / class / corlib / System / Double.cs
index c362b170be90a7e2925401f79fad1f1dacd79916..7f72c334561992a7ad3dd881b45001cd0c08d56e 100644 (file)
@@ -35,22 +35,29 @@ namespace System {
                        if (!(v is System.Double))
                                throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
 
-                       if (IsPositiveInfinity(value) && IsPositiveInfinity((double) v)){
+                       double dv = (double)v;
+
+                       if (IsPositiveInfinity(value) && IsPositiveInfinity(dv))
                                return 0;
-                       }
 
-                       if (IsNegativeInfinity(value) && IsNegativeInfinity((double) v)){
+                       if (IsNegativeInfinity(value) && IsNegativeInfinity(dv))
                                return 0;
-                       }
 
-                       if (IsNaN((double) v)) {
+                       if (IsNaN(dv))
                                if (IsNaN(value))
                                        return 0;
                                else
                                        return 1;
-                       }
 
-                       return (int) (value - ((double) v));
+                       if (IsNaN(value))
+                               if (IsNaN(dv))
+                                       return 0;
+                               else
+                                       return -1;
+
+                       if (value > dv) return 1;
+                       else if (value < dv) return -1;
+                       else return 0;
                }
 
                public override bool Equals (object o)
@@ -108,7 +115,16 @@ namespace System {
                        return Parse (s, style, null);
                }
 
-               [MonoTODO]
+               // We're intentionally using constants here to avoid some bigger headaches in mcs.
+               // This struct must be compiled before System.Enum so we can't use enums here.
+               private const int State_AllowSign = 1;
+               private const int State_Digits = 2;
+               private const int State_Decimal = 3;
+               private const int State_ExponentSign = 4;
+               private const int State_Exponent = 5;
+               private const int State_ConsumeWhiteSpace = 6;
+               
+               [MonoTODO("check if digits are group in correct numbers between the group separators")]
                public static double Parse (string s, NumberStyles style, IFormatProvider provider)
                {
                        if (s == null) throw new ArgumentNullException();
@@ -121,62 +137,182 @@ namespace System {
                        if (s == format.NaNSymbol) return Double.NaN;
                        if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
                        if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
-                       string[] sl;
-                       long integral = 0;
-                       long fraction = 0;
-                       long exponent = 1;
-                       double retval = 0;
-                       if ((style & NumberStyles.AllowLeadingWhite) != 0)
-                       {
-                               s.TrimStart(null);
-                       }
-                       if ((style & NumberStyles.AllowTrailingWhite) != 0)
-                       {
-                               s.TrimEnd(null);
-                       }
-                       sl = s.Split(new Char[] {'e', 'E'}, 2);
-                       if (sl.Length > 1)
-                       {
-                               if ((style & NumberStyles.AllowExponent) == 0)
-                               {
+
+                       //
+                       // validate and prepare string for C
+                       //
+                       int len = s.Length;
+                       byte [] b = new byte [len + 1];
+                       int didx = 0;
+                       int sidx = 0;
+                       char c;
+                       
+                       if ((style & NumberStyles.AllowLeadingWhite) != 0){
+                               while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
+                                      sidx++;
+
+                               if (sidx == len)
                                        throw new FormatException();
-                               }
-                               exponent = long.Parse(sl[1], NumberStyles.AllowLeadingSign, format);
                        }
-                       s = sl[0];
-                       sl = s.Split(format.NumberDecimalSeparator.ToCharArray(), 2);
-                       if (sl.Length > 1)
-                       {
-                               if ((style & NumberStyles.AllowDecimalPoint) == 0)
-                               {
-                                       throw new FormatException();
-                               }
-                               fraction = long.Parse(sl[1], NumberStyles.None, format);
+
+                       bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
+
+                       //
+                       // Machine state
+                       //
+                       int state = State_AllowSign;
+
+                       //
+                       // Setup
+                       //
+                       string decimal_separator = null;
+                       string group_separator = null;
+                       int decimal_separator_len = 0;
+                       int group_separator_len = 0;
+                       if ((style & NumberStyles.AllowDecimalPoint) != 0){
+                               decimal_separator = format.NumberDecimalSeparator;
+                               decimal_separator_len = decimal_separator.Length;
                        }
-                       NumberStyles tempstyle = NumberStyles.None;
-                       if ((style & NumberStyles.AllowLeadingSign) != 0){
-                               tempstyle = NumberStyles.AllowLeadingSign;
+                       if ((style & NumberStyles.AllowThousands) != 0){
+                               group_separator = format.NumberGroupSeparator;
+                               group_separator_len = group_separator.Length;
                        }
+                       string positive = format.PositiveSign;
+                       string negative = format.NegativeSign;
+                       
+                       for (; sidx < len; sidx++){
+                               c = s [sidx];
+
+                               switch (state){
+                               case State_AllowSign:
+                                       if ((style & NumberStyles.AllowLeadingSign) != 0){
+                                               if (c == positive [0] &&
+                                                   s.Substring (sidx, positive.Length) == positive){
+                                                       state = State_Digits;
+                                                       sidx += positive.Length-1;
+                                                       continue;
+                                               }
+
+                                               if (c == negative [0] &&
+                                                   s.Substring (sidx, negative.Length) == negative){
+                                                       state = State_Digits;
+                                                       b [didx++] = (byte) '-';
+                                                       sidx += negative.Length-1;
+                                                       continue;
+                                               }
+                                       }
+                                       state = State_Digits;
+                                       goto case State_Digits;
+                                       
+                               case State_Digits:
+                                       if (Char.IsDigit (c)){
+                                               b [didx++] = (byte) c;
+                                               break;
+                                       }
+                                       if (c == 'e' || c == 'E')
+                                               goto case State_Decimal;
+                                       
+                                       if (decimal_separator != null &&
+                                           decimal_separator [0] == c){
+                                               if (s.Substring (sidx, decimal_separator_len) ==
+                                                   decimal_separator){
+                                                       b [didx++] = (byte) '.';
+                                                       sidx += decimal_separator_len-1;
+                                                       state = State_Decimal; 
+                                                       break;
+                                               }
+                                       }
+                                       if (group_separator != null &&
+                                           group_separator [0] == c){
+                                               if (s.Substring (sidx, group_separator_len) ==
+                                                   group_separator){
+                                                       sidx += group_separator_len-1;
+                                                       state = State_Digits; 
+                                                       break;
+                                               }
+                                       }
+                                       
+                                       if (Char.IsWhiteSpace (c))
+                                               goto case State_ConsumeWhiteSpace;
+
+                                       throw new FormatException ("Unknown char: " + c);
+
+                               case State_Decimal:
+                                       if (Char.IsDigit (c)){
+                                               b [didx++] = (byte) c;
+                                               break;
+                                       }
+
+                                       if (c == 'e' || c == 'E'){
+                                               if ((style & NumberStyles.AllowExponent) == 0)
+                                                       throw new FormatException ("Unknown char: " + c);
+                                               b [didx++] = (byte) c;
+                                               state = State_ExponentSign;
+                                               break;
+                                       }
+                                       
+                                       if (Char.IsWhiteSpace (c))
+                                               goto case State_ConsumeWhiteSpace;
+                                       throw new FormatException ("Unknown char: " + c);
 
-                       if (sl[0].Length > 0)
-                               integral = long.Parse(sl[0], tempstyle, format);
-                       else
-                               integral = 0;
+                               case State_ExponentSign:
+                                       if (Char.IsDigit (c)){
+                                               state = State_Exponent;
+                                               goto case State_Exponent;
+                                       }
 
-                       retval = fraction;
+                                       if (c == positive [0] &&
+                                           s.Substring (sidx, positive.Length) == positive){
+                                               state = State_Digits;
+                                               sidx += positive.Length-1;
+                                               continue;
+                                       }
 
-                       // FIXME: what about the zeros between the decimal point 
-                       // and the first non-zero digit?
-                       while (retval >1) retval /= 10;
-                       if (integral < 0){
-                               retval -= integral;
-                               retval = -retval;
+                                       if (c == negative [0] &&
+                                           s.Substring (sidx, negative.Length) == negative){
+                                               state = State_Digits;
+                                               b [didx++] = (byte) '-';
+                                               sidx += negative.Length-1;
+                                               continue;
+                                       }
+
+                                       if (Char.IsWhiteSpace (c))
+                                               goto case State_ConsumeWhiteSpace;
+                                       
+                                       throw new FormatException ("Unknown char: " + c);
+
+                               case State_Exponent:
+                                       if (Char.IsDigit (c)){
+                                               b [didx++] = (byte) c;
+                                               break;
+                                       }
+                                       
+                                       if (Char.IsWhiteSpace (c))
+                                               goto case State_ConsumeWhiteSpace;
+                                       throw new FormatException ("Unknown char: " + c);
+
+                               case State_ConsumeWhiteSpace:
+                                       if (allow_trailing_white && Char.IsWhiteSpace (c))
+                                               break;
+                                       throw new FormatException ("Unknown char");
+                               }
+                       }
+
+                       b [didx] = 0;
+                       unsafe {
+                               fixed (byte *p = &b [0]){
+                                       double retVal = ParseImpl (p);
+                                       if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
+                                               throw new OverflowException();
+
+                                       return retVal;
+                               }
                        }
-                       else retval += integral;
-                       if (exponent != 1) retval *= Math.Pow(10, exponent);
-                       return retval;
                }
 
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               unsafe private static extern double ParseImpl (byte *byte_ptr);
+               
                public override string ToString ()
                {
                        return ToString (null, null);