StringBuilderExtensions.cs 6.5 KB

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