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;
internal double m_value;
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern internal static void AssertEndianity (out double value);
-
public int CompareTo (object v)
{
if (v == null)
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 value == m_value;
+ }
+#endif
+
public override unsafe int GetHashCode ()
{
double d = m_value;
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)
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
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);
//
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;
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;
sidx = len;
continue;
}
+
switch (state){
case State_AllowSign:
if ((style & NumberStyles.AllowLeadingSign) != 0){
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;
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)){
}
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;
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)){
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;
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,
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);
public string ToString (string format, IFormatProvider fp)
{
- NumberFormatInfo nfi = fp != null ? fp.GetFormat (typeof (NumberFormatInfo)) as NumberFormatInfo : null;
- return DoubleFormatter.NumberToString (format, nfi, m_value);
+ NumberFormatInfo nfi = NumberFormatInfo.GetInstance (fp);
+ return NumberFormatter.NumberToString (format, m_value, nfi);
}
// =========== IConvertible Methods =========== //