2
0

StringBuilderExtensions.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // StringBuilderExtensions.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.Globalization;
  12. using System.Text;
  13. #endregion
  14. namespace PerformanceMeasuring.GameDebugTools
  15. {
  16. /// <summary>
  17. /// Options for StringBuilder extension methods.
  18. /// </summary>
  19. [Flags]
  20. public enum AppendNumberOptions
  21. {
  22. // Normal format.
  23. None = 0,
  24. // Added "+" sign for positive value.
  25. PositiveSign = 1,
  26. // Insert Number group separation characters.
  27. // In Use, added "," for every 3 digits.
  28. NumberGroup = 2,
  29. }
  30. /// <summary>
  31. /// Static class for string builder extension methods.
  32. /// </summary>
  33. /// <remarks>
  34. /// You can specified StringBuilder for SpriteFont.DrawString from XNA GS 3.0.
  35. /// And you can save unwanted memory allocations.
  36. ///
  37. /// But there are still problems for adding numerical value to StringBuilder.
  38. /// One of them is boxing occurred when you use StringBuilder.AppendFormat method.
  39. /// Another issue is memory allocation occurred when you specify int or float for
  40. /// StringBuild.Append method.
  41. ///
  42. /// This class provides solution for those issue.
  43. ///
  44. /// All methods are defined as extension methods as StringBuilder. So, you can use
  45. /// those method like below.
  46. ///
  47. /// stringBuilder.AppendNumber(12345);
  48. ///
  49. /// </remarks>
  50. public static class StringBuilderExtensions
  51. {
  52. #region Fields
  53. /// <summary>
  54. /// Cache for NumberGroupSizes of NumberFormat class.
  55. /// </summary>
  56. static int[] numberGroupSizes =
  57. CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes;
  58. /// <summary>
  59. /// string conversion buffer.
  60. /// </summary>
  61. static char[] numberString = new char[32];
  62. #endregion
  63. /// <summary>
  64. /// Convert integer to string and add to string builder.
  65. /// </summary>
  66. public static void AppendNumber(this StringBuilder builder, int number)
  67. {
  68. AppendNumbernternal(builder, number, 0, AppendNumberOptions.None);
  69. }
  70. /// <summary>
  71. /// Convert integer to string and add to string builder.
  72. /// </summary>
  73. /// <param name="number"></param>
  74. /// <param name="options">Format options</param>
  75. public static void AppendNumber(this StringBuilder builder, int number,
  76. AppendNumberOptions options)
  77. {
  78. AppendNumbernternal(builder, number, 0, options);
  79. }
  80. /// <summary>
  81. /// Convert float to string and add to string builder.
  82. /// </summary>
  83. /// <remarks>It shows 2 decimal digits.</remarks>
  84. public static void AppendNumber(this StringBuilder builder, float number)
  85. {
  86. AppendNumber(builder, number, 2, AppendNumberOptions.None);
  87. }
  88. /// <summary>
  89. /// Convert float to string and add to string builder.
  90. /// </summary>
  91. /// <remarks>It shows 2 decimal digits.</remarks>
  92. public static void AppendNumber(this StringBuilder builder, float number,
  93. AppendNumberOptions options)
  94. {
  95. AppendNumber(builder, number, 2, options);
  96. }
  97. /// <summary>
  98. /// Convert float to string and add to string builder.
  99. /// </summary>
  100. public static void AppendNumber(this StringBuilder builder, float number,
  101. int decimalCount, AppendNumberOptions options)
  102. {
  103. // Handle NaN, Infinity cases.
  104. if (float.IsNaN(number))
  105. {
  106. builder.Append("NaN");
  107. }
  108. else if (float.IsNegativeInfinity(number))
  109. {
  110. builder.Append("-Infinity");
  111. }
  112. else if (float.IsPositiveInfinity(number))
  113. {
  114. builder.Append("+Infinity");
  115. }
  116. else
  117. {
  118. int intNumber =
  119. (int)(number * (float)Math.Pow(10, decimalCount) + 0.5f);
  120. AppendNumbernternal(builder, intNumber, decimalCount, options);
  121. }
  122. }
  123. static void AppendNumbernternal(StringBuilder builder, int number,
  124. int decimalCount, AppendNumberOptions options)
  125. {
  126. // Initialize variables for conversion.
  127. NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat;
  128. int idx = numberString.Length;
  129. int decimalPos = idx - decimalCount;
  130. if (decimalPos == idx)
  131. decimalPos = idx + 1;
  132. int numberGroupIdx = 0;
  133. int numberGroupCount = numberGroupSizes[numberGroupIdx] + decimalCount;
  134. bool showNumberGroup = (options & AppendNumberOptions.NumberGroup) != 0;
  135. bool showPositiveSign = (options & AppendNumberOptions.PositiveSign) != 0;
  136. bool isNegative = number < 0;
  137. number = Math.Abs(number);
  138. // Converting from smallest digit.
  139. do
  140. {
  141. // Add decimal separator ("." in US).
  142. if (idx == decimalPos)
  143. {
  144. numberString[--idx] = nfi.NumberDecimalSeparator[0];
  145. }
  146. // Added number group separator ("," in US).
  147. if (--numberGroupCount < 0 && showNumberGroup)
  148. {
  149. numberString[--idx] = nfi.NumberGroupSeparator[0];
  150. if (numberGroupIdx < numberGroupSizes.Length - 1)
  151. numberGroupIdx++;
  152. numberGroupCount = numberGroupSizes[numberGroupIdx] - 1;
  153. }
  154. // Convert current digit to character and add to buffer.
  155. numberString[--idx] = (char)('0' + (number % 10));
  156. number /= 10;
  157. } while (number > 0 || decimalPos <= idx);
  158. // Added sign character if needed.
  159. if (isNegative)
  160. {
  161. numberString[--idx] = nfi.NegativeSign[0];
  162. }
  163. else if (showPositiveSign)
  164. {
  165. numberString[--idx] = nfi.PositiveSign[0];
  166. }
  167. // Added converted string to StringBuilder.
  168. builder.Append(numberString, idx, numberString.Length - idx);
  169. }
  170. }
  171. }