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 <mgba-util/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
128size_t CircleBufferWrite(struct CircleBuffer* buffer, const void* input, size_t length) {
129 int8_t* data = buffer->writePtr;
130 if (buffer->size + sizeof(int16_t) > buffer->capacity) {
131 return 0;
132 }
133 size_t remaining = buffer->capacity - ((int8_t*) data - (int8_t*) buffer->data);
134 if (length <= remaining) {
135 memcpy(data, input, length);
136 if (length == remaining) {
137 buffer->writePtr = buffer->data;
138 } else {
139 buffer->writePtr = (int8_t*) data + length;
140 }
141 } else {
142 memcpy(data, input, remaining);
143 memcpy(buffer->data, (const int8_t*) input + remaining, length - remaining);
144 buffer->writePtr = (int8_t*) buffer->data + length - remaining;
145 }
146
147 buffer->size += length;
148#ifndef NDEBUG
149 if (!_checkIntegrity(buffer)) {
150 abort();
151 }
152#endif
153 return length;
154}
155
156int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value) {
157 int8_t* data = buffer->readPtr;
158 if (buffer->size < sizeof(int8_t)) {
159 return 0;
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(int8_t);
170#ifndef NDEBUG
171 if (!_checkIntegrity(buffer)) {
172 abort();
173 }
174#endif
175 return 1;
176}
177
178int CircleBufferRead16(struct CircleBuffer* buffer, int16_t* value) {
179 int16_t* data = buffer->readPtr;
180 if (buffer->size < sizeof(int16_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 return read;
188 }
189 *value = *data;
190 ++data;
191 size_t size = (int8_t*) data - (int8_t*) buffer->data;
192 if (size < buffer->capacity) {
193 buffer->readPtr = data;
194 } else {
195 buffer->readPtr = buffer->data;
196 }
197 buffer->size -= sizeof(int16_t);
198#ifndef NDEBUG
199 if (!_checkIntegrity(buffer)) {
200 abort();
201 }
202#endif
203 return 2;
204}
205
206int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value) {
207 int32_t* data = buffer->readPtr;
208 if (buffer->size < sizeof(int32_t)) {
209 return 0;
210 }
211 if ((intptr_t) data & 0x3) {
212 int read = 0;
213 read += CircleBufferRead8(buffer, &((int8_t*) value)[0]);
214 read += CircleBufferRead8(buffer, &((int8_t*) value)[1]);
215 read += CircleBufferRead8(buffer, &((int8_t*) value)[2]);
216 read += CircleBufferRead8(buffer, &((int8_t*) value)[3]);
217 return read;
218 }
219 *value = *data;
220 ++data;
221 size_t size = (int8_t*) data - (int8_t*) buffer->data;
222 if (size < buffer->capacity) {
223 buffer->readPtr = data;
224 } else {
225 buffer->readPtr = buffer->data;
226 }
227 buffer->size -= sizeof(int32_t);
228#ifndef NDEBUG
229 if (!_checkIntegrity(buffer)) {
230 abort();
231 }
232#endif
233 return 4;
234}
235
236size_t CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length) {
237 int8_t* data = buffer->readPtr;
238 if (buffer->size == 0) {
239 return 0;
240 }
241 if (length > buffer->size) {
242 length = buffer->size;
243 }
244 size_t remaining = buffer->capacity - ((int8_t*) data - (int8_t*) buffer->data);
245 if (length <= remaining) {
246 memcpy(output, data, length);
247 if (length == remaining) {
248 buffer->readPtr = buffer->data;
249 } else {
250 buffer->readPtr = (int8_t*) data + length;
251 }
252 } else {
253 memcpy(output, data, remaining);
254 memcpy((int8_t*) output + remaining, buffer->data, length - remaining);
255 buffer->readPtr = (int8_t*) buffer->data + length - remaining;
256 }
257
258 buffer->size -= length;
259#ifndef NDEBUG
260 if (!_checkIntegrity(buffer)) {
261 abort();
262 }
263#endif
264 return length;
265}
266
267size_t CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length) {
268 int8_t* data = buffer->readPtr;
269 if (buffer->size == 0) {
270 return 0;
271 }
272 if (length > buffer->size) {
273 length = buffer->size;
274 }
275 size_t remaining = buffer->capacity - ((int8_t*) data - (int8_t*) buffer->data);
276 if (length <= remaining) {
277 memcpy(output, data, length);
278 } else {
279 memcpy(output, data, remaining);
280 memcpy((int8_t*) output + remaining, buffer->data, length - remaining);
281 }
282
283 return length;
284}