remove warning
[mono.git] / mcs / class / corlib / System / Double.cs
index 765c252f0872fb96287dad34b798cd0e472c34d9..23198122acc40039ff119af139ebb7f3cfd0b7da 100644 (file)
@@ -9,13 +9,47 @@
 // (C) Bob Smith.    http://www.thestuff.net
 //
 
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
 using System.Globalization;
 using System.Runtime.CompilerServices;
 
+#if NET_2_0
+using System.Runtime.ConstrainedExecution;
+#endif
+
 namespace System {
        
        [Serializable]
-       public struct Double : IComparable, IFormattable, IConvertible {
+#if NET_2_0
+       [System.Runtime.InteropServices.ComVisible (true)]
+#endif
+       public struct Double : IComparable, IFormattable, IConvertible
+#if NET_2_0
+               , IComparable <double>, IEquatable <double>
+#endif
+       {
                public const double Epsilon = 4.9406564584124650e-324;
                public const double MaxValue =  1.7976931348623157e308;
                public const double MinValue = -1.7976931348623157e308;
@@ -23,10 +57,7 @@ namespace System {
                public const double NegativeInfinity = -1.0d / 0.0d;
                public const double PositiveInfinity = 1.0d / 0.0d;
                
-               internal double value;
-
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               unsafe extern internal static void AssertEndianity (double *value);
+               internal double m_value;
 
                public int CompareTo (object v)
                {
@@ -38,26 +69,26 @@ namespace System {
 
                        double dv = (double)v;
 
-                       if (IsPositiveInfinity(value) && IsPositiveInfinity(dv))
+                       if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
                                return 0;
 
-                       if (IsNegativeInfinity(value) && IsNegativeInfinity(dv))
+                       if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
                                return 0;
 
                        if (IsNaN(dv))
-                               if (IsNaN(value))
+                               if (IsNaN(m_value))
                                        return 0;
                                else
                                        return 1;
 
-                       if (IsNaN(value))
+                       if (IsNaN(m_value))
                                if (IsNaN(dv))
                                        return 0;
                                else
                                        return -1;
 
-                       if (value > dv) return 1;
-                       else if (value < dv) return -1;
+                       if (m_value > dv) return 1;
+                       else if (m_value < dv) return -1;
                        else return 0;
                }
 
@@ -67,18 +98,58 @@ namespace System {
                                return false;
 
                        if (IsNaN ((double)o)) {
+                               if (IsNaN(m_value))
+                                       return true;
+                               else
+                                       return false;
+                       }
+
+                       return ((double) o) == m_value;
+               }
+
+#if NET_2_0
+               public int CompareTo (double value)
+               {
+                       if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
+                               return 0;
+
+                       if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
+                               return 0;
+
+                       if (IsNaN(value))
+                               if (IsNaN(m_value))
+                                       return 0;
+                               else
+                                       return 1;
+
+                       if (IsNaN(m_value))
                                if (IsNaN(value))
+                                       return 0;
+                               else
+                                       return -1;
+
+                       if (m_value > value) return 1;
+                       else if (m_value < value) return -1;
+                       else return 0;
+               }
+
+               public bool Equals (double value)
+               {
+                       if (IsNaN (value)) {
+                               if (IsNaN(m_value))
                                        return true;
                                else
                                        return false;
                        }
 
-                       return ((double) o) == value;
+                       return value == m_value;
                }
+#endif
 
-               public override int GetHashCode ()
+               public override unsafe int GetHashCode ()
                {
-                       return (int) value;
+                       double d = m_value;
+                       return (*((long*)&d)).GetHashCode ();
                }
 
                public static bool IsInfinity (double d)
@@ -86,9 +157,14 @@ namespace System {
                        return (d == PositiveInfinity || d == NegativeInfinity);
                }
 
+#if NET_2_0
+               [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
+#endif
                public static bool IsNaN (double d)
                {
+#pragma warning disable 1718
                        return (d != d);
+#pragma warning restore
                }
 
                public static bool IsNegativeInfinity (double d)
@@ -124,20 +200,63 @@ namespace System {
                private const int State_ExponentSign = 4;
                private const int State_Exponent = 5;
                private const int State_ConsumeWhiteSpace = 6;
+               private const int State_Exit = 7;
                
-               [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();
-                       if (style > NumberStyles.Any)
-                       {
-                               throw new ArgumentException();
+                       Exception exc;
+                       double result;
+                       
+                       if (!Parse (s, style, provider, false, out result, out exc))
+                               throw exc;
+
+                       return result;
+               }
+               
+               // FIXME: check if digits are group in correct numbers between the group separators
+               internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
+               {
+                       result = 0;
+                       exc = null;
+                       
+                       if (s == null) {
+                               if (!tryParse)
+                                       exc = new ArgumentNullException ("s");
+                               return false;
+                       }
+                       if (s.Length == 0) {
+                               if (!tryParse)
+                                       exc = new FormatException ();
+                               return false;
+                       }
+#if NET_2_0
+                       // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
+                       if ((style & NumberStyles.AllowHexSpecifier) != 0) {
+                               string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
+                               throw new ArgumentException (msg);
+                       }
+#endif
+                       if (style > NumberStyles.Any) {
+                               if (!tryParse)
+                                       exc = new ArgumentException();
+                               return false;
                        }
+
                        NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
                        if (format == null) throw new Exception("How did this happen?");
-                       if (s == format.NaNSymbol) return Double.NaN;
-                       if (s == format.PositiveInfinitySymbol) return Double.PositiveInfinity;
-                       if (s == format.NegativeInfinitySymbol) return Double.NegativeInfinity;
+                       
+                       if (s == format.NaNSymbol) {
+                               result = Double.NaN;
+                               return true;
+                       }
+                       if (s == format.PositiveInfinitySymbol) {
+                               result = Double.PositiveInfinity;
+                               return true;
+                       }
+                       if (s == format.NegativeInfinitySymbol) {
+                               result = Double.NegativeInfinity;
+                               return true;
+                       }
 
                        //
                        // validate and prepare string for C
@@ -152,8 +271,11 @@ namespace System {
                                while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
                                       sidx++;
 
-                               if (sidx == len)
-                                       throw new FormatException();
+                               if (sidx == len) {
+                                       if (!tryParse)
+                                               exc = Int32.GetFormatException ();
+                                       return false;
+                               }
                        }
 
                        bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
@@ -168,8 +290,10 @@ namespace System {
                        //
                        string decimal_separator = null;
                        string group_separator = null;
+                       string currency_symbol = null;
                        int decimal_separator_len = 0;
                        int group_separator_len = 0;
+                       int currency_symbol_len = 0;
                        if ((style & NumberStyles.AllowDecimalPoint) != 0){
                                decimal_separator = format.NumberDecimalSeparator;
                                decimal_separator_len = decimal_separator.Length;
@@ -178,12 +302,21 @@ namespace System {
                                group_separator = format.NumberGroupSeparator;
                                group_separator_len = group_separator.Length;
                        }
+                       if ((style & NumberStyles.AllowCurrencySymbol) != 0){
+                               currency_symbol = format.CurrencySymbol;
+                               currency_symbol_len = currency_symbol.Length;
+                       }
                        string positive = format.PositiveSign;
                        string negative = format.NegativeSign;
                        
                        for (; sidx < len; sidx++){
                                c = s [sidx];
 
+                               if (c == '\0') {
+                                       sidx = len;
+                                       continue;
+                               }
+
                                switch (state){
                                case State_AllowSign:
                                        if ((style & NumberStyles.AllowLeadingSign) != 0){
@@ -214,9 +347,8 @@ namespace System {
                                                goto case State_Decimal;
                                        
                                        if (decimal_separator != null &&
-                                           decimal_separator [0] == c){
-                                               if (s.Substring (sidx, decimal_separator_len) ==
-                                                   decimal_separator){
+                                           decimal_separator [0] == c) {
+                                               if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
                                                        b [didx++] = (byte) '.';
                                                        sidx += decimal_separator_len-1;
                                                        state = State_Decimal; 
@@ -232,11 +364,22 @@ namespace System {
                                                        break;
                                                }
                                        }
+                                       if (currency_symbol != null &&
+                                           currency_symbol [0] == c){
+                                               if (s.Substring (sidx, currency_symbol_len) ==
+                                                   currency_symbol){
+                                                       sidx += currency_symbol_len-1;
+                                                       state = State_Digits; 
+                                                       break;
+                                               }
+                                       }
                                        
                                        if (Char.IsWhiteSpace (c))
                                                goto case State_ConsumeWhiteSpace;
 
-                                       throw new FormatException ("Unknown char: " + c);
+                                       if (!tryParse)
+                                               exc = new FormatException ("Unknown char: " + c);
+                                       return false;
 
                                case State_Decimal:
                                        if (Char.IsDigit (c)){
@@ -245,8 +388,11 @@ namespace System {
                                        }
 
                                        if (c == 'e' || c == 'E'){
-                                               if ((style & NumberStyles.AllowExponent) == 0)
-                                                       throw new FormatException ("Unknown char: " + c);
+                                               if ((style & NumberStyles.AllowExponent) == 0) {
+                                                       if (!tryParse)
+                                                               exc = new FormatException ("Unknown char: " + c);
+                                                       return false;
+                                               }
                                                b [didx++] = (byte) c;
                                                state = State_ExponentSign;
                                                break;
@@ -254,7 +400,10 @@ namespace System {
                                        
                                        if (Char.IsWhiteSpace (c))
                                                goto case State_ConsumeWhiteSpace;
-                                       throw new FormatException ("Unknown char: " + c);
+                                       
+                                       if (!tryParse)
+                                               exc = new FormatException ("Unknown char: " + c);
+                                       return false;
 
                                case State_ExponentSign:
                                        if (Char.IsDigit (c)){
@@ -280,8 +429,10 @@ namespace System {
                                        if (Char.IsWhiteSpace (c))
                                                goto case State_ConsumeWhiteSpace;
                                        
-                                       throw new FormatException ("Unknown char: " + c);
-
+                                       if (!tryParse)
+                                               exc = new FormatException ("Unknown char: " + c);
+                                       return false;
+                                       
                                case State_Exponent:
                                        if (Char.IsDigit (c)){
                                                b [didx++] = (byte) c;
@@ -290,43 +441,69 @@ namespace System {
                                        
                                        if (Char.IsWhiteSpace (c))
                                                goto case State_ConsumeWhiteSpace;
-                                       throw new FormatException ("Unknown char: " + c);
+                                       
+                                       if (!tryParse)
+                                               exc = new FormatException ("Unknown char: " + c);
+                                       return false;
 
                                case State_ConsumeWhiteSpace:
-                                       if (allow_trailing_white && Char.IsWhiteSpace (c))
+                                       if (allow_trailing_white && Char.IsWhiteSpace (c)) {
+                                               state = State_ConsumeWhiteSpace;
                                                break;
-                                       throw new FormatException ("Unknown char");
+                                       }
+                                       
+                                       if (!tryParse)
+                                               exc = new FormatException ("Unknown char");
+                                       return false;
                                }
+
+                               if (state == State_Exit)
+                                       break;
                        }
 
                        b [didx] = 0;
                        unsafe {
                                fixed (byte *p = &b [0]){
-                                       double retVal = ParseImpl (p);
-                                       if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal))
-                                               throw new OverflowException();
+                                       double retVal;
+                                       if (!ParseImpl (p, out retVal)) {
+                                               if (!tryParse)
+                                                       exc = Int32.GetFormatException ();
+                                               return false;
+                                       }
+                                       if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
+                                               if (!tryParse)
+                                                       exc = new OverflowException ();
+                                               return false;
+                                       }
 
-                                       return retVal;
+                                       result = retVal;
+                                       return true;
                                }
                        }
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               unsafe private static extern double ParseImpl (byte *byte_ptr);
+               unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
                
                public static bool TryParse (string s,
                                             NumberStyles style,
                                             IFormatProvider provider,
-                                            ref double result)
+                                            out double result)
                {
-                       try {
-                               result = Parse (s, style, provider);
-                               return true;
-                       } catch {
+                       Exception exc;
+                       if (!Parse (s, style, provider, true, out result, out exc)) {
+                               result = 0;
                                return false;
                        }
-               }
 
+                       return true;
+               }
+#if NET_2_0
+               public static bool TryParse (string s, out double result)
+               {
+                       return TryParse (s, NumberStyles.Any, null, out result);
+               }
+#endif
                public override string ToString ()
                {
                        return ToString (null, null);
@@ -344,12 +521,8 @@ namespace System {
 
                public string ToString (string format, IFormatProvider fp)
                {
-                       if (fp is CultureInfo)
-                               return DoubleFormatter.NumberToString(format,
-                               ((CultureInfo)fp).NumberFormat, value);
-                       else
-                               return DoubleFormatter.NumberToString(format,
-                               (NumberFormatInfo)fp, value);
+                       NumberFormatInfo nfi = NumberFormatInfo.GetInstance (fp);
+                       return NumberFormatter.NumberToString (format, m_value, nfi);
                }
 
                // =========== IConvertible Methods =========== //
@@ -361,17 +534,17 @@ namespace System {
 
                object IConvertible.ToType (Type conversionType, IFormatProvider provider)
                {
-                       return System.Convert.ToType(value, conversionType, provider);
+                       return System.Convert.ToType(m_value, conversionType, provider);
                }
                
                bool IConvertible.ToBoolean (IFormatProvider provider)
                {
-                       return System.Convert.ToBoolean(value);
+                       return System.Convert.ToBoolean(m_value);
                }
                
                byte IConvertible.ToByte (IFormatProvider provider)
                {
-                       return System.Convert.ToByte(value);
+                       return System.Convert.ToByte(m_value);
                }
                
                char IConvertible.ToChar (IFormatProvider provider)
@@ -379,7 +552,6 @@ namespace System {
                        throw new InvalidCastException();
                }
                
-               [CLSCompliant(false)]
                DateTime IConvertible.ToDateTime (IFormatProvider provider)
                {
                        throw new InvalidCastException();
@@ -387,38 +559,37 @@ namespace System {
                
                decimal IConvertible.ToDecimal (IFormatProvider provider)
                {
-                       return System.Convert.ToDecimal(value);
+                       return System.Convert.ToDecimal(m_value);
                }
                
                double IConvertible.ToDouble (IFormatProvider provider)
                {
-                       return System.Convert.ToDouble(value);
+                       return System.Convert.ToDouble(m_value);
                }
                
                short IConvertible.ToInt16 (IFormatProvider provider)
                {
-                       return System.Convert.ToInt16(value);
+                       return System.Convert.ToInt16(m_value);
                }
                
                int IConvertible.ToInt32 (IFormatProvider provider)
                {
-                       return System.Convert.ToInt32(value);
+                       return System.Convert.ToInt32(m_value);
                }
                
                long IConvertible.ToInt64 (IFormatProvider provider)
                {
-                       return System.Convert.ToInt64(value);
+                       return System.Convert.ToInt64(m_value);
                }
                
-               [CLSCompliant(false)] 
                sbyte IConvertible.ToSByte (IFormatProvider provider)
                {
-                       return System.Convert.ToSByte(value);
+                       return System.Convert.ToSByte(m_value);
                }
                
                float IConvertible.ToSingle (IFormatProvider provider)
                {
-                       return System.Convert.ToSingle(value);
+                       return System.Convert.ToSingle(m_value);
                }
                
 /*
@@ -428,22 +599,19 @@ namespace System {
                }
 */
 
-               [CLSCompliant(false)]
                ushort IConvertible.ToUInt16 (IFormatProvider provider)
                {
-                       return System.Convert.ToUInt16(value);
+                       return System.Convert.ToUInt16(m_value);
                }
                
-               [CLSCompliant(false)]
                uint IConvertible.ToUInt32 (IFormatProvider provider)
                {
-                       return System.Convert.ToUInt32(value);
+                       return System.Convert.ToUInt32(m_value);
                }
                
-               [CLSCompliant(false)]
                ulong IConvertible.ToUInt64 (IFormatProvider provider)
                {
-                       return System.Convert.ToUInt64(value);
+                       return System.Convert.ToUInt64(m_value);
                }
        }
 }