The circular buffer or ring buffer can often times be difficult to implement.  I pulled my hair out for hours trying to implement one using a dynamic array, but I finally found a simple solution that works very well and efficiently.

First of all what is a circular buffer?

The simplest way to think of it is as an array in which each end is connected.  A circular buffer has two indexes: a read index and a write index.  For each read operation, the read index will be incremented by one, and vice versa for write operations.

So how do we give an array circular behavior? 

Achieving this is relatively easy.  We must keep track of the size of the buffer.  Each time we increment an index, we check to see if the index is equal to the buffer size.  If it is, then this indicates the index has reached the end of the buffer and must be wrapped around, so we set it to 0.  Let’s look at some code shall we?

#include  
class Buffer{
public:
    Buffer(unsigned size);
    void write(double input);
    double read();
private:
    std::vector buffer;
    unsigned readIndex;
    unsigned writeIndex;
};

This is the layout for our class. I decided to use a vector instead of a dynamic array to avoid the complications that pointers introduce.

Now when we call the constructor we will specify the size which will be an unsigned integer. The write function accepts a double which will be written at the position where the write index currently is, and read will return a double from the position where the read index currently is.

The function definitions will look like this.

Constructor:

Buffer::Buffer(unsigned size) : buffer(size){
    readIndex = 0;
    writeIndex = size - 1;
}

The constructor for the vector called buffer is called and passed the size. This initializes the vector to the size that we passed to it. Then we simply set the readIndex to 0 and the writeIndex to the size of the vector minus 1. We do this because the nth element in a vector is one less than it’s size.

Write Method:

void Buffer::write(double input){
    buffer[writeIndex++] = input;
    if(writeIndex >= buffer.size())
        writeIndex = 0;
}

The write method is pretty straight forward. We access the element in the buffer at the position of write index and assign it to the input. We also post increment the write index as we pass it. Then we check to see if the index has reached the end of the buffer. If it has, we wrap it back around to the beginning by setting it to 0.

Read Method:

double Buffer::read(){
    double val = buffer[readIndex++];
    if(readIndex >= buffer.size())
        readIndex = 0;
    return val;
}

The read method is a little more complicated but the concept is still the same. We read from the buffer at the read index and assign that value you to a variable called val. The read index is incremented when it is used to access the buffer, so we must then check to see if it has reached the end of the buffer. If it has, then we assign it to 0 to wrap it to the beginning. Lastly we return the value that was read.

Our completed class should look like this.

#include 
class Buffer{
public:
    Buffer(unsigned size);
    void write(double input);
    double read();
private:
    std::vector buffer;
    unsigned readIndex;
    unsigned writeIndex;
};

Buffer::Buffer(unsigned size) : buffer(size){
    readIndex = 0;
    writeIndex = size - 1;
}

void Buffer::write(double input){
    buffer[writeIndex++] = input;
    if(writeIndex >= buffer.size())
        writeIndex = 0;
}

double Buffer::read(){
    double val = buffer[readIndex++];
    if(readIndex >= buffer.size())
        readIndex = 0;
    return val;
}

That’s it!

[mc4wp_form id=”11930″]


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *