public static void FormatDecimal(StringBuffer formatter, uint* value, StringView specifier, CachedCulture culture) { int digits; var fmt = ParseFormatSpecifier(specifier, out digits); var number = new Number(); var buffer = stackalloc char[MaxNumberDigits + 1]; number.Digits = buffer; DecimalToNumber(value, ref number); if (fmt != 0) NumberToString(formatter, ref number, fmt, digits, culture, isDecimal: true); else NumberToCustomFormatString(formatter, ref number, specifier, culture); }
public static void FormatDouble(StringBuffer formatter, double value, StringView specifier, CachedCulture culture) { int digits; int precision = DoublePrecision; var fmt = ParseFormatSpecifier(specifier, out digits); // ANDing with 0xFFDF has the effect of uppercasing the character switch (fmt & 0xFFDF) { case 'G': if (digits > 15) precision = 17; break; case 'E': if (digits > 14) precision = 17; break; } var number = new Number(); var buffer = stackalloc char[MaxFloatingDigits + 1]; number.Digits = buffer; DoubleToNumber(value, precision, ref number); if (number.Scale == ScaleNaN) { formatter.Append(culture.NaN); return; } if (number.Scale == ScaleInf) { if (number.Sign > 0) formatter.Append(culture.NegativeInfinity); else formatter.Append(culture.PositiveInfinity); return; } if (fmt != 0) NumberToString(formatter, ref number, fmt, digits, culture); else NumberToCustomFormatString(formatter, ref number, specifier, culture); }
static void NumberToCustomFormatString(StringBuffer formatter, ref Number number, StringView specifier, CachedCulture culture) { }
public static void FormatSByte(StringBuffer formatter, sbyte value, StringView specifier, CachedCulture culture) { if (value < 0 && !specifier.IsEmpty) { // if we're negative and doing a hex format, mask out the bits for the conversion char c = specifier.Data[0]; if (c == 'X' || c == 'x') { FormatUInt32(formatter, (uint)(value & 0xFF), specifier, culture); return; } } FormatInt32(formatter, value, specifier, culture); }
public static void FormatUInt32(StringBuffer formatter, uint value, StringView specifier, CachedCulture culture) { int digits; var fmt = ParseFormatSpecifier(specifier, out digits); // ANDing with 0xFFDF has the effect of uppercasing the character switch (fmt & 0xFFDF) { case 'G': if (digits > 0) { goto default; } else { goto case 'D'; } case 'D': UInt32ToDecStr(formatter, value, digits); break; case 'X': // fmt-('X'-'A'+1) gives us the base hex character in either // uppercase or lowercase, depending on the casing of fmt Int32ToHexStr(formatter, value, fmt - ('X' - 'A' + 10), digits); break; default: var number = new Number(); var buffer = stackalloc char[MaxNumberDigits + 1]; number.Digits = buffer; UInt32ToNumber(value, ref number); if (fmt != 0) { NumberToString(formatter, ref number, fmt, digits, culture); } else { NumberToCustomFormatString(formatter, ref number, specifier, culture); } break; } }
static void NumberToString(StringBuffer formatter, ref Number number, char format, int maxDigits, CachedCulture culture, bool isDecimal = false) { // ANDing with 0xFFDF has the effect of uppercasing the character switch (format & 0xFFDF) { case 'C': { var cultureData = culture.CurrencyData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = FormatCurrency( buffer, ref number, maxDigits, cultureData, number.Sign > 0 ? culture.CurrencyNegativePattern : culture.CurrencyPositivePattern, culture.CurrencySymbol ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'F': { var cultureData = culture.FixedData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = buffer; if (number.Sign > 0) { AppendString(&ptr, cultureData.NegativeSign); } ptr = FormatFixed(ptr, ref number, maxDigits, cultureData); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'N': { var cultureData = culture.NumberData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = FormatNumber( buffer, ref number, maxDigits, number.Sign > 0 ? culture.NumberNegativePattern : culture.NumberPositivePattern, cultureData ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'E': { var cultureData = culture.ScientificData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); maxDigits++; RoundNumber(ref number, maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = buffer; if (number.Sign > 0) { AppendString(&ptr, cultureData.NegativeSign); } ptr = FormatScientific( ptr, ref number, maxDigits, format, // TODO: fix casing cultureData.DecimalSeparator, culture.PositiveSign, culture.NegativeSign ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'P': { number.Scale += 2; var cultureData = culture.PercentData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = FormatPercent( buffer, ref number, maxDigits, cultureData, number.Sign > 0 ? culture.PercentNegativePattern : culture.PercentPositivePattern, culture.PercentSymbol ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'G': { var enableRounding = true; if (maxDigits < 1) { if (isDecimal && maxDigits == -1) { // if we're formatting a decimal, default to 29 digits precision // only for G formatting without a precision specifier maxDigits = DecimalPrecision; enableRounding = false; } else { maxDigits = number.Precision; } } var bufferSize = maxDigits + culture.DecimalBufferSize; var buffer = stackalloc char[bufferSize]; var ptr = buffer; // round for G formatting only if a precision is given // we need to handle the minus zero case also if (enableRounding) { RoundNumber(ref number, maxDigits); } else if (isDecimal && number.Digits[0] == 0) { number.Sign = 0; } if (number.Sign > 0) { AppendString(&ptr, culture.NegativeSign); } ptr = FormatGeneral( ptr, ref number, maxDigits, (char)(format - ('G' - 'E')), culture.NumberData.DecimalSeparator, culture.PositiveSign, culture.NegativeSign, !enableRounding ); formatter.Append(buffer, (int)(ptr - buffer)); break; } default: throw new FormatException(string.Format(SR.UnknownFormatSpecifier, format)); } }
public static void FormatDecimal(StringBuffer formatter, uint *value, StringView specifier, CachedCulture culture) { int digits; var fmt = ParseFormatSpecifier(specifier, out digits); var number = new Number(); var buffer = stackalloc char[MaxNumberDigits + 1]; number.Digits = buffer; DecimalToNumber(value, ref number); if (fmt != 0) { NumberToString(formatter, ref number, fmt, digits, culture, isDecimal: true); } else { NumberToCustomFormatString(formatter, ref number, specifier, culture); } }
public static void FormatDouble(StringBuffer formatter, double value, StringView specifier, CachedCulture culture) { int digits; int precision = DoublePrecision; var fmt = ParseFormatSpecifier(specifier, out digits); // ANDing with 0xFFDF has the effect of uppercasing the character switch (fmt & 0xFFDF) { case 'G': if (digits > 15) { precision = 17; } break; case 'E': if (digits > 14) { precision = 17; } break; } var number = new Number(); var buffer = stackalloc char[MaxFloatingDigits + 1]; number.Digits = buffer; DoubleToNumber(value, precision, ref number); if (number.Scale == ScaleNaN) { formatter.Append(culture.NaN); return; } if (number.Scale == ScaleInf) { if (number.Sign > 0) { formatter.Append(culture.NegativeInfinity); } else { formatter.Append(culture.PositiveInfinity); } return; } if (fmt != 0) { NumberToString(formatter, ref number, fmt, digits, culture); } else { NumberToCustomFormatString(formatter, ref number, specifier, culture); } }
/// <summary> /// Initializes a new instance of the <see cref="StringBuffer"/> class. /// </summary> /// <param name="capacity">The initial size of the string buffer.</param> public StringBuffer(int capacity) { buffer = new char[capacity]; culture = CachedCurrentCulture; }
public static void FormatInt16(StringBuffer formatter, short value, StringView specifier, CachedCulture culture) { if (value < 0 && !specifier.IsEmpty) { // if we're negative and doing a hex format, mask out the bits for the conversion char c = specifier.Data[0]; if (c == 'X' || c == 'x') FormatUInt32(formatter, (uint)(value & 0xFFFF), specifier, culture); } FormatInt32(formatter, value, specifier, culture); }
static void NumberToString(StringBuffer formatter, ref Number number, char format, int maxDigits, CachedCulture culture, bool isDecimal = false) { // ANDing with 0xFFDF has the effect of uppercasing the character switch (format & 0xFFDF) { case 'C': { var cultureData = culture.CurrencyData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = FormatCurrency( buffer, ref number, maxDigits, cultureData, number.Sign > 0 ? culture.CurrencyNegativePattern : culture.CurrencyPositivePattern, culture.CurrencySymbol ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'F': { var cultureData = culture.FixedData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = buffer; if (number.Sign > 0) AppendString(&ptr, cultureData.NegativeSign); ptr = FormatFixed(ptr, ref number, maxDigits, cultureData); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'N': { var cultureData = culture.NumberData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = FormatNumber( buffer, ref number, maxDigits, number.Sign > 0 ? culture.NumberNegativePattern : culture.NumberPositivePattern, cultureData ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'E': { var cultureData = culture.ScientificData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); maxDigits++; RoundNumber(ref number, maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = buffer; if (number.Sign > 0) AppendString(&ptr, cultureData.NegativeSign); ptr = FormatScientific( ptr, ref number, maxDigits, format, // TODO: fix casing cultureData.DecimalSeparator, culture.PositiveSign, culture.NegativeSign ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'P': { number.Scale += 2; var cultureData = culture.PercentData; var bufferSize = cultureData.GetBufferSize(ref maxDigits, number.Scale); RoundNumber(ref number, number.Scale + maxDigits); var buffer = stackalloc char[bufferSize]; var ptr = FormatPercent( buffer, ref number, maxDigits, cultureData, number.Sign > 0 ? culture.PercentNegativePattern : culture.PercentPositivePattern, culture.PercentSymbol ); formatter.Append(buffer, (int)(ptr - buffer)); break; } case 'G': { var enableRounding = true; if (maxDigits < 1) { if (isDecimal && maxDigits == -1) { // if we're formatting a decimal, default to 29 digits precision // only for G formatting without a precision specifier maxDigits = DecimalPrecision; enableRounding = false; } else maxDigits = number.Precision; } var bufferSize = maxDigits + culture.DecimalBufferSize; var buffer = stackalloc char[bufferSize]; var ptr = buffer; // round for G formatting only if a precision is given // we need to handle the minus zero case also if (enableRounding) RoundNumber(ref number, maxDigits); else if (isDecimal && number.Digits[0] == 0) number.Sign = 0; if (number.Sign > 0) AppendString(&ptr, culture.NegativeSign); ptr = FormatGeneral( ptr, ref number, maxDigits, (char)(format - ('G' - 'E')), culture.NumberData.DecimalSeparator, culture.PositiveSign, culture.NegativeSign, !enableRounding ); formatter.Append(buffer, (int)(ptr - buffer)); break; } default: throw new FormatException(string.Format(SR.UnknownFormatSpecifier, format)); } }
public static void FormatUInt64(StringBuffer formatter, ulong value, StringView specifier, CachedCulture culture) { int digits; var fmt = ParseFormatSpecifier(specifier, out digits); // ANDing with 0xFFDF has the effect of uppercasing the character switch (fmt & 0xFFDF) { case 'G': if (digits > 0) goto default; else goto case 'D'; case 'D': UInt64ToDecStr(formatter, value, digits); break; case 'X': // fmt-('X'-'A'+1) gives us the base hex character in either // uppercase or lowercase, depending on the casing of fmt Int64ToHexStr(formatter, value, fmt - ('X' - 'A' + 10), digits); break; default: var number = new Number(); var buffer = stackalloc char[MaxNumberDigits + 1]; number.Digits = buffer; UInt64ToNumber(value, ref number); if (fmt != 0) NumberToString(formatter, ref number, fmt, digits, culture); else NumberToCustomFormatString(formatter, ref number, specifier, culture); break; } }