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