all repos — mgba @ 1de5d4e330563d1cfd889534ba3c81979af607b7

mGBA Game Boy Advance Emulator

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
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 CircleBufferWrite(struct CircleBuffer* buffer, const void* input, size_t length) {
209	int8_t* data = buffer->writePtr;
210	if (buffer->size + length > buffer->capacity) {
211		return 0;
212	}
213	size_t remaining = buffer->capacity - ((int8_t*) data - (int8_t*) buffer->data);
214	if (length <= remaining) {
215		memcpy(data, input, length);
216		if (length == remaining) {
217			buffer->writePtr = buffer->data;
218		} else {
219			buffer->writePtr = (int8_t*) data + length;
220		}
221	} else {
222		memcpy(data, input, remaining);
223		memcpy(buffer->data, (int8_t*) input + remaining, length - remaining);
224		buffer->writePtr = (int8_t*) buffer->data + length - remaining;
225	}
226
227	buffer->size += length;
228#ifndef NDEBUG
229	if (!_checkIntegrity(buffer)) {
230		abort();
231	}
232#endif
233	return length;
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}