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