/* movstat/ringbuf.c * * Ring buffer module * * Copyright (C) 2018 Patrick Alken * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __GSL_RINGBUF_C__ #define __GSL_RINGBUF_C__ /*typedef int ringbuf_type;*/ typedef struct { ringbuf_type_t *array; int head; int tail; int size; /* total elements allocated */ } ringbuf; static size_t ringbuf_size(const size_t n); static int ringbuf_empty(ringbuf * d); static int ringbuf_is_empty(const ringbuf * d); static int ringbuf_is_full(const ringbuf * d); static int ringbuf_insert(const ringbuf_type_t x, ringbuf * d); static int ringbuf_pop_back(ringbuf * b); static ringbuf_type_t ringbuf_peek(const int i, const ringbuf * b); static ringbuf_type_t ringbuf_peek_front(const ringbuf * d); static ringbuf_type_t ringbuf_peek_back(const ringbuf * d); static size_t ringbuf_copy(double * dest, const ringbuf * b); static size_t ringbuf_size(const size_t n) { size_t size = 0; size += sizeof(ringbuf); size += n * sizeof(ringbuf_type_t); /* b->array */ return size; } static int ringbuf_init(const size_t n, ringbuf * b) { b->array = (ringbuf_type_t *) ((char *) b + sizeof(ringbuf)); b->head = -1; b->tail = 0; b->size = (int) n; return GSL_SUCCESS; } /* empty the buffer */ static int ringbuf_empty(ringbuf * b) { b->head = -1; b->tail = 0; return GSL_SUCCESS; } /* check if buffer is empty */ static int ringbuf_is_empty(const ringbuf * b) { return (b->head == -1); } /* check if buffer is full */ static int ringbuf_is_full(const ringbuf * b) { return ((b->head == 0 && b->tail == b->size - 1) || (b->head == b->tail + 1)); } /* insert element into buffer, overwriting oldest element if necessary */ static int ringbuf_insert(const ringbuf_type_t x, ringbuf * b) { if (b->head == -1) /* buffer is empty */ { b->head = 0; b->tail = 0; } else if (b->head == 0) /* head is in first position, wrap to end */ { b->head = b->size - 1; if (b->tail == b->head && b->size > 1) --(b->tail); /* buffer is full so decrease tail */ } else /* decrement head */ { --(b->head); if (b->tail == b->head) { /* buffer is full so update tail */ if (b->tail == 0) b->tail = b->size - 1; else --(b->tail); } } /* insert element */ b->array[b->head] = x; return GSL_SUCCESS; } static int ringbuf_pop_back(ringbuf * b) { if (ringbuf_is_empty(b) || b->tail < 0) { GSL_ERROR("buffer is empty", GSL_EBADLEN); } else { if (b->head == b->tail) /* buffer has only one element */ { b->head = -1; b->tail = -1; } else if (b->tail == 0) /* tail is in first position, wrap to end */ { b->tail = b->size - 1; } else /* decrement tail */ { --(b->tail); } return GSL_SUCCESS; } } static ringbuf_type_t ringbuf_peek(const int i, const ringbuf * b) { if (ringbuf_is_empty(b)) { GSL_ERROR("buffer is empty", GSL_EBADLEN); } else { return b->array[(b->head + i) % b->size]; } } static ringbuf_type_t ringbuf_peek_front(const ringbuf * b) { if (ringbuf_is_empty(b)) { GSL_ERROR("buffer is empty", GSL_EBADLEN); } else { return b->array[b->head]; } } static ringbuf_type_t ringbuf_peek_back(const ringbuf * b) { if (ringbuf_is_empty(b) || b->tail < 0) { GSL_ERROR("buffer is empty", GSL_EBADLEN); } else { return b->array[b->tail]; } } static size_t ringbuf_copy(double * dest, const ringbuf * b) { if (ringbuf_is_empty(b) || b->tail < 0) { return 0; } else { const int n = (b->head > b->tail) ? (b->size - b->head + b->tail + 1) : (b->tail - b->head + 1); int i; for (i = 0; i < n; ++i) dest[n - i - 1] = b->array[(b->head + i) % b->size]; return (size_t) n; } } #endif /* __GSL_RINGBUF_C__ */