/** \file
    \brief Circular buffer FIFO template

    This FIFO template should be thread-safe in single-producer, single-consumer
    scenario assuming that integer (m_Read, m_Write) reads and writes are atomic
    on the target platform and there will be no instruction reordering (either
    hardware-based out-of-order execution or compiler optimalization) around
    m_Read/m_Write operations. "Volatile" keyword will keep it safe at least
    with VC++.
    This FIFO is intended to be used without any temporary data object and
    unnecessary memory copying. To put data in call getWriteable() to get pointer
    to storage type/class, fill it and then call push(). To get data call
    getReadable() to get pointer to container and call pop() to discard data after
    use.
*/

#ifndef FIFO_H
#define FIFO_H

template<class T, int Size>
class Fifo
{
private:
    volatile int m_Read;
    volatile int m_Write;
    volatile T m_Data[Size];

public:
    Fifo()
    {
        m_Read = 0;
        m_Write = 0;
    }

    volatile T* getWriteable(void)
    {
        int nextElement = (m_Write + 1) % Size;
        if(nextElement != m_Read)
        {
            return &m_Data[m_Write];
        }
        else
        {
            return NULL;
        }
    }

    bool push(void)
    {
        int nextElement = (m_Write + 1) % Size;
        if(nextElement != m_Read)
        {
            m_Write = nextElement;
            return true;
        }
        else
            return false;
    }

    volatile T* getReadable(void)
    {
        if(m_Read == m_Write)
            return NULL;
        return &m_Data[m_Read];
    }

    bool pop(void)
    {
        if(m_Read == m_Write)
            return false;
        int nextElement = (m_Read + 1) % Size;
        m_Read = nextElement;
        return true;
    }
};

#endif


