You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

357 lines
12 KiB

4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
4 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. namespace Apewer
  5. {
  6. /// <summary>数组构建器。</summary>
  7. public sealed class ArrayBuilder<T>
  8. {
  9. private Type _type = typeof(T);
  10. private T[] _array;
  11. private int _capacity;
  12. private int _count;
  13. private int _step;
  14. /// <summary>创建构建程序实例。</summary>
  15. /// <param name="step">每次扩容的增量,最小值:1,默认值:256。</param>
  16. /// <exception cref="ArgumentNullException"></exception>
  17. public ArrayBuilder(int step = 256)
  18. {
  19. if (step < 1) throw new ArgumentOutOfRangeException(nameof(step));
  20. _step = step;
  21. _capacity = step;
  22. _count = 0;
  23. _array = new T[step];
  24. }
  25. private ArrayBuilder(ArrayBuilder<T> old)
  26. {
  27. _step = old._step;
  28. _capacity = old._capacity;
  29. _count = old._count;
  30. _array = new T[_capacity];
  31. if (_count > 0) Array.Copy(old._array, _array, _count);
  32. }
  33. /// <summary>获取或设置指定位置的元素,索引器范围为 [0, Length)。</summary>
  34. /// <exception cref="ArgumentOutOfRangeException"></exception>
  35. public T this[int index]
  36. {
  37. get
  38. {
  39. if (index < 0 || index >= _count) throw new ArgumentOutOfRangeException("索引超出了当前数组的范围。");
  40. return _array[index];
  41. }
  42. set
  43. {
  44. if (index < 0 || index >= _count) throw new ArgumentOutOfRangeException("索引超出了当前数组的范围。");
  45. _array[index] = value;
  46. }
  47. }
  48. /// <summary>源数组。</summary>
  49. public T[] Origin { get => _array; }
  50. /// <summary>缓冲区的容量。</summary>
  51. public int Capacity { get => _capacity; }
  52. /// <summary>当前的元素数量。</summary>
  53. public int Length { get => _count; }
  54. /// <summary>当前的元素数量。</summary>
  55. public int Count { get => _count; }
  56. /// <summary>指定元素在数组中的偏移位置。</summary>
  57. public int IndexOf(T value)
  58. {
  59. var array = _array;
  60. var length = _count;
  61. if (length < 1) return -1;
  62. for (var i = 0; i < length; i++)
  63. {
  64. var item = array[i];
  65. if (item == null) continue;
  66. if (item.Equals(value)) return i;
  67. }
  68. return -1;
  69. }
  70. /// <summary>已包含指定的元素。</summary>
  71. public bool Contains(T value) => IndexOf(value) > -1;
  72. /// <summary>添加元素。</summary>
  73. public void Add(T item)
  74. {
  75. if (_capacity - _count < 1)
  76. {
  77. _capacity += _step;
  78. var temp = new T[_capacity];
  79. Array.Copy(_array, temp, _count);
  80. _array = temp;
  81. }
  82. _array[_count] = item;
  83. _count++;
  84. }
  85. /// <summary>添加多个元素。</summary>
  86. public void Add(params T[] items)
  87. {
  88. if (items == null) return;
  89. var length = items.Length;
  90. if (length < 1) return;
  91. if (_capacity - _count < length)
  92. {
  93. _capacity = _count + length;
  94. var temp = new T[_capacity];
  95. Array.Copy(_array, temp, _count);
  96. _array = temp;
  97. }
  98. Array.Copy(items, 0, _array, _count, length);
  99. _count += length;
  100. }
  101. /// <summary>添加多个元素。</summary>
  102. public void Add(ICollection<T> items)
  103. {
  104. if (items == null) return;
  105. var length = items.Count;
  106. if (length < 1) return;
  107. if (_capacity - _count < length)
  108. {
  109. _capacity = _count + length;
  110. var temp = new T[_capacity];
  111. Array.Copy(_array, temp, _count);
  112. _array = temp;
  113. }
  114. items.CopyTo(_array, _count);
  115. _count += length;
  116. }
  117. /// <summary>添加多个元素。</summary>
  118. public void Add(IEnumerable<T> items)
  119. {
  120. if (items == null) return;
  121. foreach (var item in items) Add(item);
  122. }
  123. /// <summary>添加元素。</summary>
  124. /// <param name="buffer">要添加的元素数组。</param>
  125. /// <param name="offset">buffer 的开始位置。</param>
  126. /// <param name="count">buffer 的元素数量。</param>
  127. /// <exception cref="ArgumentNullException"></exception>
  128. /// <exception cref="ArgumentOutOfRangeException"></exception>
  129. public void Add(T[] buffer, int offset, int count)
  130. {
  131. if (buffer == null) throw new ArgumentNullException(nameof(buffer));
  132. var length = buffer.Length;
  133. if (offset < 0 || offset >= length || count < 0) throw new ArgumentOutOfRangeException();
  134. if (offset + count > length) throw new ArgumentOutOfRangeException();
  135. if (_capacity - _count < length)
  136. {
  137. _capacity = _count + length;
  138. var temp = new T[_capacity];
  139. Array.Copy(_array, temp, _count);
  140. _array = temp;
  141. }
  142. Array.Copy(buffer, offset, _array, _count, count);
  143. _count += count;
  144. }
  145. /// <summary>清空所有元素。</summary>
  146. public void Clear()
  147. {
  148. _capacity = 0;
  149. _count = 0;
  150. _array = new T[0];
  151. }
  152. // 修剪数组,去除剩余空间。
  153. void Trim()
  154. {
  155. if (_count == 0)
  156. {
  157. if (_capacity > 0)
  158. {
  159. _capacity = 0;
  160. _array = new T[0];
  161. }
  162. return;
  163. }
  164. if (_count == _capacity) return;
  165. var array = new T[_count];
  166. Array.Copy(_array, array, _count);
  167. _capacity = _count;
  168. }
  169. #region 模仿 JavaScript 数组方法。
  170. /// <summary>添加元素。</summary>
  171. public void Push(T item) => Add(item);
  172. /// <summary>取出最后一个元素。</summary>
  173. public T Pop(Func<T> @default = null)
  174. {
  175. if (_count > 0)
  176. {
  177. var offset = _count - 1;
  178. var value = _array[offset];
  179. _array[offset] = default(T);
  180. _count -= 1;
  181. return value;
  182. }
  183. return @default == null ? default(T) : @default.Invoke();
  184. }
  185. /// <summary>取出第一个元素,当数组为空时使用指定方法返回默认值。</summary>
  186. public T Shift(Func<T> @default = null)
  187. {
  188. if (_count > 0)
  189. {
  190. var value = _array[0];
  191. var temp = new T[_count];
  192. if (_count > 1) Array.Copy(_array, 1, temp, 0, _count - 1);
  193. _array = temp;
  194. _count -= 1;
  195. return value;
  196. }
  197. return @default == null ? default(T) : @default.Invoke();
  198. }
  199. /// <summary>添加元素到数组最前端。</summary>
  200. public void Unshift(T item)
  201. {
  202. var remains = _capacity - _count;
  203. var length = remains > 0 ? _capacity : (_capacity + _step);
  204. var temp = new T[length];
  205. temp[0] = item;
  206. if (_count > 0)
  207. {
  208. Array.Copy(_array, 0, temp, 1, _count);
  209. _count++;
  210. }
  211. _capacity = length;
  212. _array = temp;
  213. }
  214. #endregion
  215. #region 导出、转换。
  216. /// <summary>导出字符串。</summary>
  217. public override string ToString() => ToString(null);
  218. /// <summary>导出字符串。</summary>
  219. /// <param name="separator">分隔符。</param>
  220. public string ToString(string separator)
  221. {
  222. var sb = new StringBuilder();
  223. var hasSeparator = !string.IsNullOrEmpty(separator);
  224. if (_type.IsValueType)
  225. {
  226. for (var i = 0; i < _count; i++)
  227. {
  228. if (i > 0 && hasSeparator) sb.Append(separator);
  229. sb.Append(_array[i].ToString());
  230. }
  231. }
  232. else
  233. {
  234. var isString = _type == typeof(string);
  235. for (var i = 0; i < _count; i++)
  236. {
  237. if (_array[i] == null) continue;
  238. if (i > 0 && hasSeparator) sb.Append(separator);
  239. sb.Append(isString ? _array[i] as string : _array[i].ToString());
  240. }
  241. }
  242. return sb.ToString();
  243. }
  244. /// <summary>导出到新数组。</summary>
  245. /// <param name="clear">导出后清空元素。</param>
  246. public T[] Export(bool clear = false)
  247. {
  248. if (_count == 0) return new T[0];
  249. if (_count == _capacity) return _array;
  250. var array = new T[_count];
  251. Array.Copy(_array, array, _count);
  252. if (clear) _array = new T[0];
  253. return array;
  254. }
  255. /// <summary>克隆当前实例,生成新实例。</summary>
  256. public ArrayBuilder<T> Clone() => new ArrayBuilder<T>(this);
  257. /// <summary>使用 Export 方法实现从 ArrayBuilder&lt;T&gt; 到 T[] 的隐式转换。</summary>
  258. public static implicit operator T[](ArrayBuilder<T> instance) => instance == null ? null : instance.Export();
  259. internal static string Text(ArrayBuilder<char> ab)
  260. {
  261. if (ab == null) return "";
  262. if (ab._count < 1) return "";
  263. return new string(ab._array, 0, ab._count);
  264. }
  265. internal static string Text(ArrayBuilder<char> ab, int start, int count)
  266. {
  267. if (start < 0) throw new ArgumentOutOfRangeException("startIndex", "起始位置不可小于 0。");
  268. if (count < 0) throw new ArgumentOutOfRangeException("maxCount", "最大数量不可小于 0。");
  269. if (ab == null || count < 1) return "";
  270. if (start < 0) start = 0;
  271. var total = ab._count;
  272. if (start + count > total) count = total - start;
  273. if (count < 1) return "";
  274. return new string(ab._array, start, count);
  275. }
  276. internal static string Join(ArrayBuilder<string> ab, string separator)
  277. {
  278. if (ab == null) return "";
  279. return Join(ab, separator, 0, ab._count);
  280. }
  281. internal static string Join(ArrayBuilder<string> ab, string separator, int start, int count)
  282. {
  283. if (start < 0) throw new ArgumentOutOfRangeException("startIndex", "起始位置不可小于 0。");
  284. if (count < 0) throw new ArgumentOutOfRangeException("maxCount", "最大数量不可小于 0。");
  285. if (ab == null || count < 1) return ""; // 数组为空。
  286. if (start < 0) start = 0; // 修正起始位置最小值。
  287. var total = ab._count; // 数组中的元素总数。
  288. if (start + count > total) count = total - start; // 最大数量。
  289. if (count < 1) return ""; // 不取任何元素。
  290. var end = start + count; // 结束位置。
  291. var se = string.IsNullOrEmpty(separator); // 分隔符为空。
  292. var sb = new StringBuilder();
  293. for (var i = start; i < end; i++)
  294. {
  295. var item = ab._array[i];
  296. if (i > start && !se) sb.Append(separator);
  297. if (item == null || item == "") continue;
  298. sb.Append(item);
  299. }
  300. return sb.ToString();
  301. }
  302. #endregion
  303. }
  304. }