2 * Copyright (c) 2008, 2009, 2010, 2013, 2014 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 /* A non-exhaustive test for some of the functions and macros declared in
31 /* Sample hmap element. */
34 struct hmap_node node;
37 typedef size_t hash_func(int value);
40 compare_ints(const void *a_, const void *b_)
44 return *a < *b ? -1 : *a > *b;
47 /* Verifies that 'hmap' contains exactly the 'n' values in 'values'. */
49 check_hmap(struct hmap *hmap, const int values[], size_t n,
52 int *sort_values, *hmap_values;
56 /* Check that all the values are there in iteration. */
57 sort_values = xmalloc(sizeof *sort_values * n);
58 hmap_values = xmalloc(sizeof *sort_values * n);
61 HMAP_FOR_EACH (e, node, hmap) {
63 hmap_values[i++] = e->value;
67 memcpy(sort_values, values, sizeof *sort_values * n);
68 qsort(sort_values, n, sizeof *sort_values, compare_ints);
69 qsort(hmap_values, n, sizeof *hmap_values, compare_ints);
71 for (i = 0; i < n; i++) {
72 assert(sort_values[i] == hmap_values[i]);
78 /* Check that all the values are there in lookup. */
79 for (i = 0; i < n; i++) {
82 HMAP_FOR_EACH_WITH_HASH (e, node, hash(values[i]), hmap) {
83 count += e->value == values[i];
89 assert(hmap_is_empty(hmap) == !n);
90 assert(hmap_count(hmap) == n);
93 /* Puts the 'n' values in 'values' into 'elements', and then puts those
94 * elements into 'hmap'. */
96 make_hmap(struct hmap *hmap, struct element elements[],
97 int values[], size_t n, hash_func *hash)
102 for (i = 0; i < n; i++) {
103 elements[i].value = i;
104 hmap_insert(hmap, &elements[i].node, hash(elements[i].value));
110 shuffle(int *p, size_t n)
112 for (; n > 1; n--, p++) {
113 int *q = &p[random_range(n)];
121 /* Prints the values in 'hmap', plus 'name' as a title. */
123 print_hmap(const char *name, struct hmap *hmap)
128 HMAP_FOR_EACH (e, node, hmap) {
129 printf(" %d(%"PRIuSIZE")", e->value, e->node.hash & hmap->mask);
134 /* Prints the 'n' values in 'values', plus 'name' as a title. */
136 print_ints(const char *name, const int *values, size_t n)
141 for (i = 0; i < n; i++) {
142 printf(" %d", values[i]);
149 identity_hash(int value)
157 return hash_int(value, 0x1234abcd);
161 constant_hash(int value OVS_UNUSED)
166 /* Tests basic hmap insertion and deletion. */
168 test_hmap_insert_delete(hash_func *hash)
170 enum { N_ELEMS = 100 };
172 struct element elements[N_ELEMS];
178 for (i = 0; i < N_ELEMS; i++) {
179 elements[i].value = i;
180 hmap_insert(&hmap, &elements[i].node, hash(i));
182 check_hmap(&hmap, values, i + 1, hash);
184 shuffle(values, N_ELEMS);
185 for (i = 0; i < N_ELEMS; i++) {
186 hmap_remove(&hmap, &elements[values[i]].node);
187 check_hmap(&hmap, values + (i + 1), N_ELEMS - (i + 1), hash);
192 /* Tests basic hmap_reserve() and hmap_shrink(). */
194 test_hmap_reserve_shrink(hash_func *hash)
196 enum { N_ELEMS = 32 };
200 for (i = 0; i < N_ELEMS; i++) {
201 struct element elements[N_ELEMS];
207 hmap_reserve(&hmap, i);
208 for (j = 0; j < N_ELEMS; j++) {
209 elements[j].value = j;
210 hmap_insert(&hmap, &elements[j].node, hash(j));
212 check_hmap(&hmap, values, j + 1, hash);
214 shuffle(values, N_ELEMS);
215 for (j = 0; j < N_ELEMS; j++) {
216 hmap_remove(&hmap, &elements[values[j]].node);
218 check_hmap(&hmap, values + (j + 1), N_ELEMS - (j + 1), hash);
224 /* Tests that HMAP_FOR_EACH_SAFE properly allows for deletion of the current
225 * element of a hmap. */
227 test_hmap_for_each_safe(hash_func *hash)
229 enum { MAX_ELEMS = 10 };
231 unsigned long int pattern;
233 for (n = 0; n <= MAX_ELEMS; n++) {
234 for (pattern = 0; pattern < 1ul << n; pattern++) {
235 struct element elements[MAX_ELEMS];
236 int values[MAX_ELEMS];
238 struct element *e, *next;
242 make_hmap(&hmap, elements, values, n, hash);
246 HMAP_FOR_EACH_SAFE (e, next, node, &hmap) {
248 if (pattern & (1ul << e->value)) {
250 hmap_remove(&hmap, &e->node);
252 assert(j < n_remaining);
253 if (values[j] == e->value) {
254 values[j] = values[--n_remaining];
259 check_hmap(&hmap, values, n_remaining, hash);
264 for (i = 0; i < n; i++) {
265 if (pattern & (1ul << i)) {
269 assert(n == n_remaining);
277 run_test(void (*function)(hash_func *))
279 hash_func *hash_funcs[] = { identity_hash, good_hash, constant_hash };
282 for (i = 0; i < ARRAY_SIZE(hash_funcs); i++) {
283 function(hash_funcs[i]);
290 test_hmap_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
292 run_test(test_hmap_insert_delete);
293 run_test(test_hmap_for_each_safe);
294 run_test(test_hmap_reserve_shrink);
298 OVSTEST_REGISTER("test-hmap", test_hmap_main);