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
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 .NET 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
Stack<T> then you'll be right at home.
Get- Removes and returns one or more items from the start of the buffer
Put- Adds one or more items to the end of the buffer. If the buffer is full, then items at the start will be overwritten
Peek- Retrieve one or more items from the start of the buffer, without removing them
PeekLast- Retrieve the last item in the buffer without removing it
ToArray- Return all items in the buffer
CopyTo- An advanced version of
ToArray, allows you to copy items from the buffer into another array
Clear- Resets the buffer
There are also some properties to control behaviour or provide state information.
Capacity- The total number of items the buffer can hold
Size- The current number of items in the buffer
true, new items overwrite the oldest items when the buffer is full. Otherwise, an exception is thrown
trueif the buffer is empty
trueif the buffer is full and
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
this has tests which cover almost all the code paths.
.NET Framework 2.0 or later.
- 2014-06-21 - First published
- 2020-11-21 - Updated formatting