//
// Author:
// Kazuki Oikawa (kazuki@panicode.com)
+// Eyal Alaluf (eyala@mainsoft.com)
//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2008 Mainsoft Co. (http://www.mainsoft.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+// NumberFormatter is shared with Grasshopper and hence the #if TARGET_JVM for
+// marking the use of unsafe code that is not supported in Grasshopper.
+#if !TARGET_JVM
+#define UNSAFE_TABLES
+#endif
-using System.Collections;
using System.Globalization;
using System.Text;
+using System.Threading;
+using System.Runtime.CompilerServices;
namespace System
{
- class NumberFormatter
+ internal sealed partial class NumberFormatter
{
- static char[] digitLowerTable = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
- static char[] digitUpperTable = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
-
- #region NumberToString
- public static string NumberToString (string format, sbyte value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X'))
- return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-value, value >= 0, 1, precision, specifier == 'X');
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, byte value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X'))
- return FormatHexadecimal (value, true, 1, precision, specifier == 'X');
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, ushort value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X'))
- return FormatHexadecimal (value, true, 2, precision, specifier == 'X');
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, short value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X'))
- return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-value, value >= 0, 2, precision, specifier == 'X');
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, uint value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X'))
- return FormatHexadecimal (value, true, 4, precision, specifier == 'X');
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, int value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X'))
- return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-(long)value, value >= 0, 4, precision, specifier == 'X');
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, ulong value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X'))
- return FormatHexadecimal (value, true, 8, precision, specifier == 'X');
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, long value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X'))
- return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-value, value >= 0, 8, precision, specifier == 'X');
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, float value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X')) throw new FormatException ();
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, double value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X')) throw new FormatException ();
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, decimal value, NumberFormatInfo nfi)
- {
- char specifier;
- int precision;
- bool custom;
- ParseBasicFormat (format, out specifier, out precision, out custom);
- if (!custom && (specifier == 'x' || specifier == 'X')) throw new FormatException ();
- return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
- }
- public static string NumberToString (string format, NumberStore ns, NumberFormatInfo nfi, char specifier, int precision, bool custom)
- {
- if (ns.IsNaN) {
- return nfi.NaNSymbol;
- }
- if (ns.IsInfinity) {
- if (ns.Positive)
- return nfi.PositiveInfinitySymbol;
- else
- return nfi.NegativeInfinitySymbol;
- }
-
- if (nfi == null)
- nfi = NumberFormatInfo.GetInstance (null);
-
- if (custom){
- if (ns.IsFloatingSource)
- ns.RoundEffectiveDigits (ns.DefaultPrecision);
- return FormatCustom (format, ns, nfi);
- }
-
- if (ns.IsFloatingSource) {
- switch(specifier) {
- case 'p':
- case 'P':
- case 'c':
- case 'C':
- case 'f':
- case 'F':
- case 'N':
- case 'n':
- ns.RoundEffectiveDigits (ns.DefaultPrecision);
- break;
- case 'g':
- case 'G':
- if (precision <= 0)
- ns.RoundEffectiveDigits (ns.DefaultPrecision, ns.IsBankerApplicable, true);
- else
- ns.RoundEffectiveDigits (precision);
- break;
- case 'r':
- case 'R':
- ns.RoundEffectiveDigits (ns.DefaultMaxPrecision);
-
- // FIXME: it is a quick workaround for non-roundtrip issue (bug #320433).
- if (ns.ToStringVerificationNeeded) {
- string orgStr = FormatGeneral (ns, ns.DefaultPrecision, nfi, true, true);
- double orgValue = double.Parse (orgStr);
- NumberStore tmpNS = new NumberStore (orgValue);
- tmpNS.RoundEffectiveDigits (tmpNS.DefaultMaxPrecision);
- tmpNS.RoundEffectiveDigits (tmpNS.DefaultMaxPrecision - 1);
- string tmpStr = FormatGeneral (tmpNS, ns.DefaultPrecision, nfi, true, true);
- double tmpValue = double.Parse (tmpStr);
- if (orgValue == tmpValue && orgStr.Length - tmpStr.Length > 1)
- ns = tmpNS;
- }
- break;
- default:
- if (precision > ns.DefaultPrecision)
- ns.RoundEffectiveDigits (precision + 1);
- else
- ns.RoundEffectiveDigits (ns.DefaultPrecision + 1);
- break;
- }
- }
-
- switch(specifier) {
- case 'c':
- case 'C':
- return FormatCurrency (ns, precision, nfi);
- case 'd':
- case 'D':
- return FormatDecimal (ns, precision, nfi);
- case 'e':
- case 'E':
- return FormatExponential (ns, precision, nfi, specifier == 'E');
- case 'f':
- case 'F':
- return FormatFixedPoint (ns, precision, nfi);
- case 'g':
- case 'G':
- if (ns.IsFloatingSource || ns.IsDecimalSource || precision != -1)
- return FormatGeneral (ns, precision, nfi, specifier == 'G', false);
- return FormatDecimal (ns, precision, nfi);
- case 'n':
- case 'N':
- return FormatNumber (ns, precision, nfi);
- case 'p':
- case 'P':
- return FormatPercent (ns, precision, nfi);
- case 'r':
- case 'R':
- if (ns.IsFloatingSource) {
- return FormatGeneral (ns, ns.DefaultPrecision, nfi, true, true);
- } else {
- throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
- }
- default:
- throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
- }
+ #region Static Fields
+
+ const int DefaultExpPrecision = 6;
+ const int HundredMillion = 100000000;
+ const long SeventeenDigitsThreshold = 10000000000000000;
+ const ulong ULongDivHundredMillion = UInt64.MaxValue / HundredMillion;
+ const ulong ULongModHundredMillion = 1 + UInt64.MaxValue % HundredMillion;
+
+ const int DoubleBitsExponentShift = 52;
+ const int DoubleBitsExponentMask = 0x7ff;
+ const long DoubleBitsMantissaMask = 0xfffffffffffff;
+ const int DecimalBitsScaleMask = 0x1f0000;
+
+ const int SingleDefPrecision = 7;
+ const int DoubleDefPrecision = 15;
+ const int Int8DefPrecision = 3;
+ const int UInt8DefPrecision = 3;
+ const int Int16DefPrecision = 5;
+ const int UInt16DefPrecision = 5;
+ const int Int32DefPrecision = 10;
+ const int UInt32DefPrecision = 10;
+ const int Int64DefPrecision = 19;
+ const int UInt64DefPrecision = 20;
+ const int DecimalDefPrecision = 100;
+ const int TenPowersListLength = 19;
+
+ const double MinRoundtripVal = -1.79769313486231E+308;
+ const double MaxRoundtripVal = 1.79769313486231E+308;
+
+#if UNSAFE_TABLES
+ // The below arrays are taken from mono/metatdata/number-formatter.h
+
+ private static readonly unsafe ulong* MantissaBitsTable;
+ private static readonly unsafe int* TensExponentTable;
+ private static readonly unsafe char* DigitLowerTable;
+ private static readonly unsafe char* DigitUpperTable;
+ private static readonly unsafe long* TenPowersList;
+
+ // DecHexDigits s a translation table from a decimal number to its
+ // digits hexadecimal representation (e.g. DecHexDigits [34] = 0x34).
+ private static readonly unsafe int* DecHexDigits;
+
+ [MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
+ private unsafe static extern void GetFormatterTables (out ulong* MantissaBitsTable, out int* TensExponentTable,
+ out char* DigitLowerTable, out char* DigitUpperTable,
+ out long* TenPowersList, out int* DecHexDigits);
+
+ unsafe static NumberFormatter()
+ {
+ GetFormatterTables (out MantissaBitsTable, out TensExponentTable,
+ out DigitLowerTable, out DigitUpperTable, out TenPowersList, out DecHexDigits);
}
- #endregion
- #region BasicParser
- private static void ParseBasicFormat (string format, out char specifier, out int precision, out bool custom)
+ unsafe
+#endif
+ static long GetTenPowerOf(int i)
{
- if (format == null || format.Length == 0) {
- precision = -1;
- specifier = 'G';
- custom = false;
- return;
- }
+ return TenPowersList [i];
+ }
+ #endregion Static Fields
- precision = -1;
- specifier = format[0];
- custom = false;
+ #region Fields
- if (Char.IsLetter (specifier)) {
- if (format.Length == 1)
- return;
+ private NumberFormatInfo _nfi;
- bool flag = true;
- precision = 0;
- for (int i = 1; i < format.Length; i++) {
- char c = format [i];
- if (char.IsDigit (c)) {
- precision = precision * 10 + (c - '0');
- if (precision > 99) {
- flag = false;
- break;
- }
- }
- else {
- flag = false;
- break;
- }
- }
- if (flag)
- return;
- }
+ //part of the private stringbuffer
+ private char[] _cbuf;
- custom = true;
- return;
- }
+ private bool _NaN;
+ private bool _infinity;
+ private bool _isCustomFormat;
+ private bool _specifierIsUpper;
+ private bool _positive;
+ private char _specifier;
+ private int _precision;
+ private int _defPrecision;
- #endregion
+ private int _digitsLen;
+ private int _offset; // Represent the first digit offset.
+ private int _decPointPos;
- #region Helpers
- private static void ZeroTrimEnd (StringBuilder sb)
- {
- ZeroTrimEnd (sb, false);
- }
- private static void ZeroTrimEnd (StringBuilder sb, bool canEmpty)
- {
- int len = 0;
- for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i --) {
- if (sb [i] != '0')
- break;
- len ++;
- }
+ // The following fields are a hexadeimal representation of the digits.
+ // For instance _val = 0x234 represents the digits '2', '3', '4'.
+ private uint _val1; // Digits 0 - 7.
+ private uint _val2; // Digits 8 - 15.
+ private uint _val3; // Digits 16 - 23.
+ private uint _val4; // Digits 23 - 31. Only needed for decimals.
- if (len > 0)
- sb.Remove (sb.Length - len, len);
- }
- #endregion
+ #endregion Fields
- #region Basic
- internal static string FormatCurrency (NumberStore ns, int precision, NumberFormatInfo nfi)
- {
- precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
- ns.RoundDecimal (precision);
- StringBuilder sb = new StringBuilder (ns.IntegerDigits * 2 + precision * 2 + 16);
- bool needNegativeSign = !ns.Positive && !ns.ZeroOnly;
+ #region Constructor Helpers
- if (!needNegativeSign) {
- switch (nfi.CurrencyPositivePattern) {
- case 0:
- sb.Append (nfi.CurrencySymbol);
- break;
- case 2:
- sb.Append (nfi.CurrencySymbol);
- sb.Append (' ');
- break;
- }
- } else {
- switch (nfi.CurrencyNegativePattern) {
- case 0:
- sb.Append ('(');
- sb.Append (nfi.CurrencySymbol);
- break;
- case 1:
- sb.Append (nfi.NegativeSign);
- sb.Append (nfi.CurrencySymbol);
- break;
- case 2:
- sb.Append (nfi.CurrencySymbol);
- sb.Append (nfi.NegativeSign);
- break;
- case 3:
- sb.Append (nfi.CurrencySymbol);
- break;
- case 4:
- sb.Append ('(');
- break;
- case 5:
- sb.Append (nfi.NegativeSign);
- break;
- case 8:
- sb.Append (nfi.NegativeSign);
- break;
- case 9:
- sb.Append (nfi.NegativeSign);
- sb.Append (nfi.CurrencySymbol);
- sb.Append (' ');
- break;
- case 11:
- sb.Append (nfi.CurrencySymbol);
- sb.Append (' ');
- break;
- case 12:
- sb.Append (nfi.CurrencySymbol);
- sb.Append (' ');
- sb.Append (nfi.NegativeSign);
- break;
- case 14:
- sb.Append ('(');
- sb.Append (nfi.CurrencySymbol);
- sb.Append (' ');
- break;
- case 15:
- sb.Append ('(');
- break;
- }
+ // Translate an unsigned int to hexadecimal digits.
+ // i.e. 123456789 is represented by _val1 = 0x23456789 and _val2 = 0x1
+ private void InitDecHexDigits (uint value)
+ {
+ if (value >= HundredMillion) {
+ int div1 = (int)(value / HundredMillion);
+ value -= HundredMillion * (uint)div1;
+ _val2 = FastToDecHex (div1);
}
+ _val1 = ToDecHex ((int)value);
+ }
- ns.AppendIntegerStringWithGroupSeparator (sb, nfi.CurrencyGroupSizes, nfi.CurrencyGroupSeparator);
-
- if (precision > 0)
- {
- sb.Append (nfi.CurrencyDecimalSeparator);
- ns.AppendDecimalString (precision, sb);
- }
+ // Translate an unsigned long to hexadecimal digits.
+ private void InitDecHexDigits (ulong value)
+ {
+ if (value >= HundredMillion) {
+ long div1 = (long)(value / HundredMillion);
+ value -= HundredMillion * (ulong)div1;
+ if (div1 >= HundredMillion) {
+ int div2 = (int)(div1 / HundredMillion);
+ div1 = div1 - div2 * (long)HundredMillion;
+ _val3 = ToDecHex (div2);
+ }
+ if (div1 != 0)
+ _val2 = ToDecHex ((int)(div1));
+ }
+ if (value != 0)
+ _val1 = ToDecHex ((int)value);
+ }
- if (!needNegativeSign) {
- switch (nfi.CurrencyPositivePattern) {
- case 1:
- sb.Append (nfi.CurrencySymbol);
- break;
- case 3:
- sb.Append (' ');
- sb.Append (nfi.CurrencySymbol);
- break;
- }
- } else {
- switch (nfi.CurrencyNegativePattern) {
- case 0:
- sb.Append (')');
- break;
- case 3:
- sb.Append (nfi.NegativeSign);
- break;
- case 4:
- sb.Append (nfi.CurrencySymbol);
- sb.Append (')');
- break;
- case 5:
- sb.Append (nfi.CurrencySymbol);
- break;
- case 6:
- sb.Append (nfi.NegativeSign);
- sb.Append (nfi.CurrencySymbol);
- break;
- case 7:
- sb.Append (nfi.CurrencySymbol);
- sb.Append (nfi.NegativeSign);
- break;
- case 8:
- sb.Append (' ');
- sb.Append (nfi.CurrencySymbol);
- break;
- case 10:
- sb.Append (' ');
- sb.Append (nfi.CurrencySymbol);
- sb.Append (nfi.NegativeSign);
- break;
- case 11:
- sb.Append (nfi.NegativeSign);
- break;
- case 13:
- sb.Append (nfi.NegativeSign);
- sb.Append (' ');
- sb.Append (nfi.CurrencySymbol);
- break;
- case 14:
- sb.Append (')');
- break;
- case 15:
- sb.Append (' ');
- sb.Append (nfi.CurrencySymbol);
- sb.Append (')');
- break;
- }
+ // Translate a decimal integer to hexadecimal digits.
+ // The decimal integer is 96 digits and its value is hi * 2^64 + lo.
+ // is the lower 64 bits.
+ private void InitDecHexDigits (uint hi, ulong lo)
+ {
+ if (hi == 0) {
+ InitDecHexDigits (lo); // Only the lower 64 bits matter.
+ return;
}
- return sb.ToString ();
+ // Compute (hi, lo) = (hi , lo) / HundredMillion.
+ uint divhi = hi / HundredMillion;
+ ulong remhi = hi - divhi * HundredMillion;
+ ulong divlo = lo / HundredMillion;
+ ulong remlo = lo - divlo * HundredMillion + remhi * ULongModHundredMillion;
+ hi = divhi;
+ lo = divlo + remhi * ULongDivHundredMillion;
+ divlo = remlo / HundredMillion;
+ remlo -= divlo * HundredMillion;
+ lo += divlo;
+ _val1 = ToDecHex ((int)remlo);
+
+ // Divide hi * 2 ^ 64 + lo by HundredMillion using the fact that
+ // hi < HundredMillion.
+ divlo = lo / HundredMillion;
+ remlo = lo - divlo * HundredMillion;
+ lo = divlo;
+ if (hi != 0) {
+ lo += hi * ULongDivHundredMillion;
+ remlo += hi * ULongModHundredMillion;
+ divlo = remlo / HundredMillion;
+ lo += divlo;
+ remlo -= divlo * HundredMillion;
+ }
+ _val2 = ToDecHex ((int)remlo);
+
+ // Now we are left with 64 bits store in lo.
+ if (lo >= HundredMillion) {
+ divlo = lo / HundredMillion;
+ lo -= divlo * HundredMillion;
+ _val4 = ToDecHex ((int)divlo);
+ }
+ _val3 = ToDecHex ((int)lo);
}
- internal static string FormatDecimal (NumberStore ns, int precision, NumberFormatInfo nfi)
- {
- if (ns.IsFloatingSource || ns.IsDecimalSource)
- throw new FormatException ();
- precision = precision > 0 ? precision : 1;
- precision = ns.IntegerDigits > precision ? ns.IntegerDigits : precision;
+ // Helper to translate an int in the range 0 .. 9999 to its
+ // Hexadecimal digits representation.
+#if UNSAFE_TABLES
+ unsafe
+#endif
+ private static uint FastToDecHex (int val)
+ {
+ if (val < 100)
+ return (uint)DecHexDigits [val];
- StringBuilder sb = new StringBuilder (precision + nfi.NegativeSign.Length);
+ // Uses 2^19 (524288) to compute val / 100 for val < 10000.
+ int v = (val * 5243) >> 19;
+ return (uint)((DecHexDigits [v] << 8) | DecHexDigits [val - v * 100]);
+ }
- if (!ns.Positive && !ns.CheckZeroOnlyInteger ()) {
- sb.Append (nfi.NegativeSign);
+ // Helper to translate an int in the range 0 .. 99999999 to its
+ // Hexadecimal digits representation.
+ private static uint ToDecHex (int val)
+ {
+ uint res = 0;
+ if (val >= 10000) {
+ int v = val / 10000;
+ val -= v * 10000;
+ res = FastToDecHex (v) << 16;
}
-
- ns.AppendIntegerString (precision, sb);
-
- return sb.ToString ();
+ return res | FastToDecHex (val);
}
- internal static string FormatFixedPoint (NumberStore ns, int precision, NumberFormatInfo nfi)
- {
- precision = precision >= 0 ? precision : nfi.NumberDecimalDigits;
- ns.RoundDecimal (precision);
- StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + nfi.NumberDecimalSeparator.Length);
-
- if (!ns.Positive && !ns.ZeroOnly)
- cb.Append (nfi.NegativeSign);
+ // Helper to count number of hexadecimal digits in a number.
+ private static int FastDecHexLen (int val)
+ {
+ if (val < 0x100)
+ if (val < 0x10)
+ return 1;
+ else
+ return 2;
+ else if (val < 0x1000)
+ return 3;
+ else
+ return 4;
+ }
- ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
+ private static int DecHexLen (uint val)
+ {
+ if (val < 0x10000)
+ return FastDecHexLen ((int)val);
+ return 4 + FastDecHexLen ((int)(val >> 16));
+ }
- if (precision > 0) {
- cb.Append (nfi.NumberDecimalSeparator);
- ns.AppendDecimalString (precision, cb);
- }
+ // Count number of hexadecimal digits stored in _val1 .. _val4.
+ private int DecHexLen ()
+ {
+ if (_val4 != 0)
+ return DecHexLen (_val4) + 24;
+ else if (_val3 != 0)
+ return DecHexLen (_val3) + 16;
+ else if (_val2 != 0)
+ return DecHexLen (_val2) + 8;
+ else if (_val1 != 0)
+ return DecHexLen (_val1);
+ else
+ return 0;
+ }
- return cb.ToString ();
+ // Helper to count the 10th scale (number of digits) in a number
+ private static int ScaleOrder (long hi)
+ {
+ for (int i = TenPowersListLength - 1; i >= 0; i--)
+ if (hi >= GetTenPowerOf (i))
+ return i + 1;
+ return 1;
}
- internal static string FormatGeneral (NumberStore ns)
+ // Compute the initial precision for rounding a floating number
+ // according to the used format.
+ int InitialFloatingPrecision ()
{
- return FormatGeneral (ns, -1, NumberFormatInfo.CurrentInfo, true, false);
+ if (_specifier == 'R')
+ return _defPrecision + 2;
+ if (_precision < _defPrecision)
+ return _defPrecision;
+ if (_specifier == 'G')
+ return Math.Min (_defPrecision + 2, _precision);
+ if (_specifier == 'E')
+ return Math.Min (_defPrecision + 2, _precision + 1);
+ return _defPrecision;
}
- internal static string FormatGeneral (NumberStore ns, IFormatProvider provider)
+
+ // Parse the given format and extract the precision in it.
+ // Returns -1 for empty formats and -2 to indicate that the format
+ // is a custom format.
+ private static int ParsePrecision (string format)
{
- return FormatGeneral (ns, -1, NumberFormatInfo.GetInstance (provider), true, false);
+ int precision = 0;
+ for (int i = 1; i < format.Length; i++) {
+ int val = format [i] - '0';
+ precision = precision * 10 + val;
+ if (val < 0 || val > 9 || precision > 99)
+ return -2;
+ }
+ return precision;
}
- private static string FormatGeneral (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper, bool roundtrip)
+
+ #endregion Constructor Helpers
+
+ #region Constructors
+
+ // Parse the given format and initialize the following fields:
+ // _isCustomFormat, _specifierIsUpper, _specifier & _precision.
+ public NumberFormatter (Thread current)
{
- if (ns.ZeroOnly)
- return "0";
+ _cbuf = EmptyArray<char>.Value;
+ if (current == null)
+ return;
+ CurrentCulture = current.CurrentCulture;
+ }
- precision = precision > 0 ? precision : ns.DefaultPrecision;
-
- int exponent = 0;
- bool expMode = (ns.IsDecimalSource && precision == ns.DefaultPrecision ? false : (ns.IntegerDigits > precision || ns.DecimalPointPosition <= -4));
- if (expMode) {
- while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
- if (ns.DecimalPointPosition > 1) {
- ns.Divide10 (1);
- exponent ++;
- } else {
- ns.Multiply10 (1);
- exponent --;
- }
- }
+ private void Init (string format)
+ {
+ _val1 = _val2 = _val3 = _val4 = 0;
+ _offset = 0;
+ _NaN = _infinity = false;
+ _isCustomFormat = false;
+ _specifierIsUpper = true;
+ _precision = -1;
+
+ if (format == null || format.Length == 0) {
+ _specifier = 'G';
+ return;
}
- precision = precision < ns.DefaultPrecision + 2 ? (precision < ns.DefaultMaxPrecision ? precision : ns.DefaultMaxPrecision) : ns.DefaultPrecision + 2;
- StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + 16);
- if (expMode) {
- if (ns.RoundDecimal (precision - 1)) {
- ns.Divide10 (1);
- exponent ++;
+ char specifier = format [0];
+ if (specifier >= 'a' && specifier <= 'z') {
+ specifier = (char)(specifier - 'a' + 'A');
+ _specifierIsUpper = false;
+ }
+ else if (specifier < 'A' || specifier > 'Z') {
+ _isCustomFormat = true;
+ _specifier = '0';
+ return;
+ }
+ _specifier = specifier;
+ if (format.Length > 1) {
+ _precision = ParsePrecision (format);
+ if (_precision == -2) { // Is it a custom format?
+ _isCustomFormat = true;
+ _specifier = '0';
+ _precision = -1;
}
- } else if (!roundtrip) {
- if (ns.IsDecimalSource)
- ns.RoundPos (precision);
- else
- ns.RoundDecimal (precision, true, false);
}
+ }
- if (!ns.Positive) {
- cb.Append (nfi.NegativeSign);
- }
+ private void InitHex (ulong value)
+ {
+ switch (_defPrecision) {
+ case Int8DefPrecision: value = (byte) value; break;
+ case Int16DefPrecision: value = (ushort) value; break;
+ case Int32DefPrecision: value = (uint) value; break;
+ }
+ _val1 = (uint)value;
+ _val2 = (uint)(value >> 32);
+ _decPointPos = _digitsLen = DecHexLen ();
+ if (value == 0)
+ _decPointPos = 1;
+ }
- ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
+ private void Init (string format, int value, int defPrecision)
+ {
+ Init (format);
+ _defPrecision = defPrecision;
+ _positive = value >= 0;
- if (ns.DecimalDigits > 0) {
- cb.Append (nfi.NumberDecimalSeparator);
- ns.AppendDecimalString (ns.DecimalDigits, cb);
+ if (value == 0 || _specifier == 'X') {
+ InitHex ((ulong)value);
+ return;
}
- if (expMode) {
- if (upper)
- cb.Append ('E');
- else
- cb.Append ('e');
+ if (value < 0)
+ value = -value;
+ InitDecHexDigits ((uint)value);
+ _decPointPos = _digitsLen = DecHexLen ();
+ }
- if (exponent >= 0)
- cb.Append (nfi.PositiveSign);
- else {
- cb.Append (nfi.NegativeSign);
- exponent = -exponent;
- }
+ private void Init (string format, uint value, int defPrecision)
+ {
+ Init (format);
+ _defPrecision = defPrecision;
+ _positive = true;
- if (exponent == 0) {
- cb.Append ('0', 2);
- } else if (exponent < 10) {
- cb.Append ('0');
- cb.Append (digitLowerTable [exponent]);
- } else if (exponent < 100) {
- cb.Append (digitLowerTable [exponent / 10 % 10]);
- cb.Append (digitLowerTable [exponent % 10]);
- } else if (exponent < 1000) {
- cb.Append (digitLowerTable [exponent / 100 % 10]);
- cb.Append (digitLowerTable [exponent / 10 % 10]);
- cb.Append (digitLowerTable [exponent % 10]);
- }
+ if (value == 0 || _specifier == 'X') {
+ InitHex (value);
+ return;
}
- return cb.ToString ();
+ InitDecHexDigits (value);
+ _decPointPos = _digitsLen = DecHexLen ();
}
- internal static string FormatNumber (NumberStore ns, int precision, NumberFormatInfo nfi)
- {
- precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
- StringBuilder sb = new StringBuilder(ns.IntegerDigits * 3 + precision);
- ns.RoundDecimal (precision);
- bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
+ private void Init (string format, long value)
+ {
+ Init (format);
+ _defPrecision = Int64DefPrecision;
+ _positive = value >= 0;
- if (needNegativeSign) {
- switch (nfi.NumberNegativePattern) {
- case 0:
- sb.Append ('(');
- break;
- case 1:
- sb.Append (nfi.NegativeSign);
- break;
- case 2:
- sb.Append (nfi.NegativeSign);
- sb.Append (' ');
- break;
- }
+ if (value == 0 || _specifier == 'X') {
+ InitHex ((ulong)value);
+ return;
}
- ns.AppendIntegerStringWithGroupSeparator (sb, nfi.NumberGroupSizes, nfi.NumberGroupSeparator);
+ if (value < 0)
+ value = -value;
+ InitDecHexDigits ((ulong)value);
+ _decPointPos = _digitsLen = DecHexLen ();
+ }
- if (precision > 0) {
- sb.Append (nfi.NumberDecimalSeparator);
- ns.AppendDecimalString (precision, sb);
- }
+ private void Init (string format, ulong value)
+ {
+ Init (format);
+ _defPrecision = UInt64DefPrecision;
+ _positive = true;
- if (needNegativeSign) {
- switch (nfi.NumberNegativePattern) {
- case 0:
- sb.Append (')');
- break;
- case 3:
- sb.Append (nfi.NegativeSign);
- break;
- case 4:
- sb.Append (' ');
- sb.Append (nfi.NegativeSign);
- break;
- }
+ if (value == 0 || _specifier == 'X') {
+ InitHex ((ulong)value);
+ return;
}
- return sb.ToString ();
+ InitDecHexDigits (value);
+ _decPointPos = _digitsLen = DecHexLen ();
}
- internal static string FormatPercent (NumberStore ns, int precision, NumberFormatInfo nfi)
- {
- precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
- ns.Multiply10 (2);
- ns.RoundDecimal (precision);
- bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
- StringBuilder sb = new StringBuilder(ns.IntegerDigits * 2 + precision + 16);
-
- if (!needNegativeSign) {
- if (nfi.PercentPositivePattern == 2) {
- sb.Append (nfi.PercentSymbol);
- }
- } else {
- switch (nfi.PercentNegativePattern) {
- case 0:
- sb.Append (nfi.NegativeSign);
- break;
- case 1:
- sb.Append (nfi.NegativeSign);
- break;
- case 2:
- sb.Append (nfi.NegativeSign);
- sb.Append (nfi.PercentSymbol);
- break;
- }
+#if UNSAFE_TABLES // No unsafe code under TARGET_JVM
+ unsafe
+#endif
+ private void Init (string format, double value, int defPrecision)
+ {
+ Init (format);
+
+ _defPrecision = defPrecision;
+ long bits = BitConverter.DoubleToInt64Bits (value);
+ _positive = bits >= 0;
+ bits &= Int64.MaxValue;
+ if (bits == 0) {
+ _decPointPos = 1;
+ _digitsLen = 0;
+ _positive = true;
+ return;
}
- ns.AppendIntegerStringWithGroupSeparator (sb, nfi.PercentGroupSizes, nfi.PercentGroupSeparator);
-
- if (precision > 0) {
- sb.Append (nfi.PercentDecimalSeparator);
- ns.AppendDecimalString (precision, sb);
+ int e = (int)(bits >> DoubleBitsExponentShift);
+ long m = bits & DoubleBitsMantissaMask;
+ if (e == DoubleBitsExponentMask) {
+ _NaN = m != 0;
+ _infinity = m == 0;
+ return;
}
- if (!needNegativeSign) {
- switch (nfi.PercentPositivePattern) {
- case 0:
- sb.Append (' ');
- sb.Append (nfi.PercentSymbol);
- break;
- case 1:
- sb.Append (nfi.PercentSymbol);
- break;
- }
- } else {
- switch (nfi.PercentNegativePattern) {
- case 0:
- sb.Append (' ');
- sb.Append (nfi.PercentSymbol);
- break;
- case 1:
- sb.Append (nfi.PercentSymbol);
- break;
+ int expAdjust = 0;
+ if (e == 0) {
+ // We need 'm' to be large enough so we won't lose precision.
+ e = 1;
+ int scale = ScaleOrder (m);
+ if (scale < DoubleDefPrecision) {
+ expAdjust = scale - DoubleDefPrecision;
+ m *= GetTenPowerOf (-expAdjust);
}
}
-
- return sb.ToString ();
+ else {
+ m = (m + DoubleBitsMantissaMask + 1) * 10;
+ expAdjust = -1;
+ }
+
+ // multiply the mantissa by 10 ^ N
+ ulong lo = (uint)m;
+ ulong hi = (ulong)m >> 32;
+ ulong lo2 = MantissaBitsTable [e];
+ ulong hi2 = lo2 >> 32;
+ lo2 = (uint)lo2;
+ ulong mm = hi * lo2 + lo * hi2 + ((lo * lo2) >> 32);
+ long res = (long)(hi * hi2 + (mm >> 32));
+ while (res < SeventeenDigitsThreshold) {
+ mm = (mm & UInt32.MaxValue) * 10;
+ res = res * 10 + (long)(mm >> 32);
+ expAdjust--;
+ }
+ if ((mm & 0x80000000) != 0)
+ res++;
+
+ int order = DoubleDefPrecision + 2;
+ _decPointPos = TensExponentTable [e] + expAdjust + order;
+
+ // Rescale 'res' to the initial precision (15-17 for doubles).
+ int initialPrecision = InitialFloatingPrecision ();
+ if (order > initialPrecision) {
+ long val = GetTenPowerOf (order - initialPrecision);
+ res = (res + (val >> 1)) / val;
+ order = initialPrecision;
+ }
+ if (res >= GetTenPowerOf (order)) {
+ order++;
+ _decPointPos++;
+ }
+
+ InitDecHexDigits ((ulong)res);
+ _offset = CountTrailingZeros ();
+ _digitsLen = order - _offset;
}
- unsafe static string FormatHexadecimal (ulong value, bool positive, int byteSize, int precision, bool upper)
+
+ private void Init (string format, decimal value)
{
- if (!positive) {
- /* for large values the cast to ulong is going to return 0 anyway (at least on x86, possibly a MS/Mono runtime bug) */
-#if FALSE
- if (byteSize < 8) {
- value = (ulong)(Math.Pow (2, byteSize * 8)) - value;
- } else {
- value = 0 - value;
- }
-#else
- switch (byteSize) {
- case 1:
- value = (ulong)(256UL - value);
- break;
- case 2:
- value = (ulong)(65536UL - value);
- break;
- case 4:
- value = (ulong)(4294967296UL - value);
- break;
- case 8:
- value = 0 - value;
- break;
- }
-#endif
+ Init (format);
+ _defPrecision = DecimalDefPrecision;
+
+ int[] bits = decimal.GetBits (value);
+ int scale = (bits [3] & DecimalBitsScaleMask) >> 16;
+ _positive = bits [3] >= 0;
+ if (bits [0] == 0 && bits [1] == 0 && bits [2] == 0) {
+ _decPointPos = -scale;
+ _positive = true;
+ _digitsLen = 0;
+ return;
}
- char[] digits = (upper ? digitUpperTable : digitLowerTable);
- int size = precision > 16 ? precision : 16;
- char* buffer = stackalloc char [size];
- char* last = buffer + size;
- char* ptr = last;
-
- while (value > 0) {
- *--ptr = digits[value & 0xF];
- value >>= 4;
+ InitDecHexDigits ((uint)bits [2], ((ulong)bits [1] << 32) | (uint)bits [0]);
+ _digitsLen = DecHexLen ();
+ _decPointPos = _digitsLen - scale;
+ if (_precision != -1 || _specifier != 'G') {
+ _offset = CountTrailingZeros ();
+ _digitsLen -= _offset;
}
-
- while (ptr == last || last - ptr < precision)
- *--ptr = '0';
-
- return new string (ptr, 0, (int)(last - ptr));
}
- internal static string FormatExponential (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper)
- {
- if (precision < 0)
- precision = 6;
- if (ns.ZeroOnly) {
- StringBuilder sb = new StringBuilder (precision + nfi.PositiveSign.Length + 6);
- sb.Append ('0');
- if (precision > 0) {
- sb.Append ('.');
- sb.Append ('0', precision);
- }
+ #endregion Constructors
- if (upper)
- sb.Append ('E');
- else
- sb.Append ('e');
+ #region Inner String Buffer
- sb.Append (nfi.PositiveSign);
- sb.Append ('0', 3);
-
- return sb.ToString ();
- }
+ //_cbuf moved to before other fields to improve layout
+ private int _ind;
- int exponent = 0;
- while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
- if (ns.DecimalPointPosition > 1) {
- ns.Divide10 (1);
- exponent ++;
- } else {
- ns.Multiply10 (1);
- exponent --;
- }
- }
+ private void ResetCharBuf (int size)
+ {
+ _ind = 0;
+ if (_cbuf.Length < size)
+ _cbuf = new char [size];
+ }
- if (ns.RoundDecimal (precision)) {
- ns.Divide10 (1);
- exponent ++;
- }
+ private void Resize (int len)
+ {
+ Array.Resize (ref _cbuf, len);
+ }
- StringBuilder cb = new StringBuilder (ns.DecimalDigits + 1 + 8);
+ private void Append (char c)
+ {
+ if (_ind == _cbuf.Length)
+ Resize (_ind + 10);
+ _cbuf [_ind++] = c;
+ }
- if (!ns.Positive) {
- cb.Append (nfi.NegativeSign);
- }
+ private void Append (char c, int cnt)
+ {
+ if (_ind + cnt > _cbuf.Length)
+ Resize (_ind + cnt + 10);
+ while (cnt-- > 0)
+ _cbuf [_ind++] = c;
+ }
- ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
+ private void Append (string s)
+ {
+ int slen = s.Length;
+ if (_ind + slen > _cbuf.Length)
+ Resize (_ind + slen + 10);
+ for (int i = 0; i < slen; i++)
+ _cbuf [_ind++] = s [i];
+ }
- if (precision > 0) {
- cb.Append (nfi.NumberDecimalSeparator);
- ns.AppendDecimalString (precision, cb);
- }
+ #endregion Inner String Buffer
- if (upper)
- cb.Append ('E');
- else
- cb.Append ('e');
+ #region Helper properties
- if (exponent >= 0)
- cb.Append (nfi.PositiveSign);
- else {
- cb.Append (nfi.NegativeSign);
- exponent = -exponent;
+ private NumberFormatInfo GetNumberFormatInstance (IFormatProvider fp)
+ {
+ if (_nfi != null && fp == null)
+ return _nfi;
+ return NumberFormatInfo.GetInstance (fp);
+ }
+
+ public CultureInfo CurrentCulture {
+ set {
+ if (value != null && value.IsReadOnly)
+ _nfi = value.NumberFormat;
+ else
+ _nfi = null;
}
+ }
- if (exponent == 0) {
- cb.Append ('0', 3);
- } else if (exponent < 10) {
- cb.Append ('0', 2);
- cb.Append (digitLowerTable [exponent]);
- } else if (exponent < 100) {
- cb.Append ('0', 1);
- cb.Append (digitLowerTable [exponent / 10 % 10]);
- cb.Append (digitLowerTable [exponent % 10]);
- } else if (exponent < 1000) {
- cb.Append (digitLowerTable [exponent / 100 % 10]);
- cb.Append (digitLowerTable [exponent / 10 % 10]);
- cb.Append (digitLowerTable [exponent % 10]);
- /*} else { // exponent range is 0...+-324
- int pos = cb.Length;
- int count = 3;
- while (exponent > 0 || --count > 0) {
- cb.Insert (pos, digitLowerTable [exponent % 10]);
- exponent /= 10;
- }*/
- }
-
- return cb.ToString ();
+ private int IntegerDigits {
+ get { return _decPointPos > 0 ? _decPointPos : 1; }
+ }
+
+ private int DecimalDigits {
+ get { return _digitsLen > _decPointPos ? _digitsLen - _decPointPos : 0; }
+ }
+
+ private bool IsFloatingSource {
+ get { return _defPrecision == DoubleDefPrecision || _defPrecision == SingleDefPrecision; }
+ }
+
+ private bool IsZero {
+ get { return _digitsLen == 0; }
}
- #endregion
- #region Custom
- internal static string FormatCustom (string format, NumberStore ns, NumberFormatInfo nfi)
+ private bool IsZeroInteger {
+ get { return _digitsLen == 0 || _decPointPos <= 0; }
+ }
+
+ #endregion Helper properties
+
+ #region Round
+
+ private void RoundPos (int pos)
{
- bool p = ns.Positive;
- int offset = 0;
- int length = 0;
- CustomInfo.GetActiveSection (format,ref p, ns.ZeroOnly, ref offset, ref length);
- if (length == 0) {
- return ns.Positive ? String.Empty : nfi.NegativeSign;
- }
- ns.Positive = p;
+ RoundBits (_digitsLen - pos);
+ }
- CustomInfo info = CustomInfo.Parse (format, offset, length, nfi);
-#if false
- Console.WriteLine("Format : {0}",format);
- Console.WriteLine("DecimalDigits : {0}",info.DecimalDigits);
- Console.WriteLine("DecimalPointPos : {0}",info.DecimalPointPos);
- Console.WriteLine("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
- Console.WriteLine("IntegerDigits : {0}",info.IntegerDigits);
- Console.WriteLine("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
- Console.WriteLine("IntegerHeadPos : {0}",info.IntegerHeadPos);
- Console.WriteLine("UseExponent : {0}",info.UseExponent);
- Console.WriteLine("ExponentDigits : {0}",info.ExponentDigits);
- Console.WriteLine("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
- Console.WriteLine("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
- Console.WriteLine("DividePlaces : {0}",info.DividePlaces);
- Console.WriteLine("Percents : {0}",info.Percents);
- Console.WriteLine("Permilles : {0}",info.Permilles);
-#endif
- StringBuilder sb_int = new StringBuilder(info.IntegerDigits * 2);
- StringBuilder sb_dec = new StringBuilder(info.DecimalDigits * 2);
- StringBuilder sb_exp = (info.UseExponent ? new StringBuilder(info.ExponentDigits * 2) : null);
+ private bool RoundDecimal (int decimals)
+ {
+ return RoundBits (_digitsLen - _decPointPos - decimals);
+ }
- int diff = 0;
- if (info.Percents > 0) {
- ns.Multiply10 (2 * info.Percents);
- }
- if (info.Permilles > 0) {
- ns.Multiply10 (3 * info.Permilles);
- }
- if (info.DividePlaces > 0) {
- ns.Divide10 (info.DividePlaces);
+ private bool RoundBits (int shift)
+ {
+ if (shift <= 0)
+ return false;
+
+ if (shift > _digitsLen) {
+ _digitsLen = 0;
+ _decPointPos = 1;
+ _val1 = _val2 = _val3 = _val4 = 0;
+ _positive = true;
+ return false;
}
+ shift += _offset;
+ _digitsLen += _offset;
+ while (shift > 8) {
+ _val1 = _val2;
+ _val2 = _val3;
+ _val3 = _val4;
+ _val4 = 0;
+ _digitsLen -= 8;
+ shift -= 8;
+ }
+ shift = (shift - 1) << 2;
+ uint v = _val1 >> shift;
+ uint rem16 = v & 0xf;
+ _val1 = (v ^ rem16) << shift;
+ bool res = false;
+ if (rem16 >= 0x5) {
+ _val1 |= 0x99999999 >> (28 - shift);
+ AddOneToDecHex ();
+ int newlen = DecHexLen ();
+ res = newlen != _digitsLen;
+ _decPointPos = _decPointPos + newlen - _digitsLen;
+ _digitsLen = newlen;
+ }
+ RemoveTrailingZeros ();
+ return res;
+ }
- bool expPositive = true;
- if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
- if (!ns.ZeroOnly) {
- while (true) {
- while (ns.IntegerDigits > info.IntegerDigits) {
- ns.Divide10 (1);
- diff--;
- if (ns.IntegerDigits == 1 && ns.GetChar (0) == '0')
- break;
- }
- while (ns.IntegerDigits < info.IntegerDigits || (ns.IntegerDigits == info.IntegerDigits && ns.GetChar (0) == '0')) {
- ns.Multiply10 (1);
- diff++;
- }
+ private void RemoveTrailingZeros ()
+ {
+ _offset = CountTrailingZeros ();
+ _digitsLen -= _offset;
+ if (_digitsLen == 0) {
+ _offset = 0;
+ _decPointPos = 1;
+ _positive = true;
+ }
+ }
- if (!ns.RoundDecimal (info.DecimalDigits))
- break;
+ private void AddOneToDecHex ()
+ {
+ if (_val1 == 0x99999999) {
+ _val1 = 0;
+ if (_val2 == 0x99999999) {
+ _val2 = 0;
+ if (_val3 == 0x99999999) {
+ _val3 = 0;
+ _val4 = AddOneToDecHex (_val4);
}
+ else
+ _val3 = AddOneToDecHex (_val3);
}
-
- expPositive = diff <= 0;
- NumberStore.AppendIntegerStringFromUInt32 (sb_exp, (uint)(diff >= 0 ? diff : -diff));
- } else {
- ns.RoundDecimal (info.DecimalDigits);
- if (ns.ZeroOnly)
- ns.Positive = true;
+ else
+ _val2 = AddOneToDecHex (_val2);
}
+ else
+ _val1 = AddOneToDecHex (_val1);
+ }
- if (info.IntegerDigits != 0 || !ns.CheckZeroOnlyInteger ()) {
- ns.AppendIntegerString (ns.IntegerDigits, sb_int);
- }
- /* if (sb_int.Length > info.IntegerDigits) {
- int len = 0;
- while (sb_int.Length > info.IntegerDigits && len < sb_int.Length) {
- if (sb_int [len] == '0')
- len ++;
+ // Assume val != 0x99999999
+ private static uint AddOneToDecHex (uint val)
+ {
+ if ((val & 0xffff) == 0x9999)
+ if ((val & 0xffffff) == 0x999999)
+ if ((val & 0xfffffff) == 0x9999999)
+ return val + 0x06666667;
else
- break;
- }
- sb_int.Remove (0, len);
- } */
+ return val + 0x00666667;
+ else if ((val & 0xfffff) == 0x99999)
+ return val + 0x00066667;
+ else
+ return val + 0x00006667;
+ else if ((val & 0xff) == 0x99)
+ if ((val & 0xfff) == 0x999)
+ return val + 0x00000667;
+ else
+ return val + 0x00000067;
+ else if ((val & 0xf) == 0x9)
+ return val + 0x00000007;
+ else
+ return val + 1;
+ }
- ns.AppendDecimalString (ns.DecimalDigits, sb_dec);
+ private int CountTrailingZeros ()
+ {
+ if (_val1 != 0)
+ return CountTrailingZeros (_val1);
+ if (_val2 != 0)
+ return CountTrailingZeros (_val2) + 8;
+ if (_val3 != 0)
+ return CountTrailingZeros (_val3) + 16;
+ if (_val4 != 0)
+ return CountTrailingZeros (_val4) + 24;
+ return _digitsLen;
+ }
- if (info.UseExponent) {
- if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
- ns.Positive = true;
+ private static int CountTrailingZeros (uint val)
+ {
+ if ((val & 0xffff) == 0)
+ if ((val & 0xffffff) == 0)
+ if ((val & 0xfffffff) == 0)
+ return 7;
+ else
+ return 6;
+ else if ((val & 0xfffff) == 0)
+ return 5;
+ else
+ return 4;
+ else if ((val & 0xff) == 0)
+ if ((val & 0xfff) == 0)
+ return 3;
+ else
+ return 2;
+ else if ((val & 0xf) == 0)
+ return 1;
+ else
+ return 0;
+ }
- if (sb_int.Length < info.IntegerDigits)
- sb_int.Insert (0, "0", info.IntegerDigits - sb_int.Length);
+ #endregion Round
- while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
- sb_exp.Insert (0, '0');
+ #region public number formatting methods
- if (expPositive && !info.ExponentNegativeSignOnly)
- sb_exp.Insert (0, nfi.PositiveSign);
- else if(!expPositive)
- sb_exp.Insert (0, nfi.NegativeSign);
- } else {
- if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
- sb_int.Insert (0, "0", info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
- if (info.IntegerDigits == info.IntegerHeadSharpDigits && NumberStore.IsZeroOnly (sb_int))
- sb_int.Remove (0, sb_int.Length);
- }
+ [ThreadStatic]
+ static NumberFormatter threadNumberFormatter;
- ZeroTrimEnd (sb_dec, true);
- while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
- sb_dec.Append ('0');
- if (sb_dec.Length > info.DecimalDigits)
- sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);
+ private static NumberFormatter GetInstance()
+ {
+ NumberFormatter res = threadNumberFormatter;
+ threadNumberFormatter = null;
+ if (res == null)
+ return new NumberFormatter (Thread.CurrentThread);
+ res.CurrentCulture = Thread.CurrentThread.CurrentCulture;
+ return res;
+ }
- return info.Format (format, offset, length, nfi, ns.Positive, sb_int, sb_dec, sb_exp);
+ private void Release()
+ {
+ threadNumberFormatter = this;
}
- private class CustomInfo
+ public static string NumberToString (string format, sbyte value, IFormatProvider fp)
{
- public bool UseGroup = false;
- public int DecimalDigits = 0;
- public int DecimalPointPos = -1;
- public int DecimalTailSharpDigits = 0;
- public int IntegerDigits = 0;
- public int IntegerHeadSharpDigits = 0;
- public int IntegerHeadPos = 0;
- public bool UseExponent = false;
- public int ExponentDigits = 0;
- public int ExponentTailSharpDigits = 0;
- public bool ExponentNegativeSignOnly = true;
- public int DividePlaces = 0;
- public int Percents = 0;
- public int Permilles = 0;
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value, Int8DefPrecision);
+ string res = inst.IntegerToString (format, fp);
+ inst.Release();
+ return res;
+ }
- public static void GetActiveSection (string format, ref bool positive, bool zero, ref int offset, ref int length)
- {
- int[] lens = new int [3];
- int index = 0;
- int lastPos = 0;
- char literal = '\0';
- for (int i = 0; i < format.Length; i++) {
- char c = format [i];
+ public static string NumberToString (string format, byte value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value, UInt8DefPrecision);
+ string res = inst.IntegerToString (format, fp);
+ inst.Release();
+ return res;
+ }
- if (c == literal || (literal == '\0' && (c == '\"' || c == '\''))) {
- if (literal == '\0')
- literal = c;
- else
- literal = '\0';
- continue;
- }
-
- if (literal == '\0' && format [i] == ';' && (i == 0 || format [i - 1] != '\\')) {
- lens [index ++] = i - lastPos;
- lastPos = i + 1;
- if (index == 3)
- break;
- }
- }
+ public static string NumberToString (string format, ushort value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value, Int16DefPrecision);
+ string res = inst.IntegerToString (format, fp);
+ inst.Release();
+ return res;
+ }
- if (index == 0) {
- offset = 0;
- length = format.Length;
- return;
- }
- if (index == 1) {
- if (positive || zero) {
- offset = 0;
- length = lens [0];
- return;
- }
- if (lens [0] + 1 < format.Length) {
- positive = true;
- offset = lens [0] + 1;
- length = format.Length - offset;
- return;
- } else {
- offset = 0;
- length = lens [0];
- return;
- }
- }
- if (index == 2) {
- if (zero) {
- offset = lens [0] + lens [1] + 2;
- length = format.Length - offset;
- return;
- }
- if (positive) {
- offset = 0;
- length = lens [0];
- return;
- }
- if (lens [1] > 0) {
- positive = true;
- offset = lens [0] + 1;
- length = lens [1];
- return;
- } else {
- offset = 0;
- length = lens [0];
- return;
- }
- }
- if (index == 3) {
- if (zero) {
- offset = lens [0] + lens [1] + 2;
- length = lens [2];
- return;
- }
- if (positive) {
- offset = 0;
- length = lens [0];
- return;
- }
- if (lens [1] > 0) {
- positive = true;
- offset = lens [0] + 1;
- length = lens [1];
- return;
- } else {
- offset = 0;
- length = lens [0];
- return;
- }
- }
+ public static string NumberToString (string format, short value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value, UInt16DefPrecision);
+ string res = inst.IntegerToString (format, fp);
+ inst.Release();
+ return res;
+ }
- throw new ArgumentException ();
- }
+ public static string NumberToString (string format, uint value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value, Int32DefPrecision);
+ string res = inst.IntegerToString (format, fp);
+ inst.Release();
+ return res;
+ }
- public static CustomInfo Parse (string format, int offset, int length, NumberFormatInfo nfi)
- {
- char literal = '\0';
- bool integerArea = true;
- bool decimalArea = false;
- bool exponentArea = false;
- bool sharpContinues = true;
+ public static string NumberToString (string format, int value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value, UInt32DefPrecision);
+ string res = inst.IntegerToString (format, fp);
+ inst.Release();
+ return res;
+ }
- CustomInfo info = new CustomInfo ();
- int groupSeparatorCounter = 0;
+ public static string NumberToString (string format, ulong value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value);
+ string res = inst.IntegerToString (format, fp);
+ inst.Release();
+ return res;
+ }
- for (int i = offset; i - offset < length; i++) {
- char c = format [i];
+ public static string NumberToString (string format, long value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value);
+ string res = inst.IntegerToString (format, fp);
+ inst.Release();
+ return res;
+ }
- if (c == literal && c != '\0') {
- literal = '\0';
- continue;
- }
- if (literal != '\0')
- continue;
+ public static string NumberToString (string format, float value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value, SingleDefPrecision);
+ NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
+ string res;
+ if (inst._NaN)
+ res = nfi.NaNSymbol;
+ else if (inst._infinity)
+ if (inst._positive)
+ res = nfi.PositiveInfinitySymbol;
+ else
+ res = nfi.NegativeInfinitySymbol;
+ else if (inst._specifier == 'R')
+ res = inst.FormatRoundtrip (value, nfi);
+ else
+ res = inst.NumberToString (format, nfi);
+ inst.Release();
+ return res;
+ }
- if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
- exponentArea = false;
- integerArea = (info.DecimalPointPos < 0);
- decimalArea = !integerArea;
- i--;
- continue;
- }
+ public static string NumberToString (string format, double value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value, DoubleDefPrecision);
+ NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
+ string res;
+ if (inst._NaN)
+ res = nfi.NaNSymbol;
+ else if (inst._infinity)
+ if (inst._positive)
+ res = nfi.PositiveInfinitySymbol;
+ else
+ res = nfi.NegativeInfinitySymbol;
+ else if (inst._specifier == 'R')
+ res = inst.FormatRoundtrip (value, nfi);
+ else
+ res = inst.NumberToString (format, nfi);
+ inst.Release();
+ return res;
+ }
- switch (c) {
- case '\\':
- i ++;
- continue;
- case '\'':
- case '\"':
- if (c == '\"' || c == '\'') {
- literal = c;
- }
- continue;
- case '#':
- if (sharpContinues && integerArea)
- info.IntegerHeadSharpDigits ++;
- else if (decimalArea)
- info.DecimalTailSharpDigits ++;
- else if (exponentArea)
- info.ExponentTailSharpDigits ++;
+ public static string NumberToString (string format, decimal value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (format, value);
+ string res = inst.NumberToString (format, inst.GetNumberFormatInstance (fp));
+ inst.Release();
+ return res;
+ }
- goto case '0';
- case '0':
- if (c != '#') {
- sharpContinues = false;
- if (decimalArea)
- info.DecimalTailSharpDigits = 0;
- else if (exponentArea)
- info.ExponentTailSharpDigits = 0;
- }
- if (info.IntegerHeadPos == -1)
- info.IntegerHeadPos = i;
+ public static string NumberToString (uint value, IFormatProvider fp)
+ {
+ if (value >= HundredMillion)
+ return NumberToString (null, value, fp);
- if (integerArea) {
- info.IntegerDigits ++;
- if (groupSeparatorCounter > 0)
- info.UseGroup = true;
- groupSeparatorCounter = 0;
- } else if (decimalArea) {
- info.DecimalDigits ++;
- } else if (exponentArea) {
- info.ExponentDigits ++;
- }
- break;
- case 'e':
- case 'E':
- if (info.UseExponent)
- break;
+ NumberFormatter inst = GetInstance();
+ string res = inst.FastIntegerToString ((int)value, fp);
+ inst.Release();
+ return res;
+ }
- info.UseExponent = true;
- integerArea = false;
- decimalArea = false;
- exponentArea = true;
- if (i + 1 - offset < length) {
- char nc = format [i + 1];
- if (nc == '+')
- info.ExponentNegativeSignOnly = false;
- if (nc == '+' || nc == '-') {
- i ++;
- } else if (nc != '0' && nc != '#') {
- info.UseExponent = false;
- if (info.DecimalPointPos < 0)
- integerArea = true;
- }
- c = '\0';
- }
-
- break;
- case '.':
- integerArea = false;
- decimalArea = true;
- exponentArea = false;
- if (info.DecimalPointPos == -1)
- info.DecimalPointPos = i;
- break;
- case '%':
- info.Percents++;
- break;
- case '\u2030':
- info.Permilles++;
- break;
- case ',':
- if (integerArea && info.IntegerDigits > 0)
- groupSeparatorCounter ++;
- break;
- default:
- break;
- }
- }
+ public static string NumberToString (int value, IFormatProvider fp)
+ {
+ if (value >= HundredMillion || value <= -HundredMillion)
+ return NumberToString (null, value, fp);
- if (info.ExponentDigits == 0)
- info.UseExponent = false;
- else
- info.IntegerHeadSharpDigits = 0;
+ NumberFormatter inst = GetInstance();
+ string res = inst.FastIntegerToString (value, fp);
+ inst.Release();
+ return res;
+ }
- if (info.DecimalDigits == 0)
- info.DecimalPointPos = -1;
+ public static string NumberToString (ulong value, IFormatProvider fp)
+ {
+ if (value >= HundredMillion)
+ return NumberToString (null, value, fp);
- info.DividePlaces += groupSeparatorCounter * 3;
+ NumberFormatter inst = GetInstance();
+ string res = inst.FastIntegerToString ((int)value, fp);
+ inst.Release();
+ return res;
+ }
- return info;
- }
+ public static string NumberToString (long value, IFormatProvider fp)
+ {
+ if (value >= HundredMillion || value <= -HundredMillion)
+ return NumberToString (null, value, fp);
- public string Format (string format, int offset, int length, NumberFormatInfo nfi, bool positive, StringBuilder sb_int, StringBuilder sb_dec, StringBuilder sb_exp)
- {
- StringBuilder sb = new StringBuilder ();
- char literal = '\0';
- bool integerArea = true;
- bool decimalArea = false;
- int intSharpCounter = 0;
- int sb_int_index = 0;
- int sb_dec_index = 0;
+ NumberFormatter inst = GetInstance();
+ string res = inst.FastIntegerToString ((int)value, fp);
+ inst.Release();
+ return res;
+ }
- int[] groups = nfi.NumberGroupSizes;
- string groupSeparator = nfi.NumberGroupSeparator;
- int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0, fraction = 0;
- if (UseGroup && groups.Length > 0) {
- intLen = sb_int.Length;
- for (int i = 0; i < groups.Length; i++) {
- total += groups [i];
- if (total <= intLen)
- groupIndex = i;
- }
- groupSize = groups [groupIndex];
- fraction = intLen > total ? intLen - total : 0;
- if (groupSize == 0) {
- while (groupIndex >= 0 && groups [groupIndex] == 0)
- groupIndex --;
-
- groupSize = fraction > 0 ? fraction : groups [groupIndex];
- }
- if (fraction == 0) {
- counter = groupSize;
- } else {
- groupIndex += fraction / groupSize;
- counter = fraction % groupSize;
- if (counter == 0)
- counter = groupSize;
- else
- groupIndex ++;
- }
- } else {
- UseGroup = false;
- }
+ public static string NumberToString (float value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ inst.Init (null, value, SingleDefPrecision);
+ NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
+ string res;
+ if (inst._NaN)
+ res = nfi.NaNSymbol;
+ else if (inst._infinity)
+ if (inst._positive)
+ res = nfi.PositiveInfinitySymbol;
+ else
+ res = nfi.NegativeInfinitySymbol;
+ else
+ res = inst.FormatGeneral (-1, nfi);
+ inst.Release();
+ return res;
+ }
- for (int i = offset; i - offset < length; i++) {
- char c = format [i];
+ public static string NumberToString (double value, IFormatProvider fp)
+ {
+ NumberFormatter inst = GetInstance();
+ NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
+ inst.Init (null, value, DoubleDefPrecision);
+ string res;
+ if (inst._NaN)
+ res = nfi.NaNSymbol;
+ else if (inst._infinity)
+ if (inst._positive)
+ res = nfi.PositiveInfinitySymbol;
+ else
+ res = nfi.NegativeInfinitySymbol;
+ else
+ res = inst.FormatGeneral (-1, nfi);
+ inst.Release();
+ return res;
+ }
- if (c == literal && c != '\0') {
- literal = '\0';
- continue;
- }
- if (literal != '\0') {
- sb.Append (c);
- continue;
- }
+ private string FastIntegerToString (int value, IFormatProvider fp)
+ {
+ if (value < 0) {
+ string sign = GetNumberFormatInstance(fp).NegativeSign;
+ ResetCharBuf (8 + sign.Length);
+ value = -value;
+ Append (sign);
+ }
+ else
+ ResetCharBuf (8);
- switch (c) {
- case '\\':
- i ++;
- if (i - offset < length)
- sb.Append (format [i]);
- continue;
- case '\'':
- case '\"':
- if (c == '\"' || c == '\'') {
- literal = c;
- }
- continue;
- case '#':
- goto case '0';
- case '0':
- if (integerArea) {
- intSharpCounter++;
- if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
- while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
- sb.Append (sb_int[ sb_int_index++]);
- if (UseGroup && --intLen > 0 && --counter == 0) {
- sb.Append (groupSeparator);
- if (--groupIndex < groups.Length && groupIndex >= 0)
- groupSize = groups [groupIndex];
- counter = groupSize;
- }
- }
- break;
- } else if (decimalArea) {
- if (sb_dec_index < sb_dec.Length)
- sb.Append (sb_dec [sb_dec_index++]);
- break;
- }
+ if (value >= 10000) {
+ int v = value / 10000;
+ FastAppendDigits (v, false);
+ FastAppendDigits (value - v * 10000, true);
+ }
+ else
+ FastAppendDigits (value, false);
- sb.Append (c);
- break;
- case 'e':
- case 'E':
- if (sb_exp == null || !UseExponent) {
- sb.Append (c);
- break;
- }
+ return new string (_cbuf, 0, _ind);
+ }
- bool flag1 = true;
- bool flag2 = false;
-
- int q;
- for (q = i + 1; q - offset < length; q++) {
- if (format [q] == '0') {
- flag2 = true;
- continue;
- }
- if (q == i + 1 && (format [q] == '+' || format [q] == '-')) {
- continue;
- }
- if (!flag2)
- flag1 = false;
- break;
- }
+ private string IntegerToString (string format, IFormatProvider fp)
+ {
+ NumberFormatInfo nfi = GetNumberFormatInstance (fp);
+ switch (_specifier) {
+ case 'C':
+ return FormatCurrency (_precision, nfi);
+ case 'D':
+ return FormatDecimal (_precision, nfi);
+ case 'E':
+ return FormatExponential (_precision, nfi);
+ case 'F':
+ return FormatFixedPoint (_precision, nfi);
+ case 'G':
+ if (_precision <= 0)
+ return FormatDecimal (-1, nfi);
+ return FormatGeneral (_precision, nfi);
+ case 'N':
+ return FormatNumber (_precision, nfi);
+ case 'P':
+ return FormatPercent (_precision, nfi);
+ case 'X':
+ return FormatHexadecimal (_precision);
+ default:
+ if (_isCustomFormat)
+ return FormatCustom (format, nfi);
+ throw new FormatException ("The specified format '" + format + "' is invalid");
+ }
+ }
- if (flag1) {
- i = q - 1;
- integerArea = (DecimalPointPos < 0);
- decimalArea = !integerArea;
+ private string NumberToString (string format, NumberFormatInfo nfi)
+ {
+ switch (_specifier) {
+ case 'C':
+ return FormatCurrency (_precision, nfi);
+ case 'E':
+ return FormatExponential (_precision, nfi);
+ case 'F':
+ return FormatFixedPoint (_precision, nfi);
+ case 'G':
+ return FormatGeneral (_precision, nfi);
+ case 'N':
+ return FormatNumber (_precision, nfi);
+ case 'P':
+ return FormatPercent (_precision, nfi);
+ case 'X':
+ default:
+ if (_isCustomFormat)
+ return FormatCustom (format, nfi);
+ throw new FormatException ("The specified format '" + format + "' is invalid");
+ }
+ }
- sb.Append (c);
- sb.Append (sb_exp);
- sb_exp = null;
- } else
- sb.Append (c);
+ public string FormatCurrency (int precision, NumberFormatInfo nfi)
+ {
+ precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
+ RoundDecimal (precision);
+ ResetCharBuf (IntegerDigits * 2 + precision * 2 + 16);
- break;
- case '.':
- if (DecimalPointPos == i) {
- if (DecimalDigits > 0) {
- while (sb_int_index < sb_int.Length)
- sb.Append (sb_int [sb_int_index++]);
- }
- if (sb_dec.Length > 0)
- sb.Append (nfi.NumberDecimalSeparator);
- }
- integerArea = false;
- decimalArea = true;
- break;
- case ',':
- break;
- case '%':
- sb.Append (nfi.PercentSymbol);
- break;
- case '\u2030':
- sb.Append (nfi.PerMilleSymbol);
- break;
- default:
- sb.Append (c);
- break;
- }
+ if (_positive) {
+ switch (nfi.CurrencyPositivePattern) {
+ case 0:
+ Append (nfi.CurrencySymbol);
+ break;
+ case 2:
+ Append (nfi.CurrencySymbol);
+ Append (' ');
+ break;
+ }
+ }
+ else {
+ switch (nfi.CurrencyNegativePattern) {
+ case 0:
+ Append ('(');
+ Append (nfi.CurrencySymbol);
+ break;
+ case 1:
+ Append (nfi.NegativeSign);
+ Append (nfi.CurrencySymbol);
+ break;
+ case 2:
+ Append (nfi.CurrencySymbol);
+ Append (nfi.NegativeSign);
+ break;
+ case 3:
+ Append (nfi.CurrencySymbol);
+ break;
+ case 4:
+ Append ('(');
+ break;
+ case 5:
+ Append (nfi.NegativeSign);
+ break;
+ case 8:
+ Append (nfi.NegativeSign);
+ break;
+ case 9:
+ Append (nfi.NegativeSign);
+ Append (nfi.CurrencySymbol);
+ Append (' ');
+ break;
+ case 11:
+ Append (nfi.CurrencySymbol);
+ Append (' ');
+ break;
+ case 12:
+ Append (nfi.CurrencySymbol);
+ Append (' ');
+ Append (nfi.NegativeSign);
+ break;
+ case 14:
+ Append ('(');
+ Append (nfi.CurrencySymbol);
+ Append (' ');
+ break;
+ case 15:
+ Append ('(');
+ break;
+ }
+ }
+
+ AppendIntegerStringWithGroupSeparator (nfi.RawCurrencyGroupSizes, nfi.CurrencyGroupSeparator);
+
+ if (precision > 0) {
+ Append (nfi.CurrencyDecimalSeparator);
+ AppendDecimalString (precision);
+ }
+
+ if (_positive) {
+ switch (nfi.CurrencyPositivePattern) {
+ case 1:
+ Append (nfi.CurrencySymbol);
+ break;
+ case 3:
+ Append (' ');
+ Append (nfi.CurrencySymbol);
+ break;
+ }
+ }
+ else {
+ switch (nfi.CurrencyNegativePattern) {
+ case 0:
+ Append (')');
+ break;
+ case 3:
+ Append (nfi.NegativeSign);
+ break;
+ case 4:
+ Append (nfi.CurrencySymbol);
+ Append (')');
+ break;
+ case 5:
+ Append (nfi.CurrencySymbol);
+ break;
+ case 6:
+ Append (nfi.NegativeSign);
+ Append (nfi.CurrencySymbol);
+ break;
+ case 7:
+ Append (nfi.CurrencySymbol);
+ Append (nfi.NegativeSign);
+ break;
+ case 8:
+ Append (' ');
+ Append (nfi.CurrencySymbol);
+ break;
+ case 10:
+ Append (' ');
+ Append (nfi.CurrencySymbol);
+ Append (nfi.NegativeSign);
+ break;
+ case 11:
+ Append (nfi.NegativeSign);
+ break;
+ case 13:
+ Append (nfi.NegativeSign);
+ Append (' ');
+ Append (nfi.CurrencySymbol);
+ break;
+ case 14:
+ Append (')');
+ break;
+ case 15:
+ Append (' ');
+ Append (nfi.CurrencySymbol);
+ Append (')');
+ break;
}
+ }
- if (!positive)
- sb.Insert (0, nfi.NegativeSign);
+ return new string (_cbuf, 0, _ind);
+ }
- return sb.ToString ();
- }
+ private string FormatDecimal (int precision, NumberFormatInfo nfi)
+ {
+ if (precision < _digitsLen)
+ precision = _digitsLen;
+ if (precision == 0)
+ return "0";
+
+ ResetCharBuf (precision + 1);
+ if (!_positive)
+ Append (nfi.NegativeSign);
+ AppendDigits (0, precision);
+
+ return new string (_cbuf, 0, _ind);
}
- #endregion
+#if UNSAFE_TABLES // No unsafe code under TARGET_JVM
+ unsafe
+#endif
+ private string FormatHexadecimal (int precision)
+ {
+ int size = Math.Max (precision, _decPointPos);
+#if UNSAFE_TABLES
+ char* digits = _specifierIsUpper ? DigitUpperTable : DigitLowerTable;
+#else
+ char[] digits = _specifierIsUpper ? DigitUpperTable : DigitLowerTable;
+#endif
+ ResetCharBuf (size);
+ _ind = size;
+ ulong val = _val1 | ((ulong)_val2 << 32);
+ while (size > 0) {
+ _cbuf [--size] = digits [val & 0xf];
+ val >>= 4;
+ }
+ return new string (_cbuf, 0, _ind);
+ }
- #region Internal structures
- internal struct NumberStore
- {
- public bool ToStringVerificationNeeded;
-
- bool _NaN;
- bool _infinity;
- bool _positive;
- int _decPointPos;
- int _defPrecision;
- int _defMaxPrecision;
- int _defByteSize;
-
- byte[] _digits;
-
- static uint [] IntList = new uint [] {
- 1,
- 10,
- 100,
- 1000,
- 10000,
- 100000,
- 1000000,
- 10000000,
- 100000000,
- 1000000000,
- };
-
- static ulong [] ULongList = new ulong [] {
- 1,
- 10,
- 100,
- 1000,
- 10000,
- 100000,
- 1000000,
- 10000000,
- 100000000,
- 1000000000,
- 10000000000,
- 100000000000,
- 1000000000000,
- 10000000000000,
- 100000000000000,
- 1000000000000000,
- 10000000000000000,
- 100000000000000000,
- 1000000000000000000,
- 10000000000000000000,
- };
-
- #region Constructors
- public NumberStore (long value)
- {
- ToStringVerificationNeeded = false;
+ public string FormatFixedPoint (int precision, NumberFormatInfo nfi)
+ {
+ if (precision == -1)
+ precision = nfi.NumberDecimalDigits;
- _infinity = _NaN = false;
- _defByteSize = 8;
- _defMaxPrecision = _defPrecision = 19;
- _positive = value >= 0;
+ RoundDecimal (precision);
- if (value == 0) {
- _digits = new byte []{0};
- _decPointPos = 1;
- return;
- }
-
- ulong v = (ulong)(_positive ? value : -value);
-
- int i = 18, j = 0;
-
- if (v < 10)
- i = 0;
- else if (v < 100)
- i = 1;
- else if (v < 1000)
- i = 2;
- else if (v < 10000)
- i = 3;
- else if (v < 100000)
- i = 4;
- else if (v < 1000000)
- i = 5;
- else if (v < 10000000)
- i = 6;
- else if (v < 100000000)
- i = 7;
- else if (v < 1000000000)
- i = 8;
- else if (v < 10000000000)
- i = 9;
- else if (v < 100000000000)
- i = 10;
- else if (v < 1000000000000)
- i = 11;
- else if (v < 10000000000000)
- i = 12;
- else if (v < 100000000000000)
- i = 13;
- else if (v < 1000000000000000)
- i = 14;
- else if (v < 10000000000000000)
- i = 15;
- else if (v < 100000000000000000)
- i = 16;
- else if (v < 1000000000000000000)
- i = 17;
- else
- i = 18;
+ ResetCharBuf (IntegerDigits + precision + 2);
+
+ if (!_positive)
+ Append (nfi.NegativeSign);
- _digits = new byte [i + 1];
- do {
- ulong n = v / ULongList [i];
- _digits [j++] = (byte)n;
- v -= ULongList [i--] * n;
- } while (i >= 0);
+ AppendIntegerString (IntegerDigits);
- _decPointPos = _digits.Length;
+ if (precision > 0) {
+ Append (nfi.NumberDecimalSeparator);
+ AppendDecimalString (precision);
}
- public NumberStore (int value)
- {
- ToStringVerificationNeeded = false;
- _infinity = _NaN = false;
- _defByteSize = 4;
- _defMaxPrecision = _defPrecision = 10;
- _positive = value >= 0;
+ return new string (_cbuf, 0, _ind);
+ }
- if (value == 0) {
- _digits = new byte []{0};
- _decPointPos = 1;
- return;
- }
-
- uint v = (uint)(_positive ? value : -value);
-
- int i = 9, j = 0;
-
- if (v < 10)
- i = 0;
- else if (v < 100)
- i = 1;
- else if (v < 1000)
- i = 2;
- else if (v < 10000)
- i = 3;
- else if (v < 100000)
- i = 4;
- else if (v < 1000000)
- i = 5;
- else if (v < 10000000)
- i = 6;
- else if (v < 100000000)
- i = 7;
- else if (v < 1000000000)
- i = 8;
- else
- i = 9;
+ private string FormatRoundtrip (double origval, NumberFormatInfo nfi)
+ {
+ NumberFormatter nfc = GetClone ();
+ if (origval >= MinRoundtripVal && origval <= MaxRoundtripVal) {
+ string shortRep = FormatGeneral (_defPrecision, nfi);
+ if (origval == Double.Parse (shortRep, nfi))
+ return shortRep;
+ }
+ return nfc.FormatGeneral (_defPrecision + 2, nfi);
+ }
- _digits = new byte [i + 1];
- do {
- uint n = v / IntList [i];
- _digits [j++] = (byte)n;
- v -= IntList [i--] * n;
- } while (i >= 0);
+ private string FormatRoundtrip (float origval, NumberFormatInfo nfi)
+ {
+ NumberFormatter nfc = GetClone ();
+ string shortRep = FormatGeneral (_defPrecision, nfi);
+ // Check roundtrip only for "normal" double values.
+ if (origval == Single.Parse (shortRep, nfi))
+ return shortRep;
+ return nfc.FormatGeneral (_defPrecision + 2, nfi);
+ }
- _decPointPos = _digits.Length;
+ private string FormatGeneral (int precision, NumberFormatInfo nfi)
+ {
+ bool enableExp;
+ if (precision == -1) {
+ enableExp = IsFloatingSource;
+ precision = _defPrecision;
}
- public NumberStore (short value) : this ((int)value)
- {
- _defByteSize = 2;
- _defMaxPrecision = _defPrecision = 5;
+ else {
+ enableExp = true;
+ if (precision == 0)
+ precision = _defPrecision;
+ RoundPos (precision);
}
- public NumberStore (sbyte value) : this ((int)value)
- {
- _defByteSize = 1;
- _defMaxPrecision = _defPrecision = 3;
+
+ int intDigits = _decPointPos;
+ int digits = _digitsLen;
+ int decDigits = digits - intDigits;
+
+ if ((intDigits > precision || intDigits <= -4) && enableExp)
+ return FormatExponential (digits - 1, nfi, 2);
+
+ if (decDigits < 0)
+ decDigits = 0;
+ if (intDigits < 0)
+ intDigits = 0;
+ ResetCharBuf (decDigits + intDigits + 3);
+
+ if (!_positive)
+ Append (nfi.NegativeSign);
+
+ if (intDigits == 0)
+ Append ('0');
+ else
+ AppendDigits (digits - intDigits, digits);
+
+ if (decDigits > 0) {
+ Append (nfi.NumberDecimalSeparator);
+ AppendDigits (0, decDigits);
}
- public NumberStore (ulong value)
- {
- ToStringVerificationNeeded = false;
+ return new string (_cbuf, 0, _ind);
+ }
- _infinity = _NaN = false;
- _defByteSize = 8;
- _defMaxPrecision = _defPrecision = 20;
- _positive = true;
+ public string FormatNumber (int precision, NumberFormatInfo nfi)
+ {
+ precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
+ ResetCharBuf (IntegerDigits * 3 + precision);
+ RoundDecimal (precision);
- if (value == 0) {
- _digits = new byte []{0};
- _decPointPos = 1;
- return;
+ if (!_positive) {
+ switch (nfi.NumberNegativePattern) {
+ case 0:
+ Append ('(');
+ break;
+ case 1:
+ Append (nfi.NegativeSign);
+ break;
+ case 2:
+ Append (nfi.NegativeSign);
+ Append (' ');
+ break;
}
+ }
- int i = 19, j = 0;
-
- if (value < 10)
- i = 0;
- else if (value < 100)
- i = 1;
- else if (value < 1000)
- i = 2;
- else if (value < 10000)
- i = 3;
- else if (value < 100000)
- i = 4;
- else if (value < 1000000)
- i = 5;
- else if (value < 10000000)
- i = 6;
- else if (value < 100000000)
- i = 7;
- else if (value < 1000000000)
- i = 8;
- else if (value < 10000000000)
- i = 9;
- else if (value < 100000000000)
- i = 10;
- else if (value < 1000000000000)
- i = 11;
- else if (value < 10000000000000)
- i = 12;
- else if (value < 100000000000000)
- i = 13;
- else if (value < 1000000000000000)
- i = 14;
- else if (value < 10000000000000000)
- i = 15;
- else if (value < 100000000000000000)
- i = 16;
- else if (value < 1000000000000000000)
- i = 17;
- else if (value < 10000000000000000000)
- i = 18;
- else
- i = 19;
+ AppendIntegerStringWithGroupSeparator (nfi.RawNumberGroupSizes, nfi.NumberGroupSeparator);
- _digits = new byte [i + 1];
- do {
- ulong n = value / ULongList [i];
- _digits [j++] = (byte)n;
- value -= ULongList [i--] * n;
- } while (i >= 0);
+ if (precision > 0) {
+ Append (nfi.NumberDecimalSeparator);
+ AppendDecimalString (precision);
+ }
- _decPointPos = _digits.Length;
+ if (!_positive) {
+ switch (nfi.NumberNegativePattern) {
+ case 0:
+ Append (')');
+ break;
+ case 3:
+ Append (nfi.NegativeSign);
+ break;
+ case 4:
+ Append (' ');
+ Append (nfi.NegativeSign);
+ break;
+ }
}
- public NumberStore (uint value)
- {
- ToStringVerificationNeeded = false;
- _infinity = _NaN = false;
- _positive = true;
- _defByteSize = 4;
- _defMaxPrecision = _defPrecision = 10;
+ return new string (_cbuf, 0, _ind);
+ }
- if (value == 0) {
- _digits = new byte []{0};
- _decPointPos = 1;
- return;
+ public string FormatPercent (int precision, NumberFormatInfo nfi)
+ {
+ precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
+ Multiply10(2);
+ RoundDecimal (precision);
+ ResetCharBuf (IntegerDigits * 2 + precision + 16);
+
+ if (_positive) {
+ if (nfi.PercentPositivePattern == 2)
+ Append (nfi.PercentSymbol);
+ }
+ else {
+ switch (nfi.PercentNegativePattern) {
+ case 0:
+ Append (nfi.NegativeSign);
+ break;
+ case 1:
+ Append (nfi.NegativeSign);
+ break;
+ case 2:
+ Append (nfi.NegativeSign);
+ Append (nfi.PercentSymbol);
+ break;
}
-
- int i = 9, j = 0;
-
- if (value < 10)
- i = 0;
- else if (value < 100)
- i = 1;
- else if (value < 1000)
- i = 2;
- else if (value < 10000)
- i = 3;
- else if (value < 100000)
- i = 4;
- else if (value < 1000000)
- i = 5;
- else if (value < 10000000)
- i = 6;
- else if (value < 100000000)
- i = 7;
- else if (value < 1000000000)
- i = 8;
- else
- i = 9;
+ }
- _digits = new byte [i + 1];
- do {
- uint n = value / IntList [i];
- _digits [j++] = (byte)n;
- value -= IntList [i--] * n;
- } while (i >= 0);
+ AppendIntegerStringWithGroupSeparator (nfi.RawPercentGroupSizes, nfi.PercentGroupSeparator);
- _decPointPos = _digits.Length;
+ if (precision > 0) {
+ Append (nfi.PercentDecimalSeparator);
+ AppendDecimalString (precision);
}
- public NumberStore (ushort value) : this ((uint)value)
- {
- _defByteSize = 2;
- _defMaxPrecision = _defPrecision = 5;
+
+ if (_positive) {
+ switch (nfi.PercentPositivePattern) {
+ case 0:
+ Append (' ');
+ Append (nfi.PercentSymbol);
+ break;
+ case 1:
+ Append (nfi.PercentSymbol);
+ break;
+ }
}
- public NumberStore (byte value) : this ((uint)value)
- {
- _defByteSize = 1;
- _defMaxPrecision = _defPrecision = 3;
+ else {
+ switch (nfi.PercentNegativePattern) {
+ case 0:
+ Append (' ');
+ Append (nfi.PercentSymbol);
+ break;
+ case 1:
+ Append (nfi.PercentSymbol);
+ break;
+ }
}
- public NumberStore(double value)
- {
- ToStringVerificationNeeded = true;
-
- _digits = null;
- _defByteSize = 64;
- _defPrecision = 15;
- _defMaxPrecision = _defPrecision + 2;
-
- if (double.IsNaN (value) || double.IsInfinity (value)) {
- _NaN = double.IsNaN (value);
- _infinity = double.IsInfinity (value);
- _positive = value > 0;
- _decPointPos = 0;
- return;
- } else {
- _NaN = _infinity = false;
- }
+ return new string (_cbuf, 0, _ind);
+ }
- long bits = BitConverter.DoubleToInt64Bits (value);
- _positive = (bits >= 0);
- int e = (int) ((bits >> 52) & 0x7ffL);
- long m = bits & 0xfffffffffffffL;
+ public string FormatExponential (int precision, NumberFormatInfo nfi)
+ {
+ if (precision == -1)
+ precision = DefaultExpPrecision;
- if (e == 0 && m == 0) {
- _decPointPos = 1;
- _digits = new byte []{0};
- _positive = true;
- return;
- }
+ RoundPos (precision + 1);
+ return FormatExponential (precision, nfi, 3);
+ }
- if (e == 0) {
- e ++;
- } else if (e != 0) {
- m |= (1L << 52);
- }
+ private string FormatExponential (int precision, NumberFormatInfo nfi, int expDigits)
+ {
+ int decDigits = _decPointPos;
+ int digits = _digitsLen;
+ int exponent = decDigits - 1;
+ decDigits = _decPointPos = 1;
- e -= 1075;
+ ResetCharBuf (precision + 8);
- int nsize = 0;
- while ((m & 1) == 0) {
- m >>= 1;
- e ++;
- nsize ++;
- }
+ if (!_positive)
+ Append (nfi.NegativeSign);
- long mt = m;
- int length = 1;
- byte[] temp = new byte [56];
- for (int i = temp.Length - 1; i >= 0; i--, length++) {
- temp [i] = (byte)(mt % 10);
- mt /= 10;
- if (mt == 0)
- break;
- }
+ AppendOneDigit (digits - 1);
- _decPointPos = temp.Length - 1;
+ if (precision > 0) {
+ Append (nfi.NumberDecimalSeparator);
+ AppendDigits (digits - precision - 1, digits - _decPointPos);
+ }
- if (e >= 0) {
- for (int i = 0; i < e; i++) {
- if (MultiplyBy (ref temp, ref length, 2)) {
- _decPointPos ++;
- }
- }
- } else {
- for (int i = 0; i < -e; i++) {
- if (MultiplyBy (ref temp, ref length, 5)) {
- _decPointPos ++;
- }
- }
- _decPointPos += e;
- }
+ AppendExponent (nfi, exponent, expDigits);
- int ulvc = 1;
- ulong ulv = 0;
- for (int i = 0; i < temp.Length; i++)
- if (temp [i] != 0) {
- _decPointPos -= i - 1;
- _digits = new byte [temp.Length - i];
- for (int q = i; q < temp.Length; q++) {
- _digits [q - i] = temp [q];
- if (ulvc < 20) {
- ulv = ulv * 10 + temp [q];
- ulvc ++;
- }
- }
- break;
- }
+ return new string (_cbuf, 0, _ind);
+ }
+
+ public string FormatCustom (string format, NumberFormatInfo nfi)
+ {
+ bool p = _positive;
+ int offset = 0;
+ int length = 0;
+ CustomInfo.GetActiveSection (format, ref p, IsZero, ref offset, ref length);
+ if (length == 0)
+ return _positive ? string.Empty : nfi.NegativeSign;
+ _positive = p;
- RoundEffectiveDigits (17, true, true);
+ CustomInfo info = CustomInfo.Parse (format, offset, length, nfi);
+#if false
+ Console.WriteLine ("Format : {0}",format);
+ Console.WriteLine ("DecimalDigits : {0}",info.DecimalDigits);
+ Console.WriteLine ("DecimalPointPos : {0}",info.DecimalPointPos);
+ Console.WriteLine ("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
+ Console.WriteLine ("IntegerDigits : {0}",info.IntegerDigits);
+ Console.WriteLine ("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
+ Console.WriteLine ("IntegerHeadPos : {0}",info.IntegerHeadPos);
+ Console.WriteLine ("UseExponent : {0}",info.UseExponent);
+ Console.WriteLine ("ExponentDigits : {0}",info.ExponentDigits);
+ Console.WriteLine ("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
+ Console.WriteLine ("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
+ Console.WriteLine ("DividePlaces : {0}",info.DividePlaces);
+ Console.WriteLine ("Percents : {0}",info.Percents);
+ Console.WriteLine ("Permilles : {0}",info.Permilles);
+#endif
+ StringBuilder sb_int = new StringBuilder (info.IntegerDigits * 2);
+ StringBuilder sb_dec = new StringBuilder (info.DecimalDigits * 2);
+ StringBuilder sb_exp = (info.UseExponent ? new StringBuilder (info.ExponentDigits * 2) : null);
+
+ int diff = 0;
+ if (info.Percents > 0)
+ Multiply10(2 * info.Percents);
+ if (info.Permilles > 0)
+ Multiply10(3 * info.Permilles);
+ if (info.DividePlaces > 0)
+ Divide10(info.DividePlaces);
+
+ bool expPositive = true;
+ if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
+ if (!IsZero) {
+ RoundPos (info.DecimalDigits + info.IntegerDigits);
+ diff -= _decPointPos - info.IntegerDigits;
+ _decPointPos = info.IntegerDigits;
+ }
+
+ expPositive = diff <= 0;
+ AppendNonNegativeNumber (sb_exp, diff < 0 ? -diff : diff);
}
- public NumberStore(float value)
- {
- ToStringVerificationNeeded = false;
-
- _digits = null;
- _defByteSize = 32;
- _defPrecision = 7;
- _defMaxPrecision = _defPrecision + 2;
-
- if (float.IsNaN (value) || float.IsInfinity (value)) {
- _NaN = float.IsNaN (value);
- _infinity = float.IsInfinity (value);
- _positive = value > 0;
- _decPointPos = 0;
- return;
- } else
- _infinity = _NaN = false;
+ else
+ RoundDecimal (info.DecimalDigits);
- long bits = BitConverter.DoubleToInt64Bits (value);
- _positive = (bits >= 0);
- int e = (int) ((bits >> 52) & 0x7ffL);
- long m = bits & 0xfffffffffffffL;
+ if (info.IntegerDigits != 0 || !IsZeroInteger)
+ AppendIntegerString (IntegerDigits, sb_int);
- if (e == 0 && m == 0) {
- _decPointPos = 1;
- _digits = new byte []{0};
+ AppendDecimalString (DecimalDigits, sb_dec);
+
+ if (info.UseExponent) {
+ if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
_positive = true;
- return;
- }
- if (e == 0) {
- e ++;
- } else if (e != 0) {
- m |= (1L << 52);
- }
+ if (sb_int.Length < info.IntegerDigits)
+ sb_int.Insert (0, "0", info.IntegerDigits - sb_int.Length);
- e -= 1075;
+ while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
+ sb_exp.Insert (0, '0');
- int nsize = 0;
- while ((m & 1) == 0) {
- m >>= 1;
- e ++;
- nsize ++;
- }
+ if (expPositive && !info.ExponentNegativeSignOnly)
+ sb_exp.Insert (0, nfi.PositiveSign);
+ else if (!expPositive)
+ sb_exp.Insert (0, nfi.NegativeSign);
+ }
+ else {
+ if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
+ sb_int.Insert (0, "0", info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
+ if (info.IntegerDigits == info.IntegerHeadSharpDigits && IsZeroOnly (sb_int))
+ sb_int.Remove (0, sb_int.Length);
+ }
- long mt = m;
- int length = 1;
- byte[] temp = new byte [26];
- for (int i = temp.Length - 1; i >= 0; i--, length++) {
- temp [i] = (byte)(mt % 10);
- mt /= 10;
- if (mt == 0)
- break;
- }
+ ZeroTrimEnd (sb_dec, true);
+ while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
+ sb_dec.Append ('0');
+ if (sb_dec.Length > info.DecimalDigits)
+ sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);
- _decPointPos = temp.Length - 1;
+ return info.Format (format, offset, length, nfi, _positive, sb_int, sb_dec, sb_exp);
+ }
+ #endregion public number formatting methods
- if (e >= 0) {
- for (int i = 0; i < e; i++) {
- if (MultiplyBy (ref temp, ref length, 2)) {
- _decPointPos ++;
- }
- }
- } else {
- for (int i = 0; i < -e; i++) {
- if (MultiplyBy (ref temp, ref length, 5)) {
- _decPointPos ++;
- }
- }
- _decPointPos += e;
- }
+ #region StringBuilder formatting helpers
- int ulvc = 1;
- ulong ulv = 0;
- for (int i = 0; i < temp.Length; i++)
- if (temp [i] != 0) {
- _decPointPos -= i - 1;
- _digits = new byte [temp.Length - i];
- for (int q = i; q < temp.Length; q++) {
- _digits [q - i] = temp [q];
- if (ulvc < 20) {
- ulv = ulv * 10 + temp [q];
- ulvc ++;
- }
- }
- break;
- }
+ private static void ZeroTrimEnd (StringBuilder sb, bool canEmpty)
+ {
+ int len = 0;
+ for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i--) {
+ if (sb [i] != '0')
+ break;
+ len++;
+ }
+
+ if (len > 0)
+ sb.Remove (sb.Length - len, len);
+ }
+
+ private static bool IsZeroOnly (StringBuilder sb)
+ {
+ for (int i = 0; i < sb.Length; i++)
+ if (char.IsDigit (sb [i]) && sb [i] != '0')
+ return false;
+ return true;
+ }
+
+ private static void AppendNonNegativeNumber (StringBuilder sb, int v)
+ {
+ if (v < 0)
+ throw new ArgumentException ();
+
+ int i = ScaleOrder (v) - 1;
+ do {
+ int n = v / (int)GetTenPowerOf (i);
+ sb.Append ((char)('0' | n));
+ v -= (int)GetTenPowerOf (i--) * n;
+ } while (i >= 0);
+ }
+
+ #endregion StringBuilder formatting helpers
+
+ #region Append helpers
- RoundEffectiveDigits (9, true, true);
+ private void AppendIntegerString (int minLength, StringBuilder sb)
+ {
+ if (_decPointPos <= 0) {
+ sb.Append ('0', minLength);
+ return;
}
- internal bool MultiplyBy (ref byte[] buffer,ref int length, int amount)
- {
- int mod = 0;
- int ret;
- int start = buffer.Length - length - 1;
- if (start < 0) start = 0;
-
- for (int i = buffer.Length - 1; i > start; i--) {
- ret = buffer [i] * amount + mod;
- mod = ret / 10;
- buffer [i] = (byte)(ret % 10);
- }
+ if (_decPointPos < minLength)
+ sb.Append ('0', minLength - _decPointPos);
- if (mod != 0) {
- length = buffer.Length - start;
+ AppendDigits (_digitsLen - _decPointPos, _digitsLen, sb);
+ }
- if (start == 0) {
- buffer [0] = (byte)mod;
- Array.Copy (buffer, 0, buffer, 1, buffer.Length - 1);
- buffer [0] = 0;
- return true;
- }
- else {
- buffer [start] = (byte)mod;
- }
- }
+ private void AppendIntegerString (int minLength)
+ {
+ if (_decPointPos <= 0) {
+ Append ('0', minLength);
+ return;
+ }
+
+ if (_decPointPos < minLength)
+ Append ('0', minLength - _decPointPos);
+
+ AppendDigits (_digitsLen - _decPointPos, _digitsLen);
+ }
+
+ private void AppendDecimalString (int precision, StringBuilder sb)
+ {
+ AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos, sb);
+ }
+
+ private void AppendDecimalString (int precision)
+ {
+ AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos);
+ }
+
+ private void AppendIntegerStringWithGroupSeparator (int[] groups, string groupSeparator)
+ {
+ if (IsZeroInteger) {
+ Append ('0');
+ return;
+ }
- return false;
+ int total = 0;
+ int groupIndex = 0;
+ for (int i = 0; i < groups.Length; i++) {
+ total += groups [i];
+ if (total <= _decPointPos)
+ groupIndex = i;
+ else
+ break;
}
+ if (groups.Length > 0 && total > 0) {
+ int counter;
+ int groupSize = groups [groupIndex];
+ int fraction = _decPointPos > total ? _decPointPos - total : 0;
+ if (groupSize == 0) {
+ while (groupIndex >= 0 && groups [groupIndex] == 0)
+ groupIndex--;
- public NumberStore (decimal value)
- {
- ToStringVerificationNeeded = false;
-
- int[] bits = decimal.GetBits (value);
- _positive = (bits [3] & 0x80000000) == 0;
- bits[3] = bits [3] & 0x7FFFFFFF;
- int ss = (bits [3] & 0x1F0000) >> 16;
- ulong lo = (ulong)((((ulong)bits[1]) << 32) | (uint)bits [0]);
- ulong hi = (uint)bits [2];
- uint rest = 0;
-
- int digits = 0;
- while (hi > 0 || lo > 0) {
- digits ++;
- DivideDecimal (ref lo, ref hi, 10, ref rest);
+ groupSize = fraction > 0 ? fraction : groups [groupIndex];
+ }
+ if (fraction == 0)
+ counter = groupSize;
+ else {
+ groupIndex += fraction / groupSize;
+ counter = fraction % groupSize;
+ if (counter == 0)
+ counter = groupSize;
+ else
+ groupIndex++;
}
- lo = (ulong)((((ulong)bits[1]) << 32) | (uint)bits [0]);
- hi = (uint)bits [2];
+ if (total >= _decPointPos) {
+ int lastGroupSize = groups [0];
+ if (total > lastGroupSize) {
+ int lastGroupDiff = -(lastGroupSize - _decPointPos);
+ int lastGroupMod;
- _digits = new byte [digits];
- int i = digits;
- while (hi > 0 || lo > 0) {
- DivideDecimal (ref lo, ref hi, 10, ref rest);
- _digits [--i] = (byte)rest;
+ if (lastGroupDiff < lastGroupSize)
+ counter = lastGroupDiff;
+ else if (lastGroupSize > 0 && (lastGroupMod = _decPointPos % lastGroupSize) > 0)
+ counter = lastGroupMod;
+ }
+ }
+
+ for (int i = 0; ;) {
+ if ((_decPointPos - i) <= counter || counter == 0) {
+ AppendDigits (_digitsLen - _decPointPos, _digitsLen - i);
+ break;
+ }
+ AppendDigits (_digitsLen - i - counter, _digitsLen - i);
+ i += counter;
+ Append (groupSeparator);
+ if (--groupIndex < groups.Length && groupIndex >= 0)
+ groupSize = groups [groupIndex];
+ counter = groupSize;
}
-
- _infinity = _NaN = false;
- _decPointPos = _digits.Length - ss;
- _defPrecision = _defMaxPrecision = 100;
- _defByteSize = 16;
- }
- static int DivideDecimal (ref ulong lo, ref ulong hi, uint factor, ref uint rest)
- {
- ulong a, b, c, h;
-
- h = hi;
- a = (uint)(h >> 32);
- b = a / factor;
- a -= b * factor;
- a <<= 32;
- a |= (uint) h;
- c = a / factor;
- a -= c * factor;
- a <<= 32;
- hi = b << 32 | (uint)c;
-
- h = lo;
- a |= (uint)(h >> 32);
- b = a / factor;
- a -= b * factor;
- a <<= 32;
- a |= (uint) h;
- c = a / factor;
- a -= c * factor;
- lo = b << 32 | (uint)c;
-
- rest = (uint)a;
-
- a <<= 1;
- return (a >= factor || (a == factor && (c & 1) == 1)) ? 1 : 0;
- }
- #endregion
-
- #region Public Property
- public bool IsNaN
- {
- get { return _NaN; }
- }
- public bool IsInfinity {
- get { return _infinity; }
- }
- public int DecimalPointPosition {
- get { return _decPointPos; }
- }
- public bool Positive {
- get { return _positive; }
- set { _positive = value;}
- }
- public int DefaultPrecision {
- get { return _defPrecision; }
- }
- public int DefaultMaxPrecision {
- get { return _defMaxPrecision; }
- }
- public int DefaultByteSize {
- get { return _defByteSize; }
}
- public bool HasDecimal {
- get { return _digits.Length > _decPointPos; }
+ else {
+ AppendDigits (_digitsLen - _decPointPos, _digitsLen);
}
- public int IntegerDigits {
- get { return _decPointPos > 0 ? _decPointPos : 1; }
+ }
+
+ // minDigits is in the range 1..3
+ private void AppendExponent (NumberFormatInfo nfi, int exponent, int minDigits)
+ {
+ if (_specifierIsUpper || _specifier == 'R')
+ Append ('E');
+ else
+ Append ('e');
+
+ if (exponent >= 0)
+ Append (nfi.PositiveSign);
+ else {
+ Append (nfi.NegativeSign);
+ exponent = -exponent;
}
- public int DecimalDigits {
- get { return HasDecimal ? _digits.Length - _decPointPos : 0; }
+
+ if (exponent == 0)
+ Append ('0', minDigits);
+ else if (exponent < 10) {
+ Append ('0', minDigits - 1);
+ Append ((char)('0' | exponent));
}
- public bool IsFloatingSource {
- get { return _defPrecision == 15 || _defPrecision == 7; }
+ else {
+ uint hexDigit = FastToDecHex (exponent);
+ if (exponent >= 100 || minDigits == 3)
+ Append ((char)('0' | (hexDigit >> 8)));
+ Append ((char)('0' | ((hexDigit >> 4) & 0xf)));
+ Append ((char)('0' | (hexDigit & 0xf)));
}
- public bool IsDecimalSource {
- get { return _defPrecision > 30; }
+ }
+
+ private void AppendOneDigit (int start)
+ {
+ if (_ind == _cbuf.Length)
+ Resize (_ind + 10);
+
+ start += _offset;
+ uint v;
+ if (start < 0)
+ v = 0;
+ else if (start < 8)
+ v = _val1;
+ else if (start < 16)
+ v = _val2;
+ else if (start < 24)
+ v = _val3;
+ else if (start < 32)
+ v = _val4;
+ else
+ v = 0;
+ v >>= (start & 0x7) << 2;
+ _cbuf [_ind++] = (char)('0' | v & 0xf);
+ }
+
+#if UNSAFE_TABLES // No unsafe code under TARGET_JVM
+ unsafe
+#endif
+ private void FastAppendDigits (int val, bool force)
+ {
+ int i = _ind;
+ int digits;
+ if (force || val >= 100) {
+ int v = (val * 5243) >> 19;
+ digits = DecHexDigits [v];
+ if (force || val >= 1000)
+ _cbuf [i++] = (char)('0' | digits >> 4);
+ _cbuf [i++] = (char)('0' | (digits & 0xf));
+ digits = DecHexDigits [val - v * 100];
}
- public bool IsBankerApplicable {
- get {
- if ((_digits == null) || (_digits.Length < 2))
- return false;
- return ((_digits [_digits.Length - 2] & 1) == 1);
+ else
+ digits = DecHexDigits [val];
+
+ if (force || val >= 10)
+ _cbuf [i++] = (char)('0' | digits >> 4);
+ _cbuf [i++] = (char)('0' | (digits & 0xf));
+ _ind = i;
+ }
+
+ private void AppendDigits (int start, int end)
+ {
+ if (start >= end)
+ return;
+
+ int i = _ind + (end - start);
+ if (i > _cbuf.Length)
+ Resize (i + 10);
+ _ind = i;
+
+ end += _offset;
+ start += _offset;
+
+ for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
+ uint v;
+ if (next == 8)
+ v = _val1;
+ else if (next == 16)
+ v = _val2;
+ else if (next == 24)
+ v = _val3;
+ else if (next == 32)
+ v = _val4;
+ else
+ v = 0;
+ v >>= (start & 0x7) << 2;
+ if (next > end)
+ next = end;
+
+ _cbuf [--i] = (char)('0' | v & 0xf);
+ switch (next - start) {
+ case 8:
+ _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 7;
+ case 7:
+ _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 6;
+ case 6:
+ _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 5;
+ case 5:
+ _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 4;
+ case 4:
+ _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 3;
+ case 3:
+ _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 2;
+ case 2:
+ _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 1;
+ case 1:
+ if (next == end)
+ return;
+ continue;
}
}
- public bool ZeroOnly {
- get {
- for (int i = 0; i < _digits.Length; i++)
- if (_digits [i] != 0)
- return false;
- return true;
+ }
+
+ private void AppendDigits (int start, int end, StringBuilder sb)
+ {
+ if (start >= end)
+ return;
+
+ int i = sb.Length + (end - start);
+ sb.Length = i;
+
+ end += _offset;
+ start += _offset;
+
+ for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
+ uint v;
+ if (next == 8)
+ v = _val1;
+ else if (next == 16)
+ v = _val2;
+ else if (next == 24)
+ v = _val3;
+ else if (next == 32)
+ v = _val4;
+ else
+ v = 0;
+ v >>= (start & 0x7) << 2;
+ if (next > end)
+ next = end;
+ sb [--i] = (char)('0' | v & 0xf);
+ switch (next - start) {
+ case 8:
+ sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 7;
+ case 7:
+ sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 6;
+ case 6:
+ sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 5;
+ case 5:
+ sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 4;
+ case 4:
+ sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 3;
+ case 3:
+ sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 2;
+ case 2:
+ sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+ goto case 1;
+ case 1:
+ if (next == end)
+ return;
+ continue;
}
}
- #endregion
+ }
- #region Public Method
+ #endregion Append helpers
- #region Round
- public bool RoundPos (int pos)
- {
- return RoundPos (pos, true);
- }
- public bool RoundPos (int pos, bool carryFive)
- {
- bool carry = false;
+ #region others
- if (_decPointPos <= 0)
- pos = pos - _decPointPos - 1;
+ private void Multiply10(int count)
+ {
+ if (count <= 0 || _digitsLen == 0)
+ return;
- if (pos >= _digits.Length)
- return false;
+ _decPointPos += count;
+ }
- if (pos < 0) {
- _digits = new byte [1];
- _digits [0] = 0;
- _decPointPos = 1;
- _positive = true;
- return false;
- }
+ private void Divide10(int count)
+ {
+ if (count <= 0 || _digitsLen == 0)
+ return;
- for (int i = pos; i >= 0; i--) {
- RoundHelper (i, carryFive, ref carry);
- if (!carry)
- break;
- }
+ _decPointPos -= count;
+ }
- if (carry) {
- byte[] temp = new byte [_digits.Length + 1];
- _digits.CopyTo (temp, 1);
- temp [0] = 1;
- _digits = temp;
- _decPointPos ++;
- pos ++;
- }
+ private NumberFormatter GetClone ()
+ {
+ return (NumberFormatter)this.MemberwiseClone ();
+ }
- for (int i = pos; i < _digits.Length; i++)
- _digits [i] = 0;
- TrimDecimalEndZeros ();
+ #endregion others
- return carry;
- }
- public bool RoundDecimal (int decimals)
- {
- return RoundDecimal (decimals, true, true);
- }
- public bool RoundDecimal (int decimals, bool carryFive, bool countZero)
+ #region custom
+
+ private class CustomInfo
+ {
+ public bool UseGroup = false;
+ public int DecimalDigits = 0;
+ public int DecimalPointPos = -1;
+ public int DecimalTailSharpDigits = 0;
+ public int IntegerDigits = 0;
+ public int IntegerHeadSharpDigits = 0;
+ public int IntegerHeadPos = 0;
+ public bool UseExponent = false;
+ public int ExponentDigits = 0;
+ public int ExponentTailSharpDigits = 0;
+ public bool ExponentNegativeSignOnly = true;
+ public int DividePlaces = 0;
+ public int Percents = 0;
+ public int Permilles = 0;
+
+ public static void GetActiveSection (string format, ref bool positive, bool zero, ref int offset, ref int length)
{
- bool carry = false;
+ int[] lens = new int [3];
+ int index = 0;
+ int lastPos = 0;
+ bool quoted = false;
- if (countZero || (_decPointPos > 0))
- decimals += _decPointPos;
+ for (int i = 0; i < format.Length; i++) {
+ char c = format [i];
- if (!HasDecimal || decimals >= _digits.Length)
- return false;
+ if (c == '\"' || c == '\'') {
+ if (i == 0 || format [i - 1] != '\\')
+ quoted = !quoted;
- if (decimals < 0) {
- _digits = new byte [1];
- _digits [0] = 0;
- _decPointPos = 1;
- _positive = true;
- return false;
- }
+ continue;
+ }
- for (int i = decimals; i >= 0; i--) {
- RoundHelper (i, carryFive, ref carry);
- if (!carry)
- break;
+ if (c == ';' && !quoted && (i == 0 || format [i - 1] != '\\')) {
+ lens [index++] = i - lastPos;
+ lastPos = i + 1;
+ if (index == 3)
+ break;
+ }
}
- if (carry) {
- byte[] temp = new byte [_digits.Length + 1];
- _digits.CopyTo (temp, 1);
- temp [0] = 1;
- _digits = temp;
- _decPointPos ++;
- decimals ++;
+ if (index == 0) {
+ offset = 0;
+ length = format.Length;
+ return;
}
-
- for (int i = decimals; i < _digits.Length; i++)
- _digits [i] = 0;
- TrimDecimalEndZeros ();
-
- return carry;
- }
- void RoundHelper (int index, bool carryFive, ref bool carry)
- {
- if (carry) {
- if (_digits [index] == 9) {
- carry = true;
- _digits [index] = 0;
- } else {
- carry = false;
- _digits [index] ++;
+ if (index == 1) {
+ if (positive || zero) {
+ offset = 0;
+ length = lens [0];
+ return;
+ }
+ if (lens [0] + 1 < format.Length) {
+ positive = true;
+ offset = lens [0] + 1;
+ length = format.Length - offset;
+ return;
+ }
+ else {
+ offset = 0;
+ length = lens [0];
+ return;
}
- } else if (_digits [index] >= (carryFive ? 5 : 6)) {
- carry = true;
}
+ if (index == 2) {
+ if (zero) {
+ offset = lens [0] + lens [1] + 2;
+ length = format.Length - offset;
+ return;
+ }
+ if (positive) {
+ offset = 0;
+ length = lens [0];
+ return;
+ }
+ if (lens [1] > 0) {
+ positive = true;
+ offset = lens [0] + 1;
+ length = lens [1];
+ return;
+ }
+ else {
+ offset = 0;
+ length = lens [0];
+ return;
+ }
+ }
+ if (index == 3) {
+ if (zero) {
+ offset = lens [0] + lens [1] + 2;
+ length = lens [2];
+ return;
+ }
+ if (positive) {
+ offset = 0;
+ length = lens [0];
+ return;
+ }
+ if (lens [1] > 0) {
+ positive = true;
+ offset = lens [0] + 1;
+ length = lens [1];
+ return;
+ }
+ else {
+ offset = 0;
+ length = lens [0];
+ return;
+ }
+ }
+
+ throw new ArgumentException ();
}
- public bool RoundEffectiveDigits (int digits)
- {
- return RoundEffectiveDigits (digits, true, true);
- }
- public bool RoundEffectiveDigits (int digits, bool carryFive, bool carryEven)
+
+ public static CustomInfo Parse (string format, int offset, int length, NumberFormatInfo nfi)
{
- bool carry = false;
+ char literal = '\0';
+ bool integerArea = true;
+ bool decimalArea = false;
+ bool exponentArea = false;
+ bool sharpContinues = true;
- if (digits >= _digits.Length || digits < 0)
- return false;
+ CustomInfo info = new CustomInfo ();
+ int groupSeparatorCounter = 0;
- if (digits + 1 < _digits.Length && _digits [digits + 1] == 5 && _digits [digits] % 2 == (carryEven ? 0 : 1))
- carryFive = false;
-
- /// are we cutting from the maximum precision ?
- if (_digits.Length == _defMaxPrecision) {
- // special case if we *aren't* cutting inside the extra precision (e.g. 16 on 17)
- if (digits != _defMaxPrecision - 1) {
- // ok, here we look at the *two* extra numbers we're keeping
- // (we keep 17 digits while the true precision is 15 digits).
- int extra = _digits[_defMaxPrecision - 2] * 10 + _digits[_defMaxPrecision - 1];
- carry = (extra >= 50);
- if (carry) {
- _digits[_defMaxPrecision - 2] = 0;
- _digits[_defMaxPrecision - 1] = 0;
- int d = _digits.Length - 3;
- CarryPropagation (ref d, carryFive, ref carry);
- }
+ for (int i = offset; i - offset < length; i++) {
+ char c = format [i];
+
+ if (c == literal && c != '\0') {
+ literal = '\0';
+ continue;
}
- }
- CarryPropagation (ref digits, carryFive, ref carry);
+ if (literal != '\0')
+ continue;
- for (int i = digits; i < _digits.Length; i++)
- _digits [i] = 0;
- TrimDecimalEndZeros ();
+ if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
+ exponentArea = false;
+ integerArea = (info.DecimalPointPos < 0);
+ decimalArea = !integerArea;
+ i--;
+ continue;
+ }
- return carry;
- }
+ switch (c) {
+ case '\\':
+ i++;
+ continue;
+ case '\'':
+ case '\"':
+ if (c == '\"' || c == '\'') {
+ literal = c;
+ }
+ continue;
+ case '#':
+ if (sharpContinues && integerArea)
+ info.IntegerHeadSharpDigits++;
+ else if (decimalArea)
+ info.DecimalTailSharpDigits++;
+ else if (exponentArea)
+ info.ExponentTailSharpDigits++;
+
+ goto case '0';
+ case '0':
+ if (c != '#') {
+ sharpContinues = false;
+ if (decimalArea)
+ info.DecimalTailSharpDigits = 0;
+ else if (exponentArea)
+ info.ExponentTailSharpDigits = 0;
+ }
+ if (info.IntegerHeadPos == -1)
+ info.IntegerHeadPos = i;
- private void CarryPropagation (ref int digits, bool carryFive, ref bool carry)
- {
- for (int i = digits; i >= 0; i--) {
- RoundHelper (i, carryFive, ref carry);
- if (!carry)
+ if (integerArea) {
+ info.IntegerDigits++;
+ if (groupSeparatorCounter > 0)
+ info.UseGroup = true;
+ groupSeparatorCounter = 0;
+ }
+ else if (decimalArea)
+ info.DecimalDigits++;
+ else if (exponentArea)
+ info.ExponentDigits++;
break;
- }
-
- if (carry) {
- byte[] temp = new byte[_digits.Length + 1];
- _digits.CopyTo (temp, 1);
- temp[0] = 1;
- _digits = temp;
- _decPointPos++;
- digits++;
- }
- }
+ case 'e':
+ case 'E':
+ if (info.UseExponent)
+ break;
- #endregion
+ info.UseExponent = true;
+ integerArea = false;
+ decimalArea = false;
+ exponentArea = true;
+ if (i + 1 - offset < length) {
+ char nc = format [i + 1];
+ if (nc == '+')
+ info.ExponentNegativeSignOnly = false;
+ if (nc == '+' || nc == '-')
+ i++;
+ else if (nc != '0' && nc != '#') {
+ info.UseExponent = false;
+ if (info.DecimalPointPos < 0)
+ integerArea = true;
+ }
+ }
- #region Trim
- public void TrimDecimalEndZeros ()
- {
- int len = 0;
- for (int i = _digits.Length - 1; i >= 0; i --) {
- if (_digits [i] != 0)
break;
- len ++;
- }
-
- if (len > 0) {
- byte[] temp = new byte [_digits.Length - len];
- Array.Copy (_digits, 0, temp, 0, temp.Length);
- _digits = temp;
- }
- }
- public void TrimIntegerStartZeros ()
- {
- if (_decPointPos < 0 && _decPointPos >= _digits.Length)
- return;
-
- int len = 0;
- for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
- if (_digits [i] != 0)
+ case '.':
+ integerArea = false;
+ decimalArea = true;
+ exponentArea = false;
+ if (info.DecimalPointPos == -1)
+ info.DecimalPointPos = i;
break;
- len ++;
- }
-
- if (len == _decPointPos)
- len --;
-
- if (len == _digits.Length) {
- _digits = new byte [1];
- _digits [0] = 0;
- _decPointPos = 1;
- _positive = true;
- } else if (len > 0) {
- byte[] temp = new byte [_digits.Length - len];
- Array.Copy (_digits, len, temp, 0, temp.Length);
- _digits = temp;
- _decPointPos -= len;
+ case '%':
+ info.Percents++;
+ break;
+ case '\u2030':
+ info.Permilles++;
+ break;
+ case ',':
+ if (integerArea && info.IntegerDigits > 0)
+ groupSeparatorCounter++;
+ break;
+ default:
+ break;
+ }
}
- }
- #endregion
+ if (info.ExponentDigits == 0)
+ info.UseExponent = false;
+ else
+ info.IntegerHeadSharpDigits = 0;
- #region Integer
- public void AppendIntegerString (int minLength, StringBuilder cb)
- {
- if (IntegerDigits == 0) {
- cb.Append ('0', minLength);
- return;
- }
- if (_decPointPos <= 0) {
- cb.Append ('0', minLength);
- return;
- }
+ if (info.DecimalDigits == 0)
+ info.DecimalPointPos = -1;
- if (_decPointPos < minLength)
- cb.Append ('0', minLength - _decPointPos);
+ info.DividePlaces += groupSeparatorCounter * 3;
- for (int i = 0; i < _decPointPos; i++) {
- if (i < _digits.Length)
- cb.Append ((char)('0' + _digits [i]));
- else
- cb.Append ('0');
- }
+ return info;
}
- public void AppendIntegerStringWithGroupSeparator (StringBuilder sb, int[] groups, string groupSeparator)
- {
- if (_decPointPos <= 0) {
- sb.Append ('0');
- return;
- }
- int intLen = IntegerDigits;
- int total = 0;
- int groupIndex = 0;
- for (int i = 0; i < groups.Length; i++) {
- total += groups [i];
- if (total <= intLen)
- groupIndex = i;
- }
+ public string Format (string format, int offset, int length, NumberFormatInfo nfi, bool positive, StringBuilder sb_int, StringBuilder sb_dec, StringBuilder sb_exp)
+ {
+ StringBuilder sb = new StringBuilder ();
+ char literal = '\0';
+ bool integerArea = true;
+ bool decimalArea = false;
+ int intSharpCounter = 0;
+ int sb_int_index = 0;
+ int sb_dec_index = 0;
- if (groups.Length > 0 && total > 0) {
- int counter;
- int groupSize = groups [groupIndex];
+ int[] groups = nfi.RawNumberGroupSizes;
+ string groupSeparator = nfi.NumberGroupSeparator;
+ int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0;
+ if (UseGroup && groups.Length > 0) {
+ intLen = sb_int.Length;
+ for (int i = 0; i < groups.Length; i++) {
+ total += groups [i];
+ if (total <= intLen)
+ groupIndex = i;
+ }
+ groupSize = groups [groupIndex];
int fraction = intLen > total ? intLen - total : 0;
if (groupSize == 0) {
while (groupIndex >= 0 && groups [groupIndex] == 0)
- groupIndex --;
-
+ groupIndex--;
+
groupSize = fraction > 0 ? fraction : groups [groupIndex];
}
- if (fraction == 0) {
+ if (fraction == 0)
counter = groupSize;
- } else {
+ else {
groupIndex += fraction / groupSize;
counter = fraction % groupSize;
if (counter == 0)
counter = groupSize;
else
- groupIndex ++;
- }
-
- for (int i = 0; i < _decPointPos; i++) {
- if (i < _digits.Length) {
- sb.Append ((char)('0' + _digits [i]));
- } else {
- sb.Append ('0');
- }
-
- if (i < intLen - 1 && --counter == 0) {
- sb.Append (groupSeparator);
- if (--groupIndex < groups.Length && groupIndex >= 0)
- groupSize = groups [groupIndex];
- counter = groupSize;
- }
- }
- } else {
- for (int i = 0; i < _decPointPos; i++) {
- if (i < _digits.Length) {
- sb.Append ((char)('0' + _digits [i]));
- } else {
- sb.Append ('0');
- }
+ groupIndex++;
}
}
- }
- #endregion
+ else
+ UseGroup = false;
- #region Decimal
- public string GetDecimalString (int precision)
- {
- if (!HasDecimal)
- return new string ('0', precision);
+ for (int i = offset; i - offset < length; i++) {
+ char c = format [i];
- StringBuilder sb = new StringBuilder (precision);
- for (int i = _decPointPos; i < _digits.Length && i < precision + _decPointPos; i++) {
- if (i >= 0)
- sb.Append ((char)('0' + _digits [i]));
- else
- sb.Append ('0');
- }
- if (sb.Length < precision)
- sb.Append ('0', precision - sb.Length);
- else if (sb.Length > precision)
- sb.Remove (0, precision);
- return sb.ToString ();
- }
+ if (c == literal && c != '\0') {
+ literal = '\0';
+ continue;
+ }
+ if (literal != '\0') {
+ sb.Append (c);
+ continue;
+ }
- public void AppendDecimalString (int precision, StringBuilder cb)
- {
- if (!HasDecimal) {
- cb.Append ('0', precision);
- return;
- }
+ switch (c) {
+ case '\\':
+ i++;
+ if (i - offset < length)
+ sb.Append (format [i]);
+ continue;
+ case '\'':
+ case '\"':
+ if (c == '\"' || c == '\'')
+ literal = c;
+ continue;
+ case '#':
+ goto case '0';
+ case '0':
+ if (integerArea) {
+ intSharpCounter++;
+ if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
+ while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
+ sb.Append (sb_int [sb_int_index++]);
+ if (UseGroup && --intLen > 0 && --counter == 0) {
+ sb.Append (groupSeparator);
+ if (--groupIndex < groups.Length && groupIndex >= 0)
+ groupSize = groups [groupIndex];
+ counter = groupSize;
+ }
+ }
+ break;
+ }
+ else if (decimalArea) {
+ if (sb_dec_index < sb_dec.Length)
+ sb.Append (sb_dec [sb_dec_index++]);
+ break;
+ }
- int i = _decPointPos;
- for (; i < _digits.Length && i < precision + _decPointPos; i++) {
- if (i >= 0)
- cb.Append ((char)('0' + _digits [i]));
- else
- cb.Append ('0');
- }
+ sb.Append (c);
+ break;
+ case 'e':
+ case 'E':
+ if (sb_exp == null || !UseExponent) {
+ sb.Append (c);
+ break;
+ }
- i -= _decPointPos;
- if (i < precision)
- cb.Append ('0', precision - i);
- }
- #endregion
+ bool flag1 = true;
+ bool flag2 = false;
- #region others
- public bool CheckZeroOnlyInteger ()
- {
- for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
- if (_digits [i] != 0)
- return false;
- }
- return true;
- }
- public void Multiply10 (int count)
- {
- if (count <= 0)
- return;
+ int q;
+ for (q = i + 1; q - offset < length; q++) {
+ if (format [q] == '0') {
+ flag2 = true;
+ continue;
+ }
+ if (q == i + 1 && (format [q] == '+' || format [q] == '-'))
+ continue;
+ if (!flag2)
+ flag1 = false;
+ break;
+ }
- _decPointPos += count;
+ if (flag1) {
+ i = q - 1;
+ integerArea = (DecimalPointPos < 0);
+ decimalArea = !integerArea;
- TrimIntegerStartZeros ();
- }
- public void Divide10 (int count)
- {
- if (count <= 0)
- return;
+ sb.Append (c);
+ sb.Append (sb_exp);
+ sb_exp = null;
+ }
+ else
+ sb.Append (c);
- _decPointPos -= count;
- }
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder ();
- AppendIntegerString (IntegerDigits, sb);
- if (HasDecimal) {
- sb.Append ('.');
- AppendDecimalString (DecimalDigits, sb);
+ break;
+ case '.':
+ if (DecimalPointPos == i) {
+ if (DecimalDigits > 0) {
+ while (sb_int_index < sb_int.Length)
+ sb.Append (sb_int [sb_int_index++]);
+ }
+ if (sb_dec.Length > 0)
+ sb.Append (nfi.NumberDecimalSeparator);
+ }
+ integerArea = false;
+ decimalArea = true;
+ break;
+ case ',':
+ break;
+ case '%':
+ sb.Append (nfi.PercentSymbol);
+ break;
+ case '\u2030':
+ sb.Append (nfi.PerMilleSymbol);
+ break;
+ default:
+ sb.Append (c);
+ break;
+ }
}
- return sb.ToString ();
- }
- public char GetChar (int pos)
- {
- if (_decPointPos <= 0)
- pos += _decPointPos - 1;
-
- if (pos < 0 || pos >= _digits.Length)
- return '0';
- else
- return (char)('0' + _digits [pos]);
- }
- public byte GetDigitByte (int pos)
- {
- if (_decPointPos <= 0)
- pos += _decPointPos - 1;
-
- if (pos < 0 || pos >= _digits.Length)
- return 0;
- else
- return _digits [pos];
- }
- public NumberStore GetClone ()
- {
- NumberStore ns = new NumberStore ();
-
- ns._decPointPos = this._decPointPos;
- ns._defMaxPrecision = this._defMaxPrecision;
- ns._defPrecision = this._defPrecision;
- ns._digits = (byte[])this._digits.Clone ();
- ns._infinity = this._infinity;
- ns._NaN = this._NaN;
- ns._positive = this._positive;
-
- return ns;
- }
- public int GetDecimalPointPos ()
- {
- return _decPointPos;
- }
- public void SetDecimalPointPos (int dp)
- {
- _decPointPos = dp;
- }
- #endregion
- #endregion
+ if (!positive)
+ sb.Insert (0, nfi.NegativeSign);
- #region Public Static Method
- public static bool IsZeroOnly (StringBuilder sb)
- {
- for (int i = 0; i < sb.Length; i++)
- if (char.IsDigit (sb [i]) && sb [i] != '0')
- return false;
- return true;
- }
- public static void AppendIntegerStringFromUInt32 (StringBuilder sb, uint v)
- {
- if (v < 0)
- throw new ArgumentException ();
-
- int i = 9;
-
- if (v >= 1000000000)
- i = 9;
- else if (v >= 100000000)
- i = 8;
- else if (v >= 10000000)
- i = 7;
- else if (v >= 1000000)
- i = 6;
- else if (v >= 100000)
- i = 5;
- else if (v >= 10000)
- i = 4;
- else if (v >= 1000)
- i = 3;
- else if (v >= 100)
- i = 2;
- else if (v >= 10)
- i = 1;
- else
- i = 0;
- do {
- uint n = v / IntList [i];
- sb.Append (NumberFormatter.digitLowerTable [n]);
- v -= IntList [i--] * n;
- } while (i >= 0);
+ return sb.ToString ();
}
- #endregion
}
+
#endregion
}
}