Mercurial > gnulib
annotate tests/test-hash_map.c @ 40057:b06060465f09
maint: Run 'make update-copyright'
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Tue, 01 Jan 2019 00:25:11 +0100 |
parents | 493211f9fd3d |
children | b76c7bdde2bf |
rev | line source |
---|---|
40024 | 1 /* Test of map data type implementation. |
40057
b06060465f09
maint: Run 'make update-copyright'
Paul Eggert <eggert@cs.ucla.edu>
parents:
40024
diff
changeset
|
2 Copyright (C) 2006-2019 Free Software Foundation, Inc. |
40024 | 3 Written by Bruno Haible <bruno@clisp.org>, 2018. |
4 | |
5 This program is free software: you can redistribute it and/or modify | |
6 it under the terms of the GNU General Public License as published by | |
7 the Free Software Foundation; either version 3 of the License, or | |
8 (at your option) any later version. | |
9 | |
10 This program is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 GNU General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU General Public License | |
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ | |
17 | |
18 #include <config.h> | |
19 | |
20 #include "gl_hash_map.h" | |
21 | |
22 #include <stdlib.h> | |
23 #include <string.h> | |
24 | |
25 #include "gl_array_map.h" | |
26 #include "xalloc.h" | |
27 #include "macros.h" | |
28 | |
29 static const char *objects[30] = | |
30 { | |
31 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", | |
32 "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "<", ">", "[", "]" | |
33 }; | |
34 | |
35 #define SIZE_BITS (sizeof (size_t) * CHAR_BIT) | |
36 | |
37 static bool | |
38 string_equals (const void *x1, const void *x2) | |
39 { | |
40 const char *s1 = x1; | |
41 const char *s2 = x2; | |
42 return strcmp (s1, s2) == 0; | |
43 } | |
44 | |
45 /* A hash function for NUL-terminated char* strings using | |
46 the method described by Bruno Haible. | |
47 See https://www.haible.de/bruno/hashfunc.html. */ | |
48 static size_t | |
49 string_hash (const void *x) | |
50 { | |
51 const char *s = x; | |
52 size_t h = 0; | |
53 | |
54 for (; *s; s++) | |
55 h = *s + ((h << 9) | (h >> (SIZE_BITS - 9))); | |
56 | |
57 return h; | |
58 } | |
59 | |
60 #define RANDOM(n) (rand () % (n)) | |
61 #define RANDOM_OBJECT() objects[RANDOM (SIZEOF (objects))] | |
62 | |
63 struct pair | |
64 { | |
65 const void *key; | |
66 const void *value; | |
67 }; | |
68 | |
69 static int | |
70 cmp_pairs_in_array (const void *pairptr1, const void *pairptr2) | |
71 { | |
72 const void *key1 = ((struct pair const *)pairptr1)->key; | |
73 const void *key2 = ((struct pair const *)pairptr2)->key; | |
74 return strcmp ((const char *) key1, (const char *) key2); | |
75 } | |
76 | |
77 static void | |
78 check_equals (gl_map_t map1, gl_map_t map2) | |
79 { | |
80 size_t n = gl_map_size (map1); | |
81 struct pair *pairs_of_map1 = XNMALLOC (n, struct pair); | |
82 struct pair *pairs_of_map2 = XNMALLOC (n, struct pair); | |
83 | |
84 gl_map_iterator_t iter1, iter2; | |
85 const void *key1; | |
86 const void *value1; | |
87 const void *key2; | |
88 const void *value2; | |
89 size_t i; | |
90 | |
91 iter1 = gl_map_iterator (map1); | |
92 iter2 = gl_map_iterator (map2); | |
93 for (i = 0; i < n; i++) | |
94 { | |
95 ASSERT (gl_map_iterator_next (&iter1, &key1, &value1)); | |
96 ASSERT (gl_map_iterator_next (&iter2, &key2, &value2)); | |
97 pairs_of_map1[i].key = key1; | |
98 pairs_of_map1[i].value = value1; | |
99 pairs_of_map2[i].key = key2; | |
100 pairs_of_map2[i].value = value2; | |
101 } | |
102 ASSERT (!gl_map_iterator_next (&iter1, &key1, &value1)); | |
103 ASSERT (!gl_map_iterator_next (&iter2, &key2, &value2)); | |
104 gl_map_iterator_free (&iter1); | |
105 gl_map_iterator_free (&iter2); | |
106 | |
107 if (n > 0) | |
108 { | |
109 qsort (pairs_of_map1, n, sizeof (struct pair), cmp_pairs_in_array); | |
110 qsort (pairs_of_map2, n, sizeof (struct pair), cmp_pairs_in_array); | |
111 } | |
112 for (i = 0; i < n; i++) | |
113 { | |
114 ASSERT (pairs_of_map1[i].key == pairs_of_map2[i].key); | |
115 ASSERT (pairs_of_map1[i].value == pairs_of_map2[i].value); | |
116 } | |
117 free (pairs_of_map2); | |
118 free (pairs_of_map1); | |
119 } | |
120 | |
121 static void | |
122 check_all (gl_map_t map1, gl_map_t map2) | |
123 { | |
124 check_equals (map1, map2); | |
125 } | |
126 | |
127 int | |
128 main (int argc, char *argv[]) | |
129 { | |
130 gl_map_t map1, map2; | |
131 | |
132 /* Allow the user to provide a non-default random seed on the command line. */ | |
133 if (argc > 1) | |
134 srand (atoi (argv[1])); | |
135 | |
136 { | |
137 size_t initial_size = RANDOM (20); | |
138 size_t i; | |
139 unsigned int repeat; | |
140 | |
141 /* Create map1. */ | |
142 map1 = gl_map_nx_create_empty (GL_ARRAY_MAP, | |
143 string_equals, string_hash, NULL, NULL); | |
144 ASSERT (map1 != NULL); | |
145 | |
146 /* Create map2. */ | |
147 map2 = gl_map_nx_create_empty (GL_HASH_MAP, | |
148 string_equals, string_hash, NULL, NULL); | |
149 ASSERT (map2 != NULL); | |
150 | |
151 check_all (map1, map2); | |
152 | |
153 /* Initialize them. */ | |
154 for (i = 0; i < initial_size; i++) | |
155 { | |
156 const char *key = RANDOM_OBJECT (); | |
157 const char *value = RANDOM_OBJECT (); | |
158 ASSERT (gl_map_nx_put (map1, key, value) == gl_map_nx_put (map2, key, value)); | |
159 check_all (map1, map2); | |
160 } | |
161 | |
162 for (repeat = 0; repeat < 100000; repeat++) | |
163 { | |
164 unsigned int operation = RANDOM (3); | |
165 switch (operation) | |
166 { | |
167 case 0: | |
168 { | |
169 const char *key = RANDOM_OBJECT (); | |
170 ASSERT (gl_map_get (map1, key) == gl_map_get (map2, key)); | |
171 } | |
172 break; | |
173 case 1: | |
174 { | |
175 const char *key = RANDOM_OBJECT (); | |
176 const char *value = RANDOM_OBJECT (); | |
177 ASSERT (gl_map_nx_put (map1, key, value) == gl_map_nx_put (map2, key, value)); | |
178 } | |
179 break; | |
180 case 2: | |
181 { | |
182 const char *key = RANDOM_OBJECT (); | |
183 ASSERT (gl_map_remove (map1, key) == gl_map_remove (map2, key)); | |
184 } | |
185 break; | |
186 } | |
187 check_all (map1, map2); | |
188 } | |
189 | |
190 gl_map_free (map1); | |
191 gl_map_free (map2); | |
192 } | |
193 | |
194 return 0; | |
195 } |