2004-06-06 Sebastien Pouliot <sebastien@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 (http://www.novell.com)
9 //
10
11 using System.Globalization;
12 using System.Threading;
13
14 namespace System
15 {
16         [Serializable]
17         [CLSCompliant (false)]
18         public struct UInt64 : IComparable, IFormattable, IConvertible
19         {
20                 public const ulong MaxValue = 0xffffffffffffffff;
21                 public const ulong MinValue = 0;
22
23                 internal ulong m_value;
24
25                 public int CompareTo (object value)
26                 {
27                         if (value == null)
28                                 return 1;
29
30                         if (!(value is System.UInt64))
31                                 throw new ArgumentException (Locale.GetText ("Value is not a System.UInt64."));
32
33                         if (this.m_value == (ulong) value)
34                                 return 0;
35
36                         if (this.m_value < (ulong) value)
37                                 return -1;
38
39                         return 1;
40                 }
41
42                 public override bool Equals (object obj)
43                 {
44                         if (!(obj is System.UInt64))
45                                 return false;
46
47                         return ((ulong) obj) == m_value;
48                 }
49
50                 public override int GetHashCode ()
51                 {
52                         return (int)(m_value & 0xffffffff) ^ (int)(m_value >> 32);
53                 }
54
55                 [CLSCompliant (false)]
56                 public static ulong Parse (string s)
57                 {
58                         return Parse (s, NumberStyles.Integer, null);
59                 }
60
61                 [CLSCompliant (false)]
62                 public static ulong Parse (string s, IFormatProvider provider)
63                 {
64                         return Parse (s, NumberStyles.Integer, provider);
65                 }
66
67                 [CLSCompliant (false)]
68                 public static ulong Parse (string s, NumberStyles style)
69                 {
70                         return Parse (s, style, null);
71                 }
72
73                 [CLSCompliant (false)]
74                 public static ulong Parse (string s, NumberStyles style, IFormatProvider provider)
75                 {
76                         if (s == null)
77                                 throw new ArgumentNullException ("s");
78
79                         if (s.Length == 0)
80                                 throw new FormatException (Locale.GetText ("Input string was not in the correct format."));
81
82                         NumberFormatInfo nfi;
83                         if (provider != null) {
84                                 Type typeNFI = typeof (NumberFormatInfo);
85                                 nfi = (NumberFormatInfo) provider.GetFormat (typeNFI);
86                         }
87                         else
88                                 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
89
90                         Int32.CheckStyle (style);
91
92                         bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
93                         bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
94                         bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
95                         bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
96                         bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
97                         bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
98                         bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
99                         bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
100                         bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
101                         bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
102
103                         int pos = 0;
104
105                         if (AllowLeadingWhite)
106                                 pos = Int32.JumpOverWhite (pos, s, true);
107
108                         bool foundOpenParentheses = false;
109                         bool negative = false;
110                         bool foundSign = false;
111                         bool foundCurrency = false;
112
113                         // Pre-number stuff
114                         if (AllowParentheses && s [pos] == '(') {
115                                 foundOpenParentheses = true;
116                                 foundSign = true;
117                                 negative = true; // MS always make the number negative when there parentheses
118                                                  // even when NumberFormatInfo.NumberNegativePattern != 0!!!
119                                 pos++;
120                                 if (AllowLeadingWhite)
121                                         pos = Int32.JumpOverWhite (pos, s, true);
122
123                                 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign)
124                                         throw new FormatException (Locale.GetText ("Input string was not in the correct format."));
125                                 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign)
126                                         throw new FormatException (Locale.GetText ("Input string was not in the correct format."));
127                         }
128
129                         if (AllowLeadingSign && !foundSign) {
130                                 // Sign + Currency
131                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
132                                 if (foundSign) {
133                                         if (AllowLeadingWhite)
134                                                 pos = Int32.JumpOverWhite (pos, s, true);
135                                         if (AllowCurrencySymbol) {
136                                                 Int32.FindCurrency (ref pos, s, nfi,
137                                                                     ref foundCurrency);
138                                                 if (foundCurrency && AllowLeadingWhite)
139                                                         pos = Int32.JumpOverWhite (pos, s, true);
140                                         }
141                                 }
142                         }
143
144                         if (AllowCurrencySymbol && !foundCurrency) {
145                                 // Currency + sign
146                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
147                                 if (foundCurrency) {
148                                         if (AllowLeadingWhite)
149                                                 pos = Int32.JumpOverWhite (pos, s, true);
150                                         if (foundCurrency) {
151                                                 if (!foundSign && AllowLeadingSign) {
152                                                         Int32.FindSign (ref pos, s, nfi, ref foundSign,
153                                                                         ref negative);
154                                                         if (foundSign && AllowLeadingWhite)
155                                                                 pos = Int32.JumpOverWhite (pos, s, true);
156                                                 }
157                                         }
158                                 }
159                         }
160
161                         ulong number = 0;
162                         int nDigits = 0;
163                         bool decimalPointFound = false;
164                         ulong digitValue;
165                         char hexDigit;
166
167                         // Number stuff
168                         // Just the same as Int32, but this one adds instead of substract
169                         do {
170
171                                 if (!Int32.ValidDigit (s [pos], AllowHexSpecifier)) {
172                                         if (AllowThousands && Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator))
173                                                 continue;
174                                         else
175                                                 if (!decimalPointFound && AllowDecimalPoint && 
176                                                     Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)) {
177                                                         decimalPointFound = true;
178                                                         continue;
179                                                 }
180                                         break;
181                                 }
182                                 else if (AllowHexSpecifier) {
183                                         nDigits++;
184                                         hexDigit = s [pos++];
185                                         if (Char.IsDigit (hexDigit))
186                                                 digitValue = (ulong) (hexDigit - '0');
187                                         else if (Char.IsLower (hexDigit))
188                                                 digitValue = (ulong) (hexDigit - 'a' + 10);
189                                         else
190                                                 digitValue = (ulong) (hexDigit - 'A' + 10);
191
192                                         number = checked (number * 16 + digitValue);
193                                 }
194                                 else if (decimalPointFound) {
195                                         nDigits++;
196                                         // Allows decimal point as long as it's only 
197                                         // followed by zeroes.
198                                         if (s [pos++] != '0')
199                                                 throw new OverflowException (Locale.GetText ("Value too large or too small."));
200                                 }
201                                 else {
202                                         nDigits++;
203
204                                         try {
205                                                 number = checked (number * 10 + (ulong) (s [pos++] - '0'));
206                                         }
207                                         catch (OverflowException) {
208                                                 throw new OverflowException (Locale.GetText ("Value too large or too small."));
209                                         }
210                                 }
211                         } while (pos < s.Length);
212
213                         // Post number stuff
214                         if (nDigits == 0)
215                                 throw new FormatException (Locale.GetText ("Input string was not in the correct format."));
216
217                         if (AllowTrailingSign && !foundSign) {
218                                 // Sign + Currency
219                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
220                                 if (foundSign) {
221                                         if (AllowTrailingWhite)
222                                                 pos = Int32.JumpOverWhite (pos, s, true);
223                                         if (AllowCurrencySymbol)
224                                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
225                                 }
226                         }
227
228                         if (AllowCurrencySymbol && !foundCurrency) {
229                                 // Currency + sign
230                                 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
231                                 if (foundCurrency) {
232                                         if (AllowTrailingWhite)
233                                                 pos = Int32.JumpOverWhite (pos, s, true);
234                                         if (!foundSign && AllowTrailingSign)
235                                                 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
236                                 }
237                         }
238
239                         if (AllowTrailingWhite && pos < s.Length)
240                                 pos = Int32.JumpOverWhite (pos, s, false);
241
242                         if (foundOpenParentheses) {
243                                 if (pos >= s.Length || s [pos++] != ')')
244                                         throw new FormatException (Locale.GetText
245                                                 ("Input string was not in the correct format."));
246                                 if (AllowTrailingWhite && pos < s.Length)
247                                         pos = Int32.JumpOverWhite (pos, s, false);
248                         }
249
250                         if (pos < s.Length && s [pos] != '\u0000')
251                                 throw new FormatException (Locale.GetText ("Input string was not in the correct format."));
252
253                         // -0 is legal but other negative values are not
254                         if (negative && (number > 0)) {
255                                 throw new OverflowException (
256                                         Locale.GetText ("Negative number"));
257                         }
258
259                         return number;
260                 }
261
262                 public override string ToString ()
263                 {
264                         return ToString (null, null);
265                 }
266
267                 public string ToString (IFormatProvider provider)
268                 {
269                         return ToString (null, provider);
270                 }
271
272                 public string ToString (string format)
273                 {
274                         return ToString (format, null);
275                 }
276
277                 public string ToString (string format, IFormatProvider provider)
278                 {
279                         NumberFormatInfo nfi = NumberFormatInfo.GetInstance (provider);
280
281                         // use "G" when format is null or String.Empty
282                         if ((format == null) || (format.Length == 0))
283                                 format = "G";
284
285                         return IntegerFormatter.NumberToString (format, nfi, m_value);
286                 }
287
288                 // =========== IConvertible Methods =========== //
289                 public TypeCode GetTypeCode ()
290                 {
291                         return TypeCode.UInt64;
292                 }
293
294                 bool IConvertible.ToBoolean (IFormatProvider provider)
295                 {
296                         return System.Convert.ToBoolean (m_value);
297                 }
298
299                 byte IConvertible.ToByte (IFormatProvider provider)
300                 {
301                         return System.Convert.ToByte (m_value);
302                 }
303
304                 char IConvertible.ToChar (IFormatProvider provider)
305                 {
306                         return System.Convert.ToChar (m_value);
307                 }
308
309                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
310                 {
311                         return System.Convert.ToDateTime (m_value);
312                 }
313
314                 decimal IConvertible.ToDecimal (IFormatProvider provider)
315                 {
316                         return System.Convert.ToDecimal (m_value);
317                 }
318
319                 double IConvertible.ToDouble (IFormatProvider provider)
320                 {
321                         return System.Convert.ToDouble (m_value);
322                 }
323
324                 short IConvertible.ToInt16 (IFormatProvider provider)
325                 {
326                         return System.Convert.ToInt16 (m_value);
327                 }
328
329                 int IConvertible.ToInt32 (IFormatProvider provider)
330                 {
331                         return System.Convert.ToInt32 (m_value);
332                 }
333
334                 long IConvertible.ToInt64 (IFormatProvider provider)
335                 {
336                         return System.Convert.ToInt64 (m_value);
337                 }
338
339                 sbyte IConvertible.ToSByte(IFormatProvider provider)
340                 {
341                         return System.Convert.ToSByte (m_value);
342                 }
343
344                 float IConvertible.ToSingle (IFormatProvider provider)
345                 {
346                         return System.Convert.ToSingle (m_value);
347                 }
348
349                 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
350                 {
351                         return System.Convert.ToType (m_value, conversionType, provider);
352                 }
353
354                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
355                 {
356                         return System.Convert.ToUInt16 (m_value);
357                 }
358
359                 uint IConvertible.ToUInt32 (IFormatProvider provider)
360                 {
361                         return System.Convert.ToUInt32 (m_value);
362                 }
363
364                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
365                 {
366                         return m_value;
367                 }
368         }
369 }