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 v)
56 if (!(v is System.Int32))
57 throw new ArgumentException (Locale.GetText ("Value is not a System.Int32"));
68 public override bool Equals (object o)
70 if (!(o is System.Int32))
73 return ((int) o) == m_value;
76 public override int GetHashCode ()
82 public int CompareTo (int value)
92 public bool Equals (int value)
94 return value == m_value;
98 internal static bool Parse (string s, bool tryParse, out int result, out Exception exc)
103 bool digits_seen = false;
110 exc = new ArgumentNullException ("s");
117 for (i = 0; i < len; i++){
119 if (!Char.IsWhiteSpace (c))
125 exc = GetFormatException ();
137 for (; i < len; i++){
145 if (c >= '0' && c <= '9'){
147 val = checked (val * 10 + (c - '0') * sign);
149 } catch (OverflowException e) {
154 if (Char.IsWhiteSpace (c)){
155 for (i++; i < len; i++){
156 if (!Char.IsWhiteSpace (s [i])) {
158 exc = GetFormatException ();
166 exc = GetFormatException ();
173 exc = GetFormatException ();
182 public static int Parse (string s, IFormatProvider fp)
184 return Parse (s, NumberStyles.Integer, fp);
187 public static int Parse (string s, NumberStyles style)
189 return Parse (s, style, null);
192 internal static bool CheckStyle (NumberStyles style, bool tryParse, ref Exception exc)
194 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
195 NumberStyles ne = style ^ NumberStyles.AllowHexSpecifier;
196 if ((ne & NumberStyles.AllowLeadingWhite) != 0)
197 ne ^= NumberStyles.AllowLeadingWhite;
198 if ((ne & NumberStyles.AllowTrailingWhite) != 0)
199 ne ^= NumberStyles.AllowTrailingWhite;
202 exc = new ArgumentException (
203 "With AllowHexSpecifier only " +
204 "AllowLeadingWhite and AllowTrailingWhite " +
213 internal static bool JumpOverWhite (ref int pos, string s, bool reportError, bool tryParse, ref Exception exc)
215 while (pos < s.Length && Char.IsWhiteSpace (s [pos]))
218 if (reportError && pos >= s.Length) {
220 exc = GetFormatException ();
227 internal static void FindSign (ref int pos, string s, NumberFormatInfo nfi,
228 ref bool foundSign, ref bool negative)
230 if ((pos + nfi.NegativeSign.Length) <= s.Length &&
231 s.IndexOf (nfi.NegativeSign, pos, nfi.NegativeSign.Length) == pos) {
234 pos += nfi.NegativeSign.Length;
236 else if ((pos + nfi.PositiveSign.Length) < s.Length &&
237 s.IndexOf (nfi.PositiveSign, pos, nfi.PositiveSign.Length) == pos) {
239 pos += nfi.PositiveSign.Length;
244 internal static void FindCurrency (ref int pos,
246 NumberFormatInfo nfi,
247 ref bool foundCurrency)
249 if ((pos + nfi.CurrencySymbol.Length) <= s.Length &&
250 s.Substring (pos, nfi.CurrencySymbol.Length) == nfi.CurrencySymbol) {
251 foundCurrency = true;
252 pos += nfi.CurrencySymbol.Length;
256 internal static bool FindExponent (ref int pos, string s)
258 int i = s.IndexOfAny(new char [] {'e', 'E'}, pos);
263 if (s [i] == '+' || s [i] == '-')
266 if (!Char.IsDigit (s [i]))
268 for (; i < s.Length; ++i)
269 if (!Char.IsDigit (s [i]))
275 internal static bool FindOther (ref int pos,
279 if ((pos + other.Length) <= s.Length &&
280 s.Substring (pos, other.Length) == other) {
288 internal static bool ValidDigit (char e, bool allowHex)
291 return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
293 return Char.IsDigit (e);
296 internal static Exception GetFormatException ()
298 return new FormatException ("Input string was not in the correct format");
301 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out int result, out Exception exc)
308 exc = GetFormatException ();
314 exc = new ArgumentNullException ();
320 exc = GetFormatException ();
324 NumberFormatInfo nfi;
326 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
327 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
330 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
332 if (!CheckStyle (style, tryParse, ref exc))
335 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
336 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
337 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
338 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
339 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
340 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
341 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
342 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
343 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
344 bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
348 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
351 bool foundOpenParentheses = false;
352 bool negative = false;
353 bool foundSign = false;
354 bool foundCurrency = false;
357 if (AllowParentheses && s [pos] == '(') {
358 foundOpenParentheses = true;
360 negative = true; // MS always make the number negative when there parentheses
361 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
363 if (AllowLeadingWhite && !!JumpOverWhite (ref pos, s, true, tryParse, ref exc))
366 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
368 exc = GetFormatException ();
372 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
374 exc = GetFormatException ();
379 if (AllowLeadingSign && !foundSign) {
381 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
383 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
385 if (AllowCurrencySymbol) {
386 FindCurrency (ref pos, s, nfi,
388 if (foundCurrency && AllowLeadingWhite &&
389 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
395 if (AllowCurrencySymbol && !foundCurrency) {
397 FindCurrency (ref pos, s, nfi, ref foundCurrency);
399 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
402 if (!foundSign && AllowLeadingSign) {
403 FindSign (ref pos, s, nfi, ref foundSign,
405 if (foundSign && AllowLeadingWhite &&
406 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
415 bool decimalPointFound = false;
422 if (!ValidDigit (s [pos], AllowHexSpecifier)) {
423 if (AllowThousands &&
424 FindOther (ref pos, s, nfi.NumberGroupSeparator))
427 if (!decimalPointFound && AllowDecimalPoint &&
428 FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
429 decimalPointFound = true;
435 else if (AllowHexSpecifier) {
437 hexDigit = s [pos++];
438 if (Char.IsDigit (hexDigit))
439 digitValue = (int) (hexDigit - '0');
440 else if (Char.IsLower (hexDigit))
441 digitValue = (int) (hexDigit - 'a' + 10);
443 digitValue = (int) (hexDigit - 'A' + 10);
445 uint unumber = (uint)number;
447 number = (int)checked (unumber * 16u + (uint)digitValue);
448 } catch (OverflowException e) {
453 else if (decimalPointFound) {
455 // Allows decimal point as long as it's only
456 // followed by zeroes.
457 if (s [pos++] != '0') {
459 exc = new OverflowException ("Value too large or too " +
468 // Calculations done as negative
469 // (abs (MinValue) > abs (MaxValue))
472 (int) (s [pos++] - '0')
474 } catch (OverflowException) {
476 exc = new OverflowException ("Value too large or too " +
481 } while (pos < s.Length);
486 exc = GetFormatException ();
491 FindExponent(ref pos, s);
493 if (AllowTrailingSign && !foundSign) {
495 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
497 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
499 if (AllowCurrencySymbol)
500 FindCurrency (ref pos, s, nfi,
505 if (AllowCurrencySymbol && !foundCurrency) {
507 FindCurrency (ref pos, s, nfi, ref foundCurrency);
509 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
511 if (!foundSign && AllowTrailingSign)
512 FindSign (ref pos, s, nfi, ref foundSign,
517 if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
520 if (foundOpenParentheses) {
521 if (pos >= s.Length || s [pos++] != ')') {
523 exc = GetFormatException ();
526 if (AllowTrailingWhite && pos < s.Length &&
527 !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
531 if (pos < s.Length && s [pos] != '\u0000') {
533 exc = GetFormatException ();
537 if (!negative && !AllowHexSpecifier)
538 number = checked (-number);
545 public static int Parse (string s)
550 if (!Parse (s, false, out res, out exc))
556 public static int Parse (string s, NumberStyles style, IFormatProvider fp)
561 if (!Parse (s, style, fp, false, out res, out exc))
568 public static bool TryParse (string s, out int result)
572 if (!Parse (s, true, out result, out exc)) {
580 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out int result)
583 if (!Parse (s, style, provider, true, out result, out exc)) {
592 public override string ToString ()
594 return NumberFormatter.FormatGeneral (new NumberFormatter.NumberStore (m_value));
597 public string ToString (IFormatProvider fp)
599 return NumberFormatter.FormatGeneral (new NumberFormatter.NumberStore (m_value), fp);
602 public string ToString (string format)
604 return ToString (format, null);
607 public string ToString (string format, IFormatProvider fp )
609 NumberFormatInfo nfi = NumberFormatInfo.GetInstance( fp );
610 return NumberFormatter.NumberToString (format, m_value, nfi);
613 // =========== IConvertible Methods =========== //
615 public TypeCode GetTypeCode ()
617 return TypeCode.Int32;
620 bool IConvertible.ToBoolean (IFormatProvider provider)
622 return System.Convert.ToBoolean (m_value);
624 byte IConvertible.ToByte (IFormatProvider provider)
626 return System.Convert.ToByte (m_value);
628 char IConvertible.ToChar (IFormatProvider provider)
630 return System.Convert.ToChar (m_value);
632 DateTime IConvertible.ToDateTime (IFormatProvider provider)
634 return System.Convert.ToDateTime (m_value);
636 decimal IConvertible.ToDecimal (IFormatProvider provider)
638 return System.Convert.ToDecimal (m_value);
640 double IConvertible.ToDouble (IFormatProvider provider)
642 return System.Convert.ToDouble (m_value);
644 short IConvertible.ToInt16 (IFormatProvider provider)
646 return System.Convert.ToInt16 (m_value);
648 int IConvertible.ToInt32 (IFormatProvider provider)
652 long IConvertible.ToInt64 (IFormatProvider provider)
654 return System.Convert.ToInt64 (m_value);
657 sbyte IConvertible.ToSByte (IFormatProvider provider)
659 return System.Convert.ToSByte (m_value);
661 float IConvertible.ToSingle (IFormatProvider provider)
663 return System.Convert.ToSingle (m_value);
666 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
668 return System.Convert.ToType (m_value, conversionType, provider);
671 ushort IConvertible.ToUInt16 (IFormatProvider provider)
673 return System.Convert.ToUInt16 (m_value);
676 uint IConvertible.ToUInt32 (IFormatProvider provider)
678 return System.Convert.ToUInt32 (m_value);
680 ulong IConvertible.ToUInt64 (IFormatProvider provider)
682 return System.Convert.ToUInt64 (m_value);