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 [System.Runtime.InteropServices.ComVisible (true)]
39 public struct Int64 : IFormattable, IConvertible, IComparable, IComparable<Int64>, IEquatable <Int64>
42 public const long MaxValue = 0x7fffffffffffffff;
43 public const long MinValue = -9223372036854775808;
45 internal long m_value;
47 public int CompareTo (object value)
52 if (!(value is System.Int64))
53 throw new ArgumentException (Locale.GetText ("Value is not a System.Int64"));
55 long lValue = (long) value;
57 if (m_value == lValue)
60 return (m_value < lValue) ? -1 : 1;
63 public override bool Equals (object obj)
65 if (!(obj is System.Int64))
68 return ((long) obj) == m_value;
71 public override int GetHashCode ()
73 return (int)(m_value & 0xffffffff) ^ (int)(m_value >> 32);
76 public int CompareTo (long value)
86 public bool Equals (long obj)
88 return obj == m_value;
91 internal static bool Parse (string s, bool tryParse, out long result, out Exception exc)
96 bool digits_seen = false;
100 NumberFormatInfo nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
104 exc = new ArgumentNullException ("s");
111 for (i = 0; i < len; i++){
113 if (!Char.IsWhiteSpace (c))
119 exc = Int32.GetFormatException ();
123 if (String.Compare (s, i, nfi.PositiveSign, 0, nfi.PositiveSign.Length) == 0)
124 i += nfi.PositiveSign.Length;
125 else if (String.Compare (s, i, nfi.NegativeSign, 0, nfi.NegativeSign.Length) == 0) {
127 i += nfi.NegativeSign.Length;
130 for (; i < len; i++){
133 if (c >= '0' && c <= '9'){
134 byte d = (byte) (c - '0');
136 if (val > (MaxValue/10))
139 if (val == (MaxValue/10)){
140 if ((d > (MaxValue % 10)) && (sign == 1 || (d > ((MaxValue % 10) + 1))))
143 val = (val * sign * 10) - d;
145 val = (val * 10) + d;
147 if (Int32.ProcessTrailingWhitespace (tryParse, s, i + 1, ref exc)){
156 } else if (!Int32.ProcessTrailingWhitespace (tryParse, s, i, ref exc))
161 exc = Int32.GetFormatException ();
174 exc = new OverflowException ("Value is too large");
178 public static long Parse (string s, IFormatProvider provider)
180 return Parse (s, NumberStyles.Integer, provider);
183 public static long Parse (string s, NumberStyles style)
185 return Parse (s, style, null);
188 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out long result, out Exception exc)
195 exc = new ArgumentNullException ("s");
201 exc = Int32.GetFormatException ();
205 NumberFormatInfo nfi = null;
207 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
208 nfi = fp.GetFormat (typeNFI) as NumberFormatInfo;
211 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
213 if (!Int32.CheckStyle (style, tryParse, ref exc))
216 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
217 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
218 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
219 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
220 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
221 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
222 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
223 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
224 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
225 bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
229 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
232 bool foundOpenParentheses = false;
233 bool negative = false;
234 bool foundSign = false;
235 bool foundCurrency = false;
238 if (AllowParentheses && s [pos] == '(') {
239 foundOpenParentheses = true;
241 negative = true; // MS always make the number negative when there parentheses
242 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
244 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
247 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
249 exc = Int32.GetFormatException ();
253 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
255 exc = Int32.GetFormatException ();
260 if (AllowLeadingSign && !foundSign) {
262 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
264 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
266 if (AllowCurrencySymbol) {
267 Int32.FindCurrency (ref pos, s, nfi,
269 if (foundCurrency && AllowLeadingWhite &&
270 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
276 if (AllowCurrencySymbol && !foundCurrency) {
278 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
280 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
283 if (!foundSign && AllowLeadingSign) {
284 Int32.FindSign (ref pos, s, nfi, ref foundSign,
286 if (foundSign && AllowLeadingWhite &&
287 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
296 int decimalPointPos = -1;
301 while (pos < s.Length) {
303 if (!Int32.ValidDigit (s [pos], AllowHexSpecifier)) {
304 if (AllowThousands &&
305 (Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator)
306 || Int32.FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
309 if (AllowDecimalPoint && decimalPointPos < 0 &&
310 (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
311 || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
312 decimalPointPos = nDigits;
321 if (AllowHexSpecifier) {
322 hexDigit = s [pos++];
323 if (Char.IsDigit (hexDigit))
324 digitValue = (int) (hexDigit - '0');
325 else if (Char.IsLower (hexDigit))
326 digitValue = (int) (hexDigit - 'a' + 10);
328 digitValue = (int) (hexDigit - 'A' + 10);
330 ulong unumber = (ulong)number;
332 // IMPROVME: We could avoid catching OverflowException
334 number = (long)checked(unumber * 16ul + (ulong)digitValue);
335 } catch (OverflowException e){
345 // Calculations done as negative
346 // (abs (MinValue) > abs (MaxValue))
347 number = checked (number * 10 - (long) (s [pos++] - '0'));
348 } catch (OverflowException) {
350 exc = new OverflowException ("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 if (!negative && !AllowHexSpecifier){
412 number = checked (-number);
413 } catch (OverflowException e){
420 if (decimalPointPos >= 0)
421 exponent = exponent - nDigits + decimalPointPos;
425 // Any non-zero values after decimal point are not allowed
428 number = Math.DivRem (number, (long) Math.Pow (10, -exponent), out remainder);
429 if (remainder != 0) {
431 exc = new OverflowException ("Value too large or too small.");
434 } else if (exponent > 0) {
436 // result *= 10^exponent
438 // Reduce the risk of throwing an overflow exc
440 double res = checked (Math.Pow (10, exponent) * number);
441 if (res < MinValue || res > MaxValue) {
443 exc = new OverflowException ("Value too large or too small.");
454 public static long Parse (string s)
459 if (!Parse (s, false, out res, out exc))
465 public static long Parse (string s, NumberStyles style, IFormatProvider provider)
470 if (!Parse (s, style, provider, false, out res, out exc))
476 public static bool TryParse (string s, out long result)
479 if (!Parse (s, true, out result, out exc)) {
487 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out long result)
490 if (!Parse (s, style, provider, true, out result, out exc)) {
498 public override string ToString ()
500 return NumberFormatter.NumberToString (m_value, null);
503 public string ToString (IFormatProvider provider)
505 return NumberFormatter.NumberToString (m_value, provider);
508 public string ToString (string format)
510 return ToString (format, null);
513 public string ToString (string format, IFormatProvider provider)
515 return NumberFormatter.NumberToString (format, m_value, provider);
518 // =========== IConvertible Methods =========== //
520 public TypeCode GetTypeCode ()
522 return TypeCode.Int64;
525 bool IConvertible.ToBoolean (IFormatProvider provider)
527 return System.Convert.ToBoolean (m_value);
530 byte IConvertible.ToByte (IFormatProvider provider)
532 return System.Convert.ToByte (m_value);
535 char IConvertible.ToChar (IFormatProvider provider)
537 return System.Convert.ToChar (m_value);
540 DateTime IConvertible.ToDateTime (IFormatProvider provider)
542 return System.Convert.ToDateTime (m_value);
545 decimal IConvertible.ToDecimal (IFormatProvider provider)
547 return System.Convert.ToDecimal (m_value);
550 double IConvertible.ToDouble (IFormatProvider provider)
552 return System.Convert.ToDouble (m_value);
555 short IConvertible.ToInt16 (IFormatProvider provider)
557 return System.Convert.ToInt16 (m_value);
560 int IConvertible.ToInt32 (IFormatProvider provider)
562 return System.Convert.ToInt32 (m_value);
565 long IConvertible.ToInt64 (IFormatProvider provider)
570 sbyte IConvertible.ToSByte (IFormatProvider provider)
572 return System.Convert.ToSByte (m_value);
575 float IConvertible.ToSingle (IFormatProvider provider)
577 return System.Convert.ToSingle (m_value);
580 object IConvertible.ToType (Type targetType, IFormatProvider provider)
582 if (targetType == null)
583 throw new ArgumentNullException ("targetType");
584 return System.Convert.ToType (m_value, targetType, provider, false);
587 ushort IConvertible.ToUInt16 (IFormatProvider provider)
589 return System.Convert.ToUInt16 (m_value);
592 uint IConvertible.ToUInt32 (IFormatProvider provider)
594 return System.Convert.ToUInt32 (m_value);
597 ulong IConvertible.ToUInt64 (IFormatProvider provider)
599 return System.Convert.ToUInt64 (m_value);