C++ FIFO (Circular Buffer) class

Here’s a FIFO/Circular Buffer class I put together ages ago.  I wrote it for a Windows CE platform, but there’s no reason it wouoldn’t work on the desktop as well.


 

//
// FIFO.h
//
#include

template
class FIFO
{
public:
FIFO(int capacityInItems, TCHAR *overrunEventName, TCHAR *dataAvailEventName);
~FIFO();
void Enqueue(T& item);
T Dequeue();
T Peek();
int GetCount();
BOOL HasOverrun();
void ClearOverrun();
void Clear();
HANDLE GetOverrunEventHandle();
int GetHighWater();

private:
BYTE *m_buffer;
volatile DWORD m_pRead;
volatile DWORD m_pWrite;
volatile BOOL m_full;
volatile BOOL m_empty;
volatile BOOL m_overrun;
volatile DWORD m_highWater;
DWORD m_capacity;
HANDLE m_overrunEvent;
HANDLE m_availableEvent;

CRITICAL_SECTION m_cs;

int m_increment;
};

templateFIFO::FIFO(int capacityInItems, TCHAR *overrunEventName, TCHAR *dataAvailEventName) :
m_pWrite(0),
m_pRead(0),
m_empty(TRUE),
m_full(FALSE),
m_overrun(FALSE),
m_overrunEvent(NULL),
m_highWater(0)

{
m_increment = sizeof(T);
m_capacity = capacityInItems * m_increment;
m_buffer = (BYTE*)LocalAlloc(LPTR, m_capacity);

if(overrunEventName != NULL)
{
m_overrunEvent = CreateEvent(NULL, FALSE, FALSE, overrunEventName);
}

if(dataAvailEventName != NULL)
{
m_availableEvent = CreateEvent(NULL, TRUE, FALSE, dataAvailEventName);
}

InitializeCriticalSection(&m_cs);
}

templateFIFO::~FIFO()
{
LocalFree(m_buffer);
DeleteCriticalSection(&m_cs);
}

templatevoid FIFO::Enqueue(T& item)
{
EnterCriticalSection(&m_cs);

if(m_full)
{
// if we’re full this is an overrun!
m_overrun = TRUE;

// set an event
if(m_overrunEvent != NULL)
{
SetEvent(m_overrunEvent);
}
}

m_empty = FALSE;

// set a friendly waitable object
if(m_availableEvent)
{
SetEvent(m_availableEvent);
}

memcpy(m_buffer + m_pWrite, static_cast(&item), m_increment);

m_pWrite += m_increment;

int count = GetCount();
if(count > m_highWater)
m_highWater = count;

if(m_pWrite >= m_capacity)
{
// back to the start
m_pWrite = 0;
}

// if we’ve overrun, the oldest data is tossed
if(m_overrun)
{
m_pRead += m_increment;

if(m_pRead >= m_capacity)
{
// back to the start
m_pRead = 0;
}
}
else
{
// see if we’re full
if(m_pWrite == m_pRead)
{
m_full = TRUE;
// set an event?
}
}

LeaveCriticalSection(&m_cs);
}

templateT FIFO::Dequeue()
{
T t;

EnterCriticalSection(&m_cs);

if(m_empty)
{
memset(&t, 0, m_increment);
LeaveCriticalSection(&m_cs);
return t;
}

m_full = FALSE;

memcpy(&t, m_buffer + m_pRead, m_increment);

m_pRead += m_increment;

if(m_pRead >= m_capacity)
{
// back to the start
m_pRead = 0;
}

// see if we’re empty
if(m_pRead == m_pWrite)
{
m_empty = TRUE;

// set a friendly waitable object
if(m_availableEvent)
{
ResetEvent(m_availableEvent);
}
}

LeaveCriticalSection(&m_cs);

return t;
}

templateT FIFO::Peek()
{
T *t;

if(m_empty)
{
return NULL;
}

return t;
}

templateint FIFO::GetCount()
{
int ret = 0;

EnterCriticalSection(&m_cs);

if(m_empty)
ret = 0;
else if(m_full)
ret = m_capacity / m_increment;
else if(m_pWrite > m_pRead)
ret = (m_pWrite – m_pRead) / m_increment;
else
ret = (m_capacity / m_increment) – ((m_pRead – m_pWrite) / m_increment);

LeaveCriticalSection(&m_cs);

return ret;
}

templateBOOL FIFO::HasOverrun()
{
return m_overrun;
}

templatevoid FIFO::ClearOverrun()
{
m_overrun = FALSE;
}

templatevoid FIFO::Clear()
{
m_overrun = FALSE;
m_full = FALSE;
m_empty = TRUE;
m_pWrite = 0;
m_pRead = 0;
}

templateHANDLE FIFO::GetOverrunEventHandle()
{
return m_overrunEvent;
}

templateint FIFO::GetHighWater()
{
return m_highWater;
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s