openat: don’t close (-1)
[gnulib.git] / tests / test-hamt.c
blobb1a46198712e7e6c406cdc5422416016a18c3cc8
1 /* Test of persistent hash array mapped trie implementation.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Marc Nieper-Wißkirchen <marc@nieper-wisskirchen.de>, 2021. */
19 #include <config.h>
21 #include "hamt.h"
22 #include "macros.h"
23 #include "xalloc.h"
25 typedef struct
27 Hamt_entry entry;
28 int val;
29 } Element;
31 static int
32 entry_value (const void *elt)
34 return ((Element *) elt)->val;
37 static size_t
38 hash_element (const void *elt)
40 return entry_value (elt) & ~3; /* We drop the last bits so that we
41 can test hash collisions. */
44 static bool
45 compare_element (const void *elt1, const void *elt2)
47 return entry_value (elt1) == entry_value (elt2);
50 static void
51 free_element (Hamt_entry *elt)
53 free (elt);
56 static Hamt_entry *
57 make_element (int n)
59 Element *elt = XMALLOC (Element);
60 elt->val = n;
61 return hamt_element (&elt->entry);
64 static Hamt *
65 test_hamt_create (void)
67 return hamt_create (hash_element, compare_element, free_element);
71 static int sum = 0;
72 static int flag;
74 static bool
75 proc (Hamt_entry *elt, void *data)
77 if (data == &flag)
79 sum += entry_value (elt);
80 return true;
82 if (sum > 0)
84 sum = 0;
85 return true;
87 return false;
90 static void
91 test_general (void)
93 Hamt *hamt = test_hamt_create ();
95 Hamt_entry *x5 = make_element (5);
96 Hamt_entry *p = x5;
97 Hamt *hamt1 = hamt_insert (hamt, &p);
98 ASSERT (hamt1 != hamt);
99 ASSERT (hamt_lookup (hamt, x5) == NULL);
100 ASSERT (hamt_lookup (hamt1, x5) == x5);
101 hamt_free (hamt);
103 Hamt_entry *y5 = make_element (5);
104 p = y5;
105 Hamt *hamt2 = hamt_insert (hamt1, &p);
106 ASSERT (hamt2 == hamt1);
107 ASSERT (p == x5);
108 ASSERT (hamt_lookup (hamt1, y5) == x5);
110 p = y5;
111 hamt = hamt_replace (hamt1, &p);
112 ASSERT (p == x5);
113 ASSERT (hamt_lookup (hamt, y5) == y5);
114 hamt_free (hamt);
115 y5 = make_element (5);
117 Hamt_entry *z37 = make_element (37);
118 p = z37;
119 hamt2 = hamt_insert (hamt1, &p);
120 ASSERT (hamt2 != hamt1);
121 ASSERT (p == z37);
122 ASSERT (hamt_lookup (hamt1, z37) == NULL);
123 ASSERT (hamt_lookup (hamt2, z37) == z37);
124 hamt_free (hamt1);
126 ASSERT (hamt_lookup (hamt2, x5) == x5);
127 ASSERT (hamt_lookup (hamt2, z37) == z37);
129 ASSERT (hamt_do_while (hamt2, proc, &flag) == 2);
130 ASSERT (sum == 42);
131 ASSERT (hamt_do_while (hamt2, proc, NULL) == 1);
132 ASSERT (sum == 0);
134 p = y5;
135 hamt1 = hamt_remove (hamt2, &p);
136 ASSERT (hamt1 != hamt2);
137 ASSERT (p == x5);
139 ASSERT (hamt_lookup (hamt1, x5) == NULL);
140 ASSERT (hamt_lookup (hamt2, x5) == x5);
142 hamt_free (hamt1);
143 Hamt_entry *x4 = make_element (4);
144 hamt1 = hamt_insert (hamt2, &x4);
145 hamt_free (hamt2);
146 Hamt_entry *x6 = make_element (6);
147 hamt2 = hamt_insert (hamt1, &x6);
148 hamt_free (hamt1);
149 ASSERT (hamt_do_while (hamt2, proc, &flag) == 4);
150 ASSERT (sum == 52);
152 hamt1 = hamt_remove (hamt2, &x4);
153 sum = 0;
154 ASSERT (hamt_do_while (hamt2, proc, &flag) == 4);
155 ASSERT (sum == 52);
156 sum = 0;
157 ASSERT (hamt_do_while (hamt1, proc, &flag) == 3);
158 ASSERT (sum == 48);
160 hamt_free (hamt1);
161 hamt_free (hamt2);
162 free_element (y5);
165 static bool
166 true_processor (_GL_ATTRIBUTE_MAYBE_UNUSED Hamt_entry *elt,
167 _GL_ATTRIBUTE_MAYBE_UNUSED void *data)
169 return true;
172 static size_t
173 element_count (Hamt *hamt)
175 return hamt_do_while (hamt, true_processor, NULL);
178 struct find_values_context
180 size_t n;
181 int *elts;
182 bool *found;
185 static bool
186 find_values_processor (Hamt_entry *entry, void *data)
188 struct find_values_context *ctx = data;
189 int val = entry_value (entry);
190 for (size_t i = 0; i < ctx->n; ++i)
191 if (ctx->elts [i] == val && !ctx->found [i])
193 ctx->found [i] = true;
194 return true;
196 return false;
199 static bool
200 find_values (Hamt *hamt, size_t n, int *elts)
202 bool *found = XCALLOC (n, bool);
203 struct find_values_context ctx = {n, elts, found};
204 bool res = hamt_do_while (hamt, find_values_processor, &ctx) == n;
205 free (found);
206 return res;
209 static size_t
210 insert_values (Hamt **hamt, size_t n, int *elts, bool destructive)
212 size_t cnt = 0;
213 for (size_t i = 0; i < n; ++i)
215 Hamt_entry *p = make_element (elts [i]);
216 Hamt_entry *q = p;
217 if (destructive)
219 if (hamt_insert_x (*hamt, &p))
220 ++cnt;
221 else
222 free_element (q);
224 else
226 Hamt *new_hamt = hamt_insert (*hamt, &p);
227 if (new_hamt != *hamt)
229 hamt_free (*hamt);
230 *hamt = new_hamt;
231 ++cnt;
233 else
235 free_element (q);
239 return cnt;
242 static size_t
243 replace_values (Hamt **hamt, size_t n, int *elts, bool destructive)
245 size_t cnt = 0;
246 for (size_t i = 0; i < n; ++i)
248 Hamt_entry *p = make_element (elts [i]);
249 if (destructive)
251 if (hamt_replace_x (*hamt, p))
252 ++cnt;
254 else
256 Hamt *new_hamt = hamt_replace (*hamt, &p);
257 hamt_free (*hamt);
258 *hamt = new_hamt;
259 if (p != NULL)
260 ++cnt;
263 return cnt;
266 static size_t
267 remove_values (Hamt **hamt, size_t n, int *elts, bool destructive)
269 size_t cnt = 0;
270 for (size_t i = 0; i < n; ++i)
272 Hamt_entry *p = make_element (elts [i]);
273 Hamt_entry *q = p;
274 if (destructive)
276 if (hamt_remove_x (*hamt, p))
277 ++cnt;
279 else
281 Hamt *new_hamt = hamt_remove (*hamt, &p);
282 if (new_hamt != *hamt)
284 hamt_free (*hamt);
285 *hamt = new_hamt;
286 ++cnt;
289 free (q);
291 return cnt;
294 static int val_array1 [10] = {1, 2, 3, 4, 33, 34, 35, 36, 1024, 1025};
295 static int val_array2 [10] = {1, 2, 34, 36, 1025, 32768, 32769, 32770, 32771,
296 32772};
298 static void
299 test_functional_update (void)
301 Hamt *hamt = test_hamt_create ();
303 ASSERT (insert_values (&hamt, 10, val_array1, false) == 10);
304 ASSERT (element_count (hamt) == 10);
305 ASSERT (find_values (hamt, 10, val_array1));
306 ASSERT (insert_values (&hamt, 10, val_array2, false) == 5);
307 ASSERT (element_count (hamt) == 15);
308 ASSERT (remove_values (&hamt, 10, val_array1, false) == 10);
309 ASSERT (element_count (hamt) == 5);
310 ASSERT (remove_values (&hamt, 10, val_array2, false) == 5);
311 ASSERT (element_count (hamt) == 0);
313 ASSERT (replace_values (&hamt, 10, val_array1, false) == 0);
314 ASSERT (element_count (hamt) == 10);
315 ASSERT (find_values (hamt, 10, val_array1));
316 ASSERT (replace_values (&hamt, 10, val_array2, false) == 5);
317 ASSERT (element_count (hamt) == 15);
319 hamt_free (hamt);
322 static void
323 test_destructive_update (void)
325 Hamt *hamt = test_hamt_create ();
327 ASSERT (insert_values (&hamt, 10, val_array1, true) == 10);
328 ASSERT (element_count (hamt) == 10);
329 ASSERT (find_values (hamt, 10, val_array1));
330 ASSERT (insert_values (&hamt, 10, val_array2, true) == 5);
331 ASSERT (element_count (hamt) == 15);
332 ASSERT (remove_values (&hamt, 10, val_array1, true) == 10);
333 ASSERT (element_count (hamt) == 5);
334 ASSERT (remove_values (&hamt, 10, val_array2, true) == 5);
335 ASSERT (element_count (hamt) == 0);
337 ASSERT (replace_values (&hamt, 10, val_array1, true) == 0);
338 ASSERT (element_count (hamt) == 10);
339 ASSERT (find_values (hamt, 10, val_array1));
340 ASSERT (replace_values (&hamt, 10, val_array2, true) == 5);
341 ASSERT (element_count (hamt) == 15);
343 hamt_free (hamt);
346 static void
347 test_iterator (void)
349 Hamt *hamt = test_hamt_create ();
350 ASSERT (insert_values (&hamt, 10, val_array1, true) == 10);
351 Hamt_iterator iter[1];
352 iter[0] = hamt_iterator (hamt);
353 size_t cnt = 0;
354 bool found [10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
355 Hamt_entry *p;
356 while (hamt_iterator_next (iter, &p))
358 for (size_t i = 0; i < 10; ++i)
359 if (val_array1 [i] == entry_value (p))
361 ASSERT (!found [i]);
362 found [i] = true;
363 ++cnt;
364 break;
367 ASSERT (cnt == 10);
368 hamt_iterator_free (iter);
369 hamt_free (hamt);
373 main (void)
375 test_general ();
376 test_functional_update ();
377 test_destructive_update ();
378 test_iterator ();
380 return test_exit_status;