2009-07-27 Miguel de Icaza <miguel@novell.com>
[mono-project.git] / mcs / class / corlib / System / Int64.cs
blob6b445659c575c85950ef5ec239411fab3038aa42
1 //
2 // System.Int64.cs
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) Ximian, Inc. http://www.ximian.com
8 //
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Globalization;
32 using System.Threading;
34 namespace System {
36 [Serializable]
37 #if NET_2_0
38 [System.Runtime.InteropServices.ComVisible (true)]
39 #endif
40 public struct Int64 : IFormattable, IConvertible, IComparable
41 #if NET_2_0
42 , IComparable<Int64>, IEquatable <Int64>
43 #endif
46 public const long MaxValue = 0x7fffffffffffffff;
47 public const long MinValue = -9223372036854775808;
49 internal long m_value;
51 public int CompareTo (object value)
53 if (value == null)
54 return 1;
56 if (!(value is System.Int64))
57 throw new ArgumentException (Locale.GetText ("Value is not a System.Int64"));
59 long lValue = (long) value;
61 if (m_value == lValue)
62 return 0;
64 return (m_value < lValue) ? -1 : 1;
67 public override bool Equals (object obj)
69 if (!(obj is System.Int64))
70 return false;
72 return ((long) obj) == m_value;
75 public override int GetHashCode ()
77 return (int)(m_value & 0xffffffff) ^ (int)(m_value >> 32);
80 #if NET_2_0
81 public int CompareTo (long value)
83 if (m_value == value)
84 return 0;
85 if (m_value > value)
86 return 1;
87 else
88 return -1;
91 public bool Equals (long obj)
93 return obj == m_value;
95 #endif
97 internal static bool Parse (string s, bool tryParse, out long result, out Exception exc)
99 long val = 0;
100 int len;
101 int i;
102 int sign = 1;
103 bool digits_seen = false;
105 result = 0;
106 exc = null;
108 if (s == null) {
109 if (!tryParse)
110 exc = new ArgumentNullException ("s");
111 return false;
114 len = s.Length;
116 char c;
117 for (i = 0; i < len; i++){
118 c = s [i];
119 if (!Char.IsWhiteSpace (c))
120 break;
123 if (i == len) {
124 if (!tryParse)
125 exc = Int32.GetFormatException ();
126 return false;
129 c = s [i];
130 if (c == '+')
131 i++;
132 else if (c == '-'){
133 sign = -1;
134 i++;
137 for (; i < len; i++){
138 c = s [i];
140 if (c >= '0' && c <= '9'){
141 byte d = (byte) (c - '0');
143 if (val > (MaxValue/10))
144 goto overflow;
146 if (val == (MaxValue/10)){
147 if ((d > (MaxValue % 10)) && (sign == 1 || (d > ((MaxValue % 10) + 1))))
148 goto overflow;
149 if (sign == -1)
150 val = (val * sign * 10) - d;
151 else
152 val = (val * 10) + d;
154 if (Int32.ProcessTrailingWhitespace (tryParse, s, i + 1, ref exc)){
155 result = val;
156 return true;
158 goto overflow;
159 } else
160 val = val * 10 + d;
163 digits_seen = true;
164 } else if (!Int32.ProcessTrailingWhitespace (tryParse, s, i, ref exc))
165 return false;
168 if (!digits_seen) {
169 if (!tryParse)
170 exc = Int32.GetFormatException ();
171 return false;
174 if (sign == -1)
175 result = val * sign;
176 else
177 result = val;
179 return true;
181 overflow:
182 if (!tryParse)
183 exc = new OverflowException ("Value is too large");
184 return false;
187 public static long Parse (string s, IFormatProvider provider)
189 return Parse (s, NumberStyles.Integer, provider);
192 public static long Parse (string s, NumberStyles style)
194 return Parse (s, style, null);
197 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out long result, out Exception exc)
199 result = 0;
200 exc = null;
202 if (s == null) {
203 if (!tryParse)
204 exc = new ArgumentNullException ("s");
205 return false;
208 if (s.Length == 0) {
209 if (!tryParse)
210 exc = new FormatException ("Input string was not " +
211 "in the correct format: s.Length==0.");
212 return false;
215 NumberFormatInfo nfi;
216 if (fp != null) {
217 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
218 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
220 else
221 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
223 if (!Int32.CheckStyle (style, tryParse, ref exc))
224 return false;
226 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
227 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
228 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
229 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
230 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
231 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
232 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
233 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
234 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
236 int pos = 0;
238 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
239 return false;
241 bool foundOpenParentheses = false;
242 bool negative = false;
243 bool foundSign = false;
244 bool foundCurrency = false;
246 // Pre-number stuff
247 if (AllowParentheses && s [pos] == '(') {
248 foundOpenParentheses = true;
249 foundSign = true;
250 negative = true; // MS always make the number negative when there parentheses
251 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
252 pos++;
253 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
254 return false;
256 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
257 if (!tryParse)
258 exc = new FormatException ("Input string was not in the correct " +
259 "format: Has Negative Sign.");
260 return false;
262 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
263 if (!tryParse)
264 exc = new FormatException ("Input string was not in the correct " +
265 "format: Has Positive Sign.");
266 return false;
270 if (AllowLeadingSign && !foundSign) {
271 // Sign + Currency
272 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
273 if (foundSign) {
274 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
275 return false;
276 if (AllowCurrencySymbol) {
277 Int32.FindCurrency (ref pos, s, nfi,
278 ref foundCurrency);
279 if (foundCurrency && AllowLeadingWhite &&
280 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
281 return false;
286 if (AllowCurrencySymbol && !foundCurrency) {
287 // Currency + sign
288 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
289 if (foundCurrency) {
290 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
291 return false;
292 if (foundCurrency) {
293 if (!foundSign && AllowLeadingSign) {
294 Int32.FindSign (ref pos, s, nfi, ref foundSign,
295 ref negative);
296 if (foundSign && AllowLeadingWhite &&
297 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
298 return false;
304 long number = 0;
305 int nDigits = 0;
306 bool decimalPointFound = false;
307 int digitValue;
308 char hexDigit;
310 // Number stuff
311 do {
313 if (!Int32.ValidDigit (s [pos], AllowHexSpecifier)) {
314 if (AllowThousands &&
315 (Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator)
316 || Int32.FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
317 continue;
318 else
319 if (!decimalPointFound && AllowDecimalPoint &&
320 (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
321 || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
322 decimalPointFound = true;
323 continue;
326 break;
328 else if (AllowHexSpecifier) {
329 nDigits++;
330 hexDigit = s [pos++];
331 if (Char.IsDigit (hexDigit))
332 digitValue = (int) (hexDigit - '0');
333 else if (Char.IsLower (hexDigit))
334 digitValue = (int) (hexDigit - 'a' + 10);
335 else
336 digitValue = (int) (hexDigit - 'A' + 10);
338 ulong unumber = (ulong)number;
340 // IMPROVME: We could avoid catching OverflowException
341 try {
342 number = (long)checked(unumber * 16ul + (ulong)digitValue);
343 } catch (OverflowException e){
344 if (!tryParse)
345 exc = e;
346 return false;
349 else if (decimalPointFound) {
350 nDigits++;
351 // Allows decimal point as long as it's only
352 // followed by zeroes.
353 if (s [pos++] != '0') {
354 if (!tryParse)
355 exc = new OverflowException ("Value too large or too " +
356 "small.");
357 return false;
360 else {
361 nDigits++;
363 try {
364 // Calculations done as negative
365 // (abs (MinValue) > abs (MaxValue))
366 number = checked (
367 number * 10 -
368 (long) (s [pos++] - '0')
370 } catch (OverflowException) {
371 if (!tryParse)
372 exc = new OverflowException ("Value too large or too " +
373 "small.");
374 return false;
377 } while (pos < s.Length);
379 // Post number stuff
380 if (nDigits == 0) {
381 if (!tryParse)
382 exc = new FormatException ("Input string was not in the correct format: nDigits == 0.");
383 return false;
386 if (AllowTrailingSign && !foundSign) {
387 // Sign + Currency
388 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
389 if (foundSign) {
390 if (AllowTrailingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
391 return false;
392 if (AllowCurrencySymbol)
393 Int32.FindCurrency (ref pos, s, nfi,
394 ref foundCurrency);
398 if (AllowCurrencySymbol && !foundCurrency) {
399 // Currency + sign
400 if (nfi.CurrencyPositivePattern == 3 && s[pos++] != ' ')
401 if (tryParse)
402 return false;
403 else
404 throw new FormatException ("Input string was not in the correct format: no space between number and currency symbol.");
406 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
407 if (foundCurrency && pos < s.Length) {
408 if (AllowTrailingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
409 return false;
410 if (!foundSign && AllowTrailingSign)
411 Int32.FindSign (ref pos, s, nfi, ref foundSign,
412 ref negative);
416 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
417 return false;
419 if (foundOpenParentheses) {
420 if (pos >= s.Length || s [pos++] != ')') {
421 if (!tryParse)
422 exc = new FormatException ("Input string was not in the correct " +
423 "format: No room for close parens.");
424 return false;
426 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
427 return false;
430 if (pos < s.Length && s [pos] != '\u0000') {
431 if (!tryParse)
432 exc = new FormatException ("Input string was not in the correct format: Did not parse entire string. pos = "
433 + pos + " s.Length = " + s.Length);
434 return false;
438 if (!negative && !AllowHexSpecifier){
439 try {
440 number = checked (-number);
441 } catch (OverflowException e){
442 if (!tryParse)
443 exc = e;
444 return false;
448 result = number;
449 return true;
452 public static long Parse (string s)
454 Exception exc;
455 long res;
457 if (!Parse (s, false, out res, out exc))
458 throw exc;
460 return res;
463 public static long Parse (string s, NumberStyles style, IFormatProvider provider)
465 Exception exc;
466 long res;
468 if (!Parse (s, style, provider, false, out res, out exc))
469 throw exc;
471 return res;
474 #if NET_2_0
475 public static bool TryParse (string s, out long result)
477 Exception exc;
478 if (!Parse (s, true, out result, out exc)) {
479 result = 0;
480 return false;
483 return true;
486 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out long result)
488 Exception exc;
489 if (!Parse (s, style, provider, true, out result, out exc)) {
490 result = 0;
491 return false;
494 return true;
496 #endif
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)
567 return System.Convert.ToInt64 (m_value);
570 #if ONLY_1_1
571 #pragma warning disable 3019
572 [CLSCompliant (false)]
573 #endif
574 sbyte IConvertible.ToSByte (IFormatProvider provider)
576 return System.Convert.ToSByte (m_value);
578 #if ONLY_1_1
579 #pragma warning restore 3019
580 #endif
582 float IConvertible.ToSingle (IFormatProvider provider)
584 return System.Convert.ToSingle (m_value);
587 object IConvertible.ToType (Type targetType, IFormatProvider provider)
589 if (targetType == null)
590 throw new ArgumentNullException ("targetType");
591 return System.Convert.ToType (m_value, targetType, provider, false);
594 #if ONLY_1_1
595 #pragma warning disable 3019
596 [CLSCompliant (false)]
597 #endif
598 ushort IConvertible.ToUInt16 (IFormatProvider provider)
600 return System.Convert.ToUInt16 (m_value);
602 #if ONLY_1_1
603 #pragma warning restore 3019
604 #endif
606 #if ONLY_1_1
607 #pragma warning disable 3019
608 [CLSCompliant (false)]
609 #endif
610 uint IConvertible.ToUInt32 (IFormatProvider provider)
612 return System.Convert.ToUInt32 (m_value);
614 #if ONLY_1_1
615 #pragma warning restore 3019
616 #endif
618 #if ONLY_1_1
619 #pragma warning disable 3019
620 [CLSCompliant (false)]
621 #endif
622 ulong IConvertible.ToUInt64 (IFormatProvider provider)
624 return System.Convert.ToUInt64 (m_value);
626 #if ONLY_1_1
627 #pragma warning restore 3019
628 #endif