all repos — mgba @ 6d898542c765f4efc4a094c5ebd3f3465c36f417

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 "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}