335 lines
10 KiB
C#
335 lines
10 KiB
C#
/****************************************************************************
|
||
* Description:
|
||
*
|
||
* Author: hiramtan@live.com
|
||
****************************************************************************/
|
||
|
||
using System;
|
||
|
||
namespace BF
|
||
{
|
||
/// <summary>
|
||
/// This is a circular buffer class for reuse memory
|
||
/// </summary>
|
||
internal class CircularBuffer : IDisposable
|
||
{
|
||
|
||
private int writeRemain;
|
||
private int readRemain;
|
||
private State state;
|
||
|
||
/// <summary>
|
||
/// Read and write state
|
||
/// </summary>
|
||
public enum State
|
||
{
|
||
WriteAhead,
|
||
ReadAhead,
|
||
WriteEqualRead, // HowManyCanWrite == 0,HowManyCanRead == Size;
|
||
ReadEqualWrite, // HowManyCanWrite == Size,HowManyCanRead == 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Array to contain element
|
||
/// </summary>
|
||
public byte[] Array { get; private set; }
|
||
|
||
/// <summary>
|
||
/// Capacity
|
||
/// </summary>
|
||
public int Size { get; private set; }
|
||
|
||
/// <summary>
|
||
/// Current read and write state
|
||
/// </summary>
|
||
public State EState
|
||
{
|
||
get
|
||
{
|
||
return state;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Index of read position(this index is wait to read)
|
||
/// </summary>
|
||
public int ReadPosition { get; private set; }
|
||
|
||
/// <summary>
|
||
/// Index of write postion(this index is wait to write)
|
||
/// </summary>
|
||
public int WritePosition { get; private set; }
|
||
|
||
/// <summary>
|
||
/// how many data can write into array
|
||
/// </summary>
|
||
public int HowManyCanWrite
|
||
{
|
||
get
|
||
{
|
||
return writeRemain;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// How many data wait read
|
||
/// </summary>
|
||
public int HowManyCanRead
|
||
{
|
||
get
|
||
{
|
||
return readRemain;
|
||
}
|
||
}
|
||
|
||
public CircularBuffer(int size)
|
||
{
|
||
Size = size;
|
||
Array = new byte[Size];
|
||
writeRemain = Size;
|
||
readRemain = 0;
|
||
state = State.ReadEqualWrite;
|
||
}
|
||
|
||
/// <summary>
|
||
/// reset all state to init
|
||
/// </summary>
|
||
public void Reset()
|
||
{
|
||
writeRemain = Size;
|
||
readRemain = 0;
|
||
state = State.ReadEqualWrite;
|
||
ReadPosition = 0;
|
||
WritePosition = 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Move read index
|
||
/// </summary>
|
||
/// <param name="length"></param>
|
||
public void MoveReadPosition(int length)
|
||
{
|
||
if (length > HowManyCanRead)
|
||
{
|
||
throw new ArgumentOutOfRangeException("Read length large than data's length");
|
||
}
|
||
var index = ReadPosition + length;
|
||
if (index >= Size)
|
||
{
|
||
index -= Size;
|
||
}
|
||
ReadPosition = index;
|
||
if (ReadPosition == WritePosition)
|
||
{
|
||
state = State.ReadEqualWrite;
|
||
writeRemain = Size;
|
||
readRemain = 0;
|
||
}
|
||
else if(ReadPosition > WritePosition)
|
||
{
|
||
state = State.ReadAhead;
|
||
writeRemain = ReadPosition - WritePosition;
|
||
readRemain = (Size - ReadPosition) + WritePosition;
|
||
}
|
||
else
|
||
{
|
||
state = State.WriteAhead;
|
||
writeRemain = (Size - WritePosition) + ReadPosition;
|
||
readRemain = WritePosition - ReadPosition;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Move write index
|
||
/// </summary>
|
||
/// <param name="length"></param>
|
||
public void MoveWritePosition(int length)
|
||
{
|
||
if (length > HowManyCanWrite)
|
||
{
|
||
throw new Exception("Write length large than space");
|
||
}
|
||
var index = WritePosition + length;
|
||
if (index >= Size)
|
||
{
|
||
index -= Size;
|
||
}
|
||
WritePosition = index;
|
||
if (ReadPosition == WritePosition)
|
||
{
|
||
state = State.WriteEqualRead;
|
||
writeRemain = 0;
|
||
readRemain = Size;
|
||
}
|
||
else if(ReadPosition > WritePosition)
|
||
{
|
||
state = State.ReadAhead;
|
||
writeRemain = ReadPosition - WritePosition;
|
||
readRemain = (Size - ReadPosition) + WritePosition;
|
||
}
|
||
else
|
||
{
|
||
state = State.WriteAhead;
|
||
writeRemain = (Size - WritePosition) + ReadPosition;
|
||
readRemain = WritePosition - ReadPosition;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Write data to array
|
||
/// </summary>
|
||
/// <param name="array"></param>
|
||
public void Write(byte[] array)
|
||
{
|
||
if (array.Length > HowManyCanWrite)
|
||
{
|
||
throw new Exception("Can not write so many data to array");
|
||
}
|
||
|
||
if (state == State.WriteAhead)
|
||
{
|
||
var length = Size - WritePosition;
|
||
if (length >= array.Length) //write into end
|
||
{
|
||
for (int i = 0; i < array.Length; i++)
|
||
{
|
||
Array[WritePosition + i] = array[i];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int arrayIndex = 0;
|
||
for (int i = WritePosition; i < Size; i++) //write into end
|
||
{
|
||
Array[WritePosition + arrayIndex] = array[arrayIndex];
|
||
arrayIndex++;
|
||
}
|
||
var howManyAlreadWrite = arrayIndex; //alreay run arrayIndex++ so don't need +1
|
||
for (int i = 0; i < array.Length - howManyAlreadWrite; i++) //write into head
|
||
{
|
||
Array[i] = array[howManyAlreadWrite + i];
|
||
arrayIndex++;
|
||
}
|
||
}
|
||
}
|
||
else if (state == State.ReadAhead)
|
||
{
|
||
for (int i = 0; i < array.Length; i++)
|
||
{
|
||
Array[WritePosition + i] = array[i];
|
||
}
|
||
}
|
||
else if (state == State.ReadEqualWrite)
|
||
{
|
||
var length = Size - WritePosition;
|
||
if (length >= array.Length) //write into end
|
||
{
|
||
for (int i = 0; i < array.Length; i++)
|
||
{
|
||
Array[WritePosition + i] = array[i];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int arrayIndex = 0;
|
||
for (int i = WritePosition; i < Size; i++) //write into end
|
||
{
|
||
Array[i] = array[arrayIndex];
|
||
arrayIndex++;
|
||
}
|
||
var howManyAlreadWrite = arrayIndex; //alreay run arrayIndex++ so don't need +1
|
||
for (int i = 0; i < array.Length - howManyAlreadWrite; i++) //write into head
|
||
{
|
||
Array[i] = array[howManyAlreadWrite + i];
|
||
arrayIndex++;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
throw new Exception("Write error");
|
||
}
|
||
MoveWritePosition(array.Length);
|
||
}
|
||
|
||
public byte[] Read(int length)
|
||
{
|
||
if (length > HowManyCanRead)
|
||
{
|
||
throw new Exception("Can not read so many data from array");
|
||
}
|
||
|
||
byte[] array = new byte[length];
|
||
if (state == State.WriteAhead)
|
||
{
|
||
for (int i = 0; i < length; i++)
|
||
{
|
||
array[i] = Array[ReadPosition + i];
|
||
}
|
||
}
|
||
else if (state == State.ReadAhead)
|
||
{
|
||
var remainLength = Size - ReadPosition;
|
||
if (remainLength >= length)
|
||
{
|
||
for (int i = 0; i < length; i++)
|
||
{
|
||
array[i] = Array[ReadPosition + i];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int arrayIndex = 0;
|
||
for (int i = ReadPosition; i < Size; i++)
|
||
{
|
||
array[arrayIndex] = Array[i];
|
||
arrayIndex++;
|
||
}
|
||
var howManyAlreadRead = arrayIndex; //alreay run arrayIndex++ so don't need +1
|
||
for (int i = 0; i < length - howManyAlreadRead; i++)
|
||
{
|
||
array[howManyAlreadRead + i] = Array[i];
|
||
arrayIndex++;
|
||
}
|
||
}
|
||
}
|
||
else if (state == State.WriteEqualRead) //write index back to read index
|
||
{
|
||
var remainLength = Size - ReadPosition;
|
||
if (remainLength >= length)
|
||
{
|
||
for (int i = 0; i < length; i++)
|
||
{
|
||
array[i] = Array[ReadPosition + i];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int arrayIndex = 0;
|
||
for (int i = ReadPosition; i < Size; i++)
|
||
{
|
||
array[arrayIndex] = Array[i];
|
||
arrayIndex++;
|
||
}
|
||
var howManyAlreadRead = arrayIndex; //alreay run arrayIndex++ so don't need +1
|
||
for (int i = 0; i < length - howManyAlreadRead; i++)
|
||
{
|
||
array[howManyAlreadRead + i] = Array[i];
|
||
arrayIndex++;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
throw new Exception("read error");
|
||
}
|
||
MoveReadPosition(length);
|
||
return array;
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
Array = null;
|
||
}
|
||
}
|
||
} |