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