// intellectual property is bullshit bgdc

#ifndef RINGBUF_HPP
#define RINGBUF_HPP

#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>

// Size-agnostic reference to a ringbuf
template<typename T>
class iringbuf
{
public:
	virtual ~iringbuf() = default;

	virtual bool push(T const & value) = 0;
	virtual bool pop(T & value) = 0;
};

// Single producer, single consumer ring buffer. Size is limited to 256 to
// permit volatile access to counters. Sizes equal to a power of two provide
// the most efficient implementation.
//
// If used with more than one producer or consumer, access must be locked.
// Otherwise, threadsafe.
template<typename T, unsigned Size>
class ringbuf: public iringbuf<T>
{
public:
	static_assert(
		Size <= UINT8_MAX,
		"ringbuf size must not exceed UINT8_MAX"
	);

	ringbuf() : m_head(0), m_tail(0) {}

	// Push into the buffer or return immediately.
	//
	// Return: whether the value was pushed
	bool push(T const & value)
	{
		if (full())
			return false;
		else
		{
			m_buffer[m_head] = value;
			m_head = (m_head + 1) % Size;
			return true;
		}
	}

	// Pop out of the buffer or return immediately.
	//
	// Return: whether a value was popped
	bool pop(T & value)
	{
		if (empty())
			return false;
		else
		{
			value = m_buffer[m_tail];
			m_tail = (m_tail + 1) % Size;
			return true;
		}
	}

	// Return number of elements in the buffer
	uint8_t count() const
	{
		return m_head - m_tail;
	}

	// Return whether empty
	bool empty() const
	{
		return count() == 0;
	}

	// Return whether full
	bool full() const
	{
		return count() == Size;
	}

private:
	uint8_t volatile m_head;
	uint8_t volatile m_tail;
	T m_buffer[Size];
};

#endif // !defined(RINGBUF_HPP)
