1*4882a593Smuzhiyun // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun /*
4*4882a593Smuzhiyun * Tests for libbpf's hashmap.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (c) 2019 Facebook
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun #include "test_progs.h"
9*4882a593Smuzhiyun #include "bpf/hashmap.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun static int duration = 0;
12*4882a593Smuzhiyun
hash_fn(const void * k,void * ctx)13*4882a593Smuzhiyun static size_t hash_fn(const void *k, void *ctx)
14*4882a593Smuzhiyun {
15*4882a593Smuzhiyun return (long)k;
16*4882a593Smuzhiyun }
17*4882a593Smuzhiyun
equal_fn(const void * a,const void * b,void * ctx)18*4882a593Smuzhiyun static bool equal_fn(const void *a, const void *b, void *ctx)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun return (long)a == (long)b;
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun
next_pow_2(size_t n)23*4882a593Smuzhiyun static inline size_t next_pow_2(size_t n)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun size_t r = 1;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun while (r < n)
28*4882a593Smuzhiyun r <<= 1;
29*4882a593Smuzhiyun return r;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
exp_cap(size_t sz)32*4882a593Smuzhiyun static inline size_t exp_cap(size_t sz)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun size_t r = next_pow_2(sz);
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun if (sz * 4 / 3 > r)
37*4882a593Smuzhiyun r <<= 1;
38*4882a593Smuzhiyun return r;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define ELEM_CNT 62
42*4882a593Smuzhiyun
test_hashmap_generic(void)43*4882a593Smuzhiyun static void test_hashmap_generic(void)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun struct hashmap_entry *entry, *tmp;
46*4882a593Smuzhiyun int err, bkt, found_cnt, i;
47*4882a593Smuzhiyun long long found_msk;
48*4882a593Smuzhiyun struct hashmap *map;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun map = hashmap__new(hash_fn, equal_fn, NULL);
51*4882a593Smuzhiyun if (CHECK(IS_ERR(map), "hashmap__new",
52*4882a593Smuzhiyun "failed to create map: %ld\n", PTR_ERR(map)))
53*4882a593Smuzhiyun return;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun for (i = 0; i < ELEM_CNT; i++) {
56*4882a593Smuzhiyun const void *oldk, *k = (const void *)(long)i;
57*4882a593Smuzhiyun void *oldv, *v = (void *)(long)(1024 + i);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun err = hashmap__update(map, k, v, &oldk, &oldv);
60*4882a593Smuzhiyun if (CHECK(err != -ENOENT, "hashmap__update",
61*4882a593Smuzhiyun "unexpected result: %d\n", err))
62*4882a593Smuzhiyun goto cleanup;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun if (i % 2) {
65*4882a593Smuzhiyun err = hashmap__add(map, k, v);
66*4882a593Smuzhiyun } else {
67*4882a593Smuzhiyun err = hashmap__set(map, k, v, &oldk, &oldv);
68*4882a593Smuzhiyun if (CHECK(oldk != NULL || oldv != NULL, "check_kv",
69*4882a593Smuzhiyun "unexpected k/v: %p=%p\n", oldk, oldv))
70*4882a593Smuzhiyun goto cleanup;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun if (CHECK(err, "elem_add", "failed to add k/v %ld = %ld: %d\n",
74*4882a593Smuzhiyun (long)k, (long)v, err))
75*4882a593Smuzhiyun goto cleanup;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (CHECK(!hashmap__find(map, k, &oldv), "elem_find",
78*4882a593Smuzhiyun "failed to find key %ld\n", (long)k))
79*4882a593Smuzhiyun goto cleanup;
80*4882a593Smuzhiyun if (CHECK(oldv != v, "elem_val",
81*4882a593Smuzhiyun "found value is wrong: %ld\n", (long)oldv))
82*4882a593Smuzhiyun goto cleanup;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (CHECK(hashmap__size(map) != ELEM_CNT, "hashmap__size",
86*4882a593Smuzhiyun "invalid map size: %zu\n", hashmap__size(map)))
87*4882a593Smuzhiyun goto cleanup;
88*4882a593Smuzhiyun if (CHECK(hashmap__capacity(map) != exp_cap(hashmap__size(map)),
89*4882a593Smuzhiyun "hashmap_cap",
90*4882a593Smuzhiyun "unexpected map capacity: %zu\n", hashmap__capacity(map)))
91*4882a593Smuzhiyun goto cleanup;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun found_msk = 0;
94*4882a593Smuzhiyun hashmap__for_each_entry(map, entry, bkt) {
95*4882a593Smuzhiyun long k = (long)entry->key;
96*4882a593Smuzhiyun long v = (long)entry->value;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun found_msk |= 1ULL << k;
99*4882a593Smuzhiyun if (CHECK(v - k != 1024, "check_kv",
100*4882a593Smuzhiyun "invalid k/v pair: %ld = %ld\n", k, v))
101*4882a593Smuzhiyun goto cleanup;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun if (CHECK(found_msk != (1ULL << ELEM_CNT) - 1, "elem_cnt",
104*4882a593Smuzhiyun "not all keys iterated: %llx\n", found_msk))
105*4882a593Smuzhiyun goto cleanup;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun for (i = 0; i < ELEM_CNT; i++) {
108*4882a593Smuzhiyun const void *oldk, *k = (const void *)(long)i;
109*4882a593Smuzhiyun void *oldv, *v = (void *)(long)(256 + i);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun err = hashmap__add(map, k, v);
112*4882a593Smuzhiyun if (CHECK(err != -EEXIST, "hashmap__add",
113*4882a593Smuzhiyun "unexpected add result: %d\n", err))
114*4882a593Smuzhiyun goto cleanup;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun if (i % 2)
117*4882a593Smuzhiyun err = hashmap__update(map, k, v, &oldk, &oldv);
118*4882a593Smuzhiyun else
119*4882a593Smuzhiyun err = hashmap__set(map, k, v, &oldk, &oldv);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun if (CHECK(err, "elem_upd",
122*4882a593Smuzhiyun "failed to update k/v %ld = %ld: %d\n",
123*4882a593Smuzhiyun (long)k, (long)v, err))
124*4882a593Smuzhiyun goto cleanup;
125*4882a593Smuzhiyun if (CHECK(!hashmap__find(map, k, &oldv), "elem_find",
126*4882a593Smuzhiyun "failed to find key %ld\n", (long)k))
127*4882a593Smuzhiyun goto cleanup;
128*4882a593Smuzhiyun if (CHECK(oldv != v, "elem_val",
129*4882a593Smuzhiyun "found value is wrong: %ld\n", (long)oldv))
130*4882a593Smuzhiyun goto cleanup;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (CHECK(hashmap__size(map) != ELEM_CNT, "hashmap__size",
134*4882a593Smuzhiyun "invalid updated map size: %zu\n", hashmap__size(map)))
135*4882a593Smuzhiyun goto cleanup;
136*4882a593Smuzhiyun if (CHECK(hashmap__capacity(map) != exp_cap(hashmap__size(map)),
137*4882a593Smuzhiyun "hashmap__capacity",
138*4882a593Smuzhiyun "unexpected map capacity: %zu\n", hashmap__capacity(map)))
139*4882a593Smuzhiyun goto cleanup;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun found_msk = 0;
142*4882a593Smuzhiyun hashmap__for_each_entry_safe(map, entry, tmp, bkt) {
143*4882a593Smuzhiyun long k = (long)entry->key;
144*4882a593Smuzhiyun long v = (long)entry->value;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun found_msk |= 1ULL << k;
147*4882a593Smuzhiyun if (CHECK(v - k != 256, "elem_check",
148*4882a593Smuzhiyun "invalid updated k/v pair: %ld = %ld\n", k, v))
149*4882a593Smuzhiyun goto cleanup;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun if (CHECK(found_msk != (1ULL << ELEM_CNT) - 1, "elem_cnt",
152*4882a593Smuzhiyun "not all keys iterated after update: %llx\n", found_msk))
153*4882a593Smuzhiyun goto cleanup;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun found_cnt = 0;
156*4882a593Smuzhiyun hashmap__for_each_key_entry(map, entry, (void *)0) {
157*4882a593Smuzhiyun found_cnt++;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun if (CHECK(!found_cnt, "found_cnt",
160*4882a593Smuzhiyun "didn't find any entries for key 0\n"))
161*4882a593Smuzhiyun goto cleanup;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun found_msk = 0;
164*4882a593Smuzhiyun found_cnt = 0;
165*4882a593Smuzhiyun hashmap__for_each_key_entry_safe(map, entry, tmp, (void *)0) {
166*4882a593Smuzhiyun const void *oldk, *k;
167*4882a593Smuzhiyun void *oldv, *v;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun k = entry->key;
170*4882a593Smuzhiyun v = entry->value;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun found_cnt++;
173*4882a593Smuzhiyun found_msk |= 1ULL << (long)k;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (CHECK(!hashmap__delete(map, k, &oldk, &oldv), "elem_del",
176*4882a593Smuzhiyun "failed to delete k/v %ld = %ld\n",
177*4882a593Smuzhiyun (long)k, (long)v))
178*4882a593Smuzhiyun goto cleanup;
179*4882a593Smuzhiyun if (CHECK(oldk != k || oldv != v, "check_old",
180*4882a593Smuzhiyun "invalid deleted k/v: expected %ld = %ld, got %ld = %ld\n",
181*4882a593Smuzhiyun (long)k, (long)v, (long)oldk, (long)oldv))
182*4882a593Smuzhiyun goto cleanup;
183*4882a593Smuzhiyun if (CHECK(hashmap__delete(map, k, &oldk, &oldv), "elem_del",
184*4882a593Smuzhiyun "unexpectedly deleted k/v %ld = %ld\n",
185*4882a593Smuzhiyun (long)oldk, (long)oldv))
186*4882a593Smuzhiyun goto cleanup;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun if (CHECK(!found_cnt || !found_msk, "found_entries",
190*4882a593Smuzhiyun "didn't delete any key entries\n"))
191*4882a593Smuzhiyun goto cleanup;
192*4882a593Smuzhiyun if (CHECK(hashmap__size(map) != ELEM_CNT - found_cnt, "elem_cnt",
193*4882a593Smuzhiyun "invalid updated map size (already deleted: %d): %zu\n",
194*4882a593Smuzhiyun found_cnt, hashmap__size(map)))
195*4882a593Smuzhiyun goto cleanup;
196*4882a593Smuzhiyun if (CHECK(hashmap__capacity(map) != exp_cap(hashmap__size(map)),
197*4882a593Smuzhiyun "hashmap__capacity",
198*4882a593Smuzhiyun "unexpected map capacity: %zu\n", hashmap__capacity(map)))
199*4882a593Smuzhiyun goto cleanup;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun hashmap__for_each_entry_safe(map, entry, tmp, bkt) {
202*4882a593Smuzhiyun const void *oldk, *k;
203*4882a593Smuzhiyun void *oldv, *v;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun k = entry->key;
206*4882a593Smuzhiyun v = entry->value;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun found_cnt++;
209*4882a593Smuzhiyun found_msk |= 1ULL << (long)k;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (CHECK(!hashmap__delete(map, k, &oldk, &oldv), "elem_del",
212*4882a593Smuzhiyun "failed to delete k/v %ld = %ld\n",
213*4882a593Smuzhiyun (long)k, (long)v))
214*4882a593Smuzhiyun goto cleanup;
215*4882a593Smuzhiyun if (CHECK(oldk != k || oldv != v, "elem_check",
216*4882a593Smuzhiyun "invalid old k/v: expect %ld = %ld, got %ld = %ld\n",
217*4882a593Smuzhiyun (long)k, (long)v, (long)oldk, (long)oldv))
218*4882a593Smuzhiyun goto cleanup;
219*4882a593Smuzhiyun if (CHECK(hashmap__delete(map, k, &oldk, &oldv), "elem_del",
220*4882a593Smuzhiyun "unexpectedly deleted k/v %ld = %ld\n",
221*4882a593Smuzhiyun (long)k, (long)v))
222*4882a593Smuzhiyun goto cleanup;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (CHECK(found_cnt != ELEM_CNT || found_msk != (1ULL << ELEM_CNT) - 1,
226*4882a593Smuzhiyun "found_cnt",
227*4882a593Smuzhiyun "not all keys were deleted: found_cnt:%d, found_msk:%llx\n",
228*4882a593Smuzhiyun found_cnt, found_msk))
229*4882a593Smuzhiyun goto cleanup;
230*4882a593Smuzhiyun if (CHECK(hashmap__size(map) != 0, "hashmap__size",
231*4882a593Smuzhiyun "invalid updated map size (already deleted: %d): %zu\n",
232*4882a593Smuzhiyun found_cnt, hashmap__size(map)))
233*4882a593Smuzhiyun goto cleanup;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun found_cnt = 0;
236*4882a593Smuzhiyun hashmap__for_each_entry(map, entry, bkt) {
237*4882a593Smuzhiyun CHECK(false, "elem_exists",
238*4882a593Smuzhiyun "unexpected map entries left: %ld = %ld\n",
239*4882a593Smuzhiyun (long)entry->key, (long)entry->value);
240*4882a593Smuzhiyun goto cleanup;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun hashmap__clear(map);
244*4882a593Smuzhiyun hashmap__for_each_entry(map, entry, bkt) {
245*4882a593Smuzhiyun CHECK(false, "elem_exists",
246*4882a593Smuzhiyun "unexpected map entries left: %ld = %ld\n",
247*4882a593Smuzhiyun (long)entry->key, (long)entry->value);
248*4882a593Smuzhiyun goto cleanup;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun cleanup:
252*4882a593Smuzhiyun hashmap__free(map);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
collision_hash_fn(const void * k,void * ctx)255*4882a593Smuzhiyun static size_t collision_hash_fn(const void *k, void *ctx)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun return 0;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
test_hashmap_multimap(void)260*4882a593Smuzhiyun static void test_hashmap_multimap(void)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun void *k1 = (void *)0, *k2 = (void *)1;
263*4882a593Smuzhiyun struct hashmap_entry *entry;
264*4882a593Smuzhiyun struct hashmap *map;
265*4882a593Smuzhiyun long found_msk;
266*4882a593Smuzhiyun int err, bkt;
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* force collisions */
269*4882a593Smuzhiyun map = hashmap__new(collision_hash_fn, equal_fn, NULL);
270*4882a593Smuzhiyun if (CHECK(IS_ERR(map), "hashmap__new",
271*4882a593Smuzhiyun "failed to create map: %ld\n", PTR_ERR(map)))
272*4882a593Smuzhiyun return;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /* set up multimap:
275*4882a593Smuzhiyun * [0] -> 1, 2, 4;
276*4882a593Smuzhiyun * [1] -> 8, 16, 32;
277*4882a593Smuzhiyun */
278*4882a593Smuzhiyun err = hashmap__append(map, k1, (void *)1);
279*4882a593Smuzhiyun if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
280*4882a593Smuzhiyun goto cleanup;
281*4882a593Smuzhiyun err = hashmap__append(map, k1, (void *)2);
282*4882a593Smuzhiyun if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
283*4882a593Smuzhiyun goto cleanup;
284*4882a593Smuzhiyun err = hashmap__append(map, k1, (void *)4);
285*4882a593Smuzhiyun if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
286*4882a593Smuzhiyun goto cleanup;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun err = hashmap__append(map, k2, (void *)8);
289*4882a593Smuzhiyun if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
290*4882a593Smuzhiyun goto cleanup;
291*4882a593Smuzhiyun err = hashmap__append(map, k2, (void *)16);
292*4882a593Smuzhiyun if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
293*4882a593Smuzhiyun goto cleanup;
294*4882a593Smuzhiyun err = hashmap__append(map, k2, (void *)32);
295*4882a593Smuzhiyun if (CHECK(err, "elem_add", "failed to add k/v: %d\n", err))
296*4882a593Smuzhiyun goto cleanup;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun if (CHECK(hashmap__size(map) != 6, "hashmap_size",
299*4882a593Smuzhiyun "invalid map size: %zu\n", hashmap__size(map)))
300*4882a593Smuzhiyun goto cleanup;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* verify global iteration still works and sees all values */
303*4882a593Smuzhiyun found_msk = 0;
304*4882a593Smuzhiyun hashmap__for_each_entry(map, entry, bkt) {
305*4882a593Smuzhiyun found_msk |= (long)entry->value;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun if (CHECK(found_msk != (1 << 6) - 1, "found_msk",
308*4882a593Smuzhiyun "not all keys iterated: %lx\n", found_msk))
309*4882a593Smuzhiyun goto cleanup;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun /* iterate values for key 1 */
312*4882a593Smuzhiyun found_msk = 0;
313*4882a593Smuzhiyun hashmap__for_each_key_entry(map, entry, k1) {
314*4882a593Smuzhiyun found_msk |= (long)entry->value;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun if (CHECK(found_msk != (1 | 2 | 4), "found_msk",
317*4882a593Smuzhiyun "invalid k1 values: %lx\n", found_msk))
318*4882a593Smuzhiyun goto cleanup;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /* iterate values for key 2 */
321*4882a593Smuzhiyun found_msk = 0;
322*4882a593Smuzhiyun hashmap__for_each_key_entry(map, entry, k2) {
323*4882a593Smuzhiyun found_msk |= (long)entry->value;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun if (CHECK(found_msk != (8 | 16 | 32), "found_msk",
326*4882a593Smuzhiyun "invalid k2 values: %lx\n", found_msk))
327*4882a593Smuzhiyun goto cleanup;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun cleanup:
330*4882a593Smuzhiyun hashmap__free(map);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
test_hashmap_empty()333*4882a593Smuzhiyun static void test_hashmap_empty()
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun struct hashmap_entry *entry;
336*4882a593Smuzhiyun int bkt;
337*4882a593Smuzhiyun struct hashmap *map;
338*4882a593Smuzhiyun void *k = (void *)0;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /* force collisions */
341*4882a593Smuzhiyun map = hashmap__new(hash_fn, equal_fn, NULL);
342*4882a593Smuzhiyun if (CHECK(IS_ERR(map), "hashmap__new",
343*4882a593Smuzhiyun "failed to create map: %ld\n", PTR_ERR(map)))
344*4882a593Smuzhiyun goto cleanup;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun if (CHECK(hashmap__size(map) != 0, "hashmap__size",
347*4882a593Smuzhiyun "invalid map size: %zu\n", hashmap__size(map)))
348*4882a593Smuzhiyun goto cleanup;
349*4882a593Smuzhiyun if (CHECK(hashmap__capacity(map) != 0, "hashmap__capacity",
350*4882a593Smuzhiyun "invalid map capacity: %zu\n", hashmap__capacity(map)))
351*4882a593Smuzhiyun goto cleanup;
352*4882a593Smuzhiyun if (CHECK(hashmap__find(map, k, NULL), "elem_find",
353*4882a593Smuzhiyun "unexpected find\n"))
354*4882a593Smuzhiyun goto cleanup;
355*4882a593Smuzhiyun if (CHECK(hashmap__delete(map, k, NULL, NULL), "elem_del",
356*4882a593Smuzhiyun "unexpected delete\n"))
357*4882a593Smuzhiyun goto cleanup;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun hashmap__for_each_entry(map, entry, bkt) {
360*4882a593Smuzhiyun CHECK(false, "elem_found", "unexpected iterated entry\n");
361*4882a593Smuzhiyun goto cleanup;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun hashmap__for_each_key_entry(map, entry, k) {
364*4882a593Smuzhiyun CHECK(false, "key_found", "unexpected key entry\n");
365*4882a593Smuzhiyun goto cleanup;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun cleanup:
369*4882a593Smuzhiyun hashmap__free(map);
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
test_hashmap()372*4882a593Smuzhiyun void test_hashmap()
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun if (test__start_subtest("generic"))
375*4882a593Smuzhiyun test_hashmap_generic();
376*4882a593Smuzhiyun if (test__start_subtest("multimap"))
377*4882a593Smuzhiyun test_hashmap_multimap();
378*4882a593Smuzhiyun if (test__start_subtest("empty"))
379*4882a593Smuzhiyun test_hashmap_empty();
380*4882a593Smuzhiyun }
381