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 (!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)
279 int i = s.IndexOfAny(new char [] {'e', 'E'}, pos);
284 if (s [i] == '+' || s [i] == '-')
287 if (!Char.IsDigit (s [i]))
289 for (; i < s.Length; ++i)
290 if (!Char.IsDigit (s [i]))
296 internal static bool FindOther (ref int pos,
300 if ((pos + other.Length) <= s.Length &&
301 s.Substring (pos, other.Length) == other) {
309 internal static bool ValidDigit (char e, bool allowHex)
312 return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
314 return Char.IsDigit (e);
317 internal static Exception GetFormatException ()
319 return new FormatException ("Input string was not in the correct format");
322 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out int result, out Exception exc)
329 exc = new ArgumentNullException ();
335 exc = GetFormatException ();
339 NumberFormatInfo nfi = null;
341 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
342 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
345 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
347 if (!CheckStyle (style, tryParse, ref exc))
350 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
351 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
352 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
353 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
354 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
355 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
356 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
357 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
358 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
359 bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
363 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
366 bool foundOpenParentheses = false;
367 bool negative = false;
368 bool foundSign = false;
369 bool foundCurrency = false;
372 if (AllowParentheses && s [pos] == '(') {
373 foundOpenParentheses = true;
375 negative = true; // MS always make the number negative when there parentheses
376 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
378 if (AllowLeadingWhite && !!JumpOverWhite (ref pos, s, true, tryParse, ref exc))
381 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
383 exc = GetFormatException ();
387 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
389 exc = GetFormatException ();
394 if (AllowLeadingSign && !foundSign) {
396 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
398 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
400 if (AllowCurrencySymbol) {
401 FindCurrency (ref pos, s, nfi,
403 if (foundCurrency && AllowLeadingWhite &&
404 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
410 if (AllowCurrencySymbol && !foundCurrency) {
412 FindCurrency (ref pos, s, nfi, ref foundCurrency);
414 if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
417 if (!foundSign && AllowLeadingSign) {
418 FindSign (ref pos, s, nfi, ref foundSign,
420 if (foundSign && AllowLeadingWhite &&
421 !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
430 bool decimalPointFound = false;
437 if (!ValidDigit (s [pos], AllowHexSpecifier)) {
438 if (AllowThousands &&
439 FindOther (ref pos, s, nfi.NumberGroupSeparator))
442 if (!decimalPointFound && AllowDecimalPoint &&
443 FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
444 decimalPointFound = true;
450 else if (AllowHexSpecifier) {
452 hexDigit = s [pos++];
453 if (Char.IsDigit (hexDigit))
454 digitValue = (int) (hexDigit - '0');
455 else if (Char.IsLower (hexDigit))
456 digitValue = (int) (hexDigit - 'a' + 10);
458 digitValue = (int) (hexDigit - 'A' + 10);
460 uint unumber = (uint)number;
462 if ((unumber & 0xf0000000) != 0)
465 number = (int) (unumber * 16u + (uint) digitValue);
467 number = (int)checked (unumber * 16u + (uint)digitValue);
470 else if (decimalPointFound) {
472 // Allows decimal point as long as it's only
473 // followed by zeroes.
474 if (s [pos++] != '0') {
476 exc = new OverflowException ("Value too large or too " +
485 // Calculations done as negative
486 // (abs (MinValue) > abs (MaxValue))
489 (int) (s [pos++] - '0')
491 } catch (OverflowException) {
493 exc = new OverflowException ("Value too large or too " +
498 } while (pos < s.Length);
503 exc = GetFormatException ();
508 FindExponent(ref pos, s);
510 if (AllowTrailingSign && !foundSign) {
512 FindSign (ref pos, s, nfi, ref foundSign, ref negative);
514 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
516 if (AllowCurrencySymbol)
517 FindCurrency (ref pos, s, nfi,
522 if (AllowCurrencySymbol && !foundCurrency) {
524 FindCurrency (ref pos, s, nfi, ref foundCurrency);
526 if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
528 if (!foundSign && AllowTrailingSign)
529 FindSign (ref pos, s, nfi, ref foundSign,
534 if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
537 if (foundOpenParentheses) {
538 if (pos >= s.Length || s [pos++] != ')') {
540 exc = GetFormatException ();
543 if (AllowTrailingWhite && pos < s.Length &&
544 !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
548 if (pos < s.Length && s [pos] != '\u0000') {
550 exc = GetFormatException ();
554 if (!negative && !AllowHexSpecifier){
558 if (lval < MinValue || lval > MaxValue)
562 number = checked (-number);
570 public static int Parse (string s)
575 if (!Parse (s, false, out res, out exc))
581 public static int Parse (string s, NumberStyles style, IFormatProvider provider)
586 if (!Parse (s, style, provider, false, out res, out exc))
593 public static bool TryParse (string s, out int result)
597 if (!Parse (s, true, out result, out exc)) {
605 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out int result)
608 if (!Parse (s, style, provider, true, out result, out exc)) {
617 public override string ToString ()
619 return NumberFormatter.NumberToString (m_value, null);
622 public string ToString (IFormatProvider provider)
624 return NumberFormatter.NumberToString (m_value, provider);
627 public string ToString (string format)
629 return ToString (format, null);
632 public string ToString (string format, IFormatProvider provider)
634 return NumberFormatter.NumberToString (format, m_value, provider);
637 // =========== IConvertible Methods =========== //
639 public TypeCode GetTypeCode ()
641 return TypeCode.Int32;
644 bool IConvertible.ToBoolean (IFormatProvider provider)
646 return System.Convert.ToBoolean (m_value);
649 byte IConvertible.ToByte (IFormatProvider provider)
651 return System.Convert.ToByte (m_value);
654 char IConvertible.ToChar (IFormatProvider provider)
656 return System.Convert.ToChar (m_value);
659 DateTime IConvertible.ToDateTime (IFormatProvider provider)
661 return System.Convert.ToDateTime (m_value);
664 decimal IConvertible.ToDecimal (IFormatProvider provider)
666 return System.Convert.ToDecimal (m_value);
669 double IConvertible.ToDouble (IFormatProvider provider)
671 return System.Convert.ToDouble (m_value);
674 short IConvertible.ToInt16 (IFormatProvider provider)
676 return System.Convert.ToInt16 (m_value);
679 int IConvertible.ToInt32 (IFormatProvider provider)
684 long IConvertible.ToInt64 (IFormatProvider provider)
686 return System.Convert.ToInt64 (m_value);
689 sbyte IConvertible.ToSByte (IFormatProvider provider)
691 return System.Convert.ToSByte (m_value);
694 float IConvertible.ToSingle (IFormatProvider provider)
696 return System.Convert.ToSingle (m_value);
699 object IConvertible.ToType (Type targetType, IFormatProvider provider)
701 if (targetType == null)
702 throw new ArgumentNullException ("targetType");
703 return System.Convert.ToType (m_value, targetType, provider, false);
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);
716 ulong IConvertible.ToUInt64 (IFormatProvider provider)
718 return System.Convert.ToUInt64 (m_value);