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