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