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