2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System / Int64.cs
blobbb06bae7a6431508ec23fbb88cc3afe517a6f3fb
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 [System.Runtime.InteropServices.ComVisible (true)]
38 public struct Int64 : IFormattable, IConvertible, IComparable, IComparable<Int64>, IEquatable <Int64>
41 public const long MaxValue = 0x7fffffffffffffff;
42 public const long MinValue = -9223372036854775808;
44 internal long m_value;
46 public int CompareTo (object value)
48 if (value == null)
49 return 1;
51 if (!(value is System.Int64))
52 throw new ArgumentException (Locale.GetText ("Value is not a System.Int64"));
54 long lValue = (long) value;
56 if (m_value == lValue)
57 return 0;
59 return (m_value < lValue) ? -1 : 1;
62 public override bool Equals (object obj)
64 if (!(obj is System.Int64))
65 return false;
67 return ((long) obj) == m_value;
70 public override int GetHashCode ()
72 return (int)(m_value & 0xffffffff) ^ (int)(m_value >> 32);
75 public int CompareTo (long value)
77 if (m_value == value)
78 return 0;
79 if (m_value > value)
80 return 1;
81 else
82 return -1;
85 public bool Equals (long obj)
87 return obj == m_value;
90 internal static bool Parse (string s, bool tryParse, out long result, out Exception exc)
92 long val = 0;
93 int len;
94 int i;
95 int sign = 1;
96 bool digits_seen = false;
98 result = 0;
99 exc = null;
101 if (s == null) {
102 if (!tryParse)
103 exc = new ArgumentNullException ("s");
104 return false;
107 len = s.Length;
109 char c;
110 for (i = 0; i < len; i++){
111 c = s [i];
112 if (!Char.IsWhiteSpace (c))
113 break;
116 if (i == len) {
117 if (!tryParse)
118 exc = Int32.GetFormatException ();
119 return false;
122 c = s [i];
123 if (c == '+')
124 i++;
125 else if (c == '-'){
126 sign = -1;
127 i++;
130 for (; i < len; i++){
131 c = s [i];
133 if (c >= '0' && c <= '9'){
134 byte d = (byte) (c - '0');
136 if (val > (MaxValue/10))
137 goto overflow;
139 if (val == (MaxValue/10)){
140 if ((d > (MaxValue % 10)) && (sign == 1 || (d > ((MaxValue % 10) + 1))))
141 goto overflow;
142 if (sign == -1)
143 val = (val * sign * 10) - d;
144 else
145 val = (val * 10) + d;
147 if (Int32.ProcessTrailingWhitespace (tryParse, s, i + 1, ref exc)){
148 result = val;
149 return true;
151 goto overflow;
152 } else
153 val = val * 10 + d;
156 digits_seen = true;
157 } else if (!Int32.ProcessTrailingWhitespace (tryParse, s, i, ref exc))
158 return false;
161 if (!digits_seen) {
162 if (!tryParse)
163 exc = Int32.GetFormatException ();
164 return false;
167 if (sign == -1)
168 result = val * sign;
169 else
170 result = val;
172 return true;
174 overflow:
175 if (!tryParse)
176 exc = new OverflowException ("Value is too large");
177 return false;
180 public static long Parse (string s, IFormatProvider provider)
182 return Parse (s, NumberStyles.Integer, provider);
185 public static long Parse (string s, NumberStyles style)
187 return Parse (s, style, null);
190 internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out long result, out Exception exc)
192 result = 0;
193 exc = null;
195 if (s == null) {
196 if (!tryParse)
197 exc = new ArgumentNullException ("s");
198 return false;
201 if (s.Length == 0) {
202 if (!tryParse)
203 exc = new FormatException ("Input string was not " +
204 "in the correct format: s.Length==0.");
205 return false;
208 NumberFormatInfo nfi = null;
209 if (fp != null) {
210 Type typeNFI = typeof (System.Globalization.NumberFormatInfo);
211 nfi = (NumberFormatInfo) fp.GetFormat (typeNFI);
213 if (nfi == null)
214 nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
216 if (!Int32.CheckStyle (style, tryParse, ref exc))
217 return false;
219 bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
220 bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
221 bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
222 bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
223 bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
224 bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
225 bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
226 bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
227 bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
229 int pos = 0;
231 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
232 return false;
234 bool foundOpenParentheses = false;
235 bool negative = false;
236 bool foundSign = false;
237 bool foundCurrency = false;
239 // Pre-number stuff
240 if (AllowParentheses && s [pos] == '(') {
241 foundOpenParentheses = true;
242 foundSign = true;
243 negative = true; // MS always make the number negative when there parentheses
244 // even when NumberFormatInfo.NumberNegativePattern != 0!!!
245 pos++;
246 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
247 return false;
249 if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
250 if (!tryParse)
251 exc = new FormatException ("Input string was not in the correct " +
252 "format: Has Negative Sign.");
253 return false;
255 if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
256 if (!tryParse)
257 exc = new FormatException ("Input string was not in the correct " +
258 "format: Has Positive Sign.");
259 return false;
263 if (AllowLeadingSign && !foundSign) {
264 // Sign + Currency
265 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
266 if (foundSign) {
267 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
268 return false;
269 if (AllowCurrencySymbol) {
270 Int32.FindCurrency (ref pos, s, nfi,
271 ref foundCurrency);
272 if (foundCurrency && AllowLeadingWhite &&
273 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
274 return false;
279 if (AllowCurrencySymbol && !foundCurrency) {
280 // Currency + sign
281 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
282 if (foundCurrency) {
283 if (AllowLeadingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
284 return false;
285 if (foundCurrency) {
286 if (!foundSign && AllowLeadingSign) {
287 Int32.FindSign (ref pos, s, nfi, ref foundSign,
288 ref negative);
289 if (foundSign && AllowLeadingWhite &&
290 !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
291 return false;
297 long number = 0;
298 int nDigits = 0;
299 bool decimalPointFound = false;
300 int digitValue;
301 char hexDigit;
303 // Number stuff
304 do {
306 if (!Int32.ValidDigit (s [pos], AllowHexSpecifier)) {
307 if (AllowThousands &&
308 (Int32.FindOther (ref pos, s, nfi.NumberGroupSeparator)
309 || Int32.FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
310 continue;
311 else
312 if (!decimalPointFound && AllowDecimalPoint &&
313 (Int32.FindOther (ref pos, s, nfi.NumberDecimalSeparator)
314 || Int32.FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
315 decimalPointFound = true;
316 continue;
319 break;
321 else if (AllowHexSpecifier) {
322 nDigits++;
323 hexDigit = s [pos++];
324 if (Char.IsDigit (hexDigit))
325 digitValue = (int) (hexDigit - '0');
326 else if (Char.IsLower (hexDigit))
327 digitValue = (int) (hexDigit - 'a' + 10);
328 else
329 digitValue = (int) (hexDigit - 'A' + 10);
331 ulong unumber = (ulong)number;
333 // IMPROVME: We could avoid catching OverflowException
334 try {
335 number = (long)checked(unumber * 16ul + (ulong)digitValue);
336 } catch (OverflowException e){
337 if (!tryParse)
338 exc = e;
339 return false;
342 else if (decimalPointFound) {
343 nDigits++;
344 // Allows decimal point as long as it's only
345 // followed by zeroes.
346 if (s [pos++] != '0') {
347 if (!tryParse)
348 exc = new OverflowException ("Value too large or too " +
349 "small.");
350 return false;
353 else {
354 nDigits++;
356 try {
357 // Calculations done as negative
358 // (abs (MinValue) > abs (MaxValue))
359 number = checked (
360 number * 10 -
361 (long) (s [pos++] - '0')
363 } catch (OverflowException) {
364 if (!tryParse)
365 exc = new OverflowException ("Value too large or too " +
366 "small.");
367 return false;
370 } while (pos < s.Length);
372 // Post number stuff
373 if (nDigits == 0) {
374 if (!tryParse)
375 exc = new FormatException ("Input string was not in the correct format: nDigits == 0.");
376 return false;
379 if (AllowTrailingSign && !foundSign) {
380 // Sign + Currency
381 Int32.FindSign (ref pos, s, nfi, ref foundSign, ref negative);
382 if (foundSign) {
383 if (AllowTrailingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
384 return false;
385 if (AllowCurrencySymbol)
386 Int32.FindCurrency (ref pos, s, nfi,
387 ref foundCurrency);
391 if (AllowCurrencySymbol && !foundCurrency) {
392 // Currency + sign
393 if (nfi.CurrencyPositivePattern == 3 && s[pos++] != ' ')
394 if (tryParse)
395 return false;
396 else
397 throw new FormatException ("Input string was not in the correct format: no space between number and currency symbol.");
399 Int32.FindCurrency (ref pos, s, nfi, ref foundCurrency);
400 if (foundCurrency && pos < s.Length) {
401 if (AllowTrailingWhite && !Int32.JumpOverWhite (ref pos, s, true, tryParse, ref exc))
402 return false;
403 if (!foundSign && AllowTrailingSign)
404 Int32.FindSign (ref pos, s, nfi, ref foundSign,
405 ref negative);
409 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
410 return false;
412 if (foundOpenParentheses) {
413 if (pos >= s.Length || s [pos++] != ')') {
414 if (!tryParse)
415 exc = new FormatException ("Input string was not in the correct " +
416 "format: No room for close parens.");
417 return false;
419 if (AllowTrailingWhite && pos < s.Length && !Int32.JumpOverWhite (ref pos, s, false, tryParse, ref exc))
420 return false;
423 if (pos < s.Length && s [pos] != '\u0000') {
424 if (!tryParse)
425 exc = new FormatException ("Input string was not in the correct format: Did not parse entire string. pos = "
426 + pos + " s.Length = " + s.Length);
427 return false;
431 if (!negative && !AllowHexSpecifier){
432 try {
433 number = checked (-number);
434 } catch (OverflowException e){
435 if (!tryParse)
436 exc = e;
437 return false;
441 result = number;
442 return true;
445 public static long Parse (string s)
447 Exception exc;
448 long res;
450 if (!Parse (s, false, out res, out exc))
451 throw exc;
453 return res;
456 public static long Parse (string s, NumberStyles style, IFormatProvider provider)
458 Exception exc;
459 long res;
461 if (!Parse (s, style, provider, false, out res, out exc))
462 throw exc;
464 return res;
467 public static bool TryParse (string s, out long result)
469 Exception exc;
470 if (!Parse (s, true, out result, out exc)) {
471 result = 0;
472 return false;
475 return true;
478 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out long result)
480 Exception exc;
481 if (!Parse (s, style, provider, true, out result, out exc)) {
482 result = 0;
483 return false;
486 return true;
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 =========== //
511 public TypeCode GetTypeCode ()
513 return TypeCode.Int64;
516 bool IConvertible.ToBoolean (IFormatProvider provider)
518 return System.Convert.ToBoolean (m_value);
521 byte IConvertible.ToByte (IFormatProvider provider)
523 return System.Convert.ToByte (m_value);
526 char IConvertible.ToChar (IFormatProvider provider)
528 return System.Convert.ToChar (m_value);
531 DateTime IConvertible.ToDateTime (IFormatProvider provider)
533 return System.Convert.ToDateTime (m_value);
536 decimal IConvertible.ToDecimal (IFormatProvider provider)
538 return System.Convert.ToDecimal (m_value);
541 double IConvertible.ToDouble (IFormatProvider provider)
543 return System.Convert.ToDouble (m_value);
546 short IConvertible.ToInt16 (IFormatProvider provider)
548 return System.Convert.ToInt16 (m_value);
551 int IConvertible.ToInt32 (IFormatProvider provider)
553 return System.Convert.ToInt32 (m_value);
556 long IConvertible.ToInt64 (IFormatProvider provider)
558 return System.Convert.ToInt64 (m_value);
561 sbyte IConvertible.ToSByte (IFormatProvider provider)
563 return System.Convert.ToSByte (m_value);
566 float IConvertible.ToSingle (IFormatProvider provider)
568 return System.Convert.ToSingle (m_value);
571 object IConvertible.ToType (Type targetType, IFormatProvider provider)
573 if (targetType == null)
574 throw new ArgumentNullException ("targetType");
575 return System.Convert.ToType (m_value, targetType, provider, false);
578 ushort IConvertible.ToUInt16 (IFormatProvider provider)
580 return System.Convert.ToUInt16 (m_value);
583 uint IConvertible.ToUInt32 (IFormatProvider provider)
585 return System.Convert.ToUInt32 (m_value);
588 ulong IConvertible.ToUInt64 (IFormatProvider provider)
590 return System.Convert.ToUInt64 (m_value);