/// @file ring_buffer.h /// @brief /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. #pragma once #define DECLARE_FIXED_SIZE_RING_BUFFER(type, name, length, init) \ typedef struct fs_rb_##name##_t { \ unsigned size, read, write; \ type buffer[length]; \ } fs_rb_##name##_t; \ static inline void fs_rb_##name##_init(fs_rb_##name##_t *rb) \ { \ rb->size = length; \ rb->read = rb->write = 0; \ char *dst = (char *)rb->buffer; \ long num = sizeof(type) * length; \ while (num--) *dst++ = (char)(init & 0xFF); \ } \ static inline unsigned fs_rb_##name##_step(fs_rb_##name##_t *rb, unsigned index) \ { \ return (index == (rb->size - 1)) ? 0 : index + 1; \ } \ static inline void fs_rb_##name##_push_front(fs_rb_##name##_t *rb, type item) \ { \ if (fs_rb_##name##_step(rb, rb->write) == rb->read) \ rb->read = fs_rb_##name##_step(rb, rb->read); \ rb->buffer[rb->write] = item; \ rb->write = fs_rb_##name##_step(rb, rb->write); \ } \ static inline type fs_rb_##name##_empty(fs_rb_##name##_t *rb) \ { \ return rb->write == rb->read; \ } \ static inline type fs_rb_##name##_pop_back(fs_rb_##name##_t *rb) \ { \ type item = init; \ if (!fs_rb_##name##_empty(rb)) { \ item = rb->buffer[rb->read]; \ rb->read = fs_rb_##name##_step(rb, rb->read); \ } \ return item; \ } \ static inline type fs_rb_##name##_get(fs_rb_##name##_t *rb, unsigned index) \ { \ if (index < rb->size) \ return rb->buffer[index]; \ return init; \ } \ static inline type fs_rb_##name##_back(fs_rb_##name##_t *rb) \ { \ if (!fs_rb_##name##_empty(rb)) \ return rb->buffer[rb->read]; \ return init; \ } \ static inline type fs_rb_##name##_front(fs_rb_##name##_t *rb) \ { \ if (!fs_rb_##name##_empty(rb)) { \ if (rb->write > 0) \ return rb->buffer[rb->write - 1]; \ return rb->buffer[rb->size - 1]; \ } \ return init; \ } #ifdef __KERNEL__ #define DECLARE_RING_BUFFER(type, name, init) \ typedef struct rb_##name##_t { \ const unsigned size; \ unsigned read, write; \ type *buffer; \ } rb_##name##_t; \ static inline rb_##name##_t alloc_rb_##name(unsigned len) \ { \ rb_##name##_t rb = { len, 0U, 0U, len > 0 ? kmalloc(sizeof(type) * len) : NULL }; \ memset(rb.buffer, init, sizeof(type) * len); \ return rb; \ } \ static inline void free_rb_##name(rb_##name##_t *rb) \ { \ kfree(rb->buffer); \ } \ static inline unsigned step_rb_##name(rb_##name##_t *rb, unsigned index) \ { \ return (index == (rb->size - 1)) ? 0 : index + 1; \ } \ static inline void push_rb_##name(rb_##name##_t *rb, type item) \ { \ if (step_rb_##name(rb, rb->write) == rb->read) \ rb->read = step_rb_##name(rb, rb->read); \ rb->buffer[rb->write] = item; \ rb->write = step_rb_##name(rb, rb->write); \ } \ static inline void pop_rb_##name(rb_##name##_t *rb, type *item) \ { \ *item = init; \ if (rb->write != rb->read) { \ *item = rb->buffer[rb->read]; \ rb->read = step_rb_##name(rb, rb->read); \ } \ } \ static inline void get_rb_##name(rb_##name##_t *rb, unsigned index, type *item) \ { \ if (index < rb->size) \ *item = rb->buffer[index]; \ } #else #define DECLARE_RING_BUFFER(type, name) \ typedef struct rb_##name##_t { \ const unsigned size; \ unsigned read, write; \ type *buffer; \ } rb_##name##_t; \ static inline rb_##name##_t alloc_rb_##name(unsigned len) \ { \ rb_##name##_t rb = { len, 0U, 0U, len > 0 ? malloc(sizeof(type) * len) : NULL }; \ memset(rb.buffer, 0, sizeof(type) * len); \ return rb; \ } \ static inline void free_rb_##name(rb_##name##_t *rb) \ { \ free(rb->buffer); \ } \ static inline unsigned step_rb_##name(rb_##name##_t *rb, unsigned index) \ { \ return (index == (rb->size - 1)) ? 0 : index + 1; \ } \ static inline void push_rb_##name(rb_##name##_t *rb, type item) \ { \ if (step_rb_##name(rb, rb->write) == rb->read) \ rb->read = step_rb_##name(rb, rb->read); \ rb->buffer[rb->write] = item; \ rb->write = step_rb_##name(rb, rb->write); \ } \ static inline void pop_rb_##name(rb_##name##_t *rb, type *item) \ { \ if (rb->write != rb->read) { \ *item = rb->buffer[rb->read]; \ rb->read = step_rb_##name(rb, rb->read); \ } \ } \ static inline void get_rb_##name(rb_##name##_t *rb, unsigned index, type *item) \ { \ if (index < rb->size) \ *item = rb->buffer[index]; \ } #endif