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;
38 [System.Runtime.InteropServices.ComVisible (true)]
40 public struct Int64 : IFormattable, IConvertible, IComparable
42 , IComparable<Int64>, IEquatable <Int64>
46 public const long MaxValue = 0x7fffffffffffffff;
47 public const long MinValue = -9223372036854775808;
49 internal long m_value;
51 public int CompareTo (object v)
56 if (!(v is System.Int64))
57 throw new ArgumentException (Locale.GetText ("Value is not a System.Int64"));
59 if (m_value == (long) v)
62 if (m_value < (long) v)
68 public override bool Equals (object o)
70 if (!(o is System.Int64))
73 return ((long) o) == m_value;
76 public override int GetHashCode ()
78 return (int)(m_value & 0xffffffff) ^ (int)(m_value >> 32);
82 public int CompareTo (long value)
92 public bool Equals (long value)
94 return value == m_value;
98 internal static bool Parse (string s, bool tryParse, out long result, out Exception exc)
104 bool digits_seen = false;
111 exc = new ArgumentNullException ("s");
118 for (i = 0; i < len; i++){
120 if (!Char.IsWhiteSpace (c))
126 exc = Int32.GetFormatException ();
138 for (; i < len; i++){
141 if (c >= '0' && c <= '9'){
142 byte d = (byte) (c - '0');
144 if (val > (MaxValue/10))
147 if (val == (MaxValue/10)){
148 if ((d > (MaxValue % 10)) && (sign == 1 || (d > ((MaxValue % 10) + 1))))
151 val = (val * sign * 10) - d;
153 val = (val * 10) + d;
155 if (Int32.ProcessTrailingWhitespace (tryParse, s, i + 1, ref exc)){
165 } else if (!Int32.ProcessTrailingWhitespace (tryParse, s, i, ref exc))
171 exc = Int32.GetFormatException ();
184 exc = new OverflowException ("Value is too large");
188 public static long Parse (string s, IFormatProvider fp)
190 return Parse (s, NumberStyles.Integer, fp);
193 public static long Parse (string s, NumberStyles style)
195 return Parse (s, style, null);
198 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out long result, out Exception exc)
205 exc = new ArgumentNullException ("s");
211 exc = new FormatException ("Input string was not " +
212 "in the correct format: s.Length==0.");
216 NumberFormatInfo nfi;
218 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
219 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
222 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
224 if (!Int32.CheckStyle (style, tryParse, ref exc))
227 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
228 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
229 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
230 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
231 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
232 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
233 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
234 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
235 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
239 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
242 bool foundOpenParentheses = false;
243 bool negative = false;
244 bool foundSign = false;
245 bool foundCurrency = false;
248 if (AllowParentheses && s [pos] == '(') {
249 foundOpenParentheses = true;
251 negative = true; // MS always make the number negative when there parentheses
252 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
254 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
257 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
259 exc = new FormatException ("Input string was not in the correct " +
260 "format: Has Negative Sign.");
263 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
265 exc = new FormatException ("Input string was not in the correct " +
266 "format: Has Positive Sign.");
271 if (AllowLeadingSign && !foundSign) {
273 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
275 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
277 if (AllowCurrencySymbol) {
278 Int32.FindCurrency (ref pos, s, nfi,
280 if (foundCurrency && AllowLeadingWhite &&
281 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
287 if (AllowCurrencySymbol && !foundCurrency) {
289 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
291 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
294 if (!foundSign && AllowLeadingSign) {
295 Int32.FindSign (ref pos, s, nfi, ref foundSign,
297 if (foundSign && AllowLeadingWhite &&
298 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
307 bool decimalPointFound = false;
314 if (!Int32.ValidDigit (s [pos], AllowHexSpecifier)) {
315 if (AllowThousands &&
316 (Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator)
317 || Int32.FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
320 if (!decimalPointFound && AllowDecimalPoint &&
321 (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
322 || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
323 decimalPointFound = true;
329 else if (AllowHexSpecifier) {
331 hexDigit = s [pos++];
332 if (Char.IsDigit (hexDigit))
333 digitValue = (int) (hexDigit - '0');
334 else if (Char.IsLower (hexDigit))
335 digitValue = (int) (hexDigit - 'a' + 10);
337 digitValue = (int) (hexDigit - 'A' + 10);
339 ulong unumber = (ulong)number;
341 // IMPROVME: We could avoid catching OverflowException
343 number = (long)checked(unumber * 16ul + (ulong)digitValue);
344 } catch (OverflowException e){
350 else if (decimalPointFound) {
352 // Allows decimal point as long as it's only
353 // followed by zeroes.
354 if (s [pos++] != '0') {
356 exc = new OverflowException ("Value too large or too " +
365 // Calculations done as negative
366 // (abs (MinValue) > abs (MaxValue))
369 (long) (s [pos++] - '0')
371 } catch (OverflowException) {
373 exc = new OverflowException ("Value too large or too " +
378 } while (pos < s.Length);
383 exc = new FormatException ("Input string was not in the correct format: nDigits == 0.");
387 if (AllowTrailingSign && !foundSign) {
389 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
391 if (AllowTrailingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
393 if (AllowCurrencySymbol)
394 Int32.FindCurrency (ref pos, s, nfi,
399 if (AllowCurrencySymbol && !foundCurrency) {
401 if (nfi.CurrencyPositivePattern == 3 && s[pos++] != ' ')
405 throw new FormatException ("Input string was not in the correct format: no space between number and currency symbol.");
407 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
408 if (foundCurrency && pos < s.Length) {
409 if (AllowTrailingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
411 if (!foundSign && AllowTrailingSign)
412 Int32.FindSign (ref pos, s, nfi, ref foundSign,
417 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
420 if (foundOpenParentheses) {
421 if (pos >= s.Length || s [pos++] != ')') {
423 exc = new FormatException ("Input string was not in the correct " +
424 "format: No room for close parens.");
427 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
431 if (pos < s.Length && s [pos] != '\u0000') {
433 exc = new FormatException ("Input string was not in the correct format: Did not parse entire string. pos = "
434 + pos + " s.Length = " + s.Length);
439 if (!negative && !AllowHexSpecifier){
441 number = checked (-number);
442 } catch (OverflowException e){
453 public static long Parse (string s)
458 if (!Parse (s, false, out res, out exc))
464 public static long Parse (string s, NumberStyles style, IFormatProvider fp)
469 if (!Parse (s, style, fp, false, out res, out exc))
476 public static bool TryParse (string s, out long result)
479 if (!Parse (s, true, out result, out exc)) {
487 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out long result)
490 if (!Parse (s, style, provider, true, out result, out exc)) {
499 public override string ToString ()
501 return new NumberFormatter(null, m_value).FormatDecimal(-1, null);
504 public string ToString (IFormatProvider provider)
506 NumberFormatInfo nfi = NumberFormatInfo.GetInstance (provider);
507 return new NumberFormatter(null, m_value).FormatDecimal(-1, nfi);
510 public string ToString (string format)
512 return ToString (format, null);
515 public string ToString (string format, IFormatProvider fp)
517 NumberFormatInfo nfi = NumberFormatInfo.GetInstance( fp );
518 return NumberFormatter.NumberToString (format, m_value, nfi);
521 // =========== IConvertible Methods =========== //
523 public TypeCode GetTypeCode ()
525 return TypeCode.Int64;
528 bool IConvertible.ToBoolean (IFormatProvider provider)
530 return System.Convert.ToBoolean (m_value);
533 byte IConvertible.ToByte (IFormatProvider provider)
535 return System.Convert.ToByte (m_value);
538 char IConvertible.ToChar (IFormatProvider provider)
540 return System.Convert.ToChar (m_value);
543 DateTime IConvertible.ToDateTime (IFormatProvider provider)
545 return System.Convert.ToDateTime (m_value);
548 decimal IConvertible.ToDecimal (IFormatProvider provider)
550 return System.Convert.ToDecimal (m_value);
553 double IConvertible.ToDouble (IFormatProvider provider)
555 return System.Convert.ToDouble (m_value);
558 short IConvertible.ToInt16 (IFormatProvider provider)
560 return System.Convert.ToInt16 (m_value);
563 int IConvertible.ToInt32 (IFormatProvider provider)
565 return System.Convert.ToInt32 (m_value);
568 long IConvertible.ToInt64 (IFormatProvider provider)
570 return System.Convert.ToInt64 (m_value);
573 sbyte IConvertible.ToSByte (IFormatProvider provider)
575 return System.Convert.ToSByte (m_value);
578 float IConvertible.ToSingle (IFormatProvider provider)
580 return System.Convert.ToSingle (m_value);
583 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
585 return System.Convert.ToType (m_value, conversionType, provider);
588 ushort IConvertible.ToUInt16 (IFormatProvider provider)
590 return System.Convert.ToUInt16 (m_value);
593 uint IConvertible.ToUInt32 (IFormatProvider provider)
595 return System.Convert.ToUInt32 (m_value);
598 ulong IConvertible.ToUInt64 (IFormatProvider provider)
600 return System.Convert.ToUInt64 (m_value);