ringbuffer.c
3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/**
* Ringbuffer implementation
*
* Copyright (C) 2013 Freie Universität Berlin
* Copyright (C) 2013 INRIA
*
* 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.
*
* @ingroup core_util
* @{
* @file
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author René Kijewski <rene.kijewski@fu-berlin.de>
* @}
*/
#include "ringbuffer.h"
#include <string.h>
/**
* @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.
*/
static void add_tail(ringbuffer_t *restrict rb, char c)
{
unsigned pos = rb->start + rb->avail++;
if (pos >= rb->size) {
pos -= rb->size;
}
rb->buf[pos] = c;
}
/**
* @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.
*/
static char get_head(ringbuffer_t *restrict rb)
{
char result = rb->buf[rb->start];
if ((--rb->avail == 0) || (++rb->start == rb->size)) {
rb->start = 0;
}
return result;
}
unsigned ringbuffer_add(ringbuffer_t *restrict rb, const char *buf, unsigned n)
{
unsigned i;
for (i = 0; i < n; i++) {
if (ringbuffer_full(rb)) {
break;
}
add_tail(rb, buf[i]);
}
return i;
}
int ringbuffer_add_one(ringbuffer_t *restrict rb, char c)
{
int result = -1;
if (ringbuffer_full(rb)) {
result = (unsigned char) get_head(rb);
}
add_tail(rb, c);
return result;
}
int ringbuffer_get_one(ringbuffer_t *restrict rb)
{
if (!ringbuffer_empty(rb)) {
return (unsigned char) get_head(rb);
}
else {
return -1;
}
}
unsigned ringbuffer_get(ringbuffer_t *restrict rb, char *buf, unsigned n)
{
if (n > rb->avail) {
n = rb->avail;
}
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;
}
return n;
}
unsigned ringbuffer_remove(ringbuffer_t *restrict rb, unsigned n)
{
if (n > rb->avail) {
n = rb->avail;
rb->start = rb->avail = 0;
}
else {
rb->start += n;
rb->avail -= n;
/* compensate underflow */
if (rb->start > rb->size) {
rb->start -= rb->size;
}
}
return n;
}
int ringbuffer_peek_one(const ringbuffer_t *restrict rb_)
{
ringbuffer_t rb = *rb_;
return ringbuffer_get_one(&rb);
}
unsigned ringbuffer_peek(const ringbuffer_t *restrict rb_, char *buf, unsigned n)
{
ringbuffer_t rb = *rb_;
return ringbuffer_get(&rb, buf, n);
}