chillbuff
chillbuff.h
Go to the documentation of this file.
1/*
2 Copyright 2019 Raphael Beck
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
25#ifndef CHILLBUFF_H
26#define CHILLBUFF_H
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <stdint.h>
35#include <string.h>
36
37/* The following are the chillbuff exit codes returned from the various chillbuff functions. */
38
42#define CHILLBUFF_SUCCESS 0
43
47#define CHILLBUFF_OUT_OF_MEM 100
48
52#define CHILLBUFF_NULL_ARG 200
53
57#define CHILLBUFF_INVALID_ARG 300
58
62#define CHILLBUFF_OVERFLOW 400
63
65static void (*_chillbuff_error_callback)(const char*) = NULL;
66
72{
77
82
87
93
98typedef struct chillbuff
99{
103 void* array;
104
108 size_t length;
109
113 size_t capacity;
114
119
125
127static inline void _chillbuff_printerr(const char* error, const char* origin)
128{
129 const size_t error_length = 64 + strlen(error) + strlen(origin);
130 char* error_msg = (char*)chillbuff_malloc(error_length * sizeof(char)); // cast malloc because of compat with C++ D:
131 if (error_msg != NULL)
132 {
133 snprintf(error_msg, error_length, "\nCHILLBUFF ERROR: (%s) %s\n", origin, error);
134 if (_chillbuff_error_callback != NULL)
135 {
136 _chillbuff_error_callback(error_msg);
137 }
138 free(error_msg);
139 }
140}
141
148static inline int chillbuff_set_error_callback(void (*error_callback)(const char*))
149{
150 if (error_callback == NULL)
151 {
152 _chillbuff_printerr("The passed error callback is empty; Operation cancelled!", __func__);
153 return CHILLBUFF_NULL_ARG;
154 }
155
156 _chillbuff_error_callback = error_callback;
157 return CHILLBUFF_SUCCESS;
158}
159
164{
165 _chillbuff_error_callback = NULL;
166}
167
176static inline int chillbuff_init(chillbuff* buff, const size_t initial_capacity, const size_t element_size, const chillbuff_growth_method growth_method)
177{
178 if (buff == NULL)
179 {
180 _chillbuff_printerr("Tried to init a NULL chillbuff instance; wouldn't end well. Cancelled...", __func__);
181 return CHILLBUFF_NULL_ARG;
182 }
183
184 if (element_size == 0)
185 {
186 _chillbuff_printerr("Storing elements of size \"0\" makes no sense...", __func__);
188 }
189
190 if (growth_method < 0 || growth_method > 3)
191 {
192 _chillbuff_printerr("Invalid grow method! Please use the appropriate chillbuff_growth_method enum!", __func__);
194 }
195
196 buff->length = 0;
197 buff->element_size = element_size;
198 buff->growth_method = growth_method;
199 buff->capacity = initial_capacity == 0 ? 16 : initial_capacity;
200 buff->array = chillbuff_calloc(buff->capacity, buff->element_size);
201
202 if (buff->array == NULL)
203 {
204 _chillbuff_printerr("OUT OF MEMORY!", __func__);
206 }
207
208 return CHILLBUFF_SUCCESS;
209}
210
215static inline void chillbuff_free(chillbuff* buff)
216{
217 if (buff == NULL)
218 {
219 return;
220 }
221
222 memset(buff->array, '\0', buff->length);
223 free(buff->array);
224 buff->array = NULL;
225 buff->length = buff->capacity = buff->element_size = 0;
226}
227
234static inline void chillbuff_clear(chillbuff* buff)
235{
236 if (buff == NULL)
237 {
238 return;
239 }
240
241 memset(buff->array, '\0', buff->capacity);
242 buff->length = 0;
243}
244
253static int chillbuff_push_back(chillbuff* buff, const void* elements, const size_t elements_count)
254{
255 if (buff == NULL)
256 {
257 _chillbuff_printerr("Tried to append to a NULL chillbuff instance!", __func__);
258 return CHILLBUFF_NULL_ARG;
259 }
260
261 if (elements == NULL)
262 {
263 _chillbuff_printerr("Tried to append NULL element(s) to a chillbuff instance!", __func__);
264 return CHILLBUFF_NULL_ARG;
265 }
266
267 if (elements_count == 0)
268 {
269 _chillbuff_printerr("The passed \"elements_count\" argument is zero; nothing to append!", __func__);
271 }
272
273 for (size_t i = 0; i < elements_count; i++)
274 {
275 if (buff->length == buff->capacity)
276 {
277 size_t new_capacity;
278
279 switch (buff->growth_method)
280 {
281 default:
282 _chillbuff_printerr("Invalid grow method! Please use the appropriate chillbuff_growth_method enum!", __func__);
285 new_capacity = (buff->capacity * 2);
286 break;
288 new_capacity = (buff->capacity * 3);
289 break;
291 new_capacity = (buff->capacity + buff->element_size);
292 break;
294 new_capacity = (buff->capacity * buff->capacity);
295 break;
296 }
297
298 if (new_capacity <= buff->capacity || new_capacity >= UINT64_MAX / buff->element_size)
299 {
300 _chillbuff_printerr("Couldn't push back due to buffer OVERFLOW!", __func__);
301 return CHILLBUFF_OVERFLOW;
302 }
303
304 void* new_array = chillbuff_realloc(buff->array, new_capacity * buff->element_size);
305 if (new_array == NULL)
306 {
307 _chillbuff_printerr("Couldn't resize chillbuff underlying array; OUT OF MEMORY!", __func__);
309 }
310
311 memset((char*)new_array + (buff->element_size * buff->length), '\0', (new_capacity - buff->length) * buff->element_size);
312 buff->array = new_array;
313 buff->capacity = new_capacity;
314 }
315
316 memcpy((char*)buff->array + (buff->element_size * buff->length++), (char*)elements + (i * buff->element_size), buff->element_size);
317 }
318
319 return CHILLBUFF_SUCCESS;
320}
321
322#ifdef __cplusplus
323} // extern "C"
324#endif
325
326#endif // CHILLBUFF_H
#define CHILLBUFF_INVALID_ARG
Definition: chillbuff.h:57
struct chillbuff chillbuff
static void chillbuff_free(chillbuff *buff)
Definition: chillbuff.h:215
#define CHILLBUFF_OVERFLOW
Definition: chillbuff.h:62
static int chillbuff_init(chillbuff *buff, const size_t initial_capacity, const size_t element_size, const chillbuff_growth_method growth_method)
Definition: chillbuff.h:176
static void chillbuff_clear(chillbuff *buff)
Definition: chillbuff.h:234
chillbuff_growth_method
Definition: chillbuff.h:72
@ CHILLBUFF_GROW_EXPONENTIAL
Definition: chillbuff.h:91
@ CHILLBUFF_GROW_TRIPLICATIVE
Definition: chillbuff.h:81
@ CHILLBUFF_GROW_LINEAR
Definition: chillbuff.h:86
@ CHILLBUFF_GROW_DUPLICATIVE
Definition: chillbuff.h:76
static int chillbuff_set_error_callback(void(*error_callback)(const char *))
Definition: chillbuff.h:148
#define CHILLBUFF_NULL_ARG
Definition: chillbuff.h:52
#define CHILLBUFF_OUT_OF_MEM
Definition: chillbuff.h:47
static void chillbuff_unset_error_callback()
Definition: chillbuff.h:163
static int chillbuff_push_back(chillbuff *buff, const void *elements, const size_t elements_count)
Definition: chillbuff.h:253
#define CHILLBUFF_SUCCESS
Definition: chillbuff.h:42
Definition: chillbuff.h:99
chillbuff_growth_method growth_method
Definition: chillbuff.h:123
size_t length
Definition: chillbuff.h:108
void * array
Definition: chillbuff.h:103
size_t element_size
Definition: chillbuff.h:118
size_t capacity
Definition: chillbuff.h:113