CircularBuffer - a first-in, first-out collection of objects using a fixed buffer
I haven't had much time to work on blog posts recently, but I do have one quick post to make.
One of our current application prototype's stores a bunch of
data. Data continuously arrives, but I only want to store so
much of it. You could do this with something list a List<T>
and just remove items when the collection is too big, but I
wanted something a bit more efficient which didn't have to do
any sort of resizing or allocation when adding and removing
items. Enter the circular buffer.
What is a circular buffer?
To quote Wikipedia, a circular buffer, cyclic buffer or ring buffer is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. This structure lends itself easily to buffering data streams.
Indeed. Originally I didn't want to invent the wheel, so when I found Circular Buffer for .NET1 I thought I would use that. Unfortunately as soon as I started using, I hit some problems, both in the code and with what I was trying to do. So I stopped working on what I was doing and wrote a full set of tests for the class, fixing bugs as I went, and also adding some more features to handle what I wanted.
Eventually I decided I would put the code up on GitHub as Circular Buffer for .NET doesn't seem to be maintained any longer.
A generic CircularBuffer<T> class for .NET
On our GitHub page you can download a modified version of
the original class. I'm not going into too many details here as
it's very straightforward to use - if you've used Queue<T>
or
Stack<T>
then you'll be right at home.
Get
- Removes and returns one or more items from the start of the bufferPut
- Adds one or more items to the end of the buffer. If the buffer is full, then items at the start will be overwrittenPeek
- Retrieve one or more items from the start of the buffer, without removing themPeekLast
- Retrieve the last item in the buffer without removing itToArray
- Return all items in the bufferCopyTo
- An advanced version ofToArray
, allows you to copy items from the buffer into another arrayClear
- Resets the buffer
There are also some properties to control behaviour or provide state information.
Capacity
- The total number of items the buffer can holdSize
- The current number of items in the bufferAllowOverwrite
- Whentrue
, new items overwrite the oldest items when the buffer is full. Otherwise, an exception is thrownIsEmpty
-true
if the buffer is emptyIsFull
-true
if the buffer is full andAllowOverwrite
isfalse
Examples
This first example creates a CircularBuffer<T>
, adds four
items, then retrieves the first item.
CircularBuffer<string> target;
string firstItem;
target = new CircularBuffer<string>(10);
target.Put("Alpha");
target.Put("Beta");
target.Put("Gamma");
firstItem = target.Get(); // Returns Alpha
This second example shows how the buffer will automatically overwrite the oldest items when full.
CircularBuffer<string> target;
string firstItem;
target = new CircularBuffer<string>(3);
target.Put("Alpha");
target.Put("Beta");
target.Put("Gamma");
target.Put("Delta");
firstItem = target.Get(); // Returns beta
For more examples, see the test class CircularBufferTests
as
this has tests which cover almost all the code paths.
Requirements
.NET Framework 2.0 or later.
Download
Cyotek.Collections.Generic.CircularBuffer
Update History
- 2014-06-21 - First published
- 2020-11-21 - Updated formatting
- 2023-02-05 - Fixed swapped URLs
-
http://circularbuffer.codeplex.com/, link no longer active↩
Leave a Comment
While we appreciate comments from our users, please follow our posting guidelines. Have you tried the Cyotek Forums for support from Cyotek and the community?
Comments
Mercede
#
Is this threadsafe or we have to make it threadsafe>
Richard Moss
#
Hello,
Thanks for the question. At the moment, it's not thread safe - the initial use I had for the class didn't involve multi-threaded access and I didn't want to burden the base class with having to do processing that wouldn't be used.
Regards;
Richard Moss