2023-04-03 11:04:31 +08:00

335 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
* 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 postionthis 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;
}
}
}