Linux Audio

Check our new training course

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