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 .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 Queue<Y>
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
All content Copyright (c) by Cyotek Ltd or its respective writers. Permission to reproduce news and web log entries and other RSS feed content in unmodified form without notice is granted provided they are not used to endorse or promote any products or opinions (other than what was expressed by the author) and without taking them out of context. Written permission from the copyright owner must be obtained for everything else.
Original URL of this content is https://www.cyotek.com/blog/circularbuffer-a-first-in-first-out-collection-of-objects-using-a-fixed-buffer?source=rss.