Skip to content

Instantly share code, notes, and snippets.

@larshei
Last active March 2, 2023 09:30
Show Gist options
  • Select an option

  • Save larshei/cec020e037b0ebd103ef6252977f8b12 to your computer and use it in GitHub Desktop.

Select an option

Save larshei/cec020e037b0ebd103ef6252977f8b12 to your computer and use it in GitHub Desktop.
Tired of writing the same buffer functions all the time? not interested in setting up some fully blown buffer system? here you go. Quick and dirty fifo and ring buffer implementation in C as a single source file "include". Test and example usage at https://gist.github.com/larshei/444ecee2a90174757b49ac1fe85f604a
/* ============== FIFO BUFFER ============================================== */
/* After writing another small fifo buffers the 100th time, I created this gist.
* It is a QUICK AND DIRTY solution to get the standard functions of a fifo, namely
* - add and read elements
* - check if empty
* - reset
*
* ============== USAGE ======================================================
* 1. #define the FIFO_DATA_TYPE, FIFO_BUFFER_SIZE and FIFO_MEMORY.
* 2. Optionally: define FIFO_OVERWRITE_WHEN_FULL for ring buffer like behaviour
* 3. include this .c-file in your .c-file (yep, thats dirty).
* All functions are static, so in theory, you could include this in every
* file with a different setup and embrace the code duplication.
*
* ============== EXAMPLE ===================================================
* #define FIFO_DATA_TYPE int
* #define FIFO_BUFFER_SIZE 10
* FIFO_DATA_TYPE buffer[FIFO_BUFFER_SIZE];
* #define FIFO_MEMORY buffer
* #define FIFO_OVERWRITE_WHEN_FULL 0
*
* #include "fifo_buffer.c"
* ============== ADDITIONAL INFO ===========================================
* ALL OF THE DEFINES ABOVE WILL BE UNDEFINED IN fifo_buffer.c
*
* If you need FIFO_BUFFER_SIZE in your program, use a 2-step approach:
* #define MY_BUF_SIZE 10
* #define FIFO_BUFFER_SIZE MY_BUF_SIZE
* use MY_BUF_SIZE in your program.
* ========================================================================== */
// fifo buffer code
#ifndef FIFO_DATA_TYPE
#error "Need to define FIFO_DATA_TYPE (data type of elements stored)"
#endif
#ifndef FIFO_MEMORY
#error "Need to define FIFO_MEMORY (pointer to your buffer memory/array)"
#endif
#ifndef FIFO_BUFFER_SIZE
#error "Need to define FIFO_BUFFER_SIZE (number of FIFO_DATA_TYPE elements that can be stored in FIFO_MEMORY"
#endif
#ifndef FIFO_OVERWRITE_WHEN_FULL
#define FIFO_OVERWRITE_WHEN_FULL 0
#endif
// ----------------------------------------------------------------------------
typedef struct {
FIFO_DATA_TYPE* head;
FIFO_DATA_TYPE* tail;
FIFO_DATA_TYPE* first;
int max_element_count;
int is_empty;
} fifo_buffer_t;
// ----------------------------------------------------------------------------
static fifo_buffer_t _fifo_buffer = {
.head = FIFO_MEMORY,
.tail = FIFO_MEMORY,
.first = FIFO_MEMORY,
.max_element_count = sizeof(FIFO_MEMORY) / sizeof(FIFO_DATA_TYPE),
.is_empty = 1
};
// ----------------------------------------------------------------------------
static void fifo_wrap(FIFO_DATA_TYPE** head_or_tail) {
int needs_wrap = *head_or_tail >= _fifo_buffer.first + _fifo_buffer.max_element_count;
if ( needs_wrap ) {
*head_or_tail = _fifo_buffer.first;
}
}
// ----------------------------------------------------------------------------
static void fifo_reset() {
_fifo_buffer.head = _fifo_buffer.first;
_fifo_buffer.tail = _fifo_buffer.first;
_fifo_buffer.is_empty = 1;
}
// ----------------------------------------------------------------------------
static int fifo_add_element(FIFO_DATA_TYPE element) {
if ((_fifo_buffer.is_empty == 0) && (_fifo_buffer.head == _fifo_buffer.tail)) {
#if (defined(FIFO_OVERWRITE_WHEN_FULL) && (FIFO_OVERWRITE_WHEN_FULL != 0))
_fifo_buffer.tail++;
fifo_wrap(&_fifo_buffer.tail);
#else
return 1;
#endif
}
*_fifo_buffer.head++ = element;
fifo_wrap(&_fifo_buffer.head);
_fifo_buffer.is_empty = 0;
return 0;
}
// ----------------------------------------------------------------------------
static int fifo_is_empty() {
return _fifo_buffer.is_empty;
}
// ----------------------------------------------------------------------------
static FIFO_DATA_TYPE fifo_read_element() {
// check fifo_is_empty() before reading! As the data type stored in the
// buffer is not known, there is no default value that can be used to mark
// the read result als "invalid because empty".
#warning "!! fifo_read_element() does not check if the fifo is empty! Call fifo_is_empty() and read only if not empty !!"
FIFO_DATA_TYPE entry;
entry = *_fifo_buffer.tail++;
fifo_wrap(&_fifo_buffer.tail);
_fifo_buffer.is_empty = _fifo_buffer.tail == _fifo_buffer.head;
return entry;
}
// ----------------------------------------------------------------------------
#undef FIFO_BUFFER_SIZE
#undef FIFO_DATA_TYPE
#undef FIFO_MEMORY
#undef FIFO_OVERWRITE_WHEN_FULL
// ----------------------------------------------------------------------------
// =========== end of fifo buffer code ===========
@larshei
Copy link
Author

larshei commented Sep 15, 2020

"tests" can be found here: https://gist.github.com/larshei/444ecee2a90174757b49ac1fe85f604a
Put this file and the test in the same folder.
run

gcc fifo_buffer_test.c -o fifo
./fifo

Should show SUCCESS messages.

Change the OVERWRITE define to 0 or !0 to allow overwriting unread values in the buffer (to implement either a ring or a fifo buffer).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment