5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) Ximian, Inc. http://www.ximian.com
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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;
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
46 public int CompareTo (object value)
51 if (!(value is System.Int32))
52 throw new ArgumentException (Locale.GetText ("Value is not a System.Int32"));
63 public override bool Equals (object obj)
65 if (!(obj is System.Int32))
68 return ((int) obj) == m_value;
71 public override int GetHashCode ()
76 public int CompareTo (int value)
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)
95 for (int i = position; i < len; i++){
98 if (c != 0 && !Char.IsWhiteSpace (c)){
100 exc = GetFormatException ();
107 internal static bool Parse (string s, bool tryParse, out int result, out Exception exc)
112 bool digits_seen = false;
119 exc = new ArgumentNullException ("s");
126 for (i = 0; i < len; i++){
128 if (!Char.IsWhiteSpace (c))
134 exc = GetFormatException ();
146 for (; i < len; i++){
154 if (c >= '0' && c <= '9'){
155 byte d = (byte) (c - '0');
157 if (val > (MaxValue/10))
160 if (val == (MaxValue/10)){
161 if ((d > (MaxValue % 10)) && (sign == 1 || (d > ((MaxValue % 10) + 1))))
164 val = (val * sign * 10) - d;
166 val = (val * 10) + d;
168 if (ProcessTrailingWhitespace (tryParse, s, i + 1, ref exc)){
177 } else if (!ProcessTrailingWhitespace (tryParse, s, i, ref exc))
182 exc = GetFormatException ();
195 exc = new OverflowException ("Value is too large");
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;
219 exc = new ArgumentException (
220 "With AllowHexSpecifier only " +
221 "AllowLeadingWhite and AllowTrailingWhite " +
225 } else if ((uint) style > (uint) NumberStyles.Any){
227 exc = new ArgumentException ("Not a valid number style");
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]))
239 if (reportError && pos >= s.Length) {
241 exc = GetFormatException ();
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) {
255 pos += nfi.NegativeSign.Length;
257 else if ((pos + nfi.PositiveSign.Length) < s.Length &&
258 s.IndexOf (nfi.PositiveSign, pos, nfi.PositiveSign.Length) == pos) {
260 pos += nfi.PositiveSign.Length;
265 internal static void FindCurrency (ref int pos,
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)
280 long exp = 0; // temp long value
282 int i = s.IndexOfAny(new char [] {'e', 'E'}, pos);
288 if (++i == s.Length) {
289 exc = tryParse ? null : GetFormatException ();
293 // negative exponent not valid for Int32
295 exc = tryParse ? null : new OverflowException ("Value too large or too small.");
299 if (s [i] == '+' && ++i == s.Length) {
300 exc = tryParse ? null : GetFormatException ();
304 for (; i < s.Length; i++) {
305 if (!Char.IsDigit (s [i])) {
306 exc = tryParse ? null : GetFormatException ();
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.");
318 // exp value saved as negative
327 internal static bool FindOther (ref int pos,
331 if ((pos + other.Length) <= s.Length &&
332 s.Substring (pos, other.Length) == other) {
340 internal static bool ValidDigit (char e, bool 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)
360 exc = new ArgumentNullException ();
366 exc = GetFormatException ();
370 NumberFormatInfo nfi = null;
372 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
373 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
376 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
378 if (!CheckStyle (style, tryParse, ref exc))
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;
394 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
397 bool foundOpenParentheses = false;
398 bool negative = false;
399 bool foundSign = false;
400 bool foundCurrency = false;
403 if (AllowParentheses && s [pos] == '(') {
404 foundOpenParentheses = true;
406 negative = true; // MS always make the number negative when there parentheses
407 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
409 if (AllowLeadingWhite && !!JumpOverWhite (ref pos, s, true, tryParse, ref exc))
412 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
414 exc = GetFormatException ();
418 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
420 exc = GetFormatException ();
425 if (AllowLeadingSign && !foundSign) {
427 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
429 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
431 if (AllowCurrencySymbol) {
432 FindCurrency (ref pos, s, nfi,
434 if (foundCurrency && AllowLeadingWhite &&
435 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
441 if (AllowCurrencySymbol && !foundCurrency) {
443 FindCurrency (ref pos, s, nfi, ref foundCurrency);
445 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
448 if (!foundSign && AllowLeadingSign) {
449 FindSign (ref pos, s, nfi, ref foundSign,
451 if (foundSign && AllowLeadingWhite &&
452 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
461 bool decimalPointFound = false;
469 if (!ValidDigit (s [pos], AllowHexSpecifier)) {
470 if (AllowThousands &&
471 FindOther (ref pos, s, nfi.NumberGroupSeparator))
474 if (!decimalPointFound && AllowDecimalPoint &&
475 FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
476 decimalPointFound = true;
482 else if (AllowHexSpecifier) {
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);
490 digitValue = (int) (hexDigit - 'A' + 10);
492 uint unumber = (uint)number;
494 if ((unumber & 0xf0000000) != 0)
497 number = (int) (unumber * 16u + (uint) digitValue);
499 number = (int)checked (unumber * 16u + (uint)digitValue);
502 else if (decimalPointFound) {
504 // Allows decimal point as long as it's only
505 // followed by zeroes.
506 if (s [pos++] != '0') {
508 exc = new OverflowException ("Value too large or too " +
517 // Calculations done as negative
518 // (abs (MinValue) > abs (MaxValue))
521 (int) (s [pos++] - '0')
523 } catch (OverflowException) {
525 exc = new OverflowException ("Value too large or too " +
530 } while (pos < s.Length);
535 exc = GetFormatException ();
540 if (FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null)
543 if (AllowTrailingSign && !foundSign) {
545 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
547 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
549 if (AllowCurrencySymbol)
550 FindCurrency (ref pos, s, nfi,
555 if (AllowCurrencySymbol && !foundCurrency) {
557 FindCurrency (ref pos, s, nfi, ref foundCurrency);
559 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
561 if (!foundSign && AllowTrailingSign)
562 FindSign (ref pos, s, nfi, ref foundSign,
567 if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
570 if (foundOpenParentheses) {
571 if (pos >= s.Length || s [pos++] != ')') {
573 exc = GetFormatException ();
576 if (AllowTrailingWhite && pos < s.Length &&
577 !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
581 if (pos < s.Length && s [pos] != '\u0000') {
583 exc = GetFormatException ();
587 if (!negative && !AllowHexSpecifier){
589 long lval = -((long)number);
591 if (lval < MinValue || lval > MaxValue)
595 number = checked (-number);
598 // result *= 10^exponent
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) {
604 exc = new OverflowException ("Value too large or too small.");
616 public static int Parse (string s)
621 if (!Parse (s, false, out res, out exc))
627 public static int Parse (string s, NumberStyles style, IFormatProvider provider)
632 if (!Parse (s, style, provider, false, out res, out exc))
638 public static bool TryParse (string s, out int result)
642 if (!Parse (s, true, out result, out exc)) {
650 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out int result)
653 if (!Parse (s, style, provider, true, out result, out exc)) {
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)
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);