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