all repos — mgba @ f6a7fedb2813d070a07cd6da65e8ddd666cd41d1

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 CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value) {
101	int8_t* data = buffer->readPtr;
102	if (buffer->size < sizeof(int8_t)) {
103		return 0;
104	}
105	*value = *data;
106	++data;
107	size_t size = (int8_t*) data - (int8_t*) buffer->data;
108	if (size < buffer->capacity) {
109		buffer->readPtr = data;
110	} else {
111		buffer->readPtr = buffer->data;
112	}
113	buffer->size -= sizeof(int8_t);
114#ifndef NDEBUG
115	if (!_checkIntegrity(buffer)) {
116		abort();
117	}
118#endif
119	return 1;
120}
121
122int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value) {
123	int32_t* data = buffer->readPtr;
124	if (buffer->size < sizeof(int32_t)) {
125		return 0;
126	}
127	if ((intptr_t) data & 0x3) {
128		int read = 0;
129		read += CircleBufferRead8(buffer, &((int8_t*) value)[0]);
130		read += CircleBufferRead8(buffer, &((int8_t*) value)[1]);
131		read += CircleBufferRead8(buffer, &((int8_t*) value)[2]);
132		read += CircleBufferRead8(buffer, &((int8_t*) value)[3]);
133		return read;
134	}
135	*value = *data;
136	++data;
137	size_t size = (int8_t*) data - (int8_t*) buffer->data;
138	if (size < buffer->capacity) {
139		buffer->readPtr = data;
140	} else {
141		buffer->readPtr = buffer->data;
142	}
143	buffer->size -= sizeof(int32_t);
144#ifndef NDEBUG
145	if (!_checkIntegrity(buffer)) {
146		abort();
147	}
148#endif
149	return 4;
150}
151
152size_t CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length) {
153	int8_t* data = buffer->readPtr;
154	if (buffer->size == 0) {
155		return 0;
156	}
157	if (length > buffer->size) {
158		length = buffer->size;
159	}
160	size_t remaining = buffer->capacity - ((int8_t*) data - (int8_t*) buffer->data);
161	if (length <= remaining) {
162		memcpy(output, data, length);
163		if (length == remaining) {
164			buffer->readPtr = buffer->data;
165		} else {
166			buffer->readPtr = (int8_t*) data + length;
167		}
168	} else {
169		memcpy(output, data, remaining);
170		memcpy((int8_t*) output + remaining, buffer->data, length - remaining);
171		buffer->readPtr = (int8_t*) buffer->data + length - remaining;
172	}
173
174	buffer->size -= length;
175#ifndef NDEBUG
176	if (!_checkIntegrity(buffer)) {
177		abort();
178	}
179#endif
180	return length;
181}
182
183size_t CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length) {
184	int8_t* data = buffer->readPtr;
185	if (buffer->size == 0) {
186		return 0;
187	}
188	if (length > buffer->size) {
189		length = buffer->size;
190	}
191	size_t remaining = buffer->capacity - ((int8_t*) data - (int8_t*) buffer->data);
192	if (length <= remaining) {
193		memcpy(output, data, length);
194	} else {
195		memcpy(output, data, remaining);
196		memcpy((int8_t*) output + remaining, buffer->data, length - remaining);
197	}
198
199	return length;
200}