* Makefile: Don't build make-map.exe.
[mono.git] / mcs / class / corlib / System / Int32.cs
1 //
2 // System.Int32.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System.Globalization;
31 using System.Threading;
32
33 namespace System {
34         
35         [Serializable]
36         public struct Int32 : IFormattable, IConvertible, IComparable
37 #if NET_2_0
38                 , IComparable<Int32>, IEquatable <Int32>
39 #endif
40         {
41
42                 public const int MaxValue = 0x7fffffff;
43                 public const int MinValue = -2147483648;
44                 
45                 // This field is looked up by name in the runtime
46                 internal int m_value;
47
48                 public int CompareTo (object v)
49                 {
50                         if (v == null)
51                                 return 1;
52                         
53                         if (!(v is System.Int32))
54                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Int32"));
55
56                         int xv = (int) v;
57                         if (m_value == xv)
58                                 return 0;
59                         if (m_value > xv)
60                                 return 1;
61                         else
62                                 return -1;
63                 }
64
65                 public override bool Equals (object o)
66                 {
67                         if (!(o is System.Int32))
68                                 return false;
69
70                         return ((int) o) == m_value;
71                 }
72
73                 public override int GetHashCode ()
74                 {
75                         return m_value;
76                 }
77
78 #if NET_2_0
79                 public int CompareTo (int 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 (int value)
90                 {
91                         return value == m_value;
92                 }
93 #endif
94
95                 internal static bool Parse (string s, bool tryParse, out int result, out Exception exc)
96                 {
97                         int val = 0;
98                         int len;
99                         int i, sign = 1;
100                         bool digits_seen = false;
101
102                         result = 0;
103                         exc = null;
104
105                         if (s == null) {
106                                 if (!tryParse)
107                                         exc = new ArgumentNullException ("s");
108                                 return false;
109                         }
110
111                         len = s.Length;
112
113                         char c;
114                         for (i = 0; i < len; i++){
115                                 c = s [i];
116                                 if (!Char.IsWhiteSpace (c))
117                                         break;
118                         }
119                         
120                         if (i == len) {
121                                 if (!tryParse)
122                                         exc = GetFormatException ();
123                                 return false;
124                         }
125
126                         c = s [i];
127                         if (c == '+')
128                                 i++;
129                         else if (c == '-'){
130                                 sign = -1;
131                                 i++;
132                         }
133                         
134                         for (; i < len; i++){
135                                 c = s [i];
136
137                                 if (c == '\0') {
138                                         i = len;
139                                         continue;
140                                 }
141                                 
142                                 if (c >= '0' && c <= '9'){
143                                         try {
144                                                 val = checked (val * 10 + (c - '0') * sign);
145                                                 digits_seen = true;
146                                         } catch (OverflowException e) {
147                                                 exc = e;
148                                                 return false;
149                                         }
150                                 } else {
151                                         if (Char.IsWhiteSpace (c)){
152                                                 for (i++; i < len; i++){
153                                                         if (!Char.IsWhiteSpace (s [i])) {
154                                                                 if (!tryParse)
155                                                                         exc = GetFormatException ();
156                                                                 return false;
157                         
158                                                         }
159                                                 }
160                                                 break;
161                                         } else {
162                                                 if (!tryParse)
163                                                         exc = GetFormatException ();
164                                                 return false;
165                                         }
166                                 }
167                         }
168                         if (!digits_seen) {
169                                 if (!tryParse)
170                                         exc = GetFormatException ();
171                                 return false;
172                         }
173
174                         result = val;
175
176                         return true;
177                 }
178
179                 public static int Parse (string s, IFormatProvider fp)
180                 {
181                         return Parse (s, NumberStyles.Integer, fp);
182                 }
183
184                 public static int Parse (string s, NumberStyles style)
185                 {
186                         return Parse (s, style, null);
187                 }
188
189                 internal static bool CheckStyle (NumberStyles style, bool tryParse, ref Exception exc)
190                 {
191                         if ((style & NumberStyles.AllowHexSpecifier) != 0) {
192                                 NumberStyles ne = style ^ NumberStyles.AllowHexSpecifier;
193                                 if ((ne & NumberStyles.AllowLeadingWhite) != 0)
194                                         ne ^= NumberStyles.AllowLeadingWhite;
195                                 if ((ne & NumberStyles.AllowTrailingWhite) != 0)
196                                         ne ^= NumberStyles.AllowTrailingWhite;
197                                 if (ne != 0) {
198                                         if (!tryParse)
199                                                 exc = new ArgumentException (
200                                                         "With AllowHexSpecifier only " + 
201                                                         "AllowLeadingWhite and AllowTrailingWhite " + 
202                                                         "are permitted.");
203                                         return false;
204                                 }
205                         }
206
207                         return true;
208                 }
209                 
210                 internal static bool JumpOverWhite (ref int pos, string s, bool reportError, bool tryParse, ref Exception exc)
211                 {
212                         while (pos < s.Length && Char.IsWhiteSpace (s [pos]))
213                                 pos++;
214
215                         if (reportError && pos >= s.Length) {
216                                 if (!tryParse)
217                                         exc = GetFormatException ();
218                                 return false;
219                         }
220
221                         return true;
222                 }
223
224                 internal static void FindSign (ref int pos, string s, NumberFormatInfo nfi, 
225                                       ref bool foundSign, ref bool negative)
226                 {
227                         if ((pos + nfi.NegativeSign.Length) <= s.Length &&
228                                 s.IndexOf (nfi.NegativeSign, pos, nfi.NegativeSign.Length) == pos) {
229                                 negative = true;
230                                 foundSign = true;
231                                 pos += nfi.NegativeSign.Length;
232                         } 
233                         else if ((pos + nfi.PositiveSign.Length) < s.Length &&
234                                 s.IndexOf (nfi.PositiveSign, pos, nfi.PositiveSign.Length) == pos) {
235                                 negative = false;
236                                 pos += nfi.PositiveSign.Length;
237                                 foundSign = true;
238                         } 
239                 }
240
241                 internal static void FindCurrency (ref int pos,
242                                                  string s, 
243                                                  NumberFormatInfo nfi,
244                                                  ref bool foundCurrency)
245                 {
246                         if ((pos + nfi.CurrencySymbol.Length) <= s.Length &&
247                              s.Substring (pos, nfi.CurrencySymbol.Length) == nfi.CurrencySymbol) {
248                                 foundCurrency = true;
249                                 pos += nfi.CurrencySymbol.Length;
250                         } 
251                 }
252
253                 internal static bool FindExponent (ref int pos, string s)
254                 {
255                                 int i = s.IndexOfAny(new char [] {'e', 'E'}, pos);
256                                 if (i < 0)
257                                                 return false;
258                                 if (++i == s.Length)
259                                                 return false;
260                                 if (s [i] == '+' || s [i] == '-')
261                                                 if (++i == s.Length)
262                                                                 return false;
263                                 if (!Char.IsDigit (s [i]))
264                                                 return false;
265                                 for (; i < s.Length; ++i)
266                                                 if (!Char.IsDigit (s [i])) 
267                                                                 break;
268                                 pos = i;
269                                 return true;
270                 }
271
272                 internal static bool FindOther (ref int pos,
273                                               string s, 
274                                               string other)
275                 {
276                         if ((pos + other.Length) <= s.Length &&
277                              s.Substring (pos, other.Length) == other) {
278                                 pos += other.Length;
279                                 return true;
280                         } 
281
282                         return false;
283                 }
284
285                 internal static bool ValidDigit (char e, bool allowHex)
286                 {
287                         if (allowHex)
288                                 return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
289
290                         return Char.IsDigit (e);
291                 }
292                 
293                 internal static Exception GetFormatException ()
294                 {
295                         return new FormatException ("Input string was not in the correct format");
296                 }
297                 
298                 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out int result, out Exception exc)
299                 {
300                         result = 0;
301                         exc = null;
302
303                         if (s == null) {
304                                 if (!tryParse)
305                                         exc = GetFormatException ();
306                                 return false;
307                         }
308                         
309                         if (s == null) {
310                                 if (!tryParse)
311                                         exc = new ArgumentNullException ();
312                                 return false;
313                         }
314
315                         if (s.Length == 0) {
316                                 if (!tryParse)
317                                         exc = GetFormatException ();
318                                 return false;
319                         }
320
321                         NumberFormatInfo nfi;
322                         if (fp != null) {
323                                 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
324                                 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
325                         }
326                         else
327                                 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
328
329                         if (!CheckStyle (style, tryParse, ref exc))
330                                 return false;
331
332                         bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
333                         bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
334                         bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
335                         bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
336                         bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
337                         bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
338                         bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
339                         bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
340                         bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
341                         bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
342
343                         int pos = 0;
344
345                         if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
346                                 return false;
347
348                         bool foundOpenParentheses = false;
349                         bool negative = false;
350                         bool foundSign = false;
351                         bool foundCurrency = false;
352
353                         // Pre-number stuff
354                         if (AllowParentheses && s [pos] == '(') {
355                                 foundOpenParentheses = true;
356                                 foundSign = true;
357                                 negative = true; // MS always make the number negative when there parentheses
358                                                  // even when NumberFormatInfo.NumberNegativePattern != 0!!!
359                                 pos++;
360                                 if (AllowLeadingWhite && !!JumpOverWhite (ref pos, s, true, tryParse, ref exc))
361                                         return false;
362
363                                 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
364                                         if (!tryParse)
365                                                 exc = GetFormatException ();
366                                         return false;
367                                 }
368                                 
369                                 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
370                                         if (!tryParse)
371                                                 exc = GetFormatException ();
372                                         return false;
373                                 }
374                         }
375
376                         if (AllowLeadingSign && !foundSign) {
377                                 // Sign + Currency
378                                 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
379                                 if (foundSign) {
380                                         if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
381                                                 return false;
382                                         if (AllowCurrencySymbol) {
383                                                 FindCurrency (ref pos, s, nfi,
384                                                               ref foundCurrency);
385                                                 if (foundCurrency && AllowLeadingWhite &&
386                                                                 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
387                                                         return false;
388                                         }
389                                 }
390                         }
391                         
392                         if (AllowCurrencySymbol && !foundCurrency) {
393                                 // Currency + sign
394                                 FindCurrency (ref pos, s, nfi, ref foundCurrency);
395                                 if (foundCurrency) {
396                                         if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
397                                                 return false;
398                                         if (foundCurrency) {
399                                                 if (!foundSign && AllowLeadingSign) {
400                                                         FindSign (ref pos, s, nfi, ref foundSign,
401                                                                   ref negative);
402                                                         if (foundSign && AllowLeadingWhite &&
403                                                                         !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
404                                                                 return false;
405                                                 }
406                                         }
407                                 }
408                         }
409
410                         int number = 0;
411                         int nDigits = 0;
412                         bool decimalPointFound = false;
413                         int digitValue;
414                         char hexDigit;
415                                 
416                         // Number stuff
417                         do {
418
419                                 if (!ValidDigit (s [pos], AllowHexSpecifier)) {
420                                         if (AllowThousands &&
421                                             FindOther (ref pos, s, nfi.NumberGroupSeparator))
422                                             continue;
423                                         else
424                                         if (!decimalPointFound && AllowDecimalPoint &&
425                                             FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
426                                             decimalPointFound = true;
427                                             continue;
428                                         }
429
430                                         break;
431                                 }
432                                 else if (AllowHexSpecifier) {
433                                         nDigits++;
434                                         hexDigit = s [pos++];
435                                         if (Char.IsDigit (hexDigit))
436                                                 digitValue = (int) (hexDigit - '0');
437                                         else if (Char.IsLower (hexDigit))
438                                                 digitValue = (int) (hexDigit - 'a' + 10);
439                                         else
440                                                 digitValue = (int) (hexDigit - 'A' + 10);
441
442                                         uint unumber = (uint)number;
443                                         try {
444                                                 number = (int)checked (unumber * 16u + (uint)digitValue);
445                                         } catch (OverflowException e) {
446                                                 exc = e;
447                                                 return false;
448                                         }
449                                 }
450                                 else if (decimalPointFound) {
451                                         nDigits++;
452                                         // Allows decimal point as long as it's only 
453                                         // followed by zeroes.
454                                         if (s [pos++] != '0') {
455                                                 if (!tryParse)
456                                                         exc = new OverflowException ("Value too large or too " +
457                                                                         "small.");
458                                                 return false;
459                                         }
460                                 }
461                                 else {
462                                         nDigits++;
463
464                                         try {
465                                                 // Calculations done as negative
466                                                 // (abs (MinValue) > abs (MaxValue))
467                                                 number = checked (
468                                                         number * 10 - 
469                                                         (int) (s [pos++] - '0')
470                                                         );
471                                         } catch (OverflowException) {
472                                                 if (!tryParse)
473                                                         exc = new OverflowException ("Value too large or too " +
474                                                                         "small.");
475                                                 return false;
476                                         }
477                                 }
478                         } while (pos < s.Length);
479
480                         // Post number stuff
481                         if (nDigits == 0) {
482                                 if (!tryParse)
483                                         exc = GetFormatException ();
484                                 return false;
485                         }
486
487                         if (AllowExponent) 
488                                         FindExponent(ref pos, s);
489
490                         if (AllowTrailingSign && !foundSign) {
491                                 // Sign + Currency
492                                 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
493                                 if (foundSign) {
494                                         if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
495                                                 return false;
496                                         if (AllowCurrencySymbol)
497                                                 FindCurrency (ref pos, s, nfi,
498                                                               ref foundCurrency);
499                                 }
500                         }
501                         
502                         if (AllowCurrencySymbol && !foundCurrency) {
503                                 // Currency + sign
504                                 FindCurrency (ref pos, s, nfi, ref foundCurrency);
505                                 if (foundCurrency) {
506                                         if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
507                                                 return false;
508                                         if (!foundSign && AllowTrailingSign)
509                                                 FindSign (ref pos, s, nfi, ref foundSign,
510                                                           ref negative);
511                                 }
512                         }
513                         
514                         if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
515                                 return false;
516
517                         if (foundOpenParentheses) {
518                                 if (pos >= s.Length || s [pos++] != ')') {
519                                         if (!tryParse)
520                                                 exc = GetFormatException ();
521                                         return false;
522                                 }
523                                 if (AllowTrailingWhite && pos < s.Length &&
524                                                 !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
525                                         return false;
526                         }
527
528                         if (pos < s.Length && s [pos] != '\u0000') {
529                                 if (!tryParse)
530                                         exc = GetFormatException ();
531                                 return false;
532                         }
533                         
534                         if (!negative && !AllowHexSpecifier)
535                                 number = checked (-number);
536
537                         result = number;
538
539                         return true;
540                 }
541
542                 public static int Parse (string s) 
543                 {
544                         Exception exc;
545                         int res;
546
547                         if (!Parse (s, false, out res, out exc))
548                                 throw exc;
549
550                         return res;
551                 }
552
553                 public static int Parse (string s, NumberStyles style, IFormatProvider fp) 
554                 {
555                         Exception exc;
556                         int res;
557
558                         if (!Parse (s, style, fp, false, out res, out exc))
559                                 throw exc;
560
561                         return res;
562                 }
563
564 #if NET_2_0
565                 public static bool TryParse (string s, out int result) 
566                 {
567                         Exception exc;
568                         
569                         if (!Parse (s, true, out result, out exc)) {
570                                 result = 0;
571                                 return false;
572                         }
573
574                         return true;
575                 }
576
577                 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out int result) 
578                 {
579                         Exception exc;
580                         if (!Parse (s, style, provider, true, out result, out exc)) {
581                                 result = 0;
582                                 return false;
583                         }
584
585                         return true;
586                 }
587 #endif
588
589                 public override string ToString ()
590                 {
591                         return NumberFormatter.FormatGeneral (new NumberFormatter.NumberStore (m_value));
592                 }
593
594                 public string ToString (IFormatProvider fp)
595                 {
596                         return NumberFormatter.FormatGeneral (new NumberFormatter.NumberStore (m_value), fp);
597                 }
598
599                 public string ToString (string format)
600                 {
601                         return ToString (format, null);
602                 }
603
604                 public string ToString (string format, IFormatProvider fp )
605                 {
606                         NumberFormatInfo nfi = NumberFormatInfo.GetInstance( fp );
607                         return NumberFormatter.NumberToString (format, m_value, nfi);
608                 }
609
610                 // =========== IConvertible Methods =========== //
611
612                 public TypeCode GetTypeCode ()
613                 {
614                         return TypeCode.Int32;
615                 }
616                 
617                 bool IConvertible.ToBoolean  (IFormatProvider provider)
618                 {
619                         return System.Convert.ToBoolean (m_value);
620                 }
621                 byte IConvertible.ToByte     (IFormatProvider provider)
622                 {
623                         return System.Convert.ToByte (m_value);
624                 }
625                 char IConvertible.ToChar     (IFormatProvider provider)
626                 {
627                         return System.Convert.ToChar (m_value);
628                 }
629                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
630                 {
631                         return System.Convert.ToDateTime (m_value);
632                 }
633                 decimal IConvertible.ToDecimal  (IFormatProvider provider)
634                 {
635                         return System.Convert.ToDecimal (m_value);
636                 }
637                 double IConvertible.ToDouble   (IFormatProvider provider)
638                 {
639                         return System.Convert.ToDouble (m_value);
640                 }
641                 short IConvertible.ToInt16    (IFormatProvider provider)
642                 {
643                         return System.Convert.ToInt16 (m_value);
644                 }
645                 int IConvertible.ToInt32    (IFormatProvider provider)
646                 {
647                         return m_value;
648                 }
649                 long IConvertible.ToInt64    (IFormatProvider provider)
650                 {
651                         return System.Convert.ToInt64 (m_value);
652                 }
653
654                 sbyte IConvertible.ToSByte    (IFormatProvider provider)
655                 {
656                         return System.Convert.ToSByte (m_value);
657                 }
658                 float IConvertible.ToSingle   (IFormatProvider provider)
659                 {
660                         return System.Convert.ToSingle (m_value);
661                 }
662
663                 object IConvertible.ToType     (Type conversionType, IFormatProvider provider)
664                 {
665                         return System.Convert.ToType (m_value, conversionType, provider);
666                 }
667                 
668                 ushort IConvertible.ToUInt16   (IFormatProvider provider)
669                 {
670                         return System.Convert.ToUInt16 (m_value);
671                 }
672
673                 uint IConvertible.ToUInt32   (IFormatProvider provider)
674                 {
675                         return System.Convert.ToUInt32 (m_value);
676                 }
677                 ulong IConvertible.ToUInt64   (IFormatProvider provider)
678                 {
679                         return System.Convert.ToUInt64 (m_value);
680                 }
681         }
682 }