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