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