]> git.proxmox.com Git - mirror_ovs.git/blame - tests/test-hmap.c
vswitch: Avoid segfault when revalidating ARP flows.
[mirror_ovs.git] / tests / test-hmap.c
CommitLineData
064af421
BP
1/* A non-exhaustive test for some of the functions and macros declared in
2 * hmap.h. */
3
4#include <config.h>
5#include "hmap.h"
6#include <string.h>
7#include "hash.h"
8#include "util.h"
9
10#undef NDEBUG
11#include <assert.h>
12
13/* Sample hmap element. */
14struct element {
15 int value;
16 struct hmap_node node;
17};
18
19typedef size_t hash_func(int value);
20
21static int
22compare_ints(const void *a_, const void *b_)
23{
24 const int *a = a_;
25 const int *b = b_;
26 return *a < *b ? -1 : *a > *b;
27}
28
29/* Verifies that 'hmap' contains exactly the 'n' values in 'values'. */
30static void
31check_hmap(struct hmap *hmap, const int values[], size_t n,
32 hash_func *hash)
33{
34 int *sort_values, *hmap_values;
35 struct element *e;
36 size_t i;
37
38 /* Check that all the values are there in iteration. */
39 sort_values = xmalloc(sizeof *sort_values * n);
40 hmap_values = xmalloc(sizeof *sort_values * n);
41
42 i = 0;
43 HMAP_FOR_EACH (e, struct element, node, hmap) {
44 assert(i < n);
45 hmap_values[i++] = e->value;
46 }
47 assert(i == n);
48
49 memcpy(sort_values, values, sizeof *sort_values * n);
50 qsort(sort_values, n, sizeof *sort_values, compare_ints);
51 qsort(hmap_values, n, sizeof *hmap_values, compare_ints);
52
53 for (i = 0; i < n; i++) {
54 assert(sort_values[i] == hmap_values[i]);
55 }
56
57 free(hmap_values);
58 free(sort_values);
59
60 /* Check that all the values are there in lookup. */
61 for (i = 0; i < n; i++) {
62 size_t count = 0;
63
64 HMAP_FOR_EACH_WITH_HASH (e, struct element, node,
65 hash(values[i]), hmap) {
66 count += e->value == values[i];
67 }
68 assert(count == 1);
69 }
70
71 /* Check counters. */
72 assert(hmap_is_empty(hmap) == !n);
73 assert(hmap_count(hmap) == n);
74}
75
76/* Puts the 'n' values in 'values' into 'elements', and then puts those
77 * elements into 'hmap'. */
78static void
79make_hmap(struct hmap *hmap, struct element elements[],
80 int values[], size_t n, hash_func *hash)
81{
82 size_t i;
83
84 hmap_init(hmap);
85 for (i = 0; i < n; i++) {
86 elements[i].value = i;
87 hmap_insert(hmap, &elements[i].node, hash(elements[i].value));
88 values[i] = i;
89 }
90}
91
92static void
93shuffle(int *p, size_t n)
94{
95 for (; n > 1; n--, p++) {
96 int *q = &p[rand() % n];
97 int tmp = *p;
98 *p = *q;
99 *q = tmp;
100 }
101}
102
103#if 0
104/* Prints the values in 'hmap', plus 'name' as a title. */
105static void
106print_hmap(const char *name, struct hmap *hmap)
107{
108 struct element *e;
109
110 printf("%s:", name);
111 HMAP_FOR_EACH (e, struct element, node, hmap) {
112 printf(" %d(%zu)", e->value, e->node.hash & hmap->mask);
113 }
114 printf("\n");
115}
116
117/* Prints the 'n' values in 'values', plus 'name' as a title. */
118static void
119print_ints(const char *name, const int *values, size_t n)
120{
121 size_t i;
122
123 printf("%s:", name);
124 for (i = 0; i < n; i++) {
125 printf(" %d", values[i]);
126 }
127 printf("\n");
128}
129#endif
130
131static size_t
132identity_hash(int value)
133{
134 return value;
135}
136
137static size_t
138good_hash(int value)
139{
140 return hash_int(value, 0x1234abcd);
141}
142
143static size_t
144constant_hash(int value UNUSED)
145{
146 return 123;
147}
148
149/* Tests basic hmap insertion and deletion. */
150static void
151test_hmap_insert_delete(hash_func *hash)
152{
153 enum { N_ELEMS = 100 };
154
155 struct element elements[N_ELEMS];
156 int values[N_ELEMS];
157 struct hmap hmap;
158 size_t i;
159
160 hmap_init(&hmap);
161 for (i = 0; i < N_ELEMS; i++) {
162 elements[i].value = i;
163 hmap_insert(&hmap, &elements[i].node, hash(i));
164 values[i] = i;
165 check_hmap(&hmap, values, i + 1, hash);
166 }
167 shuffle(values, N_ELEMS);
168 for (i = 0; i < N_ELEMS; i++) {
169 hmap_remove(&hmap, &elements[values[i]].node);
170 check_hmap(&hmap, values + (i + 1), N_ELEMS - (i + 1), hash);
171 }
172 hmap_destroy(&hmap);
173}
174
175/* Tests basic hmap_reserve() and hmap_shrink(). */
176static void
177test_hmap_reserve_shrink(hash_func *hash)
178{
179 enum { N_ELEMS = 32 };
180
181 size_t i;
182
183 for (i = 0; i < N_ELEMS; i++) {
184 struct element elements[N_ELEMS];
185 int values[N_ELEMS];
186 struct hmap hmap;
187 size_t j;
188
189 hmap_init(&hmap);
190 hmap_reserve(&hmap, i);
191 for (j = 0; j < N_ELEMS; j++) {
192 elements[j].value = j;
193 hmap_insert(&hmap, &elements[j].node, hash(j));
194 values[j] = j;
195 check_hmap(&hmap, values, j + 1, hash);
196 }
197 shuffle(values, N_ELEMS);
198 for (j = 0; j < N_ELEMS; j++) {
199 hmap_remove(&hmap, &elements[values[j]].node);
200 hmap_shrink(&hmap);
201 check_hmap(&hmap, values + (j + 1), N_ELEMS - (j + 1), hash);
202 }
203 hmap_destroy(&hmap);
204 }
205}
206
207/* Tests that HMAP_FOR_EACH_SAFE properly allows for deletion of the current
208 * element of a hmap. */
209static void
210test_hmap_for_each_safe(hash_func *hash)
211{
212 enum { MAX_ELEMS = 10 };
213 size_t n;
214 unsigned long int pattern;
215
216 for (n = 0; n <= MAX_ELEMS; n++) {
217 for (pattern = 0; pattern < 1ul << n; pattern++) {
218 struct element elements[MAX_ELEMS];
219 int values[MAX_ELEMS];
220 struct hmap hmap;
221 struct element *e, *next;
222 size_t n_remaining;
223 int i;
224
225 make_hmap(&hmap, elements, values, n, hash);
226
227 i = 0;
228 n_remaining = n;
229 HMAP_FOR_EACH_SAFE (e, next, struct element, node, &hmap) {
230 assert(i < n);
231 if (pattern & (1ul << e->value)) {
232 size_t j;
233 hmap_remove(&hmap, &e->node);
234 for (j = 0; ; j++) {
235 assert(j < n_remaining);
236 if (values[j] == e->value) {
237 values[j] = values[--n_remaining];
238 break;
239 }
240 }
241 }
242 check_hmap(&hmap, values, n_remaining, hash);
243 i++;
244 }
245 assert(i == n);
246
247 for (i = 0; i < n; i++) {
248 if (pattern & (1ul << i)) {
249 n_remaining++;
250 }
251 }
252 assert(n == n_remaining);
253
254 hmap_destroy(&hmap);
255 }
256 }
257}
258
259static void
260run_test(void (*function)(hash_func *))
261{
262 hash_func *hash_funcs[] = { identity_hash, good_hash, constant_hash };
263 size_t i;
264
265 for (i = 0; i < ARRAY_SIZE(hash_funcs); i++) {
266 function(hash_funcs[i]);
267 printf(".");
268 fflush(stdout);
269 }
270}
271
272int
273main(void)
274{
275 run_test(test_hmap_insert_delete);
276 run_test(test_hmap_for_each_safe);
277 run_test(test_hmap_reserve_shrink);
278 printf("\n");
279 return 0;
280}
281