New test.
[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         public struct UInt32 : IFormattable, IConvertible, IComparable
38 #if NET_2_0
39                 , IComparable<UInt32>, IEquatable <UInt32>
40 #endif
41         {
42                 public const uint MaxValue = 0xffffffff;
43                 public const uint MinValue = 0;
44
45                 internal uint m_value;
46
47                 public int CompareTo (object value)
48                 {
49                         if (value == null)
50                                 return 1;
51
52                         if (!(value is System.UInt32))
53                                 throw new ArgumentException (Locale.GetText ("Value is not a System.UInt32."));
54
55                         if (this.m_value == (uint) value)
56                                 return 0;
57
58                         if (this.m_value < (uint) value)
59                                 return -1;
60
61                         return 1;
62                 }
63
64                 public override bool Equals (object obj)
65                 {
66                         if (!(obj is System.UInt32))
67                                 return false;
68
69                         return ((uint) obj) == m_value;
70                 }
71
72                 public override int GetHashCode ()
73                 {
74                         return (int) m_value;
75                 }
76
77 #if NET_2_0
78                 public int CompareTo (uint value)
79                 {
80                         if (m_value == value)
81                                 return 0;
82                         if (m_value > value)
83                                 return 1;
84                         else
85                                 return -1;
86                 }
87
88                 public bool Equals (uint value)
89                 {
90                         return value == m_value;
91                 }
92 #endif
93
94                 internal static bool Parse (string s, bool tryParse, out uint result, out Exception exc)
95                 {
96                         uint val = 0;
97                         int len;
98                         int i;
99                         bool digits_seen = false;
100                         bool has_negative_sign = false;
101
102                         result = 0;
103                         exc = null;
104
105                         if (s == null) {
106                                 if (!tryParse)
107                                         exc = new ArgumentNullException ("s");
108                                 return false;
109                         }
110
111                         len = s.Length;
112
113                         char c;
114                         for (i = 0; i < len; i++) {
115                                 c = s [i];
116                                 if (!Char.IsWhiteSpace (c))
117                                         break;
118                         }
119
120                         if (i == len) {
121                                 if (!tryParse)
122                                         exc = Int32.GetFormatException ();
123                                 return false;
124                         }
125
126                         if (s [i] == '+')
127                                 i++;
128                         else
129                                 if (s[i] == '-') {
130                                         i++;
131                                         has_negative_sign = true;
132                                 }
133
134                         for (; i < len; i++) {
135                                 c = s [i];
136
137                                 if (c >= '0' && c <= '9') {
138                                         uint d = (uint) (c - '0');
139
140                                         val = checked (val * 10 + d);
141                                         digits_seen = true;
142                                 }
143                                 else {
144                                         if (Char.IsWhiteSpace (c)) {
145                                                 for (i++; i < len; i++) {
146                                                         if (!Char.IsWhiteSpace (s [i])) {
147                                                                 if (!tryParse)
148                                                                         exc = Int32.GetFormatException ();
149                                                                 return false;
150                                                         }
151                                                 }
152                                                 break;
153                                         } else {
154                                                 if (!tryParse)
155                                                         exc = Int32.GetFormatException ();
156                                                 return false;
157                                         }
158                                 }
159                         }
160                         if (!digits_seen) {
161                                 if (!tryParse)
162                                         exc = Int32.GetFormatException ();
163                                 return false;
164                         }
165
166                         // -0 is legal but other negative values are not
167                         if (has_negative_sign && (val > 0)) {
168                                 if (!tryParse)
169                                         exc = new OverflowException (
170                                             Locale.GetText ("Negative number"));
171                                 return false;
172                         }
173
174                         result = val;
175                         return true;
176                 }
177
178                 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out uint result, out Exception exc)
179                 {
180                         result = 0;
181                         exc = null;
182
183                         if (s == null) {
184                                 if (!tryParse)
185                                         exc = new ArgumentNullException ("s");
186                                 return false;
187                         }
188
189                         if (s.Length == 0) {
190                                 if (!tryParse)
191                                         exc = Int32.GetFormatException ();
192                                 return false;
193                         }
194
195                         NumberFormatInfo nfi;
196                         if (provider != null) {
197                                 Type typeNFI = typeof (NumberFormatInfo);
198                                 nfi = (NumberFormatInfo) provider.GetFormat (typeNFI);
199                         }
200                         else
201                                 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
202
203                         if (!Int32.CheckStyle (style, tryParse, ref exc))
204                                 return false;
205
206                         bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
207                         bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
208                         bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
209                         bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
210                         bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
211                         bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
212                         bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
213                         bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
214                         bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
215
216                         int pos = 0;
217
218                         if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
219                                 return false;
220
221                         bool foundOpenParentheses = false;
222                         bool negative = false;
223                         bool foundSign = false;
224                         bool foundCurrency = false;
225
226                         // Pre-number stuff
227                         if (AllowParentheses && s [pos] == '(') {
228                                 foundOpenParentheses = true;
229                                 foundSign = true;
230                                 negative = true; // MS always make the number negative when there parentheses
231                                                  // even when NumberFormatInfo.NumberNegativePattern != 0!!!
232                                 pos++;
233                                 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
234                                         return false;
235
236                                 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
237                                         if (!tryParse)
238                                                 exc = Int32.GetFormatException ();
239                                         return false;
240                                 }
241                                 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
242                                         if (!tryParse)
243                                                 exc = Int32.GetFormatException ();
244                                         return false;
245                                 }
246                         }
247
248                         if (AllowLeadingSign && !foundSign) {
249                                 // Sign + Currency
250                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
251                                 if (foundSign) {
252                                         if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
253                                                 return false;
254                                         if (AllowCurrencySymbol) {
255                                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
256                                                 if (foundCurrency && AllowLeadingWhite &&
257                                                                 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
258                                                         return false;
259                                         }
260                                 }
261                         }
262
263                         if (AllowCurrencySymbol && !foundCurrency) {
264                                 // Currency + sign
265                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
266                                 if (foundCurrency) {
267                                         if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
268                                                 return false;
269                                         if (foundCurrency) {
270                                                 if (!foundSign && AllowLeadingSign) {
271                                                         Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
272                                                         if (foundSign && AllowLeadingWhite &&
273                                                                         !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
274                                                                 return false;
275                                                 }
276                                         }
277                                 }
278                         }
279
280                         uint number = 0;
281                         int nDigits = 0;
282                         bool decimalPointFound = false;
283                         uint digitValue;
284                         char hexDigit;
285
286                         // Number stuff
287                         // Just the same as Int32, but this one adds instead of substract
288                         do {
289
290                                 if (!Int32.ValidDigit (s [pos], AllowHexSpecifier)) {
291                                         if (AllowThousands && Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator))
292                                                 continue;
293                                         else
294                                                 if (!decimalPointFound && AllowDecimalPoint &&
295                                                     Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
296                                                         decimalPointFound = true;
297                                                         continue;
298                                                 }
299                                         break;
300                                 }
301                                 else if (AllowHexSpecifier) {
302                                         nDigits++;
303                                         hexDigit = s [pos++];
304                                         if (Char.IsDigit (hexDigit))
305                                                 digitValue = (uint) (hexDigit - '0');
306                                         else if (Char.IsLower (hexDigit))
307                                                 digitValue = (uint) (hexDigit - 'a' + 10);
308                                         else
309                                                 digitValue = (uint) (hexDigit - 'A' + 10);
310
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 fp) 
412                 {
413                         Exception exc;
414                         uint res;
415
416                         if (!Parse (s, style, fp, 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.FormatGeneral (new NumberFormatter.NumberStore (m_value));
463                 }
464
465                 public string ToString (IFormatProvider fp)
466                 {
467                         return NumberFormatter.FormatGeneral (new NumberFormatter.NumberStore (m_value), fp);
468                 }
469
470                 public string ToString (string format)
471                 {
472                         return ToString (format, null);
473                 }
474
475                 public string ToString (string format, IFormatProvider fp)
476                 {
477                         NumberFormatInfo nfi = NumberFormatInfo.GetInstance (fp);
478                         return NumberFormatter.NumberToString (format, m_value, nfi);
479                 }
480
481                 // =========== IConvertible Methods =========== //
482                 public TypeCode GetTypeCode ()
483                 {
484                         return TypeCode.UInt32;
485                 }
486
487                 bool IConvertible.ToBoolean (IFormatProvider provider)
488                 {
489                         return System.Convert.ToBoolean (m_value);
490                 }
491
492                 byte IConvertible.ToByte (IFormatProvider provider)
493                 {
494                         return System.Convert.ToByte (m_value);
495                 }
496
497                 char IConvertible.ToChar (IFormatProvider provider)
498                 {
499                         return System.Convert.ToChar (m_value);
500                 }
501
502                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
503                 {
504                         return System.Convert.ToDateTime (m_value);
505                 }
506
507                 decimal IConvertible.ToDecimal (IFormatProvider provider)
508                 {
509                         return System.Convert.ToDecimal (m_value);
510                 }
511
512                 double IConvertible.ToDouble (IFormatProvider provider)
513                 {
514                         return System.Convert.ToDouble (m_value);
515                 }
516
517                 short IConvertible.ToInt16 (IFormatProvider provider)
518                 {
519                         return System.Convert.ToInt16 (m_value);
520                 }
521
522                 int IConvertible.ToInt32 (IFormatProvider provider)
523                 {
524                         return System.Convert.ToInt32 (m_value);
525                 }
526
527                 long IConvertible.ToInt64 (IFormatProvider provider)
528                 {
529                         return System.Convert.ToInt64 (m_value);
530                 }
531
532                 sbyte IConvertible.ToSByte (IFormatProvider provider)
533                 {
534                         return System.Convert.ToSByte (m_value);
535                 }
536                 
537                 float IConvertible.ToSingle (IFormatProvider provider)
538                 {
539                         return System.Convert.ToSingle (m_value);
540                 }
541
542                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
543                 {
544                         return System.Convert.ToType (m_value, conversionType, provider);
545                 }
546
547                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
548                 {
549                         return System.Convert.ToUInt16 (m_value);
550                 }
551
552                 uint IConvertible.ToUInt32 (IFormatProvider provider)
553                 {
554                         return m_value;
555                 }
556
557                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
558                 {
559                         return System.Convert.ToUInt64 (m_value);
560                 }
561         }
562 }