#ifndef HTIO2_RING_BUFFER_H
#define HTIO2_RING_BUFFER_H

#include <stdint.h>
#include <limits>
#include "JUCE-3.0.8/JuceHeader.h"

namespace htio2
{

/**
 * A single-reader single-writer fixed-size ring buffer
 */
template <typename T>
class RingBuffer
{
public:
    RingBuffer(size_t capacity)
        : _capacity(capacity)
        , _size(0)
        , _i_read_seed(0)
        , _i_write_seed(0)
        , _data(new T[capacity])
    {}

    ~RingBuffer()
    {
        delete[] _data;
    }

    bool push(T value)
    {
        if (_size.get() >= _capacity)
            return false;

        // modify data
        ssize_t i_write = _i_write_seed;
        _data[i_write] = value;

        // move write index
        _i_write_seed = (i_write + 1) % _capacity;

        // update size at last
        ++_size;

        return true;
    }

    bool pop(T& result)
    {
        if (_size.get() <= 0)
            return false;

        // read data
        ssize_t i_read = _i_read_seed;
        result = _data[i_read];

        // move read index
        _i_read_seed = (i_read + 1) % _capacity;

        // update size at last
        --_size;

        return true;
    }

    void push_sync(T value)
    {
        while (!push(value))
            juce::Thread::yield();
    }

    void pop_sync(T& result)
    {
        while (!pop(result))
            juce::Thread::yield();
    }

    ssize_t size()
    {
        return _size.value;
    }


protected:
    T* _data;
    const size_t _capacity;
    juce::Atomic<ssize_t> _size;
    size_t _i_read_seed;
    size_t _i_write_seed;
};

} // namespace htio2

#endif // HTIO2_RING_BUFFER_H
