// intellectual property is bullshit bgdc

#ifndef RINGBUF_HPP
#define RINGBUF_HPP

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

// Single producer, single consumer ring buffer. Size is limited to 255 to
// permit volatile access to counters. Sizes one less than 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:
	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_tail] = value;
			m_tail = next(m_tail);
			return true;
		}
	}

	// Push into the buffer, waiting until ready.
	void push_wait(T const & value)
	{
		while (!push(value));
	}

	// 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_head];
			m_head = next(m_head);
			return true;
		}
	}

	// Pop out of the buffer, waiting until ready.
	void pop_wait(T & value)
	{
		while (!pop(value));
	}

	// Return whether empty
	bool empty() const
	{
		return m_head == m_tail;
	}

	// Return whether full
	bool full() const
	{
		return m_head == next(m_tail);
	}

private:
	uint8_t m_head;
	uint8_t m_tail;
	T m_buffer[Size + 1];

	// Return the next index
	static constexpr uint8_t next(uint8_t n)
	{
		return (n + 1) % (Size + 1);
	}
};

#endif // !defined(RINGBUF_HPP)
