/src/ZString/ZString.cs

https://github.com/Cysharp/ZString
C# | 265 lines | 195 code | 35 blank | 35 comment | 14 complexity | 832008c6349265dc7048e782ea24ea29 MD5 | raw file
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Runtime.CompilerServices;
  6. using System.Text;
  7. namespace Cysharp.Text
  8. {
  9. public static partial class ZString
  10. {
  11. static Encoding UTF8NoBom = new UTF8Encoding(false);
  12. /// <summary>Create the Utf16 string StringBuilder.</summary>
  13. public static Utf16ValueStringBuilder CreateStringBuilder()
  14. {
  15. return new Utf16ValueStringBuilder(false);
  16. }
  17. /// <summary>Create the Utf16 string StringBuilder, when true uses thread-static buffer that is faster but must return immediately.</summary>
  18. public static Utf8ValueStringBuilder CreateUtf8StringBuilder()
  19. {
  20. return new Utf8ValueStringBuilder(false);
  21. }
  22. /// <summary>Create the Utf8(`Span[byte]`) StringBuilder.</summary>
  23. /// <param name="notNested">
  24. /// If true uses thread-static buffer that is faster but must return immediately.
  25. /// </param>
  26. /// <exception cref="InvalidOperationException">
  27. /// This exception is thrown when <c>new StringBuilder(disposeImmediately: true)</c> or <c>ZString.CreateUtf8StringBuilder(notNested: true)</c> is nested.
  28. /// See the README.md
  29. /// </exception>
  30. public static Utf16ValueStringBuilder CreateStringBuilder(bool notNested)
  31. {
  32. return new Utf16ValueStringBuilder(notNested);
  33. }
  34. /// <summary>Create the Utf8(`Span[byte]`) StringBuilder, when true uses thread-static buffer that is faster but must return immediately.</summary>
  35. /// <param name="notNested">
  36. /// If true uses thread-static buffer that is faster but must return immediately.
  37. /// </param>
  38. /// <exception cref="InvalidOperationException">
  39. /// This exception is thrown when <c>new StringBuilder(disposeImmediately: true)</c> or <c>ZString.CreateUtf8StringBuilder(notNested: true)</c> is nested.
  40. /// See the README.md
  41. /// </exception>
  42. public static Utf8ValueStringBuilder CreateUtf8StringBuilder(bool notNested)
  43. {
  44. return new Utf8ValueStringBuilder(notNested);
  45. }
  46. /// <summary>Concatenates the elements of an array, using the specified seperator between each element.</summary>
  47. public static string Join<T>(char separator, params T[] values)
  48. {
  49. ReadOnlySpan<char> s = stackalloc char[1] { separator };
  50. return JoinInternal<T>(s, values.AsSpan());
  51. }
  52. /// <summary>Concatenates the elements of an array, using the specified seperator between each element.</summary>
  53. public static string Join<T>(char separator, List<T> values)
  54. {
  55. ReadOnlySpan<char> s = stackalloc char[1] { separator };
  56. return JoinInternal(s, (IReadOnlyList<T>)values);
  57. }
  58. /// <summary>Concatenates the elements of an array, using the specified seperator between each element.</summary>
  59. public static string Join<T>(char separator, ReadOnlySpan<T> values)
  60. {
  61. ReadOnlySpan<char> s = stackalloc char[1] { separator };
  62. return JoinInternal(s, values);
  63. }
  64. /// <summary>Concatenates the elements of an array, using the specified seperator between each element.</summary>
  65. public static string Join<T>(char separator, IEnumerable<T> values)
  66. {
  67. ReadOnlySpan<char> s = stackalloc char[1] { separator };
  68. return JoinInternal(s, values);
  69. }
  70. public static string Join<T>(char separator, ICollection<T> values)
  71. {
  72. ReadOnlySpan<char> s = stackalloc char[1] { separator };
  73. return JoinInternal(s, values.AsEnumerable());
  74. }
  75. public static string Join<T>(char separator, IList<T> values)
  76. {
  77. ReadOnlySpan<char> s = stackalloc char[1] { separator };
  78. return JoinInternal(s, values);
  79. }
  80. public static string Join<T>(char separator, IReadOnlyList<T> values)
  81. {
  82. ReadOnlySpan<char> s = stackalloc char[1] { separator };
  83. return JoinInternal(s, values);
  84. }
  85. public static string Join<T>(char separator, IReadOnlyCollection<T> values)
  86. {
  87. ReadOnlySpan<char> s = stackalloc char[1] { separator };
  88. return JoinInternal(s, values.AsEnumerable());
  89. }
  90. /// <summary>Concatenates the elements of an array, using the specified seperator between each element.</summary>
  91. public static string Join<T>(string separator, params T[] values)
  92. {
  93. return JoinInternal<T>(separator.AsSpan(), values.AsSpan());
  94. }
  95. /// <summary>Concatenates the elements of an array, using the specified seperator between each element.</summary>
  96. public static string Join<T>(string separator, List<T> values)
  97. {
  98. return JoinInternal(separator.AsSpan(), (IReadOnlyList<T>)values);
  99. }
  100. /// <summary>Concatenates the elements of an array, using the specified seperator between each element.</summary>
  101. public static string Join<T>(string separator, ReadOnlySpan<T> values)
  102. {
  103. return JoinInternal(separator.AsSpan(), values);
  104. }
  105. public static string Join<T>(string separator, ICollection<T> values)
  106. {
  107. return JoinInternal(separator.AsSpan(), values.AsEnumerable());
  108. }
  109. public static string Join<T>(string separator, IList<T> values)
  110. {
  111. return JoinInternal(separator.AsSpan(), values);
  112. }
  113. public static string Join<T>(string separator, IReadOnlyList<T> values)
  114. {
  115. return JoinInternal(separator.AsSpan(), values);
  116. }
  117. public static string Join<T>(string separator, IReadOnlyCollection<T> values)
  118. {
  119. return JoinInternal(separator.AsSpan(), values.AsEnumerable());
  120. }
  121. /// <summary>Concatenates the elements of an array, using the specified seperator between each element.</summary>
  122. public static string Join<T>(string separator, IEnumerable<T> values)
  123. {
  124. return JoinInternal(separator.AsSpan(), values);
  125. }
  126. /// <summary>Concatenates the string representation of some specified objects.</summary>
  127. public static string Concat<T>(params T[] values)
  128. {
  129. return JoinInternal<T>(default, values.AsSpan());
  130. }
  131. /// <summary>Concatenates the string representation of some specified objects.</summary>
  132. public static string Concat<T>(List<T> values)
  133. {
  134. return JoinInternal(default, (IReadOnlyList<T>)values);
  135. }
  136. /// <summary>Concatenates the string representation of some specified objects.</summary>
  137. public static string Concat<T>(ReadOnlySpan<T> values)
  138. {
  139. return JoinInternal(default, values);
  140. }
  141. /// <summary>Concatenates the string representation of some specified objects.</summary>
  142. public static string Concat<T>(ICollection<T> values)
  143. {
  144. return JoinInternal(default, values.AsEnumerable());
  145. }
  146. /// <summary>Concatenates the string representation of some specified objects.</summary>
  147. public static string Concat<T>(IList<T> values)
  148. {
  149. return JoinInternal(default, values);
  150. }
  151. /// <summary>Concatenates the string representation of some specified objects.</summary>
  152. public static string Concat<T>(IReadOnlyList<T> values)
  153. {
  154. return JoinInternal(default, values);
  155. }
  156. /// <summary>Concatenates the string representation of some specified objects.</summary>
  157. public static string Concat<T>(IReadOnlyCollection<T> values)
  158. {
  159. return JoinInternal(default, values.AsEnumerable());
  160. }
  161. /// <summary>Concatenates the string representation of some specified objects.</summary>
  162. public static string Concat<T>(IEnumerable<T> values)
  163. {
  164. return JoinInternal(default, values);
  165. }
  166. static string JoinInternal<T>(ReadOnlySpan<char> separator, IList<T> values)
  167. {
  168. var readOnlyList = values as IReadOnlyList<T>;
  169. // Boxing will occur, but JIT will be de-virtualized.
  170. readOnlyList = readOnlyList ?? new ReadOnlyListAdaptor<T>(values);
  171. return JoinInternal(separator, readOnlyList);
  172. }
  173. static string JoinInternal<T>(ReadOnlySpan<char> separator, IReadOnlyList<T> values)
  174. {
  175. var count = values.Count;
  176. if (count == 0)
  177. {
  178. return string.Empty;
  179. }
  180. else if (typeof(T) == typeof(string) && count == 1)
  181. {
  182. return Unsafe.As<string>(values[0]);
  183. }
  184. var sb = new Utf16ValueStringBuilder(true);
  185. try
  186. {
  187. sb.AppendJoinInternal(separator, values);
  188. return sb.ToString();
  189. }
  190. finally
  191. {
  192. sb.Dispose();
  193. }
  194. }
  195. static string JoinInternal<T>(ReadOnlySpan<char> separator, ReadOnlySpan<T> values)
  196. {
  197. if (values.Length == 0)
  198. {
  199. return string.Empty;
  200. }
  201. else if (typeof(T) == typeof(string) && values.Length == 1)
  202. {
  203. return Unsafe.As<string>(values[0]);
  204. }
  205. var sb = new Utf16ValueStringBuilder(true);
  206. try
  207. {
  208. sb.AppendJoinInternal(separator, values);
  209. return sb.ToString();
  210. }
  211. finally
  212. {
  213. sb.Dispose();
  214. }
  215. }
  216. static string JoinInternal<T>(ReadOnlySpan<char> separator, IEnumerable<T> values)
  217. {
  218. var sb = new Utf16ValueStringBuilder(true);
  219. try
  220. {
  221. sb.AppendJoinInternal(separator, values);
  222. return sb.ToString();
  223. }
  224. finally
  225. {
  226. sb.Dispose();
  227. }
  228. }
  229. }
  230. }