2002-07-22 Gonzalo Paniagua Javier <gonzalo@ximian.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
10 using System.Globalization;
11 using System.Threading;
12
13 namespace System {
14         
15         [Serializable]
16         public struct Int64 : IComparable, IFormattable, IConvertible {
17
18                 public const long MaxValue = 0x7fffffffffffffff;
19                 public const long MinValue = -9223372036854775808;
20                 
21                 public long value;
22
23                 public int CompareTo (object v)
24                 {
25                         if (v == null)
26                                 return 1;
27                         
28                         if (!(v is System.Int64))
29                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Int64"));
30
31                         if (value == (long) v)
32                                 return 0;
33
34                         if (value < (long) v)
35                                 return -1;
36
37                         return 1;
38                 }
39
40                 public override bool Equals (object o)
41                 {
42                         if (!(o is System.Int64))
43                                 return false;
44
45                         return ((long) o) == value;
46                 }
47
48                 public override int GetHashCode ()
49                 {
50                         return (int)(value & 0xffffffff) ^ (int)(value >> 32);
51                 }
52
53                 public static long Parse (string s)
54                 {
55                         long val = 0;
56                         int len;
57                         int i;
58                         int sign = 1;
59                         bool digits_seen = false;
60                         
61                         if (s == null)
62                                 throw new ArgumentNullException (Locale.GetText ("s is null"));
63
64                         len = s.Length;
65
66                         char c;
67                         for (i = 0; i < len; i++){
68                                 c = s [i];
69                                 if (!Char.IsWhiteSpace (c))
70                                         break;
71                         }
72                         
73                         if (i == len)
74                                 throw new FormatException ();
75
76                         c = s [i];
77                         if (c == '+')
78                                 i++;
79                         else if (c == '-'){
80                                 sign = -1;
81                                 i++;
82                         }
83                         
84                         for (; i < len; i++){
85                                 c = s [i];
86
87                                 if (c >= '0' && c <= '9'){
88                                         val = checked (val * 10 + (c - '0') * sign);
89                                         digits_seen = true;
90                                 } else {
91                                         if (Char.IsWhiteSpace (c)){
92                                                 for (i++; i < len; i++){
93                                                         if (!Char.IsWhiteSpace (s [i]))
94                                                                 throw new FormatException ();
95                                                 }
96                                                 break;
97                                         } else
98                                                 throw new FormatException ();
99                                 }
100                         }
101                         if (!digits_seen)
102                                 throw new FormatException ();
103                         
104                         return val;
105                 }
106
107                 public static long Parse (string s, IFormatProvider fp)
108                 {
109                         return Parse (s, NumberStyles.Integer, fp);
110                 }
111
112                 public static long Parse (string s, NumberStyles style)
113                 {
114                         return Parse (s, style, null);
115                 }
116
117                 public static long Parse (string s, NumberStyles style, IFormatProvider fp)
118                 {
119                         if (s == null)
120                                 throw new ArgumentNullException ();
121
122                         if (s.Length == 0)
123                                 throw new FormatException ("Input string was not " + 
124                                                            "in the correct format: s.Length==0.");
125
126                         NumberFormatInfo nfi;
127                         if (fp != null) {
128                                 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
129                                 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
130                         }
131                         else
132                                 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
133
134                         Int32.CheckStyle (style);
135
136                         bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
137                         bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
138                         bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
139                         bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
140                         bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
141                         bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
142                         bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
143                         bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
144                         bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
145                         bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
146
147                         int pos = 0;
148
149                         if (AllowLeadingWhite)
150                                 pos = Int32.JumpOverWhite (pos, s, true);
151
152                         bool foundOpenParentheses = false;
153                         bool negative = false;
154                         bool foundSign = false;
155                         bool foundCurrency = false;
156
157                         // Pre-number stuff
158                         if (AllowParentheses && s [pos] == '(') {
159                                 foundOpenParentheses = true;
160                                 foundSign = true;
161                                 negative = true; // MS always make the number negative when there parentheses
162                                                  // even when NumberFormatInfo.NumberNegativePattern != 0!!!
163                                 pos++;
164                                 if (AllowLeadingWhite)
165                                         pos = Int32.JumpOverWhite (pos, s, true);
166
167                                 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign)
168                                         throw new FormatException ("Input string was not in the correct " +
169                                                                    "format: Has Negative Sign.");
170                                 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign)
171                                         throw new FormatException ("Input string was not in the correct " +
172                                                                    "format: Has Positive Sign.");
173                         }
174
175                         if (AllowLeadingSign && !foundSign) {
176                                 // Sign + Currency
177                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
178                                 if (foundSign) {
179                                         if (AllowLeadingWhite)
180                                                 pos = Int32.JumpOverWhite (pos, s, true);
181                                         if (AllowCurrencySymbol) {
182                                                 Int32.FindCurrency (ref pos, s, nfi,
183                                                                     ref foundCurrency);
184                                                 if (foundCurrency && AllowLeadingWhite)
185                                                         pos = Int32.JumpOverWhite (pos, s, true);
186                                         }
187                                 }
188                         }
189                         
190                         if (AllowCurrencySymbol && !foundCurrency) {
191                                 // Currency + sign
192                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
193                                 if (foundCurrency) {
194                                         if (AllowLeadingWhite)
195                                                 pos = Int32.JumpOverWhite (pos, s, true);
196                                         if (foundCurrency) {
197                                                 if (!foundSign && AllowLeadingSign) {
198                                                         Int32.FindSign (ref pos, s, nfi, ref foundSign,
199                                                                         ref negative);
200                                                         if (foundSign && AllowLeadingWhite)
201                                                                 pos = Int32.JumpOverWhite (pos, s, true);
202                                                 }
203                                         }
204                                 }
205                         }
206                         
207                         long number = 0;
208                         int nDigits = 0;
209                         bool decimalPointFound = false;
210                         int digitValue;
211                         char hexDigit;
212                                 
213                         // Number stuff
214                         do {
215
216                                 if (!Int32.ValidDigit (s [pos], AllowHexSpecifier)) {
217                                         if (AllowThousands &&
218                                             (Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator)
219                                                 || Int32.FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
220                                             continue;
221                                         else
222                                         if (!decimalPointFound && AllowDecimalPoint &&
223                                             (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
224                                                 || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
225                                             decimalPointFound = true;
226                                             continue;
227                                         }
228
229                                         break;
230                                 }
231                                 else if (AllowHexSpecifier) {
232                                         nDigits++;
233                                         hexDigit = s [pos++];
234                                         if (Char.IsDigit (hexDigit))
235                                                 digitValue = (int) (hexDigit - '0');
236                                         else if (Char.IsLower (hexDigit))
237                                                 digitValue = (int) (hexDigit - 'a' + 10);
238                                         else
239                                                 digitValue = (int) (hexDigit - 'A' + 10);
240
241                                         number = checked (number * 16 - digitValue);
242                                 }
243                                 else if (decimalPointFound) {
244                                         nDigits++;
245                                         // Allows decimal point as long as it's only 
246                                         // followed by zeroes.
247                                         if (s [pos++] != '0')
248                                                 throw new OverflowException ("Value too large or too " +
249                                                                              "small.");
250                                 }
251                                 else {
252                                         nDigits++;
253
254                                         try {
255                                                 // Calculations done as negative
256                                                 // (abs (MinValue) > abs (MaxValue))
257                                                 number = checked (
258                                                         number * 10 - 
259                                                         (long) (s [pos++] - '0')
260                                                         );
261                                         } catch (OverflowException) {
262                                                 throw new OverflowException ("Value too large or too " +
263                                                                              "small.");
264                                         }
265                                 }
266                         } while (pos < s.Length);
267
268                         // Post number stuff
269                         if (nDigits == 0)
270                                 throw new FormatException ("Input string was not in the correct format: nDigits == 0.");
271
272                         if (AllowTrailingSign && !foundSign) {
273                                 // Sign + Currency
274                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
275                                 if (foundSign) {
276                                         if (AllowTrailingWhite)
277                                                 pos = Int32.JumpOverWhite (pos, s, true);
278                                         if (AllowCurrencySymbol)
279                                                 Int32.FindCurrency (ref pos, s, nfi,
280                                                                     ref foundCurrency);
281                                 }
282                         }
283                         
284                         if (AllowCurrencySymbol && !foundCurrency) {
285                                 // Currency + sign
286                                 if (nfi.CurrencyPositivePattern == 3 && s[pos++] != ' ')
287                                         throw new FormatException ("Input string was not in the correct format: no space between number and currency symbol.");
288
289                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
290                                 if (foundCurrency && pos < s.Length) {
291                                         if (AllowTrailingWhite)
292                                                 pos = Int32.JumpOverWhite (pos, s, true);
293                                         if (!foundSign && AllowTrailingSign)
294                                                 Int32.FindSign (ref pos, s, nfi, ref foundSign,
295                                                                 ref negative);
296                                 }
297                         }
298                         
299                         if (AllowTrailingWhite && pos < s.Length)
300                                 pos = Int32.JumpOverWhite (pos, s, false);
301
302                         if (foundOpenParentheses) {
303                                 if (pos >= s.Length || s [pos++] != ')')
304                                         throw new FormatException ("Input string was not in the correct " +
305                                                                    "format: No room for close parens.");
306                                 if (AllowTrailingWhite && pos < s.Length)
307                                         pos = Int32.JumpOverWhite (pos, s, false);
308                         }
309
310                         if (pos < s.Length && s [pos] != '\u0000')
311                                 throw new FormatException ("Input string was not in the correct format: Did not parse entire string. pos = " 
312                                                                                 + pos + " s.Length = " + s.Length);
313
314                         
315                         if (!negative)
316                                 number = -number;
317
318                         return number;
319                 }
320
321                 public override string ToString ()
322                 {
323                         return ToString (null, null);
324                 }
325
326                 public string ToString (IFormatProvider fp)
327                 {
328                         return ToString (null, fp);
329                 }
330
331                 public string ToString (string format)
332                 {
333                         return ToString (format, null);
334                 }
335
336                 public string ToString (string format, IFormatProvider fp)
337                 {
338                         NumberFormatInfo nfi = NumberFormatInfo.GetInstance( fp );
339                         
340                         if ( format == null )
341                                 format = "G";
342                         
343                         return IntegerFormatter.NumberToString (format, nfi, value);
344                 }
345
346                 // =========== IConvertible Methods =========== //
347
348                 public TypeCode GetTypeCode ()
349                 {
350                         return TypeCode.Int64;
351                 }
352
353                 bool IConvertible.ToBoolean (IFormatProvider provider)
354                 {
355                         return System.Convert.ToBoolean (value);
356                 }
357
358                 byte IConvertible.ToByte (IFormatProvider provider)
359                 {
360                         return System.Convert.ToByte (value);
361                 }
362
363                 char IConvertible.ToChar (IFormatProvider provider)
364                 {
365                         return System.Convert.ToChar (value);
366                 }
367
368                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
369                 {
370                         return System.Convert.ToDateTime (value);
371                 }
372
373                 decimal IConvertible.ToDecimal (IFormatProvider provider)
374                 {
375                         return System.Convert.ToDecimal (value);
376                 }
377
378                 double IConvertible.ToDouble (IFormatProvider provider)
379                 {
380                         return System.Convert.ToDouble (value);
381                 }
382
383                 short IConvertible.ToInt16 (IFormatProvider provider)
384                 {
385                         return System.Convert.ToInt16 (value);
386                 }
387
388                 int IConvertible.ToInt32 (IFormatProvider provider)
389                 {
390                         return System.Convert.ToInt32 (value);
391                 }
392
393                 long IConvertible.ToInt64 (IFormatProvider provider)
394                 {
395                         return System.Convert.ToInt64 (value);
396                 }
397
398                 [CLSCompliant (false)]
399                 sbyte IConvertible.ToSByte (IFormatProvider provider)
400                 {
401                         return System.Convert.ToSByte (value);
402                 }
403                 
404                 float IConvertible.ToSingle (IFormatProvider provider)
405                 {
406                         return System.Convert.ToSingle (value);
407                 }
408
409                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
410                 {
411                         return System.Convert.ToType (value, conversionType, provider);
412                 }
413
414                 [CLSCompliant (false)]
415                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
416                 {
417                         return System.Convert.ToUInt16 (value);
418                 }
419
420                 [CLSCompliant (false)]
421                 uint IConvertible.ToUInt32 (IFormatProvider provider)
422                 {
423                         return System.Convert.ToUInt32 (value);
424                 }
425
426                 [CLSCompliant (false)]
427                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
428                 {
429                         return System.Convert.ToUInt64 (value);
430                 }
431         }
432 }