5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
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)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
32 using System.Globalization;
33 using System.Threading;
38 [CLSCompliant (false)]
39 [System.Runtime.InteropServices.ComVisible (true)]
40 public struct UInt64 : IFormattable, IConvertible, IComparable, IComparable<UInt64>, IEquatable <UInt64>
42 public const ulong MaxValue = 0xffffffffffffffff;
43 public const ulong MinValue = 0;
45 internal ulong m_value;
47 public int CompareTo (object value)
52 if (!(value is System.UInt64))
53 throw new ArgumentException (Locale.GetText ("Value is not a System.UInt64."));
55 ulong int64 = (ulong) value;
60 return (m_value < int64) ? -1 : 1;
63 public override bool Equals (object obj)
65 if (!(obj is System.UInt64))
68 return ((ulong) obj) == m_value;
71 public override int GetHashCode ()
73 return (int)(m_value & 0xffffffff) ^ (int)(m_value >> 32);
76 public int CompareTo (ulong value)
86 public bool Equals (ulong obj)
88 return obj == m_value;
91 [CLSCompliant (false)]
92 public static ulong Parse (string s)
97 if (!Parse (s, false, out result, out exc))
103 internal static bool Parse (string s, bool tryParse, out ulong result, out Exception exc)
108 bool digits_seen = false;
109 bool has_negative_sign = false;
116 exc = new ArgumentNullException ("s");
123 for (i = 0; i < len; i++) {
125 if (!Char.IsWhiteSpace (c))
131 exc = Int32.GetFormatException ();
137 else if (s [i] == '-') {
139 has_negative_sign = true;
142 // Actual number stuff
143 for (; i < len; i++) {
146 if (c >= '0' && c <= '9') {
147 uint d = (uint) (c - '0');
149 if (val > MaxValue / 10 || (val == MaxValue / 10 && d > MaxValue % 10)) {
151 exc = new OverflowException ("Value is too large.");
155 val = (val * 10) + d;
157 } else if (!Int32.ProcessTrailingWhitespace (tryParse, s, i, ref exc))
163 exc = Int32.GetFormatException ();
167 if (has_negative_sign && val > 0) {
169 exc = new OverflowException ("Negative number.");
177 [CLSCompliant (false)]
178 public static ulong Parse (string s, IFormatProvider provider)
180 return Parse (s, NumberStyles.Integer, provider);
183 [CLSCompliant (false)]
184 public static ulong Parse (string s, NumberStyles style)
186 return Parse (s, style, null);
189 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out ulong result, out Exception exc)
196 exc = new ArgumentNullException ("s");
202 exc = Int32.GetFormatException ();
206 NumberFormatInfo nfi = null;
207 if (provider != null) {
208 Type typeNFI = typeof (NumberFormatInfo);
209 nfi = provider.GetFormat (typeNFI) as NumberFormatInfo;
212 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
214 if (!Int32.CheckStyle (style, tryParse, ref exc))
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;
230 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
233 bool foundOpenParentheses = false;
234 bool negative = false;
235 bool foundSign = false;
236 bool foundCurrency = false;
239 if (AllowParentheses && s [pos] == '(') {
240 foundOpenParentheses = true;
242 negative = true; // MS always make the number negative when there parentheses
243 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
245 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
248 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
250 exc = Int32.GetFormatException ();
254 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
256 exc = Int32.GetFormatException ();
261 if (AllowLeadingSign && !foundSign) {
263 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
265 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
267 if (AllowCurrencySymbol) {
268 Int32.FindCurrency (ref pos, s, nfi,
270 if (foundCurrency && AllowLeadingWhite &&
271 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
277 if (AllowCurrencySymbol && !foundCurrency) {
279 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
281 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
284 if (!foundSign && AllowLeadingSign) {
285 Int32.FindSign (ref pos, s, nfi, ref foundSign,
287 if (foundSign && AllowLeadingWhite &&
288 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
297 int decimalPointPos = -1;
302 // Just the same as Int32, but this one adds instead of substract
303 while (pos < s.Length) {
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)))
311 if (AllowDecimalPoint && decimalPointPos < 0 &&
312 (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
313 || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
314 decimalPointPos = nDigits;
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);
330 digitValue = (ulong) (hexDigit - 'A' + 10);
333 // Any number above 32 will do
334 bool can_overflow = number > 0xffff;
336 number = number * 16 + digitValue;
338 if (can_overflow && number < 16)
341 number = checked (number * 16 + digitValue);
347 number = checked (number * 10 + (ulong) (s [pos++] - '0'));
348 } catch (OverflowException) {
350 exc = new OverflowException (Locale.GetText ("Value too large or too small."));
358 exc = Int32.GetFormatException ();
364 if (Int32.FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null)
367 if (AllowTrailingSign && !foundSign) {
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))
376 if (AllowCurrencySymbol && !foundCurrency) {
377 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
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))
385 if (!foundSign && AllowTrailingSign)
386 Int32.FindSign (ref pos, s, nfi, ref foundSign,
391 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
394 if (foundOpenParentheses) {
395 if (pos >= s.Length || s [pos++] != ')') {
397 exc = Int32.GetFormatException ();
400 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
404 if (pos < s.Length && s [pos] != '\u0000') {
406 exc = Int32.GetFormatException ();
410 // -0 is legal but other negative values are not
411 if (negative && (number > 0)) {
413 exc = new OverflowException (
414 Locale.GetText ("Negative number"));
418 if (decimalPointPos >= 0)
419 exponent = exponent - nDigits + decimalPointPos;
423 // Any non-zero values after decimal point are not allowed
426 number = (ulong) Math.DivRem ((long) number, (long) Math.Pow (10, -exponent), out remainder);
427 if (remainder != 0) {
429 exc = new OverflowException ("Value too large or too small.");
432 } else if (exponent > 0) {
434 // result *= 10^exponent
436 // Reduce the risk of throwing an overflow exc
438 double res = checked (Math.Pow (10, exponent) * number);
439 if (res < MinValue || res > MaxValue) {
441 exc = new OverflowException ("Value too large or too small.");
452 [CLSCompliant (false)]
453 public static ulong Parse (string s, NumberStyles style, IFormatProvider provider)
458 if (!Parse (s, style, provider, false, out res, out exc))
465 [CLSCompliant (false)]
466 public static bool TryParse (string s, out ulong result)
469 if (!Parse (s, true, out result, out exc)) {
477 [CLSCompliant (false)]
478 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out ulong result)
481 if (!Parse (s, style, provider, true, out result, out exc)) {
489 public override string ToString ()
491 return NumberFormatter.NumberToString (m_value, null);
494 public string ToString (IFormatProvider provider)
496 return NumberFormatter.NumberToString (m_value, provider);
499 public string ToString (string format)
501 return ToString (format, null);
504 public string ToString (string format, IFormatProvider provider)
506 return NumberFormatter.NumberToString (format, m_value, provider);
509 // =========== IConvertible Methods =========== //
510 public TypeCode GetTypeCode ()
512 return TypeCode.UInt64;
515 bool IConvertible.ToBoolean (IFormatProvider provider)
517 return System.Convert.ToBoolean (m_value);
520 byte IConvertible.ToByte (IFormatProvider provider)
522 return System.Convert.ToByte (m_value);
525 char IConvertible.ToChar (IFormatProvider provider)
527 return System.Convert.ToChar (m_value);
530 DateTime IConvertible.ToDateTime (IFormatProvider provider)
532 return System.Convert.ToDateTime (m_value);
535 decimal IConvertible.ToDecimal (IFormatProvider provider)
537 return System.Convert.ToDecimal (m_value);
540 double IConvertible.ToDouble (IFormatProvider provider)
542 return System.Convert.ToDouble (m_value);
545 short IConvertible.ToInt16 (IFormatProvider provider)
547 return System.Convert.ToInt16 (m_value);
550 int IConvertible.ToInt32 (IFormatProvider provider)
552 return System.Convert.ToInt32 (m_value);
555 long IConvertible.ToInt64 (IFormatProvider provider)
557 return System.Convert.ToInt64 (m_value);
560 sbyte IConvertible.ToSByte(IFormatProvider provider)
562 return System.Convert.ToSByte (m_value);
565 float IConvertible.ToSingle (IFormatProvider provider)
567 return System.Convert.ToSingle (m_value);
570 object IConvertible.ToType (Type targetType, IFormatProvider provider)
572 if (targetType == null)
573 throw new ArgumentNullException ("targetType");
574 return System.Convert.ToType (m_value, targetType, provider, false);
577 ushort IConvertible.ToUInt16 (IFormatProvider provider)
579 return System.Convert.ToUInt16 (m_value);
582 uint IConvertible.ToUInt32 (IFormatProvider provider)
584 return System.Convert.ToUInt32 (m_value);
587 ulong IConvertible.ToUInt64 (IFormatProvider provider)