2010-03-12 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / corlib / System / UInt32.cs
1 //
2 // System.UInt32.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 // Copyright (C) 2004 Novell (http://www.novell.com)
9 //
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:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
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.
28 //
29
30 using System.Globalization;
31 using System.Threading;
32
33 namespace System
34 {
35         [Serializable]
36         [CLSCompliant (false)]
37         [System.Runtime.InteropServices.ComVisible (true)]
38         public struct UInt32 : IFormattable, IConvertible, IComparable, IComparable<UInt32>, IEquatable <UInt32>
39         {
40                 public const uint MaxValue = 0xffffffff;
41                 public const uint MinValue = 0;
42
43                 internal uint m_value;
44
45                 public int CompareTo (object value)
46                 {
47                         if (value == null)
48                                 return 1;
49
50                         if (!(value is System.UInt32))
51                                 throw new ArgumentException (Locale.GetText ("Value is not a System.UInt32."));
52
53                         uint val = (uint) value;
54
55                         if (m_value == val)
56                                 return 0;
57
58                         return (m_value < val) ? -1 : 1;
59                 }
60
61                 public override bool Equals (object obj)
62                 {
63                         if (!(obj is System.UInt32))
64                                 return false;
65
66                         return ((uint) obj) == m_value;
67                 }
68
69                 public override int GetHashCode ()
70                 {
71                         return (int) m_value;
72                 }
73
74                 public int CompareTo (uint value)
75                 {
76                         if (m_value == value)
77                                 return 0;
78                         if (m_value > value)
79                                 return 1;
80                         else
81                                 return -1;
82                 }
83
84                 public bool Equals (uint obj)
85                 {
86                         return obj == m_value;
87                 }
88
89                 internal static bool Parse (string s, bool tryParse, out uint result, out Exception exc)
90                 {
91                         uint val = 0;
92                         int len;
93                         int i;
94                         bool digits_seen = false;
95                         bool has_negative_sign = false;
96
97                         result = 0;
98                         exc = null;
99
100                         if (s == null) {
101                                 if (!tryParse)
102                                         exc = new ArgumentNullException ("s");
103                                 return false;
104                         }
105
106                         len = s.Length;
107
108                         char c;
109                         for (i = 0; i < len; i++) {
110                                 c = s [i];
111                                 if (!Char.IsWhiteSpace (c))
112                                         break;
113                         }
114
115                         if (i == len) {
116                                 if (!tryParse)
117                                         exc = Int32.GetFormatException ();
118                                 return false;
119                         }
120
121                         if (s [i] == '+')
122                                 i++;
123                         else
124                                 if (s[i] == '-') {
125                                         i++;
126                                         has_negative_sign = true;
127                                 }
128
129                         for (; i < len; i++) {
130                                 c = s [i];
131
132                                 if (c >= '0' && c <= '9') {
133                                         uint d = (uint) (c - '0');
134
135                                         if ((val > MaxValue/10) || (val == (MaxValue / 10) && d > (MaxValue % 10))){
136                                                 if (!tryParse)
137                                                         exc = new OverflowException (Locale.GetText ("Value is too large"));
138                                                 return false;
139                                         }
140                                         val = (val * 10) + d;
141                                         digits_seen = true;
142                                 } else if (!Int32.ProcessTrailingWhitespace (tryParse, s, i, ref exc)){
143                                         return false;
144                                 }
145                         }
146                         if (!digits_seen) {
147                                 if (!tryParse)
148                                         exc = Int32.GetFormatException ();
149                                 return false;
150                         }
151
152                         // -0 is legal but other negative values are not
153                         if (has_negative_sign && (val > 0)) {
154                                 if (!tryParse)
155                                         exc = new OverflowException (
156                                             Locale.GetText ("Negative number"));
157                                 return false;
158                         }
159
160                         result = val;
161                         return true;
162                 }
163
164                 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out uint result, out Exception exc)
165                 {
166                         result = 0;
167                         exc = null;
168
169                         if (s == null) {
170                                 if (!tryParse)
171                                         exc = new ArgumentNullException ("s");
172                                 return false;
173                         }
174
175                         if (s.Length == 0) {
176                                 if (!tryParse)
177                                         exc = Int32.GetFormatException ();
178                                 return false;
179                         }
180
181                         NumberFormatInfo nfi;
182                         if (provider != null) {
183                                 Type typeNFI = typeof (NumberFormatInfo);
184                                 nfi = (NumberFormatInfo) provider.GetFormat (typeNFI);
185                         }
186                         else
187                                 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
188
189                         if (!Int32.CheckStyle (style, tryParse, ref exc))
190                                 return false;
191
192                         bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
193                         bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
194                         bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
195                         bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
196                         bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
197                         bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
198                         bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
199                         bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
200                         bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
201
202                         int pos = 0;
203
204                         if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
205                                 return false;
206
207                         bool foundOpenParentheses = false;
208                         bool negative = false;
209                         bool foundSign = false;
210                         bool foundCurrency = false;
211
212                         // Pre-number stuff
213                         if (AllowParentheses && s [pos] == '(') {
214                                 foundOpenParentheses = true;
215                                 foundSign = true;
216                                 negative = true; // MS always make the number negative when there parentheses
217                                                  // even when NumberFormatInfo.NumberNegativePattern != 0!!!
218                                 pos++;
219                                 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
220                                         return false;
221
222                                 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
223                                         if (!tryParse)
224                                                 exc = Int32.GetFormatException ();
225                                         return false;
226                                 }
227                                 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
228                                         if (!tryParse)
229                                                 exc = Int32.GetFormatException ();
230                                         return false;
231                                 }
232                         }
233
234                         if (AllowLeadingSign && !foundSign) {
235                                 // Sign + Currency
236                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
237                                 if (foundSign) {
238                                         if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
239                                                 return false;
240                                         if (AllowCurrencySymbol) {
241                                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
242                                                 if (foundCurrency && AllowLeadingWhite &&
243                                                                 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
244                                                         return false;
245                                         }
246                                 }
247                         }
248
249                         if (AllowCurrencySymbol && !foundCurrency) {
250                                 // Currency + sign
251                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
252                                 if (foundCurrency) {
253                                         if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
254                                                 return false;
255                                         if (foundCurrency) {
256                                                 if (!foundSign && AllowLeadingSign) {
257                                                         Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
258                                                         if (foundSign && AllowLeadingWhite &&
259                                                                         !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
260                                                                 return false;
261                                                 }
262                                         }
263                                 }
264                         }
265
266                         uint number = 0;
267                         int nDigits = 0;
268                         bool decimalPointFound = false;
269                         uint digitValue;
270                         char hexDigit;
271
272                         // Number stuff
273                         // Just the same as Int32, but this one adds instead of substract
274                         do {
275
276                                 if (!Int32.ValidDigit (s [pos], AllowHexSpecifier)) {
277                                         if (AllowThousands && Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator))
278                                                 continue;
279                                         else
280                                                 if (!decimalPointFound && AllowDecimalPoint &&
281                                                     Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
282                                                         decimalPointFound = true;
283                                                         continue;
284                                                 }
285                                         break;
286                                 }
287                                 else if (AllowHexSpecifier) {
288                                         nDigits++;
289                                         hexDigit = s [pos++];
290                                         if (Char.IsDigit (hexDigit))
291                                                 digitValue = (uint) (hexDigit - '0');
292                                         else if (Char.IsLower (hexDigit))
293                                                 digitValue = (uint) (hexDigit - 'a' + 10);
294                                         else
295                                                 digitValue = (uint) (hexDigit - 'A' + 10);
296
297                                         if (tryParse){
298                                                 ulong l = number * 16 + digitValue;
299
300                                                 if (l > MaxValue)
301                                                         return false;
302                                                 number = (uint) l;
303                                         } else
304                                                 number = checked (number * 16 + digitValue);
305                                 }
306                                 else if (decimalPointFound) {
307                                         nDigits++;
308                                         // Allows decimal point as long as it's only 
309                                         // followed by zeroes.
310                                         if (s [pos++] != '0') {
311                                                 if (!tryParse)
312                                                         exc = new OverflowException (Locale.GetText ("Value too large or too small."));
313                                                 return false;
314                                         }
315                                 }
316                                 else {
317                                         nDigits++;
318
319                                         try {
320                                                 number = checked (number * 10 + (uint) (s [pos++] - '0'));
321                                         }
322                                         catch (OverflowException) {
323                                                 if (!tryParse)
324                                                         exc = new OverflowException (Locale.GetText ("Value too large or too small."));
325                                                 return false;
326                                         }
327                                 }
328                         } while (pos < s.Length);
329
330                         // Post number stuff
331                         if (nDigits == 0) {
332                                 if (!tryParse)
333                                         exc = Int32.GetFormatException ();
334                                 return false;
335                         }
336
337                         if (AllowTrailingSign && !foundSign) {
338                                 // Sign + Currency
339                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
340                                 if (foundSign) {
341                                         if (AllowTrailingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
342                                                 return false;
343                                         if (AllowCurrencySymbol)
344                                                 Int32. FindCurrency (ref pos, s, nfi, ref foundCurrency);
345                                 }
346                         }
347
348                         if (AllowCurrencySymbol && !foundCurrency) {
349                                 // Currency + sign
350                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
351                                 if (foundCurrency) {
352                                         if (AllowTrailingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
353                                                 return false;
354                                         if (!foundSign && AllowTrailingSign)
355                                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
356                                 }
357                         }
358
359                         if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
360                                 return false;
361
362                         if (foundOpenParentheses) {
363                                 if (pos >= s.Length || s [pos++] != ')') {
364                                         if (!tryParse)
365                                                 exc = Int32.GetFormatException ();
366                                         return false;
367                                 }
368                                 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
369                                         return false;
370                         }
371
372                         if (pos < s.Length && s [pos] != '\u0000') {
373                                 if (!tryParse)
374                                         exc = Int32.GetFormatException ();
375                                 return false;
376                         }
377
378                         // -0 is legal but other negative values are not
379                         if (negative && (number > 0)) {
380                                 if (!tryParse)
381                                         exc = new OverflowException (
382                                             Locale.GetText ("Negative number"));
383                                 return false;
384                         }
385
386                         result = number;
387
388                         return true;
389                 }
390
391                 [CLSCompliant (false)]
392                 public static uint Parse (string s) 
393                 {
394                         Exception exc;
395                         uint res;
396
397                         if (!Parse (s, false, out res, out exc))
398                                 throw exc;
399
400                         return res;
401                 }
402
403                 [CLSCompliant (false)]
404                 public static uint Parse (string s, NumberStyles style, IFormatProvider provider) 
405                 {
406                         Exception exc;
407                         uint res;
408
409                         if (!Parse (s, style, provider, false, out res, out exc))
410                                 throw exc;
411
412                         return res;
413                 }
414
415                 [CLSCompliant (false)]
416                 public static uint Parse (string s, IFormatProvider provider)
417                 {
418                         return Parse (s, NumberStyles.Integer, provider);
419                 }
420
421                 [CLSCompliant (false)]
422                 public static uint Parse (string s, NumberStyles style)
423                 {
424                         return Parse (s, style, null);
425                 }
426
427                 [CLSCompliant (false)]
428                 public static bool TryParse (string s, out uint result) 
429                 {
430                         Exception exc;
431                         if (!Parse (s, true, out result, out exc)) {
432                                 result = 0;
433                                 return false;
434                         }
435
436                         return true;
437                 }
438
439                 [CLSCompliant (false)]
440                 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out uint result) 
441                 {
442                         Exception exc;
443                         if (!Parse (s, style, provider, true, out result, out exc)) {
444                                 result = 0;
445                                 return false;
446                         }
447
448                         return true;
449                 }
450
451                 public override string ToString ()
452                 {
453                         return NumberFormatter.NumberToString (m_value, null);
454                 }
455
456                 public string ToString (IFormatProvider provider)
457                 {
458                         return NumberFormatter.NumberToString (m_value, provider);
459                 }
460
461                 public string ToString (string format)
462                 {
463                         return ToString (format, null);
464                 }
465
466                 public string ToString (string format, IFormatProvider provider)
467                 {
468                         return NumberFormatter.NumberToString (format, m_value, provider);
469                 }
470
471                 // =========== IConvertible Methods =========== //
472                 public TypeCode GetTypeCode ()
473                 {
474                         return TypeCode.UInt32;
475                 }
476
477                 bool IConvertible.ToBoolean (IFormatProvider provider)
478                 {
479                         return System.Convert.ToBoolean (m_value);
480                 }
481
482                 byte IConvertible.ToByte (IFormatProvider provider)
483                 {
484                         return System.Convert.ToByte (m_value);
485                 }
486
487                 char IConvertible.ToChar (IFormatProvider provider)
488                 {
489                         return System.Convert.ToChar (m_value);
490                 }
491
492                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
493                 {
494                         return System.Convert.ToDateTime (m_value);
495                 }
496
497                 decimal IConvertible.ToDecimal (IFormatProvider provider)
498                 {
499                         return System.Convert.ToDecimal (m_value);
500                 }
501
502                 double IConvertible.ToDouble (IFormatProvider provider)
503                 {
504                         return System.Convert.ToDouble (m_value);
505                 }
506
507                 short IConvertible.ToInt16 (IFormatProvider provider)
508                 {
509                         return System.Convert.ToInt16 (m_value);
510                 }
511
512                 int IConvertible.ToInt32 (IFormatProvider provider)
513                 {
514                         return System.Convert.ToInt32 (m_value);
515                 }
516
517                 long IConvertible.ToInt64 (IFormatProvider provider)
518                 {
519                         return System.Convert.ToInt64 (m_value);
520                 }
521
522                 sbyte IConvertible.ToSByte (IFormatProvider provider)
523                 {
524                         return System.Convert.ToSByte (m_value);
525                 }
526                 
527                 float IConvertible.ToSingle (IFormatProvider provider)
528                 {
529                         return System.Convert.ToSingle (m_value);
530                 }
531
532                 object IConvertible.ToType (Type targetType, IFormatProvider provider)
533                 {
534                         if (targetType == null)
535                                 throw new ArgumentNullException ("targetType");
536                         
537                         return System.Convert.ToType (m_value, targetType, provider, false);
538                 }
539
540                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
541                 {
542                         return System.Convert.ToUInt16 (m_value);
543                 }
544
545                 uint IConvertible.ToUInt32 (IFormatProvider provider)
546                 {
547                         return m_value;
548                 }
549
550                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
551                 {
552                         return System.Convert.ToUInt64 (m_value);
553                 }
554         }
555 }