2010-03-12 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / corlib / System / Int64.cs
1 //
2 // System.Int64.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 //
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
10 //
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:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
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.
29 //
30
31 using System.Globalization;
32 using System.Threading;
33
34 namespace System {
35         
36         [Serializable]
37         [System.Runtime.InteropServices.ComVisible (true)]
38         public struct Int64 : IFormattable, IConvertible, IComparable, IComparable<Int64>, IEquatable <Int64>
39         {
40
41                 public const long MaxValue = 0x7fffffffffffffff;
42                 public const long MinValue = -9223372036854775808;
43                 
44                 internal long m_value;
45
46                 public int CompareTo (object value)
47                 {
48                         if (value == null)
49                                 return 1;
50                         
51                         if (!(value is System.Int64))
52                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Int64"));
53
54                         long lValue = (long) value;
55
56                         if (m_value == lValue)
57                                 return 0;
58
59                         return (m_value < lValue) ? -1 : 1;
60                 }
61
62                 public override bool Equals (object obj)
63                 {
64                         if (!(obj is System.Int64))
65                                 return false;
66
67                         return ((long) obj) == m_value;
68                 }
69
70                 public override int GetHashCode ()
71                 {
72                         return (int)(m_value & 0xffffffff) ^ (int)(m_value >> 32);
73                 }
74
75                 public int CompareTo (long value)
76                 {
77                         if (m_value == value)
78                                 return 0;
79                         if (m_value > value)
80                                 return 1;
81                         else
82                                 return -1;
83                 }
84
85                 public bool Equals (long obj)
86                 {
87                         return obj == m_value;
88                 }
89
90                 internal static bool Parse (string s, bool tryParse, out long result, out Exception exc)
91                 {
92                         long val = 0;
93                         int len;
94                         int i;
95                         int sign = 1;
96                         bool digits_seen = false;
97
98                         result = 0;
99                         exc = null;
100
101                         if (s == null) {
102                                 if (!tryParse) 
103                                         exc = new ArgumentNullException ("s");
104                                 return false;
105                         }
106
107                         len = s.Length;
108
109                         char c;
110                         for (i = 0; i < len; i++){
111                                 c = s [i];
112                                 if (!Char.IsWhiteSpace (c))
113                                         break;
114                         }
115                         
116                         if (i == len) {
117                                 if (!tryParse)
118                                         exc = Int32.GetFormatException ();
119                                 return false;
120                         }
121
122                         c = s [i];
123                         if (c == '+')
124                                 i++;
125                         else if (c == '-'){
126                                 sign = -1;
127                                 i++;
128                         }
129                         
130                         for (; i < len; i++){
131                                 c = s [i];
132
133                                 if (c >= '0' && c <= '9'){
134                                         byte d = (byte) (c - '0');
135                                                 
136                                         if (val > (MaxValue/10))
137                                                 goto overflow;
138                                         
139                                         if (val == (MaxValue/10)){
140                                                 if ((d > (MaxValue % 10)) && (sign == 1 || (d > ((MaxValue % 10) + 1))))
141                                                         goto overflow;
142                                                 if (sign == -1)
143                                                         val = (val * sign * 10) - d;
144                                                 else
145                                                         val = (val * 10) + d;
146
147                                                 if (Int32.ProcessTrailingWhitespace (tryParse, s, i + 1, ref exc)){
148                                                         result = val;
149                                                         return true;
150                                                 }
151                                                 goto overflow;
152                                         } else 
153                                                 val = val * 10 + d;
154                                         
155                                         
156                                         digits_seen = true;
157                                 } else if (!Int32.ProcessTrailingWhitespace (tryParse, s, i, ref exc))
158                                         return false;
159                                         
160                         }
161                         if (!digits_seen) {
162                                 if (!tryParse)
163                                         exc = Int32.GetFormatException ();
164                                 return false;
165                         }
166                         
167                         if (sign == -1)
168                                 result = val * sign;
169                         else
170                                 result = val;
171
172                         return true;
173
174                 overflow:
175                         if (!tryParse)
176                                 exc = new OverflowException ("Value is too large");
177                         return false;
178                 }
179
180                 public static long Parse (string s, IFormatProvider provider)
181                 {
182                         return Parse (s, NumberStyles.Integer, provider);
183                 }
184
185                 public static long Parse (string s, NumberStyles style)
186                 {
187                         return Parse (s, style, null);
188                 }
189
190                 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out long result, out Exception exc)
191                 {
192                         result = 0;
193                         exc = null;
194
195                         if (s == null) {
196                                 if (!tryParse)
197                                         exc = new ArgumentNullException ("s");
198                                 return false;
199                         }
200
201                         if (s.Length == 0) {
202                                 if (!tryParse)
203                                         exc = new FormatException ("Input string was not " + 
204                                                         "in the correct format: s.Length==0.");
205                                 return false;
206                         }
207
208                         NumberFormatInfo nfi;
209                         if (fp != null) {
210                                 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
211                                 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
212                         }
213                         else
214                                 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
215
216                         if (!Int32.CheckStyle (style, tryParse, ref exc))
217                                 return false;
218
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;
228
229                         int pos = 0;
230
231                         if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
232                                 return false;
233
234                         bool foundOpenParentheses = false;
235                         bool negative = false;
236                         bool foundSign = false;
237                         bool foundCurrency = false;
238
239                         // Pre-number stuff
240                         if (AllowParentheses && s [pos] == '(') {
241                                 foundOpenParentheses = true;
242                                 foundSign = true;
243                                 negative = true; // MS always make the number negative when there parentheses
244                                                  // even when NumberFormatInfo.NumberNegativePattern != 0!!!
245                                 pos++;
246                                 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
247                                         return false;
248
249                                 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
250                                         if (!tryParse)
251                                                 exc = new FormatException ("Input string was not in the correct " +
252                                                                 "format: Has Negative Sign.");
253                                         return false;
254                                 }
255                                 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
256                                         if (!tryParse)
257                                                 exc = new FormatException ("Input string was not in the correct " +
258                                                                 "format: Has Positive Sign.");
259                                         return false;
260                                 }
261                         }
262
263                         if (AllowLeadingSign && !foundSign) {
264                                 // Sign + Currency
265                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
266                                 if (foundSign) {
267                                         if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
268                                                 return false;
269                                         if (AllowCurrencySymbol) {
270                                                 Int32.FindCurrency (ref pos, s, nfi,
271                                                                     ref foundCurrency);
272                                                 if (foundCurrency && AllowLeadingWhite && 
273                                                                 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
274                                                         return false;
275                                         }
276                                 }
277                         }
278                         
279                         if (AllowCurrencySymbol && !foundCurrency) {
280                                 // Currency + sign
281                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
282                                 if (foundCurrency) {
283                                         if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
284                                                         return false;
285                                         if (foundCurrency) {
286                                                 if (!foundSign && AllowLeadingSign) {
287                                                         Int32.FindSign (ref pos, s, nfi, ref foundSign,
288                                                                         ref negative);
289                                                         if (foundSign && AllowLeadingWhite &&
290                                                                 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
291                                                                 return false;
292                                                 }
293                                         }
294                                 }
295                         }
296                         
297                         long number = 0;
298                         int nDigits = 0;
299                         bool decimalPointFound = false;
300                         int digitValue;
301                         char hexDigit;
302                                 
303                         // Number stuff
304                         do {
305
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)))
310                                             continue;
311                                         else
312                                         if (!decimalPointFound && AllowDecimalPoint &&
313                                             (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
314                                                 || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
315                                             decimalPointFound = true;
316                                             continue;
317                                         }
318
319                                         break;
320                                 }
321                                 else if (AllowHexSpecifier) {
322                                         nDigits++;
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);
328                                         else
329                                                 digitValue = (int) (hexDigit - 'A' + 10);
330
331                                         ulong unumber = (ulong)number;
332                                         
333                                         // IMPROVME: We could avoid catching OverflowException
334                                         try {
335                                                 number = (long)checked(unumber * 16ul + (ulong)digitValue);
336                                         } catch (OverflowException e){
337                                                 if (!tryParse)
338                                                         exc = e;
339                                                 return false;
340                                         }
341                                 }
342                                 else if (decimalPointFound) {
343                                         nDigits++;
344                                         // Allows decimal point as long as it's only 
345                                         // followed by zeroes.
346                                         if (s [pos++] != '0') {
347                                                 if (!tryParse)
348                                                         exc = new OverflowException ("Value too large or too " +
349                                                                         "small.");
350                                                 return false;
351                                         }
352                                 }
353                                 else {
354                                         nDigits++;
355
356                                         try {
357                                                 // Calculations done as negative
358                                                 // (abs (MinValue) > abs (MaxValue))
359                                                 number = checked (
360                                                         number * 10 - 
361                                                         (long) (s [pos++] - '0')
362                                                         );
363                                         } catch (OverflowException) {
364                                                 if (!tryParse)
365                                                         exc = new OverflowException ("Value too large or too " +
366                                                                         "small.");
367                                                 return false;
368                                         }
369                                 }
370                         } while (pos < s.Length);
371
372                         // Post number stuff
373                         if (nDigits == 0) {
374                                 if (!tryParse)
375                                         exc = new FormatException ("Input string was not in the correct format: nDigits == 0.");
376                                 return false;
377                         }
378
379                         if (AllowTrailingSign && !foundSign) {
380                                 // Sign + Currency
381                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
382                                 if (foundSign) {
383                                         if (AllowTrailingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
384                                                 return false;
385                                         if (AllowCurrencySymbol)
386                                                 Int32.FindCurrency (ref pos, s, nfi,
387                                                                     ref foundCurrency);
388                                 }
389                         }
390                         
391                         if (AllowCurrencySymbol && !foundCurrency) {
392                                 // Currency + sign
393                                 if (nfi.CurrencyPositivePattern == 3 && s[pos++] != ' ')
394                                         if (tryParse)
395                                                 return false;
396                                         else
397                                                 throw new FormatException ("Input string was not in the correct format: no space between number and currency symbol.");
398
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))
402                                                 return false;
403                                         if (!foundSign && AllowTrailingSign)
404                                                 Int32.FindSign (ref pos, s, nfi, ref foundSign,
405                                                                 ref negative);
406                                 }
407                         }
408                         
409                         if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
410                                 return false;
411
412                         if (foundOpenParentheses) {
413                                 if (pos >= s.Length || s [pos++] != ')') {
414                                         if (!tryParse)
415                                                 exc = new FormatException ("Input string was not in the correct " +
416                                                                 "format: No room for close parens.");
417                                         return false;
418                                 }
419                                 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
420                                         return false;
421                         }
422
423                         if (pos < s.Length && s [pos] != '\u0000') {
424                                 if (!tryParse)
425                                         exc = new FormatException ("Input string was not in the correct format: Did not parse entire string. pos = " 
426                                                         + pos + " s.Length = " + s.Length);
427                                 return false;
428                         }
429
430                         
431                         if (!negative && !AllowHexSpecifier){
432                                 try {
433                                         number = checked (-number);
434                                 } catch (OverflowException e){
435                                         if (!tryParse)
436                                                 exc = e;
437                                         return false;
438                                 }
439                         }
440
441                         result = number;
442                         return true;
443                 }
444
445                 public static long Parse (string s) 
446                 {
447                         Exception exc;
448                         long res;
449
450                         if (!Parse (s, false, out res, out exc))
451                                 throw exc;
452
453                         return res;
454                 }
455
456                 public static long Parse (string s, NumberStyles style, IFormatProvider provider) 
457                 {
458                         Exception exc;
459                         long res;
460
461                         if (!Parse (s, style, provider, false, out res, out exc))
462                                 throw exc;
463
464                         return res;
465                 }
466
467                 public static bool TryParse (string s, out long result) 
468                 {
469                         Exception exc;
470                         if (!Parse (s, true, out result, out exc)) {
471                                 result = 0;
472                                 return false;
473                         }
474
475                         return true;
476                 }
477
478                 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out long result) 
479                 {
480                         Exception exc;
481                         if (!Parse (s, style, provider, true, out result, out exc)) {
482                                 result = 0;
483                                 return false;
484                         }
485
486                         return true;
487                 }
488
489                 public override string ToString ()
490                 {
491                         return NumberFormatter.NumberToString (m_value, null);
492                 }
493
494                 public string ToString (IFormatProvider provider)
495                 {
496                         return NumberFormatter.NumberToString (m_value, provider);
497                 }
498
499                 public string ToString (string format)
500                 {
501                         return ToString (format, null);
502                 }
503
504                 public string ToString (string format, IFormatProvider provider)
505                 {
506                         return NumberFormatter.NumberToString (format, m_value, provider);
507                 }
508
509                 // =========== IConvertible Methods =========== //
510
511                 public TypeCode GetTypeCode ()
512                 {
513                         return TypeCode.Int64;
514                 }
515
516                 bool IConvertible.ToBoolean (IFormatProvider provider)
517                 {
518                         return System.Convert.ToBoolean (m_value);
519                 }
520
521                 byte IConvertible.ToByte (IFormatProvider provider)
522                 {
523                         return System.Convert.ToByte (m_value);
524                 }
525
526                 char IConvertible.ToChar (IFormatProvider provider)
527                 {
528                         return System.Convert.ToChar (m_value);
529                 }
530
531                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
532                 {
533                         return System.Convert.ToDateTime (m_value);
534                 }
535
536                 decimal IConvertible.ToDecimal (IFormatProvider provider)
537                 {
538                         return System.Convert.ToDecimal (m_value);
539                 }
540
541                 double IConvertible.ToDouble (IFormatProvider provider)
542                 {
543                         return System.Convert.ToDouble (m_value);
544                 }
545
546                 short IConvertible.ToInt16 (IFormatProvider provider)
547                 {
548                         return System.Convert.ToInt16 (m_value);
549                 }
550
551                 int IConvertible.ToInt32 (IFormatProvider provider)
552                 {
553                         return System.Convert.ToInt32 (m_value);
554                 }
555
556                 long IConvertible.ToInt64 (IFormatProvider provider)
557                 {
558                         return System.Convert.ToInt64 (m_value);
559                 }
560
561                 sbyte IConvertible.ToSByte (IFormatProvider provider)
562                 {
563                         return System.Convert.ToSByte (m_value);
564                 }
565
566                 float IConvertible.ToSingle (IFormatProvider provider)
567                 {
568                         return System.Convert.ToSingle (m_value);
569                 }
570
571                 object IConvertible.ToType (Type targetType, IFormatProvider provider)
572                 {
573                         if (targetType == null)
574                                 throw new ArgumentNullException ("targetType");
575                         return System.Convert.ToType (m_value, targetType, provider, false);
576                 }
577
578                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
579                 {
580                         return System.Convert.ToUInt16 (m_value);
581                 }
582
583                 uint IConvertible.ToUInt32 (IFormatProvider provider)
584                 {
585                         return System.Convert.ToUInt32 (m_value);
586                 }
587
588                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
589                 {
590                         return System.Convert.ToUInt64 (m_value);
591                 }
592         }
593 }