5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) Ximian, Inc. http://www.ximian.com
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System
.Globalization
;
32 using System
.Threading
;
37 [System
.Runtime
.InteropServices
.ComVisible (true)]
38 public struct Int64
: IFormattable
, IConvertible
, IComparable
, IComparable
<Int64
>, IEquatable
<Int64
>
41 public const long MaxValue
= 0x7fffffffffffffff;
42 public const long MinValue
= -9223372036854775808;
44 internal long m_value
;
46 public int CompareTo (object value)
51 if (!(value is System
.Int64
))
52 throw new ArgumentException (Locale
.GetText ("Value is not a System.Int64"));
54 long lValue
= (long) value;
56 if (m_value
== lValue
)
59 return (m_value
< lValue
) ? -1 : 1;
62 public override bool Equals (object obj
)
64 if (!(obj
is System
.Int64
))
67 return ((long) obj
) == m_value
;
70 public override int GetHashCode ()
72 return (int)(m_value
& 0xffffffff) ^
(int)(m_value
>> 32);
75 public int CompareTo (long value)
85 public bool Equals (long obj
)
87 return obj
== m_value
;
90 internal static bool Parse (string s
, bool tryParse
, out long result
, out Exception exc
)
96 bool digits_seen
= false;
103 exc
= new ArgumentNullException ("s");
110 for (i
= 0; i
< len
; i
++){
112 if (!Char
.IsWhiteSpace (c
))
118 exc
= Int32
.GetFormatException ();
130 for (; i
< len
; i
++){
133 if (c
>= '0' && c
<= '9'){
134 byte d
= (byte) (c
- '0');
136 if (val
> (MaxValue
/10))
139 if (val
== (MaxValue
/10)){
140 if ((d
> (MaxValue
% 10)) && (sign
== 1 || (d
> ((MaxValue
% 10) + 1))))
143 val
= (val
* sign
* 10) - d
;
145 val
= (val
* 10) + d
;
147 if (Int32
.ProcessTrailingWhitespace (tryParse
, s
, i
+ 1, ref exc
)){
157 } else if (!Int32
.ProcessTrailingWhitespace (tryParse
, s
, i
, ref exc
))
163 exc
= Int32
.GetFormatException ();
176 exc
= new OverflowException ("Value is too large");
180 public static long Parse (string s
, IFormatProvider provider
)
182 return Parse (s
, NumberStyles
.Integer
, provider
);
185 public static long Parse (string s
, NumberStyles style
)
187 return Parse (s
, style
, null);
190 internal static bool Parse (string s
, NumberStyles style
, IFormatProvider fp
, bool tryParse
, out long result
, out Exception exc
)
197 exc
= new ArgumentNullException ("s");
203 exc
= new FormatException ("Input string was not " +
204 "in the correct format: s.Length==0.");
208 NumberFormatInfo nfi
= null;
210 Type typeNFI
= typeof (System
.Globalization
.NumberFormatInfo
);
211 nfi
= (NumberFormatInfo
) fp
.GetFormat (typeNFI
);
214 nfi
= Thread
.CurrentThread
.CurrentCulture
.NumberFormat
;
216 if (!Int32
.CheckStyle (style
, tryParse
, ref exc
))
219 bool AllowCurrencySymbol
= (style
& NumberStyles
.AllowCurrencySymbol
) != 0;
220 bool AllowHexSpecifier
= (style
& NumberStyles
.AllowHexSpecifier
) != 0;
221 bool AllowThousands
= (style
& NumberStyles
.AllowThousands
) != 0;
222 bool AllowDecimalPoint
= (style
& NumberStyles
.AllowDecimalPoint
) != 0;
223 bool AllowParentheses
= (style
& NumberStyles
.AllowParentheses
) != 0;
224 bool AllowTrailingSign
= (style
& NumberStyles
.AllowTrailingSign
) != 0;
225 bool AllowLeadingSign
= (style
& NumberStyles
.AllowLeadingSign
) != 0;
226 bool AllowTrailingWhite
= (style
& NumberStyles
.AllowTrailingWhite
) != 0;
227 bool AllowLeadingWhite
= (style
& NumberStyles
.AllowLeadingWhite
) != 0;
231 if (AllowLeadingWhite
&& !Int32
.JumpOverWhite (ref pos
, s
, true, tryParse
, ref exc
))
234 bool foundOpenParentheses
= false;
235 bool negative
= false;
236 bool foundSign
= false;
237 bool foundCurrency
= false;
240 if (AllowParentheses
&& s
[pos
] == '(') {
241 foundOpenParentheses
= true;
243 negative
= true; // MS always make the number negative when there parentheses
244 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
246 if (AllowLeadingWhite
&& !Int32
.JumpOverWhite (ref pos
, s
, true, tryParse
, ref exc
))
249 if (s
.Substring (pos
, nfi
.NegativeSign
.Length
) == nfi
.NegativeSign
) {
251 exc
= new FormatException ("Input string was not in the correct " +
252 "format: Has Negative Sign.");
255 if (s
.Substring (pos
, nfi
.PositiveSign
.Length
) == nfi
.PositiveSign
) {
257 exc
= new FormatException ("Input string was not in the correct " +
258 "format: Has Positive Sign.");
263 if (AllowLeadingSign
&& !foundSign
) {
265 Int32
.FindSign (ref pos
, s
, nfi
, ref foundSign
, ref negative
);
267 if (AllowLeadingWhite
&& !Int32
.JumpOverWhite (ref pos
, s
, true, tryParse
, ref exc
))
269 if (AllowCurrencySymbol
) {
270 Int32
.FindCurrency (ref pos
, s
, nfi
,
272 if (foundCurrency
&& AllowLeadingWhite
&&
273 !Int32
.JumpOverWhite (ref pos
, s
, true, tryParse
, ref exc
))
279 if (AllowCurrencySymbol
&& !foundCurrency
) {
281 Int32
.FindCurrency (ref pos
, s
, nfi
, ref foundCurrency
);
283 if (AllowLeadingWhite
&& !Int32
.JumpOverWhite (ref pos
, s
, true, tryParse
, ref exc
))
286 if (!foundSign
&& AllowLeadingSign
) {
287 Int32
.FindSign (ref pos
, s
, nfi
, ref foundSign
,
289 if (foundSign
&& AllowLeadingWhite
&&
290 !Int32
.JumpOverWhite (ref pos
, s
, true, tryParse
, ref exc
))
299 bool decimalPointFound
= false;
306 if (!Int32
.ValidDigit (s
[pos
], AllowHexSpecifier
)) {
307 if (AllowThousands
&&
308 (Int32
.FindOther (ref pos
, s
, nfi
.NumberGroupSeparator
)
309 || Int32
.FindOther (ref pos
, s
, nfi
.CurrencyGroupSeparator
)))
312 if (!decimalPointFound
&& AllowDecimalPoint
&&
313 (Int32
.FindOther (ref pos
, s
, nfi
.NumberDecimalSeparator
)
314 || Int32
.FindOther (ref pos
, s
, nfi
.CurrencyDecimalSeparator
))) {
315 decimalPointFound
= true;
321 else if (AllowHexSpecifier
) {
323 hexDigit
= s
[pos
++];
324 if (Char
.IsDigit (hexDigit
))
325 digitValue
= (int) (hexDigit
- '0');
326 else if (Char
.IsLower (hexDigit
))
327 digitValue
= (int) (hexDigit
- 'a' + 10);
329 digitValue
= (int) (hexDigit
- 'A' + 10);
331 ulong unumber
= (ulong)number
;
333 // IMPROVME: We could avoid catching OverflowException
335 number
= (long)checked(unumber
* 16ul + (ulong)digitValue
);
336 } catch (OverflowException e
){
342 else if (decimalPointFound
) {
344 // Allows decimal point as long as it's only
345 // followed by zeroes.
346 if (s
[pos
++] != '0') {
348 exc
= new OverflowException ("Value too large or too " +
357 // Calculations done as negative
358 // (abs (MinValue) > abs (MaxValue))
361 (long) (s
[pos
++] - '0')
363 } catch (OverflowException
) {
365 exc
= new OverflowException ("Value too large or too " +
370 } while (pos
< s
.Length
);
375 exc
= new FormatException ("Input string was not in the correct format: nDigits == 0.");
379 if (AllowTrailingSign
&& !foundSign
) {
381 Int32
.FindSign (ref pos
, s
, nfi
, ref foundSign
, ref negative
);
383 if (AllowTrailingWhite
&& !Int32
.JumpOverWhite (ref pos
, s
, true, tryParse
, ref exc
))
385 if (AllowCurrencySymbol
)
386 Int32
.FindCurrency (ref pos
, s
, nfi
,
391 if (AllowCurrencySymbol
&& !foundCurrency
) {
393 if (nfi
.CurrencyPositivePattern
== 3 && s
[pos
++] != ' ')
397 throw new FormatException ("Input string was not in the correct format: no space between number and currency symbol.");
399 Int32
.FindCurrency (ref pos
, s
, nfi
, ref foundCurrency
);
400 if (foundCurrency
&& pos
< s
.Length
) {
401 if (AllowTrailingWhite
&& !Int32
.JumpOverWhite (ref pos
, s
, true, tryParse
, ref exc
))
403 if (!foundSign
&& AllowTrailingSign
)
404 Int32
.FindSign (ref pos
, s
, nfi
, ref foundSign
,
409 if (AllowTrailingWhite
&& pos
< s
.Length
&& !Int32
.JumpOverWhite (ref pos
, s
, false, tryParse
, ref exc
))
412 if (foundOpenParentheses
) {
413 if (pos
>= s
.Length
|| s
[pos
++] != ')') {
415 exc
= new FormatException ("Input string was not in the correct " +
416 "format: No room for close parens.");
419 if (AllowTrailingWhite
&& pos
< s
.Length
&& !Int32
.JumpOverWhite (ref pos
, s
, false, tryParse
, ref exc
))
423 if (pos
< s
.Length
&& s
[pos
] != '\u0000') {
425 exc
= new FormatException ("Input string was not in the correct format: Did not parse entire string. pos = "
426 + pos
+ " s.Length = " + s
.Length
);
431 if (!negative
&& !AllowHexSpecifier
){
433 number
= checked (-number
);
434 } catch (OverflowException e
){
445 public static long Parse (string s
)
450 if (!Parse (s
, false, out res
, out exc
))
456 public static long Parse (string s
, NumberStyles style
, IFormatProvider provider
)
461 if (!Parse (s
, style
, provider
, false, out res
, out exc
))
467 public static bool TryParse (string s
, out long result
)
470 if (!Parse (s
, true, out result
, out exc
)) {
478 public static bool TryParse (string s
, NumberStyles style
, IFormatProvider provider
, out long result
)
481 if (!Parse (s
, style
, provider
, true, out result
, out exc
)) {
489 public override string ToString ()
491 return NumberFormatter
.NumberToString (m_value
, null);
494 public string ToString (IFormatProvider provider
)
496 return NumberFormatter
.NumberToString (m_value
, provider
);
499 public string ToString (string format
)
501 return ToString (format
, null);
504 public string ToString (string format
, IFormatProvider provider
)
506 return NumberFormatter
.NumberToString (format
, m_value
, provider
);
509 // =========== IConvertible Methods =========== //
511 public TypeCode
GetTypeCode ()
513 return TypeCode
.Int64
;
516 bool IConvertible
.ToBoolean (IFormatProvider provider
)
518 return System
.Convert
.ToBoolean (m_value
);
521 byte IConvertible
.ToByte (IFormatProvider provider
)
523 return System
.Convert
.ToByte (m_value
);
526 char IConvertible
.ToChar (IFormatProvider provider
)
528 return System
.Convert
.ToChar (m_value
);
531 DateTime IConvertible
.ToDateTime (IFormatProvider provider
)
533 return System
.Convert
.ToDateTime (m_value
);
536 decimal IConvertible
.ToDecimal (IFormatProvider provider
)
538 return System
.Convert
.ToDecimal (m_value
);
541 double IConvertible
.ToDouble (IFormatProvider provider
)
543 return System
.Convert
.ToDouble (m_value
);
546 short IConvertible
.ToInt16 (IFormatProvider provider
)
548 return System
.Convert
.ToInt16 (m_value
);
551 int IConvertible
.ToInt32 (IFormatProvider provider
)
553 return System
.Convert
.ToInt32 (m_value
);
556 long IConvertible
.ToInt64 (IFormatProvider provider
)
558 return System
.Convert
.ToInt64 (m_value
);
561 sbyte IConvertible
.ToSByte (IFormatProvider provider
)
563 return System
.Convert
.ToSByte (m_value
);
566 float IConvertible
.ToSingle (IFormatProvider provider
)
568 return System
.Convert
.ToSingle (m_value
);
571 object IConvertible
.ToType (Type targetType
, IFormatProvider provider
)
573 if (targetType
== null)
574 throw new ArgumentNullException ("targetType");
575 return System
.Convert
.ToType (m_value
, targetType
, provider
, false);
578 ushort IConvertible
.ToUInt16 (IFormatProvider provider
)
580 return System
.Convert
.ToUInt16 (m_value
);
583 uint IConvertible
.ToUInt32 (IFormatProvider provider
)
585 return System
.Convert
.ToUInt32 (m_value
);
588 ulong IConvertible
.ToUInt64 (IFormatProvider provider
)
590 return System
.Convert
.ToUInt64 (m_value
);