2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System / Int32.cs
blobdcb76d75e59959ada2f4a3c6b7917b3f7301cc6c
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.
30 using System.Globalization;
31 using System.Threading;
33 namespace System {
35 [Serializable]
36 [System.Runtime.InteropServices.ComVisible (true)]
37 public struct Int32 : IFormattable, IConvertible, IComparable, IComparable<Int32>, IEquatable <Int32>
40 public const int MaxValue = 0x7fffffff;
41 public const int MinValue = -2147483648;
43 // This field is looked up by name in the runtime
44 internal int m_value;
46 public int CompareTo (object value)
48 if (value == null)
49 return 1;
51 if (!(value is System.Int32))
52 throw new ArgumentException (Locale.GetText ("Value is not a System.Int32"));
54 int xv = (int) value;
55 if (m_value == xv)
56 return 0;
57 if (m_value > xv)
58 return 1;
59 else
60 return -1;
63 public override bool Equals (object obj)
65 if (!(obj is System.Int32))
66 return false;
68 return ((int) obj) == m_value;
71 public override int GetHashCode ()
73 return m_value;
76 public int CompareTo (int value)
78 if (m_value == value)
79 return 0;
80 if (m_value > value)
81 return 1;
82 else
83 return -1;
86 public bool Equals (int obj)
88 return obj == m_value;
91 internal static bool ProcessTrailingWhitespace (bool tryParse, string s, int position, ref Exception exc)
93 int len = s.Length;
95 for (int i = position; i < len; i++){
96 char c = s [i];
98 if (c != 0 && !Char.IsWhiteSpace (c)){
99 if (!tryParse)
100 exc = GetFormatException ();
101 return false;
104 return true;
107 internal static bool Parse (string s, bool tryParse, out int result, out Exception exc)
109 int val = 0;
110 int len;
111 int i, sign = 1;
112 bool digits_seen = false;
114 result = 0;
115 exc = null;
117 if (s == null) {
118 if (!tryParse)
119 exc = new ArgumentNullException ("s");
120 return false;
123 len = s.Length;
125 char c;
126 for (i = 0; i < len; i++){
127 c = s [i];
128 if (!Char.IsWhiteSpace (c))
129 break;
132 if (i == len) {
133 if (!tryParse)
134 exc = GetFormatException ();
135 return false;
138 c = s [i];
139 if (c == '+')
140 i++;
141 else if (c == '-'){
142 sign = -1;
143 i++;
146 for (; i < len; i++){
147 c = s [i];
149 if (c == '\0') {
150 i = len;
151 continue;
154 if (c >= '0' && c <= '9'){
155 byte d = (byte) (c - '0');
157 if (val > (MaxValue/10))
158 goto overflow;
160 if (val == (MaxValue/10)){
161 if ((d > (MaxValue % 10)) && (sign == 1 || (d > ((MaxValue % 10) + 1))))
162 goto overflow;
163 if (sign == -1)
164 val = (val * sign * 10) - d;
165 else
166 val = (val * 10) + d;
168 if (ProcessTrailingWhitespace (tryParse, s, i + 1, ref exc)){
169 result = val;
170 return true;
172 goto overflow;
173 } else
174 val = val * 10 + d;
176 digits_seen = true;
177 } else if (!ProcessTrailingWhitespace (tryParse, s, i, ref exc))
178 return false;
180 if (!digits_seen) {
181 if (!tryParse)
182 exc = GetFormatException ();
183 return false;
186 if (sign == -1)
187 result = val * sign;
188 else
189 result = val;
191 return true;
193 overflow:
194 if (!tryParse)
195 exc = new OverflowException ("Value is too large");
196 return false;
199 public static int Parse (string s, IFormatProvider provider)
201 return Parse (s, NumberStyles.Integer, provider);
204 public static int Parse (string s, NumberStyles style)
206 return Parse (s, style, null);
209 internal static bool CheckStyle (NumberStyles style, bool tryParse, ref Exception exc)
211 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
212 NumberStyles ne = style ^ NumberStyles.AllowHexSpecifier;
213 if ((ne & NumberStyles.AllowLeadingWhite) != 0)
214 ne ^= NumberStyles.AllowLeadingWhite;
215 if ((ne & NumberStyles.AllowTrailingWhite) != 0)
216 ne ^= NumberStyles.AllowTrailingWhite;
217 if (ne != 0) {
218 if (!tryParse)
219 exc = new ArgumentException (
220 "With AllowHexSpecifier only " +
221 "AllowLeadingWhite and AllowTrailingWhite " +
222 "are permitted.");
223 return false;
225 } else if ((uint) style > (uint) NumberStyles.Any){
226 if (!tryParse)
227 exc = new ArgumentException ("Not a valid number style");
228 return false;
231 return true;
234 internal static bool JumpOverWhite (ref int pos, string s, bool reportError, bool tryParse, ref Exception exc)
236 while (pos < s.Length && Char.IsWhiteSpace (s [pos]))
237 pos++;
239 if (reportError && pos >= s.Length) {
240 if (!tryParse)
241 exc = GetFormatException ();
242 return false;
245 return true;
248 internal static void FindSign (ref int pos, string s, NumberFormatInfo nfi,
249 ref bool foundSign, ref bool negative)
251 if ((pos + nfi.NegativeSign.Length) <= s.Length &&
252 s.IndexOf (nfi.NegativeSign, pos, nfi.NegativeSign.Length) == pos) {
253 negative = true;
254 foundSign = true;
255 pos += nfi.NegativeSign.Length;
257 else if ((pos + nfi.PositiveSign.Length) < s.Length &&
258 s.IndexOf (nfi.PositiveSign, pos, nfi.PositiveSign.Length) == pos) {
259 negative = false;
260 pos += nfi.PositiveSign.Length;
261 foundSign = true;
265 internal static void FindCurrency (ref int pos,
266 string s,
267 NumberFormatInfo nfi,
268 ref bool foundCurrency)
270 if ((pos + nfi.CurrencySymbol.Length) <= s.Length &&
271 s.Substring (pos, nfi.CurrencySymbol.Length) == nfi.CurrencySymbol) {
272 foundCurrency = true;
273 pos += nfi.CurrencySymbol.Length;
277 internal static bool FindExponent (ref int pos, string s, ref int exponent, bool tryParse, ref Exception exc)
279 exponent = 0;
280 long exp = 0; // temp long value
282 int i = s.IndexOfAny(new char [] {'e', 'E'}, pos);
283 if (i < 0) {
284 exc = null;
285 return false;
288 if (++i == s.Length) {
289 exc = tryParse ? null : GetFormatException ();
290 return true;
293 // negative exponent not valid for Int32
294 if (s [i] == '-') {
295 exc = tryParse ? null : new OverflowException ("Value too large or too small.");
296 return true;
299 if (s [i] == '+' && ++i == s.Length) {
300 exc = tryParse ? null : GetFormatException ();
301 return true;
304 for (; i < s.Length; i++) {
305 if (!Char.IsDigit (s [i])) {
306 exc = tryParse ? null : GetFormatException ();
307 return true;
310 // Reduce the risk of throwing an overflow exc
311 exp = checked (exp * 10 - (int) (s [i] - '0'));
312 if (exp < Int32.MinValue || exp > Int32.MaxValue) {
313 exc = tryParse ? null : new OverflowException ("Value too large or too small.");
314 return true;
318 // exp value saved as negative
319 exp = -exp;
321 exc = null;
322 exponent = (int)exp;
323 pos = i;
324 return true;
327 internal static bool FindOther (ref int pos,
328 string s,
329 string other)
331 if ((pos + other.Length) <= s.Length &&
332 s.Substring (pos, other.Length) == other) {
333 pos += other.Length;
334 return true;
337 return false;
340 internal static bool ValidDigit (char e, bool allowHex)
342 if (allowHex)
343 return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
345 return Char.IsDigit (e);
348 internal static Exception GetFormatException ()
350 return new FormatException ("Input string was not in the correct format");
353 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out int result, out Exception exc)
355 result = 0;
356 exc = null;
358 if (s == null) {
359 if (!tryParse)
360 exc = new ArgumentNullException ();
361 return false;
364 if (s.Length == 0) {
365 if (!tryParse)
366 exc = GetFormatException ();
367 return false;
370 NumberFormatInfo nfi = null;
371 if (fp != null) {
372 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
373 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
375 if (nfi == null)
376 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
378 if (!CheckStyle (style, tryParse, ref exc))
379 return false;
381 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
382 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
383 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
384 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
385 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
386 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
387 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
388 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
389 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
390 bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
392 int pos = 0;
394 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
395 return false;
397 bool foundOpenParentheses = false;
398 bool negative = false;
399 bool foundSign = false;
400 bool foundCurrency = false;
402 // Pre-number stuff
403 if (AllowParentheses && s [pos] == '(') {
404 foundOpenParentheses = true;
405 foundSign = true;
406 negative = true; // MS always make the number negative when there parentheses
407 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
408 pos++;
409 if (AllowLeadingWhite && !!JumpOverWhite (ref pos, s, true, tryParse, ref exc))
410 return false;
412 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
413 if (!tryParse)
414 exc = GetFormatException ();
415 return false;
418 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
419 if (!tryParse)
420 exc = GetFormatException ();
421 return false;
425 if (AllowLeadingSign && !foundSign) {
426 // Sign + Currency
427 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
428 if (foundSign) {
429 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
430 return false;
431 if (AllowCurrencySymbol) {
432 FindCurrency (ref pos, s, nfi,
433 ref foundCurrency);
434 if (foundCurrency && AllowLeadingWhite &&
435 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
436 return false;
441 if (AllowCurrencySymbol && !foundCurrency) {
442 // Currency + sign
443 FindCurrency (ref pos, s, nfi, ref foundCurrency);
444 if (foundCurrency) {
445 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
446 return false;
447 if (foundCurrency) {
448 if (!foundSign && AllowLeadingSign) {
449 FindSign (ref pos, s, nfi, ref foundSign,
450 ref negative);
451 if (foundSign && AllowLeadingWhite &&
452 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
453 return false;
459 int number = 0;
460 int nDigits = 0;
461 bool decimalPointFound = false;
462 int digitValue;
463 char hexDigit;
464 int exponent = 0;
466 // Number stuff
467 do {
469 if (!ValidDigit (s [pos], AllowHexSpecifier)) {
470 if (AllowThousands &&
471 FindOther (ref pos, s, nfi.NumberGroupSeparator))
472 continue;
473 else
474 if (!decimalPointFound && AllowDecimalPoint &&
475 FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
476 decimalPointFound = true;
477 continue;
480 break;
482 else if (AllowHexSpecifier) {
483 nDigits++;
484 hexDigit = s [pos++];
485 if (Char.IsDigit (hexDigit))
486 digitValue = (int) (hexDigit - '0');
487 else if (Char.IsLower (hexDigit))
488 digitValue = (int) (hexDigit - 'a' + 10);
489 else
490 digitValue = (int) (hexDigit - 'A' + 10);
492 uint unumber = (uint)number;
493 if (tryParse){
494 if ((unumber & 0xf0000000) != 0)
495 return false;
497 number = (int) (unumber * 16u + (uint) digitValue);
498 } else {
499 number = (int)checked (unumber * 16u + (uint)digitValue);
502 else if (decimalPointFound) {
503 nDigits++;
504 // Allows decimal point as long as it's only
505 // followed by zeroes.
506 if (s [pos++] != '0') {
507 if (!tryParse)
508 exc = new OverflowException ("Value too large or too " +
509 "small.");
510 return false;
513 else {
514 nDigits++;
516 try {
517 // Calculations done as negative
518 // (abs (MinValue) > abs (MaxValue))
519 number = checked (
520 number * 10 -
521 (int) (s [pos++] - '0')
523 } catch (OverflowException) {
524 if (!tryParse)
525 exc = new OverflowException ("Value too large or too " +
526 "small.");
527 return false;
530 } while (pos < s.Length);
532 // Post number stuff
533 if (nDigits == 0) {
534 if (!tryParse)
535 exc = GetFormatException ();
536 return false;
539 if (AllowExponent)
540 if (FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null)
541 return false;
543 if (AllowTrailingSign && !foundSign) {
544 // Sign + Currency
545 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
546 if (foundSign) {
547 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
548 return false;
549 if (AllowCurrencySymbol)
550 FindCurrency (ref pos, s, nfi,
551 ref foundCurrency);
555 if (AllowCurrencySymbol && !foundCurrency) {
556 // Currency + sign
557 FindCurrency (ref pos, s, nfi, ref foundCurrency);
558 if (foundCurrency) {
559 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
560 return false;
561 if (!foundSign && AllowTrailingSign)
562 FindSign (ref pos, s, nfi, ref foundSign,
563 ref negative);
567 if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
568 return false;
570 if (foundOpenParentheses) {
571 if (pos >= s.Length || s [pos++] != ')') {
572 if (!tryParse)
573 exc = GetFormatException ();
574 return false;
576 if (AllowTrailingWhite && pos < s.Length &&
577 !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
578 return false;
581 if (pos < s.Length && s [pos] != '\u0000') {
582 if (!tryParse)
583 exc = GetFormatException ();
584 return false;
587 if (!negative && !AllowHexSpecifier){
588 if (tryParse){
589 long lval = -((long)number);
591 if (lval < MinValue || lval > MaxValue)
592 return false;
593 number = (int) lval;
594 } else
595 number = checked (-number);
598 // result *= 10^exponent
599 if (exponent > 0) {
600 // Reduce the risk of throwing an overflow exc
601 double res = checked (Math.Pow (10, exponent) * number);
602 if (res < Int32.MinValue || res > Int32.MaxValue) {
603 if (!tryParse)
604 exc = new OverflowException ("Value too large or too small.");
605 return false;
608 number = (int)res;
611 result = number;
613 return true;
616 public static int Parse (string s)
618 Exception exc;
619 int res;
621 if (!Parse (s, false, out res, out exc))
622 throw exc;
624 return res;
627 public static int Parse (string s, NumberStyles style, IFormatProvider provider)
629 Exception exc;
630 int res;
632 if (!Parse (s, style, provider, false, out res, out exc))
633 throw exc;
635 return res;
638 public static bool TryParse (string s, out int result)
640 Exception exc;
642 if (!Parse (s, true, out result, out exc)) {
643 result = 0;
644 return false;
647 return true;
650 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out int result)
652 Exception exc;
653 if (!Parse (s, style, provider, true, out result, out exc)) {
654 result = 0;
655 return false;
658 return true;
661 public override string ToString ()
663 return NumberFormatter.NumberToString (m_value, null);
666 public string ToString (IFormatProvider provider)
668 return NumberFormatter.NumberToString (m_value, provider);
671 public string ToString (string format)
673 return ToString (format, null);
676 public string ToString (string format, IFormatProvider provider)
678 return NumberFormatter.NumberToString (format, m_value, provider);
681 // =========== IConvertible Methods =========== //
683 public TypeCode GetTypeCode ()
685 return TypeCode.Int32;
688 bool IConvertible.ToBoolean (IFormatProvider provider)
690 return System.Convert.ToBoolean (m_value);
693 byte IConvertible.ToByte (IFormatProvider provider)
695 return System.Convert.ToByte (m_value);
698 char IConvertible.ToChar (IFormatProvider provider)
700 return System.Convert.ToChar (m_value);
703 DateTime IConvertible.ToDateTime (IFormatProvider provider)
705 return System.Convert.ToDateTime (m_value);
708 decimal IConvertible.ToDecimal (IFormatProvider provider)
710 return System.Convert.ToDecimal (m_value);
713 double IConvertible.ToDouble (IFormatProvider provider)
715 return System.Convert.ToDouble (m_value);
718 short IConvertible.ToInt16 (IFormatProvider provider)
720 return System.Convert.ToInt16 (m_value);
723 int IConvertible.ToInt32 (IFormatProvider provider)
725 return m_value;
728 long IConvertible.ToInt64 (IFormatProvider provider)
730 return System.Convert.ToInt64 (m_value);
733 sbyte IConvertible.ToSByte (IFormatProvider provider)
735 return System.Convert.ToSByte (m_value);
738 float IConvertible.ToSingle (IFormatProvider provider)
740 return System.Convert.ToSingle (m_value);
743 object IConvertible.ToType (Type targetType, IFormatProvider provider)
745 if (targetType == null)
746 throw new ArgumentNullException ("targetType");
747 return System.Convert.ToType (m_value, targetType, provider, false);
750 ushort IConvertible.ToUInt16 (IFormatProvider provider)
752 return System.Convert.ToUInt16 (m_value);
755 uint IConvertible.ToUInt32 (IFormatProvider provider)
757 return System.Convert.ToUInt32 (m_value);
760 ulong IConvertible.ToUInt64 (IFormatProvider provider)
762 return System.Convert.ToUInt64 (m_value);