I needed a circular buffer for c# and I couldn't find it on the web. I implemented my version and here it is:
Note: There is no head and tail on this buffer. All you can do is write and read forever. Also, this buffer is not thread safe.
using System;
using System.Collections.Generic;
using System.Text;
namespace Utezduyar.IO.CoreCommunicator
{
/// <summary>
/// A circular buffer object.
/// </summary>
/// <example>
/// CircularBuffer<byte> buffer = new CircularBuffer<byte>(3);
/// buffer.Add(0x41);
/// buffer.Add(0x42);
/// buffer.Add(0x43);
/// buffer.Add(0x44);
/// buffer.Add(0x45);
///
/// Console.WriteLine("0:" + buffer.Get(0).ToString("X2"));
/// Console.WriteLine("1:" + buffer.Get(1).ToString("X2"));
/// Console.WriteLine("2:" + buffer.Get(2).ToString("X2"));
/// Console.WriteLine("3:" + buffer.Get(3).ToString("X2"));
/// Console.WriteLine("4:" + buffer.Get(4).ToString("X2"));
///
/// // Output:
/// // 0:45
/// // 1:44
/// // 2:43
/// // 3:45
/// // 4:44
/// </example>
public class CircularBuffer<T>
{
private T[] buffer; // Buffer
private int bufferIndex = 0; // Latest index of the buffer
/// <summary>
/// Constructor to initialize the buffer
/// </summary>
/// <param name="size">Size of the buffer</param>
public CircularBuffer(int size)
{
// Parameter check
if (size <= 0)
throw new ArgumentException("Size must be greater than 0");
// Assing variables
buffer = new T[size];
}
/// <summary>
/// Default constructor. Initializes a <c>CircularBuffer</c>
/// that can hold 256 items in it.
/// </summary>
public CircularBuffer() : this (256)
{
}
/// <summary>
/// Returns the size of the buffer
/// </summary>
/// <remarks>
/// This function returns only the size of the buffer.
/// This function can not be used to determine how
/// many bytes are in the buffer.
/// </remarks>
public int Length
{
get
{
return this.buffer.Length;
}
}
/// <summary>
/// Adds one item to the next available place in the buffer
/// </summary>
/// <remarks>
/// If the buffer is full, it overwrites
/// the very first item.
/// </remarks>
/// <param name="item">Item to add</param>
public void Add(T item)
{
if (bufferIndex == this.Length)
bufferIndex = 0;
buffer[bufferIndex++] = item;
}
/// <summary>
/// Used to retrieve item array from the buffer.
/// </summary>
/// <param name="numberOfItems">Number of items needed.</param>
/// <returns>Array of the item type. The array lenght
/// is same as <c>numberOfItems</c>.
/// </returns>
public T[] GetItems(int numberOfItems)
{
// Check arguments
if (numberOfItems <= 0)
throw new ArgumentException("numberOfItems needs to be greater than zero");
// Create the byte buffer. This byte buffer will be returned
T[] items = new T[numberOfItems];
// Get bytes from buffer
for (int i = 0; i < numberOfItems; i++)
items[i] = Get(i);
// Return
return items;
}
/// <summary>
/// Returns latest byte from buffer
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
/// <example>
/// CircularBuffer b = new CircularBuffer(10);
/// b.Add(0x41);
/// b.Add(0x42);
/// b.Get(0); // This would be 0x42
/// b.Get(1); // This would be 0x41
/// </example>
public T Get(int index)
{
// Argument check
if (index < 0)
throw new ArgumentException("Index must be greater than or equal to zero");
if (this.Length <= 0)
throw new ArgumentException
(string.Format("Buffer size is {0}. Buffer needs to be greater than 0", this.Length));
// Algorithm to find the buffer index
index = index % this.Length;
if (index < bufferIndex)
index = bufferIndex - index - 1;
else
index = bufferIndex - index - 1 + this.Length;
// Return the item
return buffer[index];
}
}
}
using System.Collections.Generic;
using System.Text;
namespace Utezduyar.IO.CoreCommunicator
{
/// <summary>
/// A circular buffer object.
/// </summary>
/// <example>
/// CircularBuffer<byte> buffer = new CircularBuffer<byte>(3);
/// buffer.Add(0x41);
/// buffer.Add(0x42);
/// buffer.Add(0x43);
/// buffer.Add(0x44);
/// buffer.Add(0x45);
///
/// Console.WriteLine("0:" + buffer.Get(0).ToString("X2"));
/// Console.WriteLine("1:" + buffer.Get(1).ToString("X2"));
/// Console.WriteLine("2:" + buffer.Get(2).ToString("X2"));
/// Console.WriteLine("3:" + buffer.Get(3).ToString("X2"));
/// Console.WriteLine("4:" + buffer.Get(4).ToString("X2"));
///
/// // Output:
/// // 0:45
/// // 1:44
/// // 2:43
/// // 3:45
/// // 4:44
/// </example>
public class CircularBuffer<T>
{
private T[] buffer; // Buffer
private int bufferIndex = 0; // Latest index of the buffer
/// <summary>
/// Constructor to initialize the buffer
/// </summary>
/// <param name="size">Size of the buffer</param>
public CircularBuffer(int size)
{
// Parameter check
if (size <= 0)
throw new ArgumentException("Size must be greater than 0");
// Assing variables
buffer = new T[size];
}
/// <summary>
/// Default constructor. Initializes a <c>CircularBuffer</c>
/// that can hold 256 items in it.
/// </summary>
public CircularBuffer() : this (256)
{
}
/// <summary>
/// Returns the size of the buffer
/// </summary>
/// <remarks>
/// This function returns only the size of the buffer.
/// This function can not be used to determine how
/// many bytes are in the buffer.
/// </remarks>
public int Length
{
get
{
return this.buffer.Length;
}
}
/// <summary>
/// Adds one item to the next available place in the buffer
/// </summary>
/// <remarks>
/// If the buffer is full, it overwrites
/// the very first item.
/// </remarks>
/// <param name="item">Item to add</param>
public void Add(T item)
{
if (bufferIndex == this.Length)
bufferIndex = 0;
buffer[bufferIndex++] = item;
}
/// <summary>
/// Used to retrieve item array from the buffer.
/// </summary>
/// <param name="numberOfItems">Number of items needed.</param>
/// <returns>Array of the item type. The array lenght
/// is same as <c>numberOfItems</c>.
/// </returns>
public T[] GetItems(int numberOfItems)
{
// Check arguments
if (numberOfItems <= 0)
throw new ArgumentException("numberOfItems needs to be greater than zero");
// Create the byte buffer. This byte buffer will be returned
T[] items = new T[numberOfItems];
// Get bytes from buffer
for (int i = 0; i < numberOfItems; i++)
items[i] = Get(i);
// Return
return items;
}
/// <summary>
/// Returns latest byte from buffer
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
/// <example>
/// CircularBuffer b = new CircularBuffer(10);
/// b.Add(0x41);
/// b.Add(0x42);
/// b.Get(0); // This would be 0x42
/// b.Get(1); // This would be 0x41
/// </example>
public T Get(int index)
{
// Argument check
if (index < 0)
throw new ArgumentException("Index must be greater than or equal to zero");
if (this.Length <= 0)
throw new ArgumentException
(string.Format("Buffer size is {0}. Buffer needs to be greater than 0", this.Length));
// Algorithm to find the buffer index
index = index % this.Length;
if (index < bufferIndex)
index = bufferIndex - index - 1;
else
index = bufferIndex - index - 1 + this.Length;
// Return the item
return buffer[index];
}
}
}
2 comments:
why this is not thread safe?
Because "buffer" is not protected by a thread control structure. The title's implication is that instances of the class should not be shared between threads without further work
Post a Comment