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 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 fp)
208 return Parse (s, NumberStyles.Integer, fp);
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 " +
237 internal static bool JumpOverWhite (ref int pos, string s, bool reportError, bool tryParse, ref Exception exc)
239 while (pos < s.Length && Char.IsWhiteSpace (s [pos]))
242 if (reportError && pos >= s.Length) {
244 exc = GetFormatException ();
251 internal static void FindSign (ref int pos, string s, NumberFormatInfo nfi,
252 ref bool foundSign, ref bool negative)
254 if ((pos + nfi.NegativeSign.Length) <= s.Length &&
255 s.IndexOf (nfi.NegativeSign, pos, nfi.NegativeSign.Length) == pos) {
258 pos += nfi.NegativeSign.Length;
260 else if ((pos + nfi.PositiveSign.Length) < s.Length &&
261 s.IndexOf (nfi.PositiveSign, pos, nfi.PositiveSign.Length) == pos) {
263 pos += nfi.PositiveSign.Length;
268 internal static void FindCurrency (ref int pos,
270 NumberFormatInfo nfi,
271 ref bool foundCurrency)
273 if ((pos + nfi.CurrencySymbol.Length) <= s.Length &&
274 s.Substring (pos, nfi.CurrencySymbol.Length) == nfi.CurrencySymbol) {
275 foundCurrency = true;
276 pos += nfi.CurrencySymbol.Length;
280 internal static bool FindExponent (ref int pos, string s)
282 int i = s.IndexOfAny(new char [] {'e', 'E'}, pos);
287 if (s [i] == '+' || s [i] == '-')
290 if (!Char.IsDigit (s [i]))
292 for (; i < s.Length; ++i)
293 if (!Char.IsDigit (s [i]))
299 internal static bool FindOther (ref int pos,
303 if ((pos + other.Length) <= s.Length &&
304 s.Substring (pos, other.Length) == other) {
312 internal static bool ValidDigit (char e, bool allowHex)
315 return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
317 return Char.IsDigit (e);
320 internal static Exception GetFormatException ()
322 return new FormatException ("Input string was not in the correct format");
325 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out int result, out Exception exc)
332 exc = GetFormatException ();
338 exc = new ArgumentNullException ();
344 exc = GetFormatException ();
348 NumberFormatInfo nfi;
350 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
351 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
354 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
356 if (!CheckStyle (style, tryParse, ref exc))
359 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
360 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
361 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
362 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
363 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
364 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
365 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
366 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
367 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
368 bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
372 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
375 bool foundOpenParentheses = false;
376 bool negative = false;
377 bool foundSign = false;
378 bool foundCurrency = false;
381 if (AllowParentheses && s [pos] == '(') {
382 foundOpenParentheses = true;
384 negative = true; // MS always make the number negative when there parentheses
385 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
387 if (AllowLeadingWhite && !!JumpOverWhite (ref pos, s, true, tryParse, ref exc))
390 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
392 exc = GetFormatException ();
396 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
398 exc = GetFormatException ();
403 if (AllowLeadingSign && !foundSign) {
405 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
407 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
409 if (AllowCurrencySymbol) {
410 FindCurrency (ref pos, s, nfi,
412 if (foundCurrency && AllowLeadingWhite &&
413 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
419 if (AllowCurrencySymbol && !foundCurrency) {
421 FindCurrency (ref pos, s, nfi, ref foundCurrency);
423 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
426 if (!foundSign && AllowLeadingSign) {
427 FindSign (ref pos, s, nfi, ref foundSign,
429 if (foundSign && AllowLeadingWhite &&
430 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
439 bool decimalPointFound = false;
446 if (!ValidDigit (s [pos], AllowHexSpecifier)) {
447 if (AllowThousands &&
448 FindOther (ref pos, s, nfi.NumberGroupSeparator))
451 if (!decimalPointFound && AllowDecimalPoint &&
452 FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
453 decimalPointFound = true;
459 else if (AllowHexSpecifier) {
461 hexDigit = s [pos++];
462 if (Char.IsDigit (hexDigit))
463 digitValue = (int) (hexDigit - '0');
464 else if (Char.IsLower (hexDigit))
465 digitValue = (int) (hexDigit - 'a' + 10);
467 digitValue = (int) (hexDigit - 'A' + 10);
469 uint unumber = (uint)number;
471 if ((unumber & 0xf0000000) != 0)
474 number = (int) (unumber * 16u + (uint) digitValue);
476 number = (int)checked (unumber * 16u + (uint)digitValue);
479 else if (decimalPointFound) {
481 // Allows decimal point as long as it's only
482 // followed by zeroes.
483 if (s [pos++] != '0') {
485 exc = new OverflowException ("Value too large or too " +
494 // Calculations done as negative
495 // (abs (MinValue) > abs (MaxValue))
498 (int) (s [pos++] - '0')
500 } catch (OverflowException) {
502 exc = new OverflowException ("Value too large or too " +
507 } while (pos < s.Length);
512 exc = GetFormatException ();
517 FindExponent(ref pos, s);
519 if (AllowTrailingSign && !foundSign) {
521 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
523 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
525 if (AllowCurrencySymbol)
526 FindCurrency (ref pos, s, nfi,
531 if (AllowCurrencySymbol && !foundCurrency) {
533 FindCurrency (ref pos, s, nfi, ref foundCurrency);
535 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
537 if (!foundSign && AllowTrailingSign)
538 FindSign (ref pos, s, nfi, ref foundSign,
543 if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
546 if (foundOpenParentheses) {
547 if (pos >= s.Length || s [pos++] != ')') {
549 exc = GetFormatException ();
552 if (AllowTrailingWhite && pos < s.Length &&
553 !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
557 if (pos < s.Length && s [pos] != '\u0000') {
559 exc = GetFormatException ();
563 if (!negative && !AllowHexSpecifier){
567 if (lval < MinValue || lval > MaxValue)
571 number = checked (-number);
579 public static int Parse (string s)
584 if (!Parse (s, false, out res, out exc))
590 public static int Parse (string s, NumberStyles style, IFormatProvider fp)
595 if (!Parse (s, style, fp, false, out res, out exc))
602 public static bool TryParse (string s, out int result)
606 if (!Parse (s, true, out result, out exc)) {
614 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out int result)
617 if (!Parse (s, style, provider, true, out result, out exc)) {
626 public override string ToString ()
628 return new NumberFormatter(null, m_value).FormatDecimal(-1, null);
631 public string ToString (IFormatProvider provider)
633 NumberFormatInfo nfi = NumberFormatInfo.GetInstance (provider);
634 return new NumberFormatter(null, m_value).FormatDecimal(-1, nfi);
637 public string ToString (string format)
639 return ToString (format, null);
642 public string ToString (string format, IFormatProvider fp )
644 NumberFormatInfo nfi = NumberFormatInfo.GetInstance( fp );
645 return NumberFormatter.NumberToString (format, m_value, nfi);
648 // =========== IConvertible Methods =========== //
650 public TypeCode GetTypeCode ()
652 return TypeCode.Int32;
655 bool IConvertible.ToBoolean (IFormatProvider provider)
657 return System.Convert.ToBoolean (m_value);
659 byte IConvertible.ToByte (IFormatProvider provider)
661 return System.Convert.ToByte (m_value);
663 char IConvertible.ToChar (IFormatProvider provider)
665 return System.Convert.ToChar (m_value);
667 DateTime IConvertible.ToDateTime (IFormatProvider provider)
669 return System.Convert.ToDateTime (m_value);
671 decimal IConvertible.ToDecimal (IFormatProvider provider)
673 return System.Convert.ToDecimal (m_value);
675 double IConvertible.ToDouble (IFormatProvider provider)
677 return System.Convert.ToDouble (m_value);
679 short IConvertible.ToInt16 (IFormatProvider provider)
681 return System.Convert.ToInt16 (m_value);
683 int IConvertible.ToInt32 (IFormatProvider provider)
687 long IConvertible.ToInt64 (IFormatProvider provider)
689 return System.Convert.ToInt64 (m_value);
692 sbyte IConvertible.ToSByte (IFormatProvider provider)
694 return System.Convert.ToSByte (m_value);
696 float IConvertible.ToSingle (IFormatProvider provider)
698 return System.Convert.ToSingle (m_value);
701 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
703 return System.Convert.ToType (m_value, conversionType, provider);
706 ushort IConvertible.ToUInt16 (IFormatProvider provider)
708 return System.Convert.ToUInt16 (m_value);
711 uint IConvertible.ToUInt32 (IFormatProvider provider)
713 return System.Convert.ToUInt32 (m_value);
715 ulong IConvertible.ToUInt64 (IFormatProvider provider)
717 return System.Convert.ToUInt64 (m_value);