/****************************************************************************
* Description:
*
* Author: hiramtan@live.com
****************************************************************************/
using System;
namespace BF
{
///
/// This is a circular buffer class for reuse memory
///
internal class CircularBuffer : IDisposable
{
private int writeRemain;
private int readRemain;
private State state;
///
/// Read and write state
///
public enum State
{
WriteAhead,
ReadAhead,
WriteEqualRead, // HowManyCanWrite == 0,HowManyCanRead == Size;
ReadEqualWrite, // HowManyCanWrite == Size,HowManyCanRead == 0;
}
///
/// Array to contain element
///
public byte[] Array { get; private set; }
///
/// Capacity
///
public int Size { get; private set; }
///
/// Current read and write state
///
public State EState
{
get
{
return state;
}
}
///
/// Index of read position(this index is wait to read)
///
public int ReadPosition { get; private set; }
///
/// Index of write postion(this index is wait to write)
///
public int WritePosition { get; private set; }
///
/// how many data can write into array
///
public int HowManyCanWrite
{
get
{
return writeRemain;
}
}
///
/// How many data wait read
///
public int HowManyCanRead
{
get
{
return readRemain;
}
}
public CircularBuffer(int size)
{
Size = size;
Array = new byte[Size];
writeRemain = Size;
readRemain = 0;
state = State.ReadEqualWrite;
}
///
/// reset all state to init
///
public void Reset()
{
writeRemain = Size;
readRemain = 0;
state = State.ReadEqualWrite;
ReadPosition = 0;
WritePosition = 0;
}
///
/// Move read index
///
///
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;
}
}
///
/// Move write index
///
///
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;
}
}
///
/// Write data to array
///
///
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;
}
}
}