// (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;
public const double NegativeInfinity = -1.0d / 0.0d;
public const double PositiveInfinity = 1.0d / 0.0d;
- internal double value;
-
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- extern internal static void AssertEndianity (out double value);
+ internal double m_value;
public int CompareTo (object v)
{
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;
}
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)
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;
for (; sidx < len; sidx++){
c = s [sidx];
+ if (c == '\0') {
+ 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,
- 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);
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 =========== //
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)
throw new InvalidCastException();
}
- [CLSCompliant(false)]
DateTime IConvertible.ToDateTime (IFormatProvider provider)
{
throw new InvalidCastException();
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);
}
/*
}
*/
- [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);
}
}
}