src/util/circle-buffer.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "circle-buffer.h"
7
8#ifndef NDEBUG
9static int _checkIntegrity(struct CircleBuffer* buffer) {
10 if ((int8_t*) buffer->writePtr - (int8_t*) buffer->readPtr == (ssize_t) buffer->size) {
11 return 1;
12 }
13 if ((ssize_t) (buffer->capacity - buffer->size) == ((int8_t*) buffer->writePtr - (int8_t*) buffer->readPtr)) {
14 return 1;
15 }
16 if ((ssize_t) (buffer->capacity - buffer->size) == ((int8_t*) buffer->readPtr - (int8_t*) buffer->writePtr)) {
17 return 1;
18 }
19 return 0;
20}
21#endif
22
23void CircleBufferInit(struct CircleBuffer* buffer, unsigned capacity) {
24 buffer->data = malloc(capacity);
25 buffer->capacity = capacity;
26 CircleBufferClear(buffer);
27}
28
29void CircleBufferDeinit(struct CircleBuffer* buffer) {
30 free(buffer->data);
31 buffer->data = 0;
32}
33
34size_t CircleBufferSize(const struct CircleBuffer* buffer) {
35 return buffer->size;
36}
37
38size_t CircleBufferCapacity(const struct CircleBuffer* buffer) {
39 return buffer->capacity;
40}
41
42void CircleBufferClear(struct CircleBuffer* buffer) {
43 buffer->size = 0;
44 buffer->readPtr = buffer->data;
45 buffer->writePtr = buffer->data;
46}
47
48int CircleBufferWrite8(struct CircleBuffer* buffer, int8_t value) {
49 int8_t* data = buffer->writePtr;
50 if (buffer->size + sizeof(int8_t) > buffer->capacity) {
51 return 0;
52 }
53 *data = value;
54 ++data;
55 size_t size = (int8_t*) data - (int8_t*) buffer->data;
56 if (size < buffer->capacity) {
57 buffer->writePtr = data;
58 } else {
59 buffer->writePtr = buffer->data;
60 }
61 buffer->size += sizeof(int8_t);
62#ifndef NDEBUG
63 if (!_checkIntegrity(buffer)) {
64 abort();
65 }
66#endif
67 return 1;
68}
69
70int CircleBufferWrite32(struct CircleBuffer* buffer, int32_t value) {
71 int32_t* data = buffer->writePtr;
72 if (buffer->size + sizeof(int32_t) > buffer->capacity) {
73 return 0;
74 }
75 if ((intptr_t) data & 0x3) {
76 int written = 0;
77 written += CircleBufferWrite8(buffer, ((int8_t*) &value)[0]);
78 written += CircleBufferWrite8(buffer, ((int8_t*) &value)[1]);
79 written += CircleBufferWrite8(buffer, ((int8_t*) &value)[2]);
80 written += CircleBufferWrite8(buffer, ((int8_t*) &value)[3]);
81 return written;
82 }
83 *data = value;
84 ++data;
85 size_t size = (int8_t*) data - (int8_t*) buffer->data;
86 if (size < buffer->capacity) {
87 buffer->writePtr = data;
88 } else {
89 buffer->writePtr = buffer->data;
90 }
91 buffer->size += sizeof(int32_t);
92#ifndef NDEBUG
93 if (!_checkIntegrity(buffer)) {
94 abort();
95 }
96#endif
97 return 4;
98}
99
100int CircleBufferWrite16(struct CircleBuffer* buffer, int16_t value) {
101 int16_t* data = buffer->writePtr;
102 if (buffer->size + sizeof(int16_t) > buffer->capacity) {
103 return 0;
104 }
105 if ((intptr_t) data & 0x3) {
106 int written = 0;
107 written += CircleBufferWrite8(buffer, ((int8_t*) &value)[0]);
108 written += CircleBufferWrite8(buffer, ((int8_t*) &value)[1]);
109 return written;
110 }
111 *data = value;
112 ++data;
113 size_t size = (int8_t*) data - (int8_t*) buffer->data;
114 if (size < buffer->capacity) {
115 buffer->writePtr = data;
116 } else {
117 buffer->writePtr = buffer->data;
118 }
119 buffer->size += sizeof(int16_t);
120#ifndef NDEBUG
121 if (!_checkIntegrity(buffer)) {
122 abort();
123 }
124#endif
125 return 2;
126}
127
128int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value) {
129 int8_t* data = buffer->readPtr;
130 if (buffer->size < sizeof(int8_t)) {
131 return 0;
132 }
133 *value = *data;
134 ++data;
135 size_t size = (int8_t*) data - (int8_t*) buffer->data;
136 if (size < buffer->capacity) {
137 buffer->readPtr = data;
138 } else {
139 buffer->readPtr = buffer->data;
140 }
141 buffer->size -= sizeof(int8_t);
142#ifndef NDEBUG
143 if (!_checkIntegrity(buffer)) {
144 abort();
145 }
146#endif
147 return 1;
148}
149
150int CircleBufferRead16(struct CircleBuffer* buffer, int16_t* value) {
151 int16_t* data = buffer->readPtr;
152 if (buffer->size < sizeof(int16_t)) {
153 return 0;
154 }
155 if ((intptr_t) data & 0x3) {
156 int read = 0;
157 read += CircleBufferRead8(buffer, &((int8_t*) value)[0]);
158 read += CircleBufferRead8(buffer, &((int8_t*) value)[1]);
159 return read;
160 }
161 *value = *data;
162 ++data;
163 size_t size = (int8_t*) data - (int8_t*) buffer->data;
164 if (size < buffer->capacity) {
165 buffer->readPtr = data;
166 } else {
167 buffer->readPtr = buffer->data;
168 }
169 buffer->size -= sizeof(int16_t);
170#ifndef NDEBUG
171 if (!_checkIntegrity(buffer)) {
172 abort();
173 }
174#endif
175 return 2;
176}
177
178int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value) {
179 int32_t* data = buffer->readPtr;
180 if (buffer->size < sizeof(int32_t)) {
181 return 0;
182 }
183 if ((intptr_t) data & 0x3) {
184 int read = 0;
185 read += CircleBufferRead8(buffer, &((int8_t*) value)[0]);
186 read += CircleBufferRead8(buffer, &((int8_t*) value)[1]);
187 read += CircleBufferRead8(buffer, &((int8_t*) value)[2]);
188 read += CircleBufferRead8(buffer, &((int8_t*) value)[3]);
189 return read;
190 }
191 *value = *data;
192 ++data;
193 size_t size = (int8_t*) data - (int8_t*) buffer->data;
194 if (size < buffer->capacity) {
195 buffer->readPtr = data;
196 } else {
197 buffer->readPtr = buffer->data;
198 }
199 buffer->size -= sizeof(int32_t);
200#ifndef NDEBUG
201 if (!_checkIntegrity(buffer)) {
202 abort();
203 }
204#endif
205 return 4;
206}
207
208size_t CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length) {
209 int8_t* data = buffer->readPtr;
210 if (buffer->size == 0) {
211 return 0;
212 }
213 if (length > buffer->size) {
214 length = buffer->size;
215 }
216 size_t remaining = buffer->capacity - ((int8_t*) data - (int8_t*) buffer->data);
217 if (length <= remaining) {
218 memcpy(output, data, length);
219 if (length == remaining) {
220 buffer->readPtr = buffer->data;
221 } else {
222 buffer->readPtr = (int8_t*) data + length;
223 }
224 } else {
225 memcpy(output, data, remaining);
226 memcpy((int8_t*) output + remaining, buffer->data, length - remaining);
227 buffer->readPtr = (int8_t*) buffer->data + length - remaining;
228 }
229
230 buffer->size -= length;
231#ifndef NDEBUG
232 if (!_checkIntegrity(buffer)) {
233 abort();
234 }
235#endif
236 return length;
237}
238
239size_t CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length) {
240 int8_t* data = buffer->readPtr;
241 if (buffer->size == 0) {
242 return 0;
243 }
244 if (length > buffer->size) {
245 length = buffer->size;
246 }
247 size_t remaining = buffer->capacity - ((int8_t*) data - (int8_t*) buffer->data);
248 if (length <= remaining) {
249 memcpy(output, data, length);
250 } else {
251 memcpy(output, data, remaining);
252 memcpy((int8_t*) output + remaining, buffer->data, length - remaining);
253 }
254
255 return length;
256}