Sequential list data type implemented by a hash table with a linked list.
[gnulib.git] / tests / test-linkedhash_list.c
1 /* Test of sequential list data type implementation.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2006.
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 2, or (at your option)
8    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, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <limits.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "gl_array_list.h"
28 #include "gl_linkedhash_list.h"
29
30 static const char *objects[15] =
31   {
32     "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o"
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 http://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 SIZEOF(array) (sizeof (array) / sizeof (array[0]))
61 #define ASSERT(condition) if (!(condition)) abort ()
62 #define RANDOM(n) (rand () % (n))
63 #define RANDOM_OBJECT() objects[RANDOM (SIZEOF (objects))]
64
65 static void
66 check_equals (gl_list_t list1, gl_list_t list2)
67 {
68   size_t n, i;
69
70   n = gl_list_size (list1);
71   ASSERT (n == gl_list_size (list2));
72   for (i = 0; i < n; i++)
73     {
74       ASSERT (gl_list_get_at (list1, i) == gl_list_get_at (list2, i));
75     }
76 }
77
78 static void
79 check_all (gl_list_t list1, gl_list_t list2, gl_list_t list3)
80 {
81   check_equals (list1, list2);
82   check_equals (list1, list3);
83 }
84
85 int
86 main (int argc, char *argv[])
87 {
88   gl_list_t list1, list2, list3;
89
90   /* Allow the user to provide a non-default random seed on the command line.  */
91   if (argc > 1)
92     srand (atoi (argv[1]));
93
94   {
95     size_t initial_size = RANDOM (50);
96     const void **contents =
97       (const void **) malloc (initial_size * sizeof (const void *));
98     size_t i;
99     unsigned int repeat;
100
101     for (i = 0; i < initial_size; i++)
102       contents[i] = RANDOM_OBJECT ();
103
104     /* Create list1.  */
105     list1 = gl_list_create (GL_ARRAY_LIST,
106                             string_equals, string_hash, true,
107                             initial_size, contents);
108     /* Create list2.  */
109     list2 = gl_list_create_empty (GL_LINKEDHASH_LIST,
110                                   string_equals, string_hash, true);
111     for (i = 0; i < initial_size; i++)
112       gl_list_add_last (list2, contents[i]);
113
114     /* Create list3.  */
115     list3 = gl_list_create (GL_LINKEDHASH_LIST,
116                             string_equals, string_hash, true,
117                             initial_size, contents);
118
119     check_all (list1, list2, list3);
120
121     for (repeat = 0; repeat < 10000; repeat++)
122       {
123         unsigned int operation = RANDOM (16);
124         switch (operation)
125           {
126           case 0:
127             if (gl_list_size (list1) > 0)
128               {
129                 size_t index = RANDOM (gl_list_size (list1));
130                 const char *obj = RANDOM_OBJECT ();
131                 gl_list_node_t node1, node2, node3;
132
133                 node1 = gl_list_set_at (list1, index, obj);
134                 ASSERT (gl_list_get_at (list1, index) == obj);
135                 ASSERT (gl_list_node_value (list1, node1) == obj);
136
137                 node2 = gl_list_set_at (list2, index, obj);
138                 ASSERT (gl_list_get_at (list2, index) == obj);
139                 ASSERT (gl_list_node_value (list2, node2) == obj);
140
141                 node3 = gl_list_set_at (list3, index, obj);
142                 ASSERT (gl_list_get_at (list3, index) == obj);
143                 ASSERT (gl_list_node_value (list3, node3) == obj);
144
145                 if (index > 0)
146                   {
147                     ASSERT (gl_list_node_value (list1, gl_list_previous_node (list1, node1))
148                             == gl_list_get_at (list1, index - 1));
149                     ASSERT (gl_list_node_value (list2, gl_list_previous_node (list3, node3))
150                             == gl_list_get_at (list2, index - 1));
151                     ASSERT (gl_list_node_value (list3, gl_list_previous_node (list3, node3))
152                             == gl_list_get_at (list2, index - 1));
153                   }
154                 if (index + 1 < gl_list_size (list1))
155                   {
156                     ASSERT (gl_list_node_value (list1, gl_list_next_node (list1, node1))
157                             == gl_list_get_at (list1, index + 1));
158                     ASSERT (gl_list_node_value (list2, gl_list_next_node (list3, node3))
159                             == gl_list_get_at (list2, index + 1));
160                     ASSERT (gl_list_node_value (list3, gl_list_next_node (list3, node3))
161                             == gl_list_get_at (list2, index + 1));
162                   }
163               }
164             break;
165           case 1:
166             {
167               const char *obj = RANDOM_OBJECT ();
168               gl_list_node_t node1, node2, node3;
169               node1 = gl_list_search (list1, obj);
170               node2 = gl_list_search (list2, obj);
171               node3 = gl_list_search (list3, obj);
172               if (node1 == NULL)
173                 {
174                   ASSERT (node2 == NULL);
175                   ASSERT (node3 == NULL);
176                 }
177               else
178                 {
179                   ASSERT (node2 != NULL);
180                   ASSERT (node3 != NULL);
181                   ASSERT (gl_list_node_value (list1, node1) == obj);
182                   ASSERT (gl_list_node_value (list2, node2) == obj);
183                   ASSERT (gl_list_node_value (list3, node3) == obj);
184                 }
185             }
186             break;
187           case 2:
188             {
189               const char *obj = RANDOM_OBJECT ();
190               size_t index1, index2, index3;
191               index1 = gl_list_indexof (list1, obj);
192               index2 = gl_list_indexof (list2, obj);
193               index3 = gl_list_indexof (list3, obj);
194               if (index1 == (size_t)(-1))
195                 {
196                   ASSERT (index2 == (size_t)(-1));
197                   ASSERT (index3 == (size_t)(-1));
198                 }
199               else
200                 {
201                   ASSERT (index2 != (size_t)(-1));
202                   ASSERT (index3 != (size_t)(-1));
203                   ASSERT (gl_list_get_at (list1, index1) == obj);
204                   ASSERT (gl_list_get_at (list2, index2) == obj);
205                   ASSERT (gl_list_get_at (list3, index3) == obj);
206                   ASSERT (index2 == index1);
207                   ASSERT (index3 == index1);
208                 }
209             }
210             break;
211           case 3: /* add 1 element */
212             {
213               const char *obj = RANDOM_OBJECT ();
214               gl_list_node_t node1, node2, node3;
215               node1 = gl_list_add_first (list1, obj);
216               node2 = gl_list_add_first (list2, obj);
217               node3 = gl_list_add_first (list3, obj);
218               ASSERT (gl_list_node_value (list1, node1) == obj);
219               ASSERT (gl_list_node_value (list2, node2) == obj);
220               ASSERT (gl_list_node_value (list3, node3) == obj);
221               ASSERT (gl_list_get_at (list1, 0) == obj);
222               ASSERT (gl_list_get_at (list2, 0) == obj);
223               ASSERT (gl_list_get_at (list3, 0) == obj);
224             }
225             break;
226           case 4: /* add 1 element */
227             {
228               const char *obj = RANDOM_OBJECT ();
229               gl_list_node_t node1, node2, node3;
230               node1 = gl_list_add_last (list1, obj);
231               node2 = gl_list_add_last (list2, obj);
232               node3 = gl_list_add_last (list3, obj);
233               ASSERT (gl_list_node_value (list1, node1) == obj);
234               ASSERT (gl_list_node_value (list2, node2) == obj);
235               ASSERT (gl_list_node_value (list3, node3) == obj);
236               ASSERT (gl_list_get_at (list1, gl_list_size (list1) - 1) == obj);
237               ASSERT (gl_list_get_at (list2, gl_list_size (list2) - 1) == obj);
238               ASSERT (gl_list_get_at (list3, gl_list_size (list3) - 1) == obj);
239             }
240             break;
241           case 5: /* add 3 elements */
242             {
243               const char *obj0 = RANDOM_OBJECT ();
244               const char *obj1 = RANDOM_OBJECT ();
245               const char *obj2 = RANDOM_OBJECT ();
246               gl_list_node_t node1, node2, node3;
247               node1 = gl_list_add_first (list1, obj2);
248               node1 = gl_list_add_before (list1, node1, obj0);
249               node1 = gl_list_add_after (list1, node1, obj1);
250               node2 = gl_list_add_first (list2, obj2);
251               node2 = gl_list_add_before (list2, node2, obj0);
252               node2 = gl_list_add_after (list2, node2, obj1);
253               node3 = gl_list_add_first (list3, obj2);
254               node3 = gl_list_add_before (list3, node3, obj0);
255               node3 = gl_list_add_after (list3, node3, obj1);
256               ASSERT (gl_list_node_value (list1, node1) == obj1);
257               ASSERT (gl_list_node_value (list2, node2) == obj1);
258               ASSERT (gl_list_node_value (list3, node3) == obj1);
259               ASSERT (gl_list_get_at (list1, 0) == obj0);
260               ASSERT (gl_list_get_at (list1, 1) == obj1);
261               ASSERT (gl_list_get_at (list1, 2) == obj2);
262               ASSERT (gl_list_get_at (list2, 0) == obj0);
263               ASSERT (gl_list_get_at (list2, 1) == obj1);
264               ASSERT (gl_list_get_at (list2, 2) == obj2);
265               ASSERT (gl_list_get_at (list3, 0) == obj0);
266               ASSERT (gl_list_get_at (list3, 1) == obj1);
267               ASSERT (gl_list_get_at (list3, 2) == obj2);
268             }
269             break;
270           case 6: /* add 1 element */
271             {
272               size_t index = RANDOM (gl_list_size (list1) + 1);
273               const char *obj = RANDOM_OBJECT ();
274               gl_list_node_t node1, node2, node3;
275               node1 = gl_list_add_at (list1, index, obj);
276               node2 = gl_list_add_at (list2, index, obj);
277               node3 = gl_list_add_at (list3, index, obj);
278               ASSERT (gl_list_get_at (list1, index) == obj);
279               ASSERT (gl_list_node_value (list1, node1) == obj);
280               ASSERT (gl_list_get_at (list2, index) == obj);
281               ASSERT (gl_list_node_value (list2, node2) == obj);
282               ASSERT (gl_list_get_at (list3, index) == obj);
283               ASSERT (gl_list_node_value (list3, node3) == obj);
284               if (index > 0)
285                 {
286                   ASSERT (gl_list_node_value (list1, gl_list_previous_node (list1, node1))
287                           == gl_list_get_at (list1, index - 1));
288                   ASSERT (gl_list_node_value (list2, gl_list_previous_node (list3, node3))
289                           == gl_list_get_at (list2, index - 1));
290                   ASSERT (gl_list_node_value (list3, gl_list_previous_node (list3, node3))
291                           == gl_list_get_at (list2, index - 1));
292                 }
293               if (index + 1 < gl_list_size (list1))
294                 {
295                   ASSERT (gl_list_node_value (list1, gl_list_next_node (list1, node1))
296                           == gl_list_get_at (list1, index + 1));
297                   ASSERT (gl_list_node_value (list2, gl_list_next_node (list3, node3))
298                           == gl_list_get_at (list2, index + 1));
299                   ASSERT (gl_list_node_value (list3, gl_list_next_node (list3, node3))
300                           == gl_list_get_at (list2, index + 1));
301                 }
302             }
303             break;
304           case 7: case 8: /* remove 1 element */
305             if (gl_list_size (list1) > 0)
306               {
307                 size_t n = gl_list_size (list1);
308                 const char *obj = gl_list_get_at (list1, RANDOM (n));
309                 gl_list_node_t node1, node2, node3;
310                 node1 = gl_list_search (list1, obj);
311                 node2 = gl_list_search (list2, obj);
312                 node3 = gl_list_search (list3, obj);
313                 ASSERT (node1 != NULL);
314                 ASSERT (node2 != NULL);
315                 ASSERT (node3 != NULL);
316                 ASSERT (gl_list_remove_node (list1, node1));
317                 ASSERT (gl_list_remove_node (list2, node2));
318                 ASSERT (gl_list_remove_node (list3, node3));
319                 ASSERT (gl_list_size (list1) == n - 1);
320               }
321             break;
322           case 9: case 10: /* remove 1 element */
323             if (gl_list_size (list1) > 0)
324               {
325                 size_t n = gl_list_size (list1);
326                 size_t index = RANDOM (n);
327                 ASSERT (gl_list_remove_at (list1, index));
328                 ASSERT (gl_list_remove_at (list2, index));
329                 ASSERT (gl_list_remove_at (list3, index));
330                 ASSERT (gl_list_size (list1) == n - 1);
331               }
332             break;
333           case 11: case 12: /* remove 1 element */
334             if (gl_list_size (list1) > 0)
335               {
336                 size_t n = gl_list_size (list1);
337                 const char *obj = gl_list_get_at (list1, RANDOM (n));
338                 ASSERT (gl_list_remove (list1, obj));
339                 ASSERT (gl_list_remove (list2, obj));
340                 ASSERT (gl_list_remove (list3, obj));
341                 ASSERT (gl_list_size (list1) == n - 1);
342               }
343             break;
344           case 13:
345             if (gl_list_size (list1) > 0)
346               {
347                 size_t n = gl_list_size (list1);
348                 const char *obj = "xyzzy";
349                 ASSERT (!gl_list_remove (list1, obj));
350                 ASSERT (!gl_list_remove (list2, obj));
351                 ASSERT (!gl_list_remove (list3, obj));
352                 ASSERT (gl_list_size (list1) == n);
353               }
354             break;
355           case 14:
356             {
357               size_t n = gl_list_size (list1);
358               gl_list_iterator_t iter1, iter2, iter3;
359               const void *elt;
360               iter1 = gl_list_iterator (list1);
361               iter2 = gl_list_iterator (list2);
362               iter3 = gl_list_iterator (list3);
363               for (i = 0; i < n; i++)
364                 {
365                   ASSERT (gl_list_iterator_next (&iter1, &elt, NULL));
366                   ASSERT (gl_list_get_at (list1, i) == elt);
367                   ASSERT (gl_list_iterator_next (&iter2, &elt, NULL));
368                   ASSERT (gl_list_get_at (list2, i) == elt);
369                   ASSERT (gl_list_iterator_next (&iter3, &elt, NULL));
370                   ASSERT (gl_list_get_at (list3, i) == elt);
371                 }
372               ASSERT (!gl_list_iterator_next (&iter1, &elt, NULL));
373               ASSERT (!gl_list_iterator_next (&iter2, &elt, NULL));
374               ASSERT (!gl_list_iterator_next (&iter3, &elt, NULL));
375               gl_list_iterator_free (&iter1);
376               gl_list_iterator_free (&iter2);
377               gl_list_iterator_free (&iter3);
378             }
379             break;
380           case 15:
381             {
382               size_t end = RANDOM (gl_list_size (list1) + 1);
383               size_t start = RANDOM (end + 1);
384               gl_list_iterator_t iter1, iter2, iter3;
385               const void *elt;
386               iter1 = gl_list_iterator_from_to (list1, start, end);
387               iter2 = gl_list_iterator_from_to (list2, start, end);
388               iter3 = gl_list_iterator_from_to (list3, start, end);
389               for (i = start; i < end; i++)
390                 {
391                   ASSERT (gl_list_iterator_next (&iter1, &elt, NULL));
392                   ASSERT (gl_list_get_at (list1, i) == elt);
393                   ASSERT (gl_list_iterator_next (&iter2, &elt, NULL));
394                   ASSERT (gl_list_get_at (list2, i) == elt);
395                   ASSERT (gl_list_iterator_next (&iter3, &elt, NULL));
396                   ASSERT (gl_list_get_at (list3, i) == elt);
397                 }
398               ASSERT (!gl_list_iterator_next (&iter1, &elt, NULL));
399               ASSERT (!gl_list_iterator_next (&iter2, &elt, NULL));
400               ASSERT (!gl_list_iterator_next (&iter3, &elt, NULL));
401               gl_list_iterator_free (&iter1);
402               gl_list_iterator_free (&iter2);
403               gl_list_iterator_free (&iter3);
404             }
405             break;
406           }
407         check_all (list1, list2, list3);
408       }
409
410     gl_list_free (list1);
411     gl_list_free (list2);
412     gl_list_free (list3);
413     free (contents);
414   }
415
416   return 0;
417 }