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
357 lines
12 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace Apewer
|
|
{
|
|
|
|
/// <summary>数组构建器。</summary>
|
|
public sealed class ArrayBuilder<T>
|
|
{
|
|
|
|
private Type _type = typeof(T);
|
|
|
|
private T[] _array;
|
|
private int _capacity;
|
|
private int _count;
|
|
private int _step;
|
|
|
|
/// <summary>创建构建程序实例。</summary>
|
|
/// <param name="step">每次扩容的增量,最小值:1,默认值:256。</param>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
public ArrayBuilder(int step = 256)
|
|
{
|
|
if (step < 1) throw new ArgumentOutOfRangeException(nameof(step));
|
|
_step = step;
|
|
_capacity = step;
|
|
_count = 0;
|
|
_array = new T[step];
|
|
}
|
|
|
|
private ArrayBuilder(ArrayBuilder<T> old)
|
|
{
|
|
_step = old._step;
|
|
_capacity = old._capacity;
|
|
_count = old._count;
|
|
_array = new T[_capacity];
|
|
if (_count > 0) Array.Copy(old._array, _array, _count);
|
|
}
|
|
|
|
/// <summary>获取或设置指定位置的元素,索引器范围为 [0, Length)。</summary>
|
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
public T this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (index < 0 || index >= _count) throw new ArgumentOutOfRangeException("索引超出了当前数组的范围。");
|
|
return _array[index];
|
|
}
|
|
set
|
|
{
|
|
if (index < 0 || index >= _count) throw new ArgumentOutOfRangeException("索引超出了当前数组的范围。");
|
|
_array[index] = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>源数组。</summary>
|
|
public T[] Origin { get => _array; }
|
|
|
|
/// <summary>缓冲区的容量。</summary>
|
|
public int Capacity { get => _capacity; }
|
|
|
|
/// <summary>当前的元素数量。</summary>
|
|
public int Length { get => _count; }
|
|
|
|
/// <summary>当前的元素数量。</summary>
|
|
public int Count { get => _count; }
|
|
|
|
/// <summary>指定元素在数组中的偏移位置。</summary>
|
|
public int IndexOf(T value)
|
|
{
|
|
var array = _array;
|
|
var length = _count;
|
|
if (length < 1) return -1;
|
|
for (var i = 0; i < length; i++)
|
|
{
|
|
var item = array[i];
|
|
if (item == null) continue;
|
|
if (item.Equals(value)) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/// <summary>已包含指定的元素。</summary>
|
|
public bool Contains(T value) => IndexOf(value) > -1;
|
|
|
|
/// <summary>添加元素。</summary>
|
|
public void Add(T item)
|
|
{
|
|
if (_capacity - _count < 1)
|
|
{
|
|
_capacity += _step;
|
|
var temp = new T[_capacity];
|
|
Array.Copy(_array, temp, _count);
|
|
_array = temp;
|
|
}
|
|
_array[_count] = item;
|
|
_count++;
|
|
}
|
|
|
|
/// <summary>添加多个元素。</summary>
|
|
public void Add(params T[] items)
|
|
{
|
|
if (items == null) return;
|
|
|
|
var length = items.Length;
|
|
if (length < 1) return;
|
|
|
|
if (_capacity - _count < length)
|
|
{
|
|
_capacity = _count + length;
|
|
var temp = new T[_capacity];
|
|
Array.Copy(_array, temp, _count);
|
|
_array = temp;
|
|
}
|
|
|
|
Array.Copy(items, 0, _array, _count, length);
|
|
_count += length;
|
|
}
|
|
|
|
/// <summary>添加多个元素。</summary>
|
|
public void Add(ICollection<T> items)
|
|
{
|
|
if (items == null) return;
|
|
|
|
var length = items.Count;
|
|
if (length < 1) return;
|
|
|
|
if (_capacity - _count < length)
|
|
{
|
|
_capacity = _count + length;
|
|
var temp = new T[_capacity];
|
|
Array.Copy(_array, temp, _count);
|
|
_array = temp;
|
|
}
|
|
|
|
items.CopyTo(_array, _count);
|
|
_count += length;
|
|
}
|
|
|
|
/// <summary>添加多个元素。</summary>
|
|
public void Add(IEnumerable<T> items)
|
|
{
|
|
if (items == null) return;
|
|
foreach (var item in items) Add(item);
|
|
}
|
|
|
|
/// <summary>添加元素。</summary>
|
|
/// <param name="buffer">要添加的元素数组。</param>
|
|
/// <param name="offset">buffer 的开始位置。</param>
|
|
/// <param name="count">buffer 的元素数量。</param>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
public void Add(T[] buffer, int offset, int count)
|
|
{
|
|
if (buffer == null) throw new ArgumentNullException(nameof(buffer));
|
|
var length = buffer.Length;
|
|
if (offset < 0 || offset >= length || count < 0) throw new ArgumentOutOfRangeException();
|
|
if (offset + count > length) throw new ArgumentOutOfRangeException();
|
|
|
|
if (_capacity - _count < length)
|
|
{
|
|
_capacity = _count + length;
|
|
var temp = new T[_capacity];
|
|
Array.Copy(_array, temp, _count);
|
|
_array = temp;
|
|
}
|
|
|
|
Array.Copy(buffer, offset, _array, _count, count);
|
|
_count += count;
|
|
}
|
|
|
|
/// <summary>清空所有元素。</summary>
|
|
public void Clear()
|
|
{
|
|
_capacity = 0;
|
|
_count = 0;
|
|
_array = new T[0];
|
|
}
|
|
|
|
// 修剪数组,去除剩余空间。
|
|
void Trim()
|
|
{
|
|
if (_count == 0)
|
|
{
|
|
if (_capacity > 0)
|
|
{
|
|
_capacity = 0;
|
|
_array = new T[0];
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (_count == _capacity) return;
|
|
|
|
var array = new T[_count];
|
|
Array.Copy(_array, array, _count);
|
|
_capacity = _count;
|
|
}
|
|
|
|
#region 模仿 JavaScript 数组方法。
|
|
|
|
/// <summary>添加元素。</summary>
|
|
public void Push(T item) => Add(item);
|
|
|
|
/// <summary>取出最后一个元素。</summary>
|
|
public T Pop(Func<T> @default = null)
|
|
{
|
|
if (_count > 0)
|
|
{
|
|
var offset = _count - 1;
|
|
var value = _array[offset];
|
|
_array[offset] = default(T);
|
|
_count -= 1;
|
|
return value;
|
|
}
|
|
return @default == null ? default(T) : @default.Invoke();
|
|
}
|
|
|
|
/// <summary>取出第一个元素,当数组为空时使用指定方法返回默认值。</summary>
|
|
public T Shift(Func<T> @default = null)
|
|
{
|
|
if (_count > 0)
|
|
{
|
|
var value = _array[0];
|
|
var temp = new T[_count];
|
|
if (_count > 1) Array.Copy(_array, 1, temp, 0, _count - 1);
|
|
_array = temp;
|
|
_count -= 1;
|
|
return value;
|
|
}
|
|
return @default == null ? default(T) : @default.Invoke();
|
|
}
|
|
|
|
/// <summary>添加元素到数组最前端。</summary>
|
|
public void Unshift(T item)
|
|
{
|
|
var remains = _capacity - _count;
|
|
var length = remains > 0 ? _capacity : (_capacity + _step);
|
|
|
|
var temp = new T[length];
|
|
temp[0] = item;
|
|
if (_count > 0)
|
|
{
|
|
Array.Copy(_array, 0, temp, 1, _count);
|
|
_count++;
|
|
}
|
|
_capacity = length;
|
|
_array = temp;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 导出、转换。
|
|
|
|
/// <summary>导出字符串。</summary>
|
|
public override string ToString() => ToString(null);
|
|
|
|
/// <summary>导出字符串。</summary>
|
|
/// <param name="separator">分隔符。</param>
|
|
public string ToString(string separator)
|
|
{
|
|
var sb = new StringBuilder();
|
|
var hasSeparator = !string.IsNullOrEmpty(separator);
|
|
if (_type.IsValueType)
|
|
{
|
|
for (var i = 0; i < _count; i++)
|
|
{
|
|
if (i > 0 && hasSeparator) sb.Append(separator);
|
|
sb.Append(_array[i].ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var isString = _type == typeof(string);
|
|
for (var i = 0; i < _count; i++)
|
|
{
|
|
if (_array[i] == null) continue;
|
|
if (i > 0 && hasSeparator) sb.Append(separator);
|
|
sb.Append(isString ? _array[i] as string : _array[i].ToString());
|
|
}
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>导出到新数组。</summary>
|
|
/// <param name="clear">导出后清空元素。</param>
|
|
public T[] Export(bool clear = false)
|
|
{
|
|
if (_count == 0) return new T[0];
|
|
if (_count == _capacity) return _array;
|
|
var array = new T[_count];
|
|
Array.Copy(_array, array, _count);
|
|
if (clear) _array = new T[0];
|
|
return array;
|
|
}
|
|
|
|
/// <summary>克隆当前实例,生成新实例。</summary>
|
|
public ArrayBuilder<T> Clone() => new ArrayBuilder<T>(this);
|
|
|
|
/// <summary>使用 Export 方法实现从 ArrayBuilder<T> 到 T[] 的隐式转换。</summary>
|
|
public static implicit operator T[](ArrayBuilder<T> instance) => instance == null ? null : instance.Export();
|
|
|
|
internal static string Text(ArrayBuilder<char> ab)
|
|
{
|
|
if (ab == null) return "";
|
|
if (ab._count < 1) return "";
|
|
return new string(ab._array, 0, ab._count);
|
|
}
|
|
|
|
internal static string Text(ArrayBuilder<char> ab, int start, int count)
|
|
{
|
|
if (start < 0) throw new ArgumentOutOfRangeException("startIndex", "起始位置不可小于 0。");
|
|
if (count < 0) throw new ArgumentOutOfRangeException("maxCount", "最大数量不可小于 0。");
|
|
|
|
if (ab == null || count < 1) return "";
|
|
if (start < 0) start = 0;
|
|
var total = ab._count;
|
|
if (start + count > total) count = total - start;
|
|
if (count < 1) return "";
|
|
return new string(ab._array, start, count);
|
|
}
|
|
|
|
internal static string Join(ArrayBuilder<string> ab, string separator)
|
|
{
|
|
if (ab == null) return "";
|
|
return Join(ab, separator, 0, ab._count);
|
|
}
|
|
|
|
internal static string Join(ArrayBuilder<string> ab, string separator, int start, int count)
|
|
{
|
|
if (start < 0) throw new ArgumentOutOfRangeException("startIndex", "起始位置不可小于 0。");
|
|
if (count < 0) throw new ArgumentOutOfRangeException("maxCount", "最大数量不可小于 0。");
|
|
|
|
if (ab == null || count < 1) return ""; // 数组为空。
|
|
if (start < 0) start = 0; // 修正起始位置最小值。
|
|
var total = ab._count; // 数组中的元素总数。
|
|
if (start + count > total) count = total - start; // 最大数量。
|
|
if (count < 1) return ""; // 不取任何元素。
|
|
|
|
var end = start + count; // 结束位置。
|
|
var se = string.IsNullOrEmpty(separator); // 分隔符为空。
|
|
var sb = new StringBuilder();
|
|
for (var i = start; i < end; i++)
|
|
{
|
|
var item = ab._array[i];
|
|
if (i > start && !se) sb.Append(separator);
|
|
if (item == null || item == "") continue;
|
|
sb.Append(item);
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|