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