#region File Description
//-----------------------------------------------------------------------------
// StringBuilderExtensions.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using System.Globalization;
using System.Text;
#endregion
namespace HoneycombRush.GameDebugTools
{
///
/// Options for StringBuilder extension methods.
///
[Flags]
public enum AppendNumberOptions
{
// Normal format.
None = 0,
// Added "+" sign for positive value.
PositiveSign = 1,
// Insert Number group separation characters.
// In Use, added "," for every 3 digits.
NumberGroup = 2,
}
///
/// Static class for string builder extension methods.
///
///
/// You can specified StringBuilder for SpriteFont.DrawString from XNA GS 3.0.
/// And you can save unwanted memory allocations.
///
/// But there are still problems for adding numerical value to StringBuilder.
/// One of them is boxing occurred when you use StringBuilder.AppendFormat method.
/// Another issue is memory allocation occurred when you specify int or float for
/// StringBuild.Append method.
///
/// This class provides solution for those issue.
///
/// All methods are defined as extension methods as StringBuilder. So, you can use
/// those method like below.
///
/// stringBuilder.AppendNumber(12345);
///
///
public static class StringBuilderExtensions
{
#region Fields
///
/// Cache for NumberGroupSizes of NumberFormat class.
///
static int[] numberGroupSizes =
CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes;
///
/// string conversion buffer.
///
static char[] numberString = new char[32];
#endregion
///
/// Convert integer to string and add to string builder.
///
public static void AppendNumber(this StringBuilder builder, int number)
{
AppendNumbernternal(builder, number, 0, AppendNumberOptions.None);
}
///
/// Convert integer to string and add to string builder.
///
///
/// Format options
public static void AppendNumber(this StringBuilder builder, int number,
AppendNumberOptions options)
{
AppendNumbernternal(builder, number, 0, options);
}
///
/// Convert float to string and add to string builder.
///
/// It shows 2 decimal digits.
public static void AppendNumber(this StringBuilder builder, float number)
{
AppendNumber(builder, number, 2, AppendNumberOptions.None);
}
///
/// Convert float to string and add to string builder.
///
/// It shows 2 decimal digits.
public static void AppendNumber(this StringBuilder builder, float number,
AppendNumberOptions options)
{
AppendNumber(builder, number, 2, options);
}
///
/// Convert float to string and add to string builder.
///
public static void AppendNumber(this StringBuilder builder, float number,
int decimalCount, AppendNumberOptions options)
{
// Handle NaN, Infinity cases.
if (float.IsNaN(number))
{
builder.Append("NaN");
}
else if (float.IsNegativeInfinity(number))
{
builder.Append("-Infinity");
}
else if (float.IsPositiveInfinity(number))
{
builder.Append("+Infinity");
}
else
{
int intNumber =
(int)(number * (float)Math.Pow(10, decimalCount) + 0.5f);
AppendNumbernternal(builder, intNumber, decimalCount, options);
}
}
static void AppendNumbernternal(StringBuilder builder, int number,
int decimalCount, AppendNumberOptions options)
{
// Initialize variables for conversion.
NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
int idx = numberString.Length;
int decimalPos = idx - decimalCount;
if (decimalPos == idx)
decimalPos = idx + 1;
int numberGroupIdx = 0;
int numberGroupCount = numberGroupSizes[numberGroupIdx] + decimalCount;
bool showNumberGroup = (options & AppendNumberOptions.NumberGroup) != 0;
bool showPositiveSign = (options & AppendNumberOptions.PositiveSign) != 0;
bool isNegative = number < 0;
number = Math.Abs(number);
// Converting from smallest digit.
do
{
// Add decimal separator ("." in US).
if (idx == decimalPos)
{
numberString[--idx] = nfi.NumberDecimalSeparator[0];
}
// Added number group separator ("," in US).
if (--numberGroupCount < 0 && showNumberGroup)
{
numberString[--idx] = nfi.NumberGroupSeparator[0];
if (numberGroupIdx < numberGroupSizes.Length - 1)
numberGroupIdx++;
numberGroupCount = numberGroupSizes[numberGroupIdx] - 1;
}
// Convert current digit to character and add to buffer.
numberString[--idx] = (char)('0' + (number % 10));
number /= 10;
} while (number > 0 || decimalPos <= idx);
// Added sign character if needed.
if (isNegative)
{
numberString[--idx] = nfi.NegativeSign[0];
}
else if (showPositiveSign)
{
numberString[--idx] = nfi.PositiveSign[0];
}
// Added converted string to StringBuilder.
builder.Append(numberString, idx, numberString.Length - idx);
}
}
}