/*
* Copyright (c) 2020, Koen Martens
*
* License: public domain.
*
* Comes with no warranties.
*
*/
#ifndef _RING_BUFFER_H
#define _RING_BUFFER_H
/*
* Declare a static ring buffer variable. This defines a circular buffer that
* can be used with the other macro's in this file.
*
* @param name: name of the static variable
* @param type: type of the buffer elements
* @param size: number of elements (usable elements is one less than this parameter)
*/
#define RING_BUFFER(name, type, size) typedef struct ringBuffer_##name { \
size_t start; \
size_t end; \
type data[size]; \
} name##_t; \
static name##_t name = {0};
/*
* Check whether ring buffer is full.
*
* @param buffer: ring buffer declared with RING_BUFFER
* @returns: true if the buffer is full, false otherwise
*/
#define RING_BUFFER_FULL(buffer) ( ((buffer.end + 1) % \
number_of_elements(buffer.data)) == buffer.start )
/*
* Check whether ring buffer is empty.
*
* @param buffer: ring buffer
*/
#define RING_BUFFER_EMPTY(buffer) ( buffer.end == buffer.start )
/*
* Remove least-recently added item from ring buffer.
*
* @param buffer: ring buffer declared with RING_BUFFER
*/
#define RING_BUFFER_TAKE(buffer) do { \
if (!RING_BUFFER_EMPTY(buffer)) \
{ \
buffer.start = (buffer.start + 1) % number_of_elements(buffer.data); \
} \
} while(false)
/*
* Add (copy) an element in the ring buffer (if not full)
*
* @param buffer: ring buffer declared with RING_BUFFER
* @param element: element to copy into buffer
*/
#define RING_BUFFER_PUT(buffer, element) do { \
if (!RING_BUFFER_FULL(buffer)) \
{ \
buffer.data[buffer.end] = element; \
buffer.end = (buffer.end + 1) % number_of_elements(buffer.data); \
} \
} while(false)
/*
* Advance the ring buffer last item index (if not full).
*
* This advances the ring buffer end index, and is intended to be used
* in cases where the caller wants to set the element directly, such as:
*
* RING_BUFFER_NEW(buffer).foo = 42;
* RING_BUFFER_ADVANCE(buffer)
*
* The above code could be written less efficiently as:
*
* myElementType element;
* element.foo = 42;
* RING_BUFFER_PUT(buffer, element);
*
* @param buffer: ring buffer declared with RING_BUFFER
*/
#define RING_BUFFER_ADVANCE(buffer) do { \
if (!RING_BUFFER_FULL(buffer)) \
{ \
buffer.end = (buffer.end + 1) % number_of_elements(buffer.data); \
} \
} while(false)
/*
* Access the head of the ring buffer (the least recently added element).
*
* @param buffer: ring buffer declared with RING_BUFFER
*/
#define RING_BUFFER_HEAD(buffer) buffer.data[buffer.start]
/*
* Access the element that would be added by calling RING_BUFFER_PUT.
* Care must be taken not to write to this element if the buffer is full.
*
* @param buffer: ring buffer declared with RING_BUFFER
*/
#define RING_BUFFER_NEW(buffer) buffer.data[buffer.end]
/*
* Reset ring buffer. After this, the ring buffer is empty.
*
* @param buffer: ring buffer declared with RING_BUFFER
*/
#define RING_BUFFER_RESET(buffer) do { \
buffer.start = buffer.end = 0; \
} while(false)
#endif /* _RING_BUFFER_H */
--
KoenMartens - 29 Feb 2020