GCC Code Coverage Report


Directory: ./
File: common/src/map.c
Date: 2026-11-08 20:01:15
Exec Total Coverage
Lines: 92 110 83.6%
Functions: 13 14 92.9%
Branches: 30 44 68.2%

Line Branch Exec Source
1 /*
2 * Common code for dealing with maps.
3 * Copyright © 2024-2026, albinoloverats ~ Software Development
4 * email: webmaster@albinoloverats.net
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <stdlib.h>
22
23 #include <stdbool.h>
24
25 #include "common.h"
26 #include "mem.h"
27 #include "map.h"
28 #include "pair.h"
29
30 typedef struct
31 {
32 list_t entries;
33 list_t keys; // keeping a list of keys might help in the future (I don't know yet)
34 int (*compare)(const void *, const void *); /*!< How to compare entries (keys) in the map */
35 bool free:1;
36 bool overwrite:1;
37 }
38 map_private_s;
39
40 typedef struct
41 {
42 pair_object_s pair; // TODO could this be pair_u and allow differing keys/values?
43 map_private_s *parent; // reference to parent gives compare function in entry compare
44 }
45 entry_s;
46
47 static int map_compare(const void *a, const void *b);
48 static void map_free(void *map);
49
50 3 extern map_t map_init(int c(const void *, const void *), bool f, bool s, bool o)
51 {
52 3 map_private_s *m = m_calloc(sizeof( map_private_s ), sizeof( byte_t ));
53 3 m->entries = list_init(map_compare, false, s);
54 3 m->keys = list_init(c, false, s);
55 3 m->compare = c;
56 3 m->free = f;
57 3 m->overwrite = o;
58 3 return m;
59 }
60
61 3 extern void map_deinit(map_t ptr)
62 {
63 3 map_private_s *map = (map_private_s *)ptr;
64
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!map)
65 ✗ return;
66 3 list_deinit(map->keys);
67 3 list_deinit(map->entries, map_free);
68 3 free(map);
69 3 return;
70 }
71
72 5 extern size_t map_size(map_t ptr)
73 {
74 5 return list_size(((map_private_s *)ptr)->entries);
75 }
76
77 9 extern bool map_add(map_t ptr, const void *k, const void *v)
78 {
79 9 map_private_s *map = (map_private_s *)ptr;
80
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!map)
81 ✗ return false;
82 9 bool exists = list_contains(map->keys, k);
83
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
9 if (exists && !map->overwrite)
84 1 return false; // already exists and not overwritting
85 entry_s *e;
86
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
8 if (exists && map->overwrite)
87 2 {
88 2 entry_s key = { { (void *)k, NULL }, map };
89 2 e = (entry_s *)list_contains(map->entries, &key);
90
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!e)
91 ✗ return false;
92
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (map->free)
93 1 free((void *)e->pair.p2);
94 2 e->pair.p2 = (void *)v;
95 }
96 else
97 {
98
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (!list_append(map->keys, k))
99 ✗ return false;
100 6 e = calloc(sizeof( entry_s ), sizeof( byte_t ));
101 6 e->parent = map;
102 6 e->pair.p1 = (void *)k;
103 6 e->pair.p2 = (void *)v;
104
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (list_append(map->entries, e))
105 6 return true;
106 ✗ list_remove_item(map->keys, k);
107 ✗ free(e);
108 ✗ return false;
109 }
110 2 return true;
111 }
112
113 5 extern const void *map_get(map_t ptr, const void *k)
114 {
115 5 map_private_s *map = (map_private_s *)ptr;
116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!map)
117 ✗ return NULL;
118
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
5 if (!list_contains(map->keys, k))
119 1 return NULL;
120 4 const entry_s *r = list_contains(map->entries, &((entry_s){ { (void *)k, NULL }, map }));
121 4 return r->pair.p2;
122 }
123
124 1 extern bool map_contains(map_t ptr, const void *k)
125 {
126 1 return map_get(ptr, k);
127 }
128
129 3 extern const void *map_remove(map_t ptr, const void *k)
130 {
131 3 map_private_s *map = (map_private_s *)ptr;
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!map)
133 ✗ return NULL;
134
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if (!list_contains(map->keys, k))
135 1 return NULL;
136 2 list_remove_item(map->keys, k);
137 2 const entry_s *r = list_remove_item(map->entries, &((entry_s){ { (void *)k, NULL }, map }));
138
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (map->free)
139 1 free((void *)r->pair.p1);
140 2 const void *x = r->pair.p2;
141 2 free((void *)r);
142 2 return x;
143 }
144
145 1 extern iter_t map_iterator(map_t ptr)
146 {
147 1 map_private_s *map_ptr = (map_private_s *)ptr;
148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!map_ptr)
149 ✗ return NULL;
150 1 return list_iterator(map_ptr->entries);
151 }
152
153 1 extern const pair_object_s *map_get_next(iter_t ptr)
154 {
155 1 return list_get_next(ptr);
156 }
157
158 2 extern bool map_has_next(iter_t ptr)
159 {
160 2 return list_has_next(ptr);
161 }
162
163 2 extern void map_for_each(map_t ptr, void f(const void *, const void *))
164 {
165 2 map_private_s *map_ptr = (map_private_s *)ptr;
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!map_ptr)
167 ✗ return;
168
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (!list_size(map_ptr->entries))
169 1 return;
170 1 iter_t iter = list_iterator(map_ptr->entries);
171 do
172 {
173 1 const entry_s *entry = (entry_s *)list_get_next(iter);
174 1 pair_object_s pair = entry->pair;
175 1 f(pair.p1, pair.p2);
176 }
177
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 while (list_has_next(iter));
178 1 free(iter);
179 1 return;
180 }
181
182 18 static int map_compare(const void *a, const void *b)
183 {
184 18 const entry_s *x = a;
185 18 const entry_s *y = b;
186
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (x->parent->compare)
187 18 return x->parent->compare(x->pair.p1, y->pair.p1);
188 ✗ return x->pair.p1 - y->pair.p1;
189 }
190
191 4 static void map_free(void *m)
192 {
193 4 entry_s *e = (entry_s *)m;
194
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (e->parent->free)
195 {
196 1 free((void *)e->pair.p1);
197 1 free((void *)e->pair.p2);
198 }
199 4 free(e);
200 4 return;
201 }
202
203 ✗ extern void map_add_comparator(map_t ptr, int c(const void *, const void *))
204 {
205 ✗ map_private_s *map_ptr = (map_private_s *)ptr;
206 ✗ if (!map_ptr)
207 ✗ return;
208 ✗ map_ptr->compare = c;
209 ✗ return;
210 }
211