using System;
using System.Threading;
namespace Island.StandardLib.Storage
{
///
/// 提供一个线程安全的、可动态扩展、可垃圾回收且支持序列化的缓存区域
///
public class MultiSizeData : IStorable
{
byte[] Data;
///
/// 读取位置
///
public int ReadPosition { get; set; }
///
/// 未读取内容长度
///
public int ReadRemainEnd => Data.Length - ReadPosition;
///
/// 读取内容和缓存起点的距离
///
public int ReadRemainBegin => ReadPosition;
///
/// 写入位置
///
public int WritePosition { get; set; }
///
/// 未写入内容长度,此值在默认应用下应为0
///
public int WriteRemainEnd => Data.Length - WritePosition;
///
/// 写入内容和缓存起点的距离
///
public int WriteRemainBegin => WritePosition;
///
/// 从这个值开始,向前的内存区域已经完成写入和读取操作,可被释放
///
public int FreePtr => ReadPosition > WritePosition ? WritePosition : ReadPosition;
///
/// 当前缓存长度
///
public int Size => Data.Length;
///
/// 初始化缓存区域,初始大小为0
///
public MultiSizeData()
{
Data = new byte[0];
lck_itio = new object();
lck_recvier = new object();
}
object lck_itio, lck_recvier;
///
/// 向缓存的任意位置写入数据,若长度不足则拓展缓存
///
/// 写入起点
/// 写入的内容
public void WriteAnyWhere(int begin, byte[] data)
{
lock (lck_itio)
{
if (Data.Length < begin + data.Length)
{
byte[] newData = new byte[begin + data.Length];
Array.Copy(Data, newData, Data.Length);
Data = newData;
}
Array.Copy(data, 0, Data, begin, data.Length);
}
}
///
/// 从缓存区域的任意位置读取数据,若当前不存在指定的区域则引发异常
///
/// 读取起点
/// 读取到的目标数组
/// 目标数组偏移量
/// 读取长度
public void ReadAnyWhere(int begin, byte[] writeTo, int offset, int size)
{
lock (lck_itio)
{
Array.Copy(Data, begin, writeTo, offset, size);
}
}
///
/// 向缓存区域的最后写入位置追加内容,若长度不足则拓展缓存
///
/// 追加的数据
public void Write(byte[] data)
{
lock (lck_recvier)
{
WriteAnyWhere(WritePosition, data);
WritePosition += data.Length;
}
}
///
/// 从缓存区域的最后读取位置读取指定长度的内容,若当前缓存长度不足则等待
///
/// 读取到的目标数组
/// 目标数组偏移量
/// 读取长度
public void Read(byte[] buffer, int offset, int size)
{
while (ReadRemainEnd < size)
Thread.Sleep(1);
lock (lck_recvier)
{
ReadAnyWhere(ReadPosition, buffer, offset, size);
ReadPosition += size;
}
}
///
/// 释放当前已读写的缓存区域,并调整读取位置和写入位置
///
public void FreeUnused()
{
lock (lck_recvier)
{
lock (lck_itio)
{
int downSize = FreePtr;
if (downSize == 0) return;
byte[] newData = new byte[Size - downSize];
Array.Copy(Data, downSize, newData, 0, Size - downSize);
ReadPosition -= downSize;
WritePosition -= downSize;
Data = newData;
}
}
}
public void ReadFromData(DataStorage data)
{
data.Read(out int read); ReadPosition = read;
data.Read(out int write); WritePosition = write;
Data = data.Read();
}
public void WriteToData(DataStorage data)
{
lock (lck_itio)
{
data.Write(ReadPosition);
data.Write(WritePosition);
data.Write(Data);
}
}
}
}