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 public struct Int32 : IFormattable, IConvertible, IComparable
38 , IComparable<Int32>, IEquatable <Int32>
42 public const int MaxValue = 0x7fffffff;
43 public const int MinValue = -2147483648;
45 // This field is looked up by name in the runtime
48 public int CompareTo (object v)
53 if (!(v is System.Int32))
54 throw new ArgumentException (Locale.GetText ("Value is not a System.Int32"));
65 public override bool Equals (object o)
67 if (!(o is System.Int32))
70 return ((int) o) == m_value;
73 public override int GetHashCode ()
79 public int CompareTo (int value)
89 public bool Equals (int value)
91 return value == m_value;
95 internal static bool Parse (string s, bool tryParse, out int result, out Exception exc)
100 bool digits_seen = false;
107 exc = new ArgumentNullException ("s");
114 for (i = 0; i < len; i++){
116 if (!Char.IsWhiteSpace (c))
122 exc = GetFormatException ();
134 for (; i < len; i++){
142 if (c >= '0' && c <= '9'){
144 val = checked (val * 10 + (c - '0') * sign);
146 } catch (OverflowException e) {
151 if (Char.IsWhiteSpace (c)){
152 for (i++; i < len; i++){
153 if (!Char.IsWhiteSpace (s [i])) {
155 exc = GetFormatException ();
163 exc = GetFormatException ();
170 exc = GetFormatException ();
179 public static int Parse (string s, IFormatProvider fp)
181 return Parse (s, NumberStyles.Integer, fp);
184 public static int Parse (string s, NumberStyles style)
186 return Parse (s, style, null);
189 internal static bool CheckStyle (NumberStyles style, bool tryParse, ref Exception exc)
191 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
192 NumberStyles ne = style ^ NumberStyles.AllowHexSpecifier;
193 if ((ne & NumberStyles.AllowLeadingWhite) != 0)
194 ne ^= NumberStyles.AllowLeadingWhite;
195 if ((ne & NumberStyles.AllowTrailingWhite) != 0)
196 ne ^= NumberStyles.AllowTrailingWhite;
199 exc = new ArgumentException (
200 "With AllowHexSpecifier only " +
201 "AllowLeadingWhite and AllowTrailingWhite " +
210 internal static bool JumpOverWhite (ref int pos, string s, bool reportError, bool tryParse, ref Exception exc)
212 while (pos < s.Length && Char.IsWhiteSpace (s [pos]))
215 if (reportError && pos >= s.Length) {
217 exc = GetFormatException ();
224 internal static void FindSign (ref int pos, string s, NumberFormatInfo nfi,
225 ref bool foundSign, ref bool negative)
227 if ((pos + nfi.NegativeSign.Length) <= s.Length &&
228 s.IndexOf (nfi.NegativeSign, pos, nfi.NegativeSign.Length) == pos) {
231 pos += nfi.NegativeSign.Length;
233 else if ((pos + nfi.PositiveSign.Length) < s.Length &&
234 s.IndexOf (nfi.PositiveSign, pos, nfi.PositiveSign.Length) == pos) {
236 pos += nfi.PositiveSign.Length;
241 internal static void FindCurrency (ref int pos,
243 NumberFormatInfo nfi,
244 ref bool foundCurrency)
246 if ((pos + nfi.CurrencySymbol.Length) <= s.Length &&
247 s.Substring (pos, nfi.CurrencySymbol.Length) == nfi.CurrencySymbol) {
248 foundCurrency = true;
249 pos += nfi.CurrencySymbol.Length;
253 internal static bool FindExponent (ref int pos, string s)
255 int i = s.IndexOfAny(new char [] {'e', 'E'}, pos);
260 if (s [i] == '+' || s [i] == '-')
263 if (!Char.IsDigit (s [i]))
265 for (; i < s.Length; ++i)
266 if (!Char.IsDigit (s [i]))
272 internal static bool FindOther (ref int pos,
276 if ((pos + other.Length) <= s.Length &&
277 s.Substring (pos, other.Length) == other) {
285 internal static bool ValidDigit (char e, bool allowHex)
288 return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
290 return Char.IsDigit (e);
293 internal static Exception GetFormatException ()
295 return new FormatException ("Input string was not in the correct format");
298 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out int result, out Exception exc)
305 exc = GetFormatException ();
311 exc = new ArgumentNullException ();
317 exc = GetFormatException ();
321 NumberFormatInfo nfi;
323 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
324 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
327 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
329 if (!CheckStyle (style, tryParse, ref exc))
332 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
333 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
334 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
335 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
336 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
337 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
338 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
339 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
340 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
341 bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
345 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
348 bool foundOpenParentheses = false;
349 bool negative = false;
350 bool foundSign = false;
351 bool foundCurrency = false;
354 if (AllowParentheses && s [pos] == '(') {
355 foundOpenParentheses = true;
357 negative = true; // MS always make the number negative when there parentheses
358 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
360 if (AllowLeadingWhite && !!JumpOverWhite (ref pos, s, true, tryParse, ref exc))
363 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
365 exc = GetFormatException ();
369 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
371 exc = GetFormatException ();
376 if (AllowLeadingSign && !foundSign) {
378 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
380 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
382 if (AllowCurrencySymbol) {
383 FindCurrency (ref pos, s, nfi,
385 if (foundCurrency && AllowLeadingWhite &&
386 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
392 if (AllowCurrencySymbol && !foundCurrency) {
394 FindCurrency (ref pos, s, nfi, ref foundCurrency);
396 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
399 if (!foundSign && AllowLeadingSign) {
400 FindSign (ref pos, s, nfi, ref foundSign,
402 if (foundSign && AllowLeadingWhite &&
403 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
412 bool decimalPointFound = false;
419 if (!ValidDigit (s [pos], AllowHexSpecifier)) {
420 if (AllowThousands &&
421 FindOther (ref pos, s, nfi.NumberGroupSeparator))
424 if (!decimalPointFound && AllowDecimalPoint &&
425 FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
426 decimalPointFound = true;
432 else if (AllowHexSpecifier) {
434 hexDigit = s [pos++];
435 if (Char.IsDigit (hexDigit))
436 digitValue = (int) (hexDigit - '0');
437 else if (Char.IsLower (hexDigit))
438 digitValue = (int) (hexDigit - 'a' + 10);
440 digitValue = (int) (hexDigit - 'A' + 10);
442 uint unumber = (uint)number;
444 number = (int)checked (unumber * 16u + (uint)digitValue);
445 } catch (OverflowException e) {
450 else if (decimalPointFound) {
452 // Allows decimal point as long as it's only
453 // followed by zeroes.
454 if (s [pos++] != '0') {
456 exc = new OverflowException ("Value too large or too " +
465 // Calculations done as negative
466 // (abs (MinValue) > abs (MaxValue))
469 (int) (s [pos++] - '0')
471 } catch (OverflowException) {
473 exc = new OverflowException ("Value too large or too " +
478 } while (pos < s.Length);
483 exc = GetFormatException ();
488 FindExponent(ref pos, s);
490 if (AllowTrailingSign && !foundSign) {
492 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
494 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
496 if (AllowCurrencySymbol)
497 FindCurrency (ref pos, s, nfi,
502 if (AllowCurrencySymbol && !foundCurrency) {
504 FindCurrency (ref pos, s, nfi, ref foundCurrency);
506 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
508 if (!foundSign && AllowTrailingSign)
509 FindSign (ref pos, s, nfi, ref foundSign,
514 if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
517 if (foundOpenParentheses) {
518 if (pos >= s.Length || s [pos++] != ')') {
520 exc = GetFormatException ();
523 if (AllowTrailingWhite && pos < s.Length &&
524 !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
528 if (pos < s.Length && s [pos] != '\u0000') {
530 exc = GetFormatException ();
534 if (!negative && !AllowHexSpecifier)
535 number = checked (-number);
542 public static int Parse (string s)
547 if (!Parse (s, false, out res, out exc))
553 public static int Parse (string s, NumberStyles style, IFormatProvider fp)
558 if (!Parse (s, style, fp, false, out res, out exc))
565 public static bool TryParse (string s, out int result)
569 if (!Parse (s, true, out result, out exc)) {
577 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out int result)
580 if (!Parse (s, style, provider, true, out result, out exc)) {
589 public override string ToString ()
591 return NumberFormatter.FormatGeneral (new NumberFormatter.NumberStore (m_value));
594 public string ToString (IFormatProvider fp)
596 return NumberFormatter.FormatGeneral (new NumberFormatter.NumberStore (m_value), fp);
599 public string ToString (string format)
601 return ToString (format, null);
604 public string ToString (string format, IFormatProvider fp )
606 NumberFormatInfo nfi = NumberFormatInfo.GetInstance( fp );
607 return NumberFormatter.NumberToString (format, m_value, nfi);
610 // =========== IConvertible Methods =========== //
612 public TypeCode GetTypeCode ()
614 return TypeCode.Int32;
617 bool IConvertible.ToBoolean (IFormatProvider provider)
619 return System.Convert.ToBoolean (m_value);
621 byte IConvertible.ToByte (IFormatProvider provider)
623 return System.Convert.ToByte (m_value);
625 char IConvertible.ToChar (IFormatProvider provider)
627 return System.Convert.ToChar (m_value);
629 DateTime IConvertible.ToDateTime (IFormatProvider provider)
631 return System.Convert.ToDateTime (m_value);
633 decimal IConvertible.ToDecimal (IFormatProvider provider)
635 return System.Convert.ToDecimal (m_value);
637 double IConvertible.ToDouble (IFormatProvider provider)
639 return System.Convert.ToDouble (m_value);
641 short IConvertible.ToInt16 (IFormatProvider provider)
643 return System.Convert.ToInt16 (m_value);
645 int IConvertible.ToInt32 (IFormatProvider provider)
649 long IConvertible.ToInt64 (IFormatProvider provider)
651 return System.Convert.ToInt64 (m_value);
654 sbyte IConvertible.ToSByte (IFormatProvider provider)
656 return System.Convert.ToSByte (m_value);
658 float IConvertible.ToSingle (IFormatProvider provider)
660 return System.Convert.ToSingle (m_value);
663 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
665 return System.Convert.ToType (m_value, conversionType, provider);
668 ushort IConvertible.ToUInt16 (IFormatProvider provider)
670 return System.Convert.ToUInt16 (m_value);
673 uint IConvertible.ToUInt32 (IFormatProvider provider)
675 return System.Convert.ToUInt32 (m_value);
677 ulong IConvertible.ToUInt64 (IFormatProvider provider)
679 return System.Convert.ToUInt64 (m_value);