2013-06-22 17:58:19 +02:00
|
|
|
/**
|
|
|
|
* Ringbuffer implementation
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013 Freie Universität Berlin
|
|
|
|
* Copyright (C) 2013 INRIA
|
|
|
|
*
|
2014-07-31 19:45:27 +02:00
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
|
|
* directory for more details.
|
2013-06-22 17:58:19 +02:00
|
|
|
*
|
2014-11-16 11:31:57 +01:00
|
|
|
* @ingroup core_util
|
2013-06-22 17:58:19 +02:00
|
|
|
* @{
|
2015-05-22 07:34:41 +02:00
|
|
|
* @file
|
2013-12-04 15:07:56 +01:00
|
|
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
2014-05-03 18:49:55 +02:00
|
|
|
* @author René Kijewski <rene.kijewski@fu-berlin.de>
|
2013-06-22 17:58:19 +02:00
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
2013-10-10 17:06:14 +02:00
|
|
|
#include "ringbuffer.h"
|
2010-09-22 17:25:19 +02:00
|
|
|
|
2014-09-11 14:12:06 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
2014-05-03 20:13:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Add an element to the end of the ringbuffer.
|
|
|
|
* @details This helper function does not check the pre-requirements for adding,
|
|
|
|
* i.e. the caller has to ensure that ringbuffer_full() is false.
|
|
|
|
* @param[in,out] rb Ringbuffer to operate on.
|
|
|
|
* @param[in] c Element to add.
|
|
|
|
*/
|
2014-05-03 18:49:55 +02:00
|
|
|
static void add_tail(ringbuffer_t *restrict rb, char c)
|
|
|
|
{
|
|
|
|
unsigned pos = rb->start + rb->avail++;
|
2020-03-30 17:02:08 +02:00
|
|
|
|
2014-05-03 18:49:55 +02:00
|
|
|
if (pos >= rb->size) {
|
|
|
|
pos -= rb->size;
|
|
|
|
}
|
|
|
|
rb->buf[pos] = c;
|
|
|
|
}
|
|
|
|
|
2014-05-03 20:13:20 +02:00
|
|
|
/**
|
|
|
|
* @brief Remove an element from the start of the ringbuffer.
|
|
|
|
* @details This helper function does not check the pre-requirements for reading,
|
|
|
|
* i.e. the caller has to ensure that ringbuffer_empty() is false.
|
|
|
|
* @param[in,out] rb Ringbuffer to operate on.
|
|
|
|
* @returns The removed element.
|
|
|
|
*/
|
2014-05-03 18:49:55 +02:00
|
|
|
static char get_head(ringbuffer_t *restrict rb)
|
|
|
|
{
|
|
|
|
char result = rb->buf[rb->start];
|
2020-03-30 17:02:08 +02:00
|
|
|
|
2014-05-03 18:49:55 +02:00
|
|
|
if ((--rb->avail == 0) || (++rb->start == rb->size)) {
|
|
|
|
rb->start = 0;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-05-03 18:55:38 +02:00
|
|
|
unsigned ringbuffer_add(ringbuffer_t *restrict rb, const char *buf, unsigned n)
|
2013-06-22 17:58:19 +02:00
|
|
|
{
|
2014-05-03 18:55:38 +02:00
|
|
|
unsigned i;
|
2020-03-30 17:02:08 +02:00
|
|
|
|
2014-05-03 18:55:38 +02:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
if (ringbuffer_full(rb)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
add_tail(rb, buf[i]);
|
2010-09-24 13:53:22 +02:00
|
|
|
}
|
2014-05-03 18:55:38 +02:00
|
|
|
return i;
|
2010-09-24 13:53:22 +02:00
|
|
|
}
|
|
|
|
|
2014-05-03 18:55:38 +02:00
|
|
|
int ringbuffer_add_one(ringbuffer_t *restrict rb, char c)
|
2013-06-22 17:58:19 +02:00
|
|
|
{
|
2014-05-03 18:55:38 +02:00
|
|
|
int result = -1;
|
2020-03-30 17:02:08 +02:00
|
|
|
|
2014-05-03 18:49:55 +02:00
|
|
|
if (ringbuffer_full(rb)) {
|
2020-03-30 17:02:08 +02:00
|
|
|
result = (unsigned char)get_head(rb);
|
2013-06-22 17:58:19 +02:00
|
|
|
}
|
2014-05-03 18:49:55 +02:00
|
|
|
add_tail(rb, c);
|
2014-05-03 18:55:38 +02:00
|
|
|
return result;
|
2010-09-22 17:25:19 +02:00
|
|
|
}
|
|
|
|
|
2014-05-03 19:17:29 +02:00
|
|
|
int ringbuffer_get_one(ringbuffer_t *restrict rb)
|
2013-06-22 17:58:19 +02:00
|
|
|
{
|
2014-05-03 18:49:55 +02:00
|
|
|
if (!ringbuffer_empty(rb)) {
|
2020-03-30 17:02:08 +02:00
|
|
|
return (unsigned char)get_head(rb);
|
2013-06-22 17:58:19 +02:00
|
|
|
}
|
2014-05-03 18:49:55 +02:00
|
|
|
else {
|
|
|
|
return -1;
|
2013-06-22 17:58:19 +02:00
|
|
|
}
|
2010-09-22 17:25:19 +02:00
|
|
|
}
|
|
|
|
|
2014-05-03 19:17:29 +02:00
|
|
|
unsigned ringbuffer_get(ringbuffer_t *restrict rb, char *buf, unsigned n)
|
2013-06-22 17:58:19 +02:00
|
|
|
{
|
2014-05-03 18:49:55 +02:00
|
|
|
if (n > rb->avail) {
|
|
|
|
n = rb->avail;
|
2010-09-22 17:25:19 +02:00
|
|
|
}
|
2014-09-11 14:12:06 +02:00
|
|
|
if (n > 0) {
|
|
|
|
unsigned bytes_till_end = rb->size - rb->start;
|
|
|
|
if (bytes_till_end >= n) {
|
|
|
|
memcpy(buf, rb->buf + rb->start, n);
|
|
|
|
if (bytes_till_end == n) {
|
|
|
|
rb->start = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb->start += n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
memcpy(buf, rb->buf + rb->start, bytes_till_end);
|
|
|
|
rb->start = n - bytes_till_end;
|
|
|
|
memcpy(buf + bytes_till_end, rb->buf, rb->start);
|
|
|
|
}
|
|
|
|
rb->avail -= n;
|
2014-05-03 18:49:55 +02:00
|
|
|
}
|
|
|
|
return n;
|
2010-09-22 17:25:19 +02:00
|
|
|
}
|
2014-05-03 18:56:48 +02:00
|
|
|
|
2014-09-11 13:31:39 +02:00
|
|
|
unsigned ringbuffer_remove(ringbuffer_t *restrict rb, unsigned n)
|
|
|
|
{
|
|
|
|
if (n > rb->avail) {
|
|
|
|
n = rb->avail;
|
|
|
|
rb->start = rb->avail = 0;
|
|
|
|
}
|
|
|
|
else {
|
2017-03-01 22:01:26 +01:00
|
|
|
rb->start += n;
|
2014-09-11 13:31:39 +02:00
|
|
|
rb->avail -= n;
|
|
|
|
|
|
|
|
/* compensate underflow */
|
2020-01-06 07:41:12 +01:00
|
|
|
if (rb->start >= rb->size) {
|
2017-03-01 22:01:26 +01:00
|
|
|
rb->start -= rb->size;
|
2014-09-11 13:31:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2014-05-03 19:17:29 +02:00
|
|
|
int ringbuffer_peek_one(const ringbuffer_t *restrict rb_)
|
2014-05-03 18:56:48 +02:00
|
|
|
{
|
2014-05-03 19:17:29 +02:00
|
|
|
ringbuffer_t rb = *rb_;
|
2020-03-30 17:02:08 +02:00
|
|
|
|
2014-05-03 19:17:29 +02:00
|
|
|
return ringbuffer_get_one(&rb);
|
2014-05-03 18:56:48 +02:00
|
|
|
}
|
|
|
|
|
2020-03-30 17:02:08 +02:00
|
|
|
unsigned ringbuffer_peek(const ringbuffer_t *restrict rb_, char *buf,
|
|
|
|
unsigned n)
|
2014-05-03 18:56:48 +02:00
|
|
|
{
|
2014-05-03 19:17:29 +02:00
|
|
|
ringbuffer_t rb = *rb_;
|
2020-03-30 17:02:08 +02:00
|
|
|
|
2014-05-03 19:17:29 +02:00
|
|
|
return ringbuffer_get(&rb, buf, n);
|
2014-05-03 18:56:48 +02:00
|
|
|
}
|