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}