libdatatypes 0.3.2
Abstract datatypes for C.
Loading...
Searching...
No Matches
assocarray.c
Go to the documentation of this file.
1/***************************************************************************
2 begin........: May 2012
3 copyright....: Sebastian Fedrau
4 email........: sebastian.fedrau@gmail.com
5 ***************************************************************************/
6
7/***************************************************************************
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License v3 as published by
10 the Free Software Foundation.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License v3 for more details.
16 ***************************************************************************/
22#define _GNU_SOURCE
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <stddef.h>
27#include <assert.h>
28#include <string.h>
29#include <limits.h>
30
31#include "assocarray.h"
32
33static int
34_assoc_array_binary_search(CompareFunc compare, void **keys, size_t len, const void *key, ssize_t *index)
35{
36 int32_t result = 0;
37
38 assert(compare != NULL);
39 assert(keys != NULL);
40 assert(len > 0 && len <= ASSOC_ARRAY_MAX_SIZE);
41 assert(key != NULL);
42 assert(index != NULL);
43
44 if(len == 1)
45 {
46 *index = 0;
47 result = compare(key, *keys);
48 }
49 else
50 {
51 ssize_t begin = 0;
52 ssize_t end = len - 1;
53
54 while(begin <= end)
55 {
56 *index = (begin + end) / 2;
57
58 result = compare(key, keys[*index]);
59
60 if(result > 0)
61 {
62 begin = *index + 1;
63 }
64 else if(result < 0)
65 {
66 end = *index - 1;
67 }
68 else
69 {
70 break;
71 }
72 }
73 }
74
75 return result;
76}
77
79assoc_array_new(CompareFunc compare_keys, FreeFunc free_key, FreeFunc free_value)
80{
81 assert(compare_keys != NULL);
82
83 AssocArray *array = (AssocArray *)malloc(sizeof(AssocArray));
84
85 if(!array)
86 {
87 perror("malloc()");
88 abort();
89 }
90
91 assoc_array_init(array, compare_keys, free_key, free_value);
92
93 return array;
94}
95
96void
97assoc_array_init(AssocArray *array, CompareFunc compare_keys, FreeFunc free_key, FreeFunc free_value)
98{
99 assert(array != NULL);
100 assert(compare_keys != NULL);
101
102 array->compare_keys = compare_keys;
103 array->size = 8;
104 array->count = 0;
105 array->free_key = free_key;
106 array->free_value = free_value;
107 array->pair.array = array;
108 array->pair.offset = 0;
109
110 array->keys = (void **)calloc(array->size, sizeof(void *));
111
112 if(!array->keys)
113 {
114 perror("calloc()");
115 abort();
116 }
117
118 array->values = (void **)calloc(array->size, sizeof(void *));
119
120 if(!array->values)
121 {
122 perror("calloc()");
123 abort();
124 }
125}
126
127void
129{
130 assert(array != NULL);
131
132 assoc_array_free(array);
133 free(array);
134}
135
136static void
137_assoc_array_free_memory(AssocArray *array)
138{
139 assert(array != NULL);
140
141 if(array->free_key || array->free_value)
142 {
143 for(size_t i = 0; i < array->count; ++i)
144 {
145 if(array->free_key)
146 {
147 array->free_key(array->keys[i]);
148 }
149
150 if(array->free_value && array->values[i])
151 {
152 array->free_value(array->values[i]);
153 }
154 }
155 }
156}
157
158void
160{
161 assert(array != NULL);
162
163 _assoc_array_free_memory(array);
164
165 free(array->keys);
166 free(array->values);
167}
168
169void
171{
172 assert(array != NULL);
173
174 _assoc_array_free_memory(array);
175 array->count = 0;
176}
177
178static void
179_assoc_array_insert_first(AssocArray *array, void *key, void *value)
180{
181 assert(array != NULL);
182 assert(key != NULL);
183
184 *array->keys = key;
185 *array->values = value;
186 ++array->count;
187}
188
189static void
190_assoc_array_replace(AssocArray *array, void *key, void *value, ssize_t offset, bool overwrite_key)
191{
192 assert(array != NULL);
193 assert(key != NULL);
194 assert(offset >= 0 && array->count > (size_t)offset);
195
196 if(overwrite_key)
197 {
198 if(array->free_key)
199 {
200 array->free_key(array->keys[offset]);
201 }
202
203 array->keys[offset] = key;
204 }
205
206 if(array->free_value && array->values[offset])
207 {
208 array->free_value(array->values[offset]);
209 }
210
211 array->values[offset] = value;
212}
213
214static void
215_assoc_array_resize_if_necessary(AssocArray *array)
216{
217 assert(array != NULL);
218
219 if(array->count == array->size)
220 {
221 if(array->size == ASSOC_ARRAY_MAX_SIZE)
222 {
223 fprintf(stderr, "%s(): array exceeds size limit.\n", __func__);
224 abort();
225 }
226
227 if(array->size > ASSOC_ARRAY_MAX_SIZE / 2)
228 {
229 array->size = ASSOC_ARRAY_MAX_SIZE;
230 }
231 else
232 {
233 array->size *= 2;
234 }
235
236 array->keys = (void **)realloc(array->keys, array->size * sizeof(void *));
237
238 if(!array->keys)
239 {
240 perror("realloc()");
241 abort();
242 }
243
244 array->values = (void **)realloc(array->values, array->size * sizeof(void *));
245
246 if(!array->values)
247 {
248 perror("realloc()");
249 abort();
250 }
251 }
252}
253
254static void
255_assoc_array_insert_before_offset(AssocArray *array, void *key, void *value, ssize_t offset)
256{
257 assert(array != NULL);
258 assert(key != NULL);
259 assert(offset >= 0 && array->count > (size_t)offset);
260
261 memmove(&array->keys[offset + 1], &array->keys[offset], (array->count - offset) * sizeof(void *));
262 memmove(&array->values[offset + 1], &array->values[offset], (array->count - offset) * sizeof(void *));
263
264 array->keys[offset] = key;
265 array->values[offset] = value;
266}
267
268static void
269_assoc_array_insert_after_offset(AssocArray *array, void *key, void *value, ssize_t offset)
270{
271 assert(array != NULL);
272 assert(key != NULL);
273 assert(offset >= 0 && array->count > (size_t)offset);
274
275 ++offset;
276
277 if((size_t)offset < array->count)
278 {
279 memmove(&array->keys[offset + 1], &array->keys[offset], (array->count - offset) * sizeof(void *));
280 memmove(&array->values[offset + 1], &array->values[offset], (array->count - offset) * sizeof(void *));
281 }
282
283 array->keys[offset] = key;
284 array->values[offset] = value;
285}
286
288assoc_array_set(AssocArray *array, void *key, void *value, bool overwrite_key)
289{
291
292 assert(array != NULL);
293 assert(key != NULL);
294
295 if(array->count)
296 {
297 ssize_t offset = 0;
298 int cmp = _assoc_array_binary_search(array->compare_keys, array->keys, array->count, key, &offset);
299
300 if(cmp)
301 {
303
304 _assoc_array_resize_if_necessary(array);
305
306 if(cmp < 0)
307 {
308 _assoc_array_insert_before_offset(array, key, value, offset);
309 }
310 else
311 {
312 _assoc_array_insert_after_offset(array, key, value, offset);
313 }
314
315 ++array->count;
316 }
317 else
318 {
320
321 _assoc_array_replace(array, key, value, offset, overwrite_key);
322 }
323 }
324 else
325 {
327
328 _assoc_array_insert_first(array, key, value);
329 }
330
331 return result;
332}
333
334void
335assoc_array_remove(AssocArray *array, const void *key)
336{
337 assert(array != NULL);
338 assert(key != NULL);
339
340 if(array->count)
341 {
342 ssize_t offset = 0;
343
344 if(!_assoc_array_binary_search(array->compare_keys, array->keys, array->count, key, &offset))
345 {
346 if(array->free_key)
347 {
348 array->free_key(array->keys[offset]);
349 }
350
351 if(array->free_value && array->values[offset])
352 {
353 array->free_value(array->values[offset]);
354 }
355
356 if((size_t)offset < array->count - 1)
357 {
358 memmove(&array->keys[offset], &array->keys[offset + 1], (array->count - 1 - offset) * sizeof(void *));
359 memmove(&array->values[offset], &array->values[offset + 1], (array->count - 1 - offset) * sizeof(void *));
360 }
361
362 --array->count;
363 }
364 }
365}
366
368assoc_array_lookup(AssocArray *array, const void *key)
369{
370 assert(array != NULL);
371 assert(key != NULL);
372
373 if(array->count)
374 {
375 ssize_t offset = 0;
376
377 if(!_assoc_array_binary_search(array->compare_keys, array->keys, array->count, key, &offset))
378 {
379 array->pair.offset = offset;
380
381 return &array->pair;
382 }
383 }
384
385 return NULL;
386}
387
388void *
390{
391 assert(pair != NULL);
392 assert(pair->array != NULL);
393
394 return pair->array->keys[pair->offset];
395}
396
397void *
399{
400 assert(pair != NULL);
401 assert(pair->array != NULL);
402
403 return pair->array->values[pair->offset];
404}
405
406void
408{
409 assert(pair != NULL);
410 assert(pair->array != NULL);
411
412 if(pair->array->free_value && pair->array->values[pair->offset])
413 {
414 pair->array->free_value(pair->array->values[pair->offset]);
415 }
416
417 pair->array->values[pair->offset] = value;
418}
419
420bool
421assoc_array_key_exists(const AssocArray *array, const void *key)
422{
423 assert(array != NULL);
424 assert(key != NULL);
425
426 if(array->count)
427 {
428 ssize_t offset = 0;
429
430 return !_assoc_array_binary_search(array->compare_keys, array->keys, array->count, key, &offset);
431 }
432
433 return false;
434}
435
436size_t
438{
439 assert(array != NULL);
440
441 return array->count;
442}
443
444size_t
446{
447 assert(array != NULL);
448
449 return array->size;
450}
451
452void
454{
455 assert(array != NULL);
456 assert(iter != NULL);
457
458 iter->array = array;
459 iter->offset = -1;
460}
461
462bool
464{
465 assert(iter != NULL);
466
467 ++iter->offset;
468
469 return (size_t)iter->offset < iter->array->count;
470}
471
472void *
474{
475 assert(iter != NULL);
476
477 return iter->array->keys[iter->offset];
478}
479
480void *
482{
483 assert(iter != NULL);
484
485 return iter->array->values[iter->offset];
486}
487
void assoc_array_iter_init(const AssocArray *array, AssocArrayIter *iter)
Definition assocarray.c:453
void assoc_array_init(AssocArray *array, CompareFunc compare_keys, FreeFunc free_key, FreeFunc free_value)
Definition assocarray.c:97
void assoc_array_pair_set_value(AssocArrayPair *pair, void *value)
Definition assocarray.c:407
void * assoc_array_iter_get_value(const AssocArrayIter *iter)
Definition assocarray.c:481
AssocArray * assoc_array_new(CompareFunc compare_keys, FreeFunc free_key, FreeFunc free_value)
Definition assocarray.c:79
void * assoc_array_iter_get_key(const AssocArrayIter *iter)
Definition assocarray.c:473
AssocArrayPair * assoc_array_lookup(AssocArray *array, const void *key)
Definition assocarray.c:368
void * assoc_array_pair_get_value(const AssocArrayPair *pair)
Definition assocarray.c:398
bool assoc_array_iter_next(AssocArrayIter *iter)
Definition assocarray.c:463
void assoc_array_remove(AssocArray *array, const void *key)
Definition assocarray.c:335
bool assoc_array_key_exists(const AssocArray *array, const void *key)
Definition assocarray.c:421
void assoc_array_clear(AssocArray *array)
Definition assocarray.c:170
size_t assoc_array_size(const AssocArray *array)
Definition assocarray.c:445
void assoc_array_free(AssocArray *array)
Definition assocarray.c:159
size_t assoc_array_count(const AssocArray *array)
Definition assocarray.c:437
AssocArrayInsertResult assoc_array_set(AssocArray *array, void *key, void *value, bool overwrite_key)
Definition assocarray.c:288
void assoc_array_destroy(AssocArray *array)
Definition assocarray.c:128
void * assoc_array_pair_get_key(const AssocArrayPair *pair)
Definition assocarray.c:389
Generic associative array.
#define ASSOC_ARRAY_MAX_SIZE
Definition assocarray.h:31
size_t count
Definition assocarray.h:52
AssocArrayInsertResult
result of assoc_array_set() method.
Definition assocarray.h:80
@ ASSOCARRAY_INSERT_RESULT_NEW
Definition assocarray.h:82
@ ASSOCARRAY_INSERT_RESULT_REPLACED
Definition assocarray.h:84
@ ASSOCARRAY_INSERT_RESULT_FAILED
Definition assocarray.h:86
void ** keys
Definition assocarray.h:42
FreeFunc free_key
Definition assocarray.h:46
struct AssocArray::_AssocArrayPair pair
Last found key-value pair.
size_t size
Definition assocarray.h:50
struct _AssocArrayPair AssocArrayIter
Definition assocarray.h:73
struct _AssocArrayPair AssocArrayPair
Definition assocarray.h:70
CompareFunc compare_keys
Definition assocarray.h:40
void ** values
Definition assocarray.h:44
const struct _AssocArray * array
Definition assocarray.h:63
FreeFunc free_value
Definition assocarray.h:48
Array containing associations between keys and values.
Definition assocarray.h:38
int32_t(* CompareFunc)(const void *a, const void *b)
Definition compare.h:30
void(* FreeFunc)(void *p)
Definition datatypes.h:33