root/maint/gnulib/tests/test-rbtreehash_list.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. string_equals
  2. string_hash
  3. check_equals
  4. check_equals_by_forward_iteration
  5. check_equals_by_backward_iteration
  6. check_all
  7. main

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

/* [previous][next][first][last][top][bottom][index][help] */