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;
37 [System.Runtime.InteropServices.ComVisible (true)]
39 public struct Int32 : IFormattable, IConvertible, IComparable
41 , IComparable<Int32>, IEquatable <Int32>
45 public const int MaxValue = 0x7fffffff;
46 public const int MinValue = -2147483648;
48 // This field is looked up by name in the runtime
51 public int CompareTo (object value)
56 if (!(value is System.Int32))
57 throw new ArgumentException (Locale.GetText ("Value is not a System.Int32"));
68 public override bool Equals (object obj)
70 if (!(obj is System.Int32))
73 return ((int) obj) == m_value;
76 public override int GetHashCode ()
82 public int CompareTo (int value)
92 public bool Equals (int obj)
94 return obj == m_value;
98 internal static bool ProcessTrailingWhitespace (bool tryParse, string s, int position, ref Exception exc)
102 for (int i = position; i < len; i++){
105 if (!Char.IsWhiteSpace (c)){
107 exc = GetFormatException ();
114 internal static bool Parse (string s, bool tryParse, out int result, out Exception exc)
119 bool digits_seen = false;
126 exc = new ArgumentNullException ("s");
133 for (i = 0; i < len; i++){
135 if (!Char.IsWhiteSpace (c))
141 exc = GetFormatException ();
153 for (; i < len; i++){
161 if (c >= '0' && c <= '9'){
162 byte d = (byte) (c - '0');
164 if (val > (MaxValue/10))
167 if (val == (MaxValue/10)){
168 if ((d > (MaxValue % 10)) && (sign == 1 || (d > ((MaxValue % 10) + 1))))
171 val = (val * sign * 10) - d;
173 val = (val * 10) + d;
175 if (ProcessTrailingWhitespace (tryParse, s, i + 1, ref exc)){
184 } else if (!ProcessTrailingWhitespace (tryParse, s, i, ref exc))
189 exc = GetFormatException ();
202 exc = new OverflowException ("Value is too large");
206 public static int Parse (string s, IFormatProvider provider)
208 return Parse (s, NumberStyles.Integer, provider);
211 public static int Parse (string s, NumberStyles style)
213 return Parse (s, style, null);
216 internal static bool CheckStyle (NumberStyles style, bool tryParse, ref Exception exc)
218 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
219 NumberStyles ne = style ^ NumberStyles.AllowHexSpecifier;
220 if ((ne & NumberStyles.AllowLeadingWhite) != 0)
221 ne ^= NumberStyles.AllowLeadingWhite;
222 if ((ne & NumberStyles.AllowTrailingWhite) != 0)
223 ne ^= NumberStyles.AllowTrailingWhite;
226 exc = new ArgumentException (
227 "With AllowHexSpecifier only " +
228 "AllowLeadingWhite and AllowTrailingWhite " +
232 } else if ((uint) style > (uint) NumberStyles.Any){
234 exc = new ArgumentException ("Not a valid number style");
241 internal static bool JumpOverWhite (ref int pos, string s, bool reportError, bool tryParse, ref Exception exc)
243 while (pos < s.Length && Char.IsWhiteSpace (s [pos]))
246 if (reportError && pos >= s.Length) {
248 exc = GetFormatException ();
255 internal static void FindSign (ref int pos, string s, NumberFormatInfo nfi,
256 ref bool foundSign, ref bool negative)
258 if ((pos + nfi.NegativeSign.Length) <= s.Length &&
259 s.IndexOf (nfi.NegativeSign, pos, nfi.NegativeSign.Length) == pos) {
262 pos += nfi.NegativeSign.Length;
264 else if ((pos + nfi.PositiveSign.Length) < s.Length &&
265 s.IndexOf (nfi.PositiveSign, pos, nfi.PositiveSign.Length) == pos) {
267 pos += nfi.PositiveSign.Length;
272 internal static void FindCurrency (ref int pos,
274 NumberFormatInfo nfi,
275 ref bool foundCurrency)
277 if ((pos + nfi.CurrencySymbol.Length) <= s.Length &&
278 s.Substring (pos, nfi.CurrencySymbol.Length) == nfi.CurrencySymbol) {
279 foundCurrency = true;
280 pos += nfi.CurrencySymbol.Length;
284 internal static bool FindExponent (ref int pos, string s)
286 int i = s.IndexOfAny(new char [] {'e', 'E'}, pos);
291 if (s [i] == '+' || s [i] == '-')
294 if (!Char.IsDigit (s [i]))
296 for (; i < s.Length; ++i)
297 if (!Char.IsDigit (s [i]))
303 internal static bool FindOther (ref int pos,
307 if ((pos + other.Length) <= s.Length &&
308 s.Substring (pos, other.Length) == other) {
316 internal static bool ValidDigit (char e, bool allowHex)
319 return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
321 return Char.IsDigit (e);
324 internal static Exception GetFormatException ()
326 return new FormatException ("Input string was not in the correct format");
329 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out int result, out Exception exc)
336 exc = new ArgumentNullException ();
342 exc = GetFormatException ();
346 NumberFormatInfo nfi = null;
348 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
349 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
352 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
354 if (!CheckStyle (style, tryParse, ref exc))
357 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
358 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
359 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
360 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
361 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
362 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
363 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
364 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
365 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
366 bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
370 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
373 bool foundOpenParentheses = false;
374 bool negative = false;
375 bool foundSign = false;
376 bool foundCurrency = false;
379 if (AllowParentheses && s [pos] == '(') {
380 foundOpenParentheses = true;
382 negative = true; // MS always make the number negative when there parentheses
383 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
385 if (AllowLeadingWhite && !!JumpOverWhite (ref pos, s, true, tryParse, ref exc))
388 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
390 exc = GetFormatException ();
394 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
396 exc = GetFormatException ();
401 if (AllowLeadingSign && !foundSign) {
403 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
405 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
407 if (AllowCurrencySymbol) {
408 FindCurrency (ref pos, s, nfi,
410 if (foundCurrency && AllowLeadingWhite &&
411 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
417 if (AllowCurrencySymbol && !foundCurrency) {
419 FindCurrency (ref pos, s, nfi, ref foundCurrency);
421 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
424 if (!foundSign && AllowLeadingSign) {
425 FindSign (ref pos, s, nfi, ref foundSign,
427 if (foundSign && AllowLeadingWhite &&
428 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
437 bool decimalPointFound = false;
444 if (!ValidDigit (s [pos], AllowHexSpecifier)) {
445 if (AllowThousands &&
446 FindOther (ref pos, s, nfi.NumberGroupSeparator))
449 if (!decimalPointFound && AllowDecimalPoint &&
450 FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
451 decimalPointFound = true;
457 else if (AllowHexSpecifier) {
459 hexDigit = s [pos++];
460 if (Char.IsDigit (hexDigit))
461 digitValue = (int) (hexDigit - '0');
462 else if (Char.IsLower (hexDigit))
463 digitValue = (int) (hexDigit - 'a' + 10);
465 digitValue = (int) (hexDigit - 'A' + 10);
467 uint unumber = (uint)number;
469 if ((unumber & 0xf0000000) != 0)
472 number = (int) (unumber * 16u + (uint) digitValue);
474 number = (int)checked (unumber * 16u + (uint)digitValue);
477 else if (decimalPointFound) {
479 // Allows decimal point as long as it's only
480 // followed by zeroes.
481 if (s [pos++] != '0') {
483 exc = new OverflowException ("Value too large or too " +
492 // Calculations done as negative
493 // (abs (MinValue) > abs (MaxValue))
496 (int) (s [pos++] - '0')
498 } catch (OverflowException) {
500 exc = new OverflowException ("Value too large or too " +
505 } while (pos < s.Length);
510 exc = GetFormatException ();
515 FindExponent(ref pos, s);
517 if (AllowTrailingSign && !foundSign) {
519 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
521 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
523 if (AllowCurrencySymbol)
524 FindCurrency (ref pos, s, nfi,
529 if (AllowCurrencySymbol && !foundCurrency) {
531 FindCurrency (ref pos, s, nfi, ref foundCurrency);
533 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
535 if (!foundSign && AllowTrailingSign)
536 FindSign (ref pos, s, nfi, ref foundSign,
541 if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
544 if (foundOpenParentheses) {
545 if (pos >= s.Length || s [pos++] != ')') {
547 exc = GetFormatException ();
550 if (AllowTrailingWhite && pos < s.Length &&
551 !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
555 if (pos < s.Length && s [pos] != '\u0000') {
557 exc = GetFormatException ();
561 if (!negative && !AllowHexSpecifier){
565 if (lval < MinValue || lval > MaxValue)
569 number = checked (-number);
577 public static int Parse (string s)
582 if (!Parse (s, false, out res, out exc))
588 public static int Parse (string s, NumberStyles style, IFormatProvider provider)
593 if (!Parse (s, style, provider, false, out res, out exc))
600 public static bool TryParse (string s, out int result)
604 if (!Parse (s, true, out result, out exc)) {
612 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out int result)
615 if (!Parse (s, style, provider, true, out result, out exc)) {
624 public override string ToString ()
626 return NumberFormatter.NumberToString (m_value, null);
629 public string ToString (IFormatProvider provider)
631 return NumberFormatter.NumberToString (m_value, provider);
634 public string ToString (string format)
636 return ToString (format, null);
639 public string ToString (string format, IFormatProvider provider)
641 return NumberFormatter.NumberToString (format, m_value, provider);
644 // =========== IConvertible Methods =========== //
646 public TypeCode GetTypeCode ()
648 return TypeCode.Int32;
651 bool IConvertible.ToBoolean (IFormatProvider provider)
653 return System.Convert.ToBoolean (m_value);
656 byte IConvertible.ToByte (IFormatProvider provider)
658 return System.Convert.ToByte (m_value);
661 char IConvertible.ToChar (IFormatProvider provider)
663 return System.Convert.ToChar (m_value);
666 DateTime IConvertible.ToDateTime (IFormatProvider provider)
668 return System.Convert.ToDateTime (m_value);
671 decimal IConvertible.ToDecimal (IFormatProvider provider)
673 return System.Convert.ToDecimal (m_value);
676 double IConvertible.ToDouble (IFormatProvider provider)
678 return System.Convert.ToDouble (m_value);
681 short IConvertible.ToInt16 (IFormatProvider provider)
683 return System.Convert.ToInt16 (m_value);
686 int IConvertible.ToInt32 (IFormatProvider provider)
691 long IConvertible.ToInt64 (IFormatProvider provider)
693 return System.Convert.ToInt64 (m_value);
697 #pragma warning disable 3019
698 [CLSCompliant (false)]
700 sbyte IConvertible.ToSByte (IFormatProvider provider)
702 return System.Convert.ToSByte (m_value);
705 #pragma warning restore 3019
708 float IConvertible.ToSingle (IFormatProvider provider)
710 return System.Convert.ToSingle (m_value);
713 object IConvertible.ToType (Type type, IFormatProvider provider)
715 return System.Convert.ToType (m_value, type, provider, false);
719 #pragma warning disable 3019
720 [CLSCompliant (false)]
722 ushort IConvertible.ToUInt16 (IFormatProvider provider)
724 return System.Convert.ToUInt16 (m_value);
727 #pragma warning restore 3019
731 #pragma warning disable 3019
732 [CLSCompliant (false)]
734 uint IConvertible.ToUInt32 (IFormatProvider provider)
736 return System.Convert.ToUInt32 (m_value);
739 #pragma warning restore 3019
743 #pragma warning disable 3019
744 [CLSCompliant (false)]
746 ulong IConvertible.ToUInt64 (IFormatProvider provider)
748 return System.Convert.ToUInt64 (m_value);
751 #pragma warning restore 3019