libcstl
Loading...
Searching...
No Matches
map.c
Go to the documentation of this file.
1/*!
2 * @file
3 */
4
5#include "cstl/map.h"
6
7#include <stdlib.h>
8
9struct cstl_map_node
10{
11 const void * key;
12 void * val;
13
14 struct cstl_rbtree_node n;
15};
16
18{
19 static const cstl_map_iterator_t end = {
20 ._ = NULL,
21
22 .key = NULL,
23 .val = NULL,
24 };
25
26 return &end;
27 (void)m;
28}
29
30/*! @private */
31static void cstl_map_iterator_init(const cstl_map_t * const m,
32 cstl_map_iterator_t * const i,
33 struct cstl_map_node * const node)
34{
35 if (node != NULL) {
36 i->key = node->key;
37 i->val = node->val;
38
39 i->_ = node;
40 } else {
41 *i = *cstl_map_iterator_end(m);
42 }
43}
44
45
46/*! @private */
47static struct cstl_map_node * cstl_map_node_alloc(
48 const void * const key, void * const val)
49{
50 struct cstl_map_node * const n = malloc(sizeof(*n));
51 if (n) {
52 n->key = key;
53 n->val = val;
54 }
55 return n;
56}
57
58/*! @private */
59static void cstl_map_node_free(void * const n)
60{
61 free(n);
62}
63
64/*! @private */
65static int cstl_map_node_cmp(const void * const _a, const void * const _b,
66 void * const p)
67{
68 cstl_map_t * const m = p;
69
70 const struct cstl_map_node * const a = _a;
71 const struct cstl_map_node * const b = _b;
72
73 return m->cmp.f(a->key, b->key, m->cmp.p);
74}
75
76/*! @private */
77struct cmc_priv
78{
79 cstl_map_t * map;
80 cstl_xtor_func_t * clr;
81 void * priv;
82};
83
84/*! @private */
85static void __cstl_map_node_clear(void * const n, void * const p)
86{
87 struct cmc_priv * const cmc = p;
88 struct cstl_map_node * const node = n;
89
90 if (cmc->clr != NULL) {
92
93 cstl_map_iterator_init(cmc->map, &i, node);
94 i._ = NULL;
95
96 cmc->clr(&i, cmc->priv);
97 }
98
99 cstl_map_node_free(node);
100}
101
102void cstl_map_clear(cstl_map_t * const map,
103 cstl_xtor_func_t * const clr, void * const priv)
104{
105 struct cmc_priv cmc;
106
107 cmc.map = map;
108 cmc.clr = clr;
109 cmc.priv = priv;
110
111 cstl_rbtree_clear(&((cstl_map_t *)map)->t, __cstl_map_node_clear, &cmc);
112}
113
114void cstl_map_init(cstl_map_t * const map,
115 cstl_compare_func_t * const cmp, void * const priv)
116{
117 map->cmp.f = cmp;
118 map->cmp.p = priv;
119
120 cstl_rbtree_init(&map->t,
121 cstl_map_node_cmp, map,
122 offsetof(struct cstl_map_node, n));
123}
124
125/*! @private */
126static struct cstl_map_node * __cstl_map_find(
127 const cstl_map_t * const map, const void * const key,
128 struct cstl_map_node ** const p)
129{
130 struct cstl_map_node node;
131
132 node.key = key;
133 return (void *)cstl_rbtree_find(&map->t, &node, (void *)p);
134}
135
136void cstl_map_find(const cstl_map_t * const map,
137 const void * const key,
138 cstl_map_iterator_t * const i)
139{
140 cstl_map_iterator_init(
141 map, i, __cstl_map_find(map, key, NULL));
142}
143
144int cstl_map_erase(cstl_map_t * const map, const void * const key,
145 cstl_map_iterator_t * const _i)
146{
148 int err;
149
150 err = -1;
151 cstl_map_find(map, key, &i);
152 if (i._ != NULL) {
154 err = 0;
155 }
156
157 if (_i != NULL) {
158 *_i = i;
159 _i->_ = NULL;
160 }
161
162 return err;
163}
164
166 cstl_map_iterator_t * const i)
167{
168 struct cstl_map_node * const n = i->_;
169 __cstl_rbtree_erase(&map->t, &n->n);
170 cstl_map_node_free(n);
171}
172
174 const void * const key, void * const val,
175 cstl_map_iterator_t * const i)
176{
177 struct cstl_map_node * node, * p;
178 int err;
179
180 err = 1;
181 node = __cstl_map_find(map, key, &p);
182 if (node == NULL) {
183 /* no existing node in the map, carry on */
184 err = -1;
185 node = cstl_map_node_alloc(key, val);
186 if (node != NULL) {
187 cstl_rbtree_insert(&map->t, node, p);
188 err = 0;
189 }
190 }
191
192 if (i != NULL) {
193 cstl_map_iterator_init(map, i, node);
194 }
195
196 return err;
197}
198
199#ifdef __cfg_test__
200// GCOV_EXCL_START
201#include <check.h>
202
203#include "cstl/string.h"
204
205START_TEST(init)
206{
207 cstl_map_t map;
208 cstl_map_init(&map, NULL, NULL);
209 cstl_map_clear(&map, NULL, NULL);
210}
211
212static int map_key_cmp(const void * const a, const void * const b,
213 void * const nil)
214{
215 return cstl_string_compare(
216 (cstl_string_t *)a, (cstl_string_t *)b);
217
218 (void)nil;
219}
220
221static void map_elem_clear(void * const e, void * const nil)
222{
223 cstl_map_iterator_t * const i = e;
224 cstl_string_t * const s = (void *)i->key;
225
226 free(i->val);
227 cstl_string_clear(s);
228 free(s);
229
230 (void)nil;
231}
232
233/*
234 * for the tests, the map is cstl_string->int with the chars
235 * containing the letters 'a' through 'z' with their
236 * corresponding integers being 0 through 25
237 */
238static void fill_map(cstl_map_t * const map)
239{
240 int j, res;
241
242 /*
243 * big assumption that 'a' is "numerically" less than 'z'
244 * and that they're contiguous
245 */
246 for (j = 0; j < (int)('z' - 'a') + 1; j++) {
248 cstl_string_t * s;
249 int * i;
250
251 s = malloc(sizeof(*s));
252 ck_assert_ptr_ne(s, NULL);
253 cstl_string_init(s);
254 cstl_string_resize(s, 1);
255 *cstl_string_data(s) = 'a' + j;
256
257 i = malloc(sizeof(*i));
258 ck_assert_ptr_nonnull(i);
259 *i = j;
260
261 res = cstl_map_insert(map, s, i, &iter);
262 ck_assert_int_eq(res, 0);
263 ck_assert_ptr_nonnull(iter._);
264 ck_assert_ptr_eq(iter.key, s);
265 ck_assert_ptr_eq(iter.val, i);
266 }
267
268 do {
270 cstl_string_t * s;
271 int * i;
272
273 j = 12;
274
275 s = malloc(sizeof(*s));
276 ck_assert_ptr_ne(s, NULL);
277 cstl_string_init(s);
278 cstl_string_resize(s, 1);
279 *cstl_string_data(s) = 'a' + j;
280
281 i = malloc(sizeof(*i));
282 ck_assert_ptr_nonnull(i);
283 *i = j;
284
285 /* insertion should fail because it's already in the map */
286 res = cstl_map_insert(map, s, i, &iter);
287 ck_assert_int_eq(res, 1);
288 ck_assert_ptr_nonnull(iter._);
289 ck_assert_ptr_ne(iter.key, s);
290 ck_assert_ptr_ne(iter.val, i);
291
292 free(i);
293 cstl_string_clear(s);
294 free(s);
295 } while (0);
296}
297
298START_TEST(fill)
299{
300 cstl_map_t map;
301
302 cstl_map_init(&map, map_key_cmp, NULL);
303 fill_map(&map);
304 cstl_map_clear(&map, map_elem_clear, NULL);
305}
306END_TEST
307
308START_TEST(find)
309{
310 DECLARE_CSTL_STRING(string, s);
311 cstl_map_t map;
313
314 cstl_map_init(&map, map_key_cmp, NULL);
315 fill_map(&map);
316
317 cstl_string_set_str(&s, "a");
318 cstl_map_find(&map, &s, &i);
319 ck_assert(!cstl_map_iterator_eq(&i, cstl_map_iterator_end(&map)));
320 ck_assert_ptr_nonnull(i.key);
321 ck_assert_ptr_nonnull(i.val);
322 ck_assert_int_eq(*(int *)i.val, 0);
323
324 cstl_string_set_str(&s, "j");
325 cstl_map_find(&map, &s, &i);
326 ck_assert(!cstl_map_iterator_eq(&i, cstl_map_iterator_end(&map)));
327 ck_assert_ptr_nonnull(i.key);
328 ck_assert_ptr_nonnull(i.val);
329 ck_assert_int_eq(*(int *)i.val, 9);
330
331 cstl_string_set_str(&s, "z");
332 cstl_map_find(&map, &s, &i);
333 ck_assert(!cstl_map_iterator_eq(&i, cstl_map_iterator_end(&map)));
334 ck_assert_ptr_nonnull(i.key);
335 ck_assert_ptr_nonnull(i.val);
336 ck_assert_int_eq(*(int *)i.val, 25);
337
338 cstl_map_clear(&map, map_elem_clear, NULL);
339 cstl_string_clear(&s);
340}
341END_TEST
342
343START_TEST(erase)
344{
345 DECLARE_CSTL_STRING(string, s);
346 cstl_map_t map;
348 int res;
349
350 cstl_map_init(&map, map_key_cmp, NULL);
351 fill_map(&map);
352
353 cstl_string_set_str(&s, "j");
354 cstl_map_find(&map, &s, &i);
355 ck_assert(!cstl_map_iterator_eq(&i, cstl_map_iterator_end(&map)));
356 cstl_map_erase_iterator(&map, &i);
357 ck_assert_ptr_nonnull(i.key);
358 ck_assert_ptr_nonnull(i.val);
359 map_elem_clear(&i, NULL);
360 cstl_map_find(&map, &s, &i);
361 ck_assert(cstl_map_iterator_eq(&i, cstl_map_iterator_end(&map)));
362
363 cstl_string_set_str(&s, "m");
364 res = cstl_map_erase(&map, &s, &i);
365 ck_assert_int_eq(res, 0);
366 ck_assert_ptr_nonnull(i.key);
367 ck_assert_ptr_nonnull(i.val);
368 map_elem_clear(&i, NULL);
369 cstl_map_find(&map, &s, &i);
370 ck_assert(cstl_map_iterator_eq(&i, cstl_map_iterator_end(&map)));
371
372 cstl_map_clear(&map, map_elem_clear, NULL);
373 cstl_string_clear(&s);
374}
375
376Suite * map_suite(void)
377{
378 Suite * const s = suite_create("map");
379
380 TCase * tc;
381
382 tc = tcase_create("map");
383 tcase_add_test(tc, init);
384 tcase_add_test(tc, fill);
385 tcase_add_test(tc, find);
386 tcase_add_test(tc, erase);
387
388 suite_add_tcase(s, tc);
389
390 return s;
391}
392
393// GCOV_EXCL_STOP
394#endif
void cstl_xtor_func_t(void *obj, void *priv)
Type for functions called to construct, clear, or destroy an object.
Definition common.h:97
int cstl_compare_func_t(const void *obj1, const void *obj2, void *priv)
Function type for comparing (in)equality of two objects.
Definition common.h:49
int cstl_map_erase(cstl_map_t *const map, const void *const key, cstl_map_iterator_t *const _i)
Erase the element with the supplied key from the map.
Definition map.c:144
void cstl_map_clear(cstl_map_t *const map, cstl_xtor_func_t *const clr, void *const priv)
Remove all elements from the map.
Definition map.c:102
void cstl_map_find(const cstl_map_t *const map, const void *const key, cstl_map_iterator_t *const i)
Find an element in the map with a matching key.
Definition map.c:136
void cstl_map_init(cstl_map_t *const map, cstl_compare_func_t *const cmp, void *const priv)
Initialize a map.
Definition map.c:114
static bool cstl_map_iterator_eq(const cstl_map_iterator_t *const a, const cstl_map_iterator_t *const b)
Compare two iterators for equality.
Definition map.h:82
void cstl_map_erase_iterator(cstl_map_t *const map, cstl_map_iterator_t *const i)
Erase the element pointed to by the iterator.
Definition map.c:165
int cstl_map_insert(cstl_map_t *const map, const void *const key, void *const val, cstl_map_iterator_t *const i)
Insert a key/value pair into the map.
Definition map.c:173
const cstl_map_iterator_t * cstl_map_iterator_end(const cstl_map_t *const m)
Return an iterator that refers to the end of the map.
Definition map.c:17
static void cstl_rbtree_init(struct cstl_rbtree *const t, cstl_compare_func_t *const cmp, void *const priv, const size_t off)
Initialize a red-black tree object.
Definition rbtree.h:128
void cstl_rbtree_insert(struct cstl_rbtree *t, void *e, void *p)
Insert a new object into the tree.
Definition rbtree.c:98
static const void * cstl_rbtree_find(const struct cstl_rbtree *const t, const void *const e, const void **const p)
Find an element within a tree.
Definition rbtree.h:187
static void cstl_rbtree_clear(struct cstl_rbtree *const t, cstl_xtor_func_t *const clr, void *const priv)
Remove all elements from the tree.
Definition rbtree.h:233
#define DECLARE_CSTL_STRING(TYPE, NAME)
(Statically) declare and initialize a vector
Definition string.h:101
struct cstl_string cstl_string_t
String of narrow characters.
Definition string.h:63
A pointer to an element within the map.
Definition map.h:46
void * val
Pointer to the value contained by the element.
Definition map.h:50
const void * key
Pointer to the key associated with the element.
Definition map.h:48
The map object.
Definition map.h:31
Node to anchor an element within a red-black tree.
Definition rbtree.h:60