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