Small library for using circular buffers (forked from François Berder's implementation in order to add methods and fix problems)

Dependents:   CircularBufferTest XBeeApi

Fork of CircularBuffer by Francois Berder

Test suite can be found in this application, CircularBufferTest

CircularBuffer.h

Committer:
johnb
Date:
2014-01-30
Revision:
8:d318a6948091
Parent:
7:e2d532183250

File content as of revision 8:d318a6948091:

#ifndef CIRCULAR_BUFFER_H
#define CIRCULAR_BUFFER_H

#include <cstddef>
#include <stdint.h>

/** This class implements a static circular buffer.

    CirularBuffer class originally by François Berder ( see http://mbed.org/users/feb11/code/CircularBuffer/ )
    Additions by John Bailey ( http://mbed.org/users/johnb/ )
*/
template<size_t T>
class CircularBuffer
{
    public :

        /** Default constructor
        */
        CircularBuffer();
        
        /** Reads data from buffer (data is removed from the buffer as 
            opposed to the peek method which allows inspection of the
            contents without modifying the buffer)
        
            \param data output buffer 
            \param length Maximum number of bytes to read
            \return Number of bytes read
            
            \note The return value cannot exceed max(length,capacity)
        */
        uint32_t read(uint8_t *data, uint32_t length);

        /** Reads data from buffer leaving the data in the buffer
            (as opposed to the read method which removed the returned
            data from the buffer)
        
            \param data output buffer 
            \param length Maximum number of bytes to read
            \return Number of bytes read
            
            \note The return value cannot exceed max(length,capacity)
        */
        uint32_t peek(uint8_t *data, uint32_t length) const;
        
        /** Writes data in buffer
        
            \param data input buffer
            \param length Maximum number of bytes to write
            \return Number of bytes wrote
            
            \note The return value cannot exceed max(length,capacity)
        */
        uint32_t write(uint8_t *data, uint32_t length);
        
        /** Returns the total capacity of this buffer
            \return Capacity of buffer
        */
        uint32_t getCapacity() const;
        
        /** Returns the number of bytes available in the buffer
            \return Number of bytes available in the buffer
        */
        uint32_t getSize() const;  
        
        /** Checks if this buffer is empty
            \return True if the buffer is empty, false otherwise
        */
        bool isEmpty() const;
        
        /** Checks if this buffer is full
            \return True if the buffer is full, false otherwise
        */        
        bool isFull() const;
        
        /* Remove the specified number of bytes from the front of the buffer
           This is more efficient than using read() to access the bytes then
           junking them.
        
           \param length The number of bytes to remove.  If the specified 
                  number of bytes don't exist in the buffer, the buffer will
                  just be emptied
        */
        void chomp( uint32_t length );
  
        /* Read a single byte from the buffer.  The byte is not removed.
           The called must be responsible for ensuring that p_length < getSize()
        
           \param p_length The index of the byte to read, relative to the start 
                           of the circulat buffer
           \returns The byte at the specified position or a garbage byte in the 
                    case that the buffer is too short to support the request */ 
        uint8_t operator[]( uint32_t p_length ) const;
        
    private :

        typedef uint16_t CircularBufferIndex_t;
    
        CircularBufferIndex_t readIndex, writeIndex;
        uint8_t buffer[T]; 
    
};

template<size_t T>
CircularBuffer<T>::CircularBuffer():
readIndex(0),
writeIndex(0)
{
}

template<size_t T>
void CircularBuffer<T>::chomp(uint32_t length)
{
    if( length >= getSize() )
    {
        readIndex = writeIndex;
    } else {
        readIndex = (readIndex + length) % T;    
    }
}

template<size_t T>
uint32_t CircularBuffer<T>::read(uint8_t *data, uint32_t length)
{
    uint32_t n = 0;
    while(n < length && getSize() > 0)
    {
        if(readIndex == T)
            readIndex = 0;
        data[n++] = buffer[readIndex++];
    }
    
    return n;
}

template<size_t T>
uint32_t CircularBuffer<T>::peek(uint8_t *data, uint32_t length) const
{
    uint32_t n = 0;
    CircularBufferIndex_t src = readIndex;
    while((n < length ) && (n < getSize()))
    {
        if(src == T) {
            src = 0;
        }
        data[n++] = buffer[src++];
    }
    
    return n;
}

template<size_t T>
uint32_t CircularBuffer<T>::write(uint8_t *data, uint32_t length)
{
    uint32_t n = 0;
    while(n < length && getSize() < T)
    {
        if(writeIndex == T)
            writeIndex = 0;
        buffer[writeIndex++] = data[n++];
    }
    
    return n;
}

template<size_t T>
uint32_t CircularBuffer<T>::getCapacity() const
{
    return T;
}
        
template<size_t T>
uint32_t CircularBuffer<T>::getSize() const
{
    return ((writeIndex >= readIndex) ? (writeIndex - readIndex) : (T + writeIndex - readIndex));
}

template<size_t T>
bool CircularBuffer<T>::isEmpty() const
{
    return getSize() == 0;
}

template<size_t T>
bool CircularBuffer<T>::isFull() const
{
    return getSize() == T;
}

template<size_t T>
uint8_t CircularBuffer<T>::operator[]( uint32_t p_length ) const
{
    return buffer[(readIndex + p_length) % T];
}


typedef CircularBuffer<32> SmallCircularBuffer;
typedef CircularBuffer<128> MediumCircularBuffer;
typedef CircularBuffer<512> BigCircularBuffer;

#endif