Home | History | Annotate | Download | only in dbus
      1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
      2 /* dbus-list.c Generic linked list utility (internal to D-Bus implementation)
      3  *
      4  * Copyright (C) 2002  Red Hat, Inc.
      5  *
      6  * Licensed under the Academic Free License version 2.1
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License as published by
     10  * the Free Software Foundation; either version 2 of the License, or
     11  * (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     21  *
     22  */
     23 
     24 #include <config.h>
     25 #include "dbus-internals.h"
     26 #include "dbus-list.h"
     27 #include "dbus-mempool.h"
     28 #include "dbus-threads-internal.h"
     29 
     30 /**
     31  * @defgroup DBusList Linked list
     32  * @ingroup  DBusInternals
     33  * @brief DBusList data structure
     34  *
     35  * Types and functions related to DBusList.
     36  */
     37 
     38 static DBusMemPool *list_pool;
     39 _DBUS_DEFINE_GLOBAL_LOCK (list);
     40 
     41 /**
     42  * @defgroup DBusListInternals Linked list implementation details
     43  * @ingroup  DBusInternals
     44  * @brief DBusList implementation details
     45  *
     46  * The guts of DBusList.
     47  *
     48  * @{
     49  */
     50 
     51 /* the mem pool is probably a speed hit, with the thread
     52  * lock, though it does still save memory - unknown.
     53  */
     54 static DBusList*
     55 alloc_link (void *data)
     56 {
     57   DBusList *link;
     58 
     59   _DBUS_LOCK (list);
     60 
     61   if (list_pool == NULL)
     62     {
     63       list_pool = _dbus_mem_pool_new (sizeof (DBusList), TRUE);
     64 
     65       if (list_pool == NULL)
     66         {
     67           _DBUS_UNLOCK (list);
     68           return NULL;
     69         }
     70 
     71       link = _dbus_mem_pool_alloc (list_pool);
     72       if (link == NULL)
     73         {
     74           _dbus_mem_pool_free (list_pool);
     75           list_pool = NULL;
     76           _DBUS_UNLOCK (list);
     77           return NULL;
     78         }
     79     }
     80   else
     81     {
     82       link = _dbus_mem_pool_alloc (list_pool);
     83     }
     84 
     85   if (link)
     86     link->data = data;
     87 
     88   _DBUS_UNLOCK (list);
     89 
     90   return link;
     91 }
     92 
     93 static void
     94 free_link (DBusList *link)
     95 {
     96   _DBUS_LOCK (list);
     97   if (_dbus_mem_pool_dealloc (list_pool, link))
     98     {
     99       _dbus_mem_pool_free (list_pool);
    100       list_pool = NULL;
    101     }
    102 
    103   _DBUS_UNLOCK (list);
    104 }
    105 
    106 static void
    107 link_before (DBusList **list,
    108              DBusList  *before_this_link,
    109              DBusList  *link)
    110 {
    111   if (*list == NULL)
    112     {
    113       link->prev = link;
    114       link->next = link;
    115       *list = link;
    116     }
    117   else
    118     {
    119       link->next = before_this_link;
    120       link->prev = before_this_link->prev;
    121       before_this_link->prev = link;
    122       link->prev->next = link;
    123 
    124       if (before_this_link == *list)
    125         *list = link;
    126     }
    127 }
    128 
    129 static void
    130 link_after (DBusList **list,
    131             DBusList  *after_this_link,
    132             DBusList  *link)
    133 {
    134   if (*list == NULL)
    135     {
    136       link->prev = link;
    137       link->next = link;
    138       *list = link;
    139     }
    140   else
    141     {
    142       link->prev = after_this_link;
    143       link->next = after_this_link->next;
    144       after_this_link->next = link;
    145       link->next->prev = link;
    146     }
    147 }
    148 
    149 /** @} */
    150 
    151 /**
    152  * @addtogroup DBusList
    153  * @{
    154  */
    155 
    156 /**
    157  * @struct DBusList
    158  *
    159  * A node in a linked list.
    160  *
    161  * DBusList is a circular list; that is, the tail of the list
    162  * points back to the head of the list. The empty list is
    163  * represented by a #NULL pointer.
    164  */
    165 
    166 /**
    167  * @def _dbus_list_get_next_link
    168  *
    169  * Gets the next link in the list, or #NULL if
    170  * there are no more links. Used for iteration.
    171  *
    172  * @code
    173  * DBusList *link;
    174  * link = _dbus_list_get_first_link (&list);
    175  * while (link != NULL)
    176  *   {
    177  *     printf ("value is %p\n", link->data);
    178  *     link = _dbus_list_get_next_link (&link);
    179  *   }
    180  * @endcode
    181  *
    182  * @param list address of the list head.
    183  * @param link current link.
    184  * @returns the next link, or %NULL if none.
    185  *
    186  */
    187 
    188 /**
    189  * @def _dbus_list_get_prev_link
    190  *
    191  * Gets the previous link in the list, or #NULL if
    192  * there are no more links. Used for iteration.
    193  *
    194  * @code
    195  * DBusList *link;
    196  * link = _dbus_list_get_last_link (&list);
    197  * while (link != NULL)
    198  *   {
    199  *     printf ("value is %p\n", link->data);
    200  *     link = _dbus_list_get_prev_link (&link);
    201  *   }
    202  * @endcode
    203  *
    204  * @param list address of the list head.
    205  * @param link current link.
    206  * @returns the previous link, or %NULL if none.
    207  *
    208  */
    209 
    210 /**
    211  * Allocates a linked list node. Useful for preallocating
    212  * nodes and using _dbus_list_append_link() to avoid
    213  * allocations.
    214  *
    215  * @param data the value to store in the link.
    216  * @returns a newly allocated link.
    217  */
    218 DBusList*
    219 _dbus_list_alloc_link (void *data)
    220 {
    221   return alloc_link (data);
    222 }
    223 
    224 /**
    225  * Frees a linked list node allocated with _dbus_list_alloc_link.
    226  * Does not free the data in the node.
    227  *
    228  * @param link the list node
    229  */
    230 void
    231 _dbus_list_free_link (DBusList *link)
    232 {
    233   free_link (link);
    234 }
    235 
    236 
    237 /**
    238  * Appends a value to the list. May return #FALSE
    239  * if insufficient memory exists to add a list link.
    240  * This is a constant-time operation.
    241  *
    242  * @param list address of the list head.
    243  * @param data the value to append.
    244  * @returns #TRUE on success.
    245  */
    246 dbus_bool_t
    247 _dbus_list_append (DBusList **list,
    248                    void      *data)
    249 {
    250   if (!_dbus_list_prepend (list, data))
    251     return FALSE;
    252 
    253   /* Now cycle the list forward one so the prepended node is the tail */
    254   *list = (*list)->next;
    255 
    256   return TRUE;
    257 }
    258 
    259 /**
    260  * Prepends a value to the list. May return #FALSE
    261  * if insufficient memory exists to add a list link.
    262  * This is a constant-time operation.
    263  *
    264  * @param list address of the list head.
    265  * @param data the value to prepend.
    266  * @returns #TRUE on success.
    267  */
    268 dbus_bool_t
    269 _dbus_list_prepend (DBusList **list,
    270                     void      *data)
    271 {
    272   DBusList *link;
    273 
    274   link = alloc_link (data);
    275   if (link == NULL)
    276     return FALSE;
    277 
    278   link_before (list, *list, link);
    279 
    280   return TRUE;
    281 }
    282 
    283 /**
    284  * Appends a link to the list.
    285  * Cannot fail due to out of memory.
    286  * This is a constant-time operation.
    287  *
    288  * @param list address of the list head.
    289  * @param link the link to append.
    290  */
    291 void
    292 _dbus_list_append_link (DBusList **list,
    293 			DBusList *link)
    294 {
    295   _dbus_list_prepend_link (list, link);
    296 
    297   /* Now cycle the list forward one so the prepended node is the tail */
    298   *list = (*list)->next;
    299 }
    300 
    301 /**
    302  * Prepends a link to the list.
    303  * Cannot fail due to out of memory.
    304  * This is a constant-time operation.
    305  *
    306  * @param list address of the list head.
    307  * @param link the link to prepend.
    308  */
    309 void
    310 _dbus_list_prepend_link (DBusList **list,
    311 			 DBusList *link)
    312 {
    313   link_before (list, *list, link);
    314 }
    315 
    316 #ifdef DBUS_BUILD_TESTS
    317 /**
    318  * Inserts data into the list before the given existing link.
    319  *
    320  * @param list the list to modify
    321  * @param before_this_link existing link to insert before, or #NULL to append
    322  * @param data the value to insert
    323  * @returns #TRUE on success, #FALSE if memory allocation fails
    324  */
    325 dbus_bool_t
    326 _dbus_list_insert_before (DBusList **list,
    327                           DBusList  *before_this_link,
    328                           void      *data)
    329 {
    330   DBusList *link;
    331 
    332   if (before_this_link == NULL)
    333     return _dbus_list_append (list, data);
    334   else
    335     {
    336       link = alloc_link (data);
    337       if (link == NULL)
    338         return FALSE;
    339 
    340       link_before (list, before_this_link, link);
    341     }
    342 
    343   return TRUE;
    344 }
    345 #endif /* DBUS_BUILD_TESTS */
    346 
    347 /**
    348  * Inserts data into the list after the given existing link.
    349  *
    350  * @param list the list to modify
    351  * @param after_this_link existing link to insert after, or #NULL to prepend
    352  * @param data the value to insert
    353  * @returns #TRUE on success, #FALSE if memory allocation fails
    354  */
    355 dbus_bool_t
    356 _dbus_list_insert_after (DBusList **list,
    357                          DBusList  *after_this_link,
    358                          void      *data)
    359 {
    360   DBusList *link;
    361 
    362   if (after_this_link == NULL)
    363     return _dbus_list_prepend (list, data);
    364   else
    365     {
    366       link = alloc_link (data);
    367       if (link == NULL)
    368         return FALSE;
    369 
    370       link_after (list, after_this_link, link);
    371     }
    372 
    373   return TRUE;
    374 }
    375 
    376 /**
    377  * Inserts a link into the list before the given existing link.
    378  *
    379  * @param list the list to modify
    380  * @param before_this_link existing link to insert before, or #NULL to append
    381  * @param link the link to insert
    382  */
    383 void
    384 _dbus_list_insert_before_link (DBusList **list,
    385                                DBusList  *before_this_link,
    386                                DBusList  *link)
    387 {
    388   if (before_this_link == NULL)
    389     _dbus_list_append_link (list, link);
    390   else
    391     link_before (list, before_this_link, link);
    392 }
    393 
    394 /**
    395  * Inserts a link into the list after the given existing link.
    396  *
    397  * @param list the list to modify
    398  * @param after_this_link existing link to insert after, or #NULL to prepend
    399  * @param link the link to insert
    400  */
    401 void
    402 _dbus_list_insert_after_link (DBusList **list,
    403                               DBusList  *after_this_link,
    404                               DBusList  *link)
    405 {
    406   if (after_this_link == NULL)
    407     _dbus_list_prepend_link (list, link);
    408   else
    409     link_after (list, after_this_link, link);
    410 }
    411 
    412 /**
    413  * Removes a value from the list. Only removes the
    414  * first value equal to the given data pointer,
    415  * even if multiple values exist which match.
    416  * This is a linear-time operation.
    417  *
    418  * @param list address of the list head.
    419  * @param data the value to remove.
    420  * @returns #TRUE if a value was found to remove.
    421  */
    422 dbus_bool_t
    423 _dbus_list_remove (DBusList **list,
    424                    void      *data)
    425 {
    426   DBusList *link;
    427 
    428   link = *list;
    429   while (link != NULL)
    430     {
    431       if (link->data == data)
    432         {
    433           _dbus_list_remove_link (list, link);
    434           return TRUE;
    435         }
    436 
    437       link = _dbus_list_get_next_link (list, link);
    438     }
    439 
    440   return FALSE;
    441 }
    442 
    443 /**
    444  * Removes a value from the list. Only removes the
    445  * last value equal to the given data pointer,
    446  * even if multiple values exist which match.
    447  * This is a linear-time operation.
    448  *
    449  * @param list address of the list head.
    450  * @param data the value to remove.
    451  * @returns #TRUE if a value was found to remove.
    452  */
    453 dbus_bool_t
    454 _dbus_list_remove_last (DBusList **list,
    455                         void      *data)
    456 {
    457   DBusList *link;
    458 
    459   link = _dbus_list_find_last (list, data);
    460   if (link)
    461     {
    462       _dbus_list_remove_link (list, link);
    463       return TRUE;
    464     }
    465   else
    466     return FALSE;
    467 }
    468 
    469 /**
    470  * Finds a value in the list. Returns the last link
    471  * with value equal to the given data pointer.
    472  * This is a linear-time operation.
    473  * Returns #NULL if no value found that matches.
    474  *
    475  * @param list address of the list head.
    476  * @param data the value to find.
    477  * @returns the link if found
    478  */
    479 DBusList*
    480 _dbus_list_find_last (DBusList **list,
    481                       void      *data)
    482 {
    483   DBusList *link;
    484 
    485   link = _dbus_list_get_last_link (list);
    486 
    487   while (link != NULL)
    488     {
    489       if (link->data == data)
    490         return link;
    491 
    492       link = _dbus_list_get_prev_link (list, link);
    493     }
    494 
    495   return NULL;
    496 }
    497 
    498 /**
    499  * Removes the given link from the list, but doesn't
    500  * free it. _dbus_list_remove_link() both removes the
    501  * link and also frees it.
    502  *
    503  * @param list the list
    504  * @param link the link in the list
    505  */
    506 void
    507 _dbus_list_unlink (DBusList **list,
    508                    DBusList  *link)
    509 {
    510   if (link->next == link)
    511     {
    512       /* one-element list */
    513       *list = NULL;
    514     }
    515   else
    516     {
    517       link->prev->next = link->next;
    518       link->next->prev = link->prev;
    519 
    520       if (*list == link)
    521         *list = link->next;
    522     }
    523 
    524   link->next = NULL;
    525   link->prev = NULL;
    526 }
    527 
    528 /**
    529  * Removes a link from the list. This is a constant-time operation.
    530  *
    531  * @param list address of the list head.
    532  * @param link the list link to remove.
    533  */
    534 void
    535 _dbus_list_remove_link (DBusList **list,
    536                         DBusList  *link)
    537 {
    538   _dbus_list_unlink (list, link);
    539   free_link (link);
    540 }
    541 
    542 /**
    543  * Frees all links in the list and sets the list head to #NULL. Does
    544  * not free the data in each link, for obvious reasons. This is a
    545  * linear-time operation.
    546  *
    547  * @param list address of the list head.
    548  */
    549 void
    550 _dbus_list_clear (DBusList **list)
    551 {
    552   DBusList *link;
    553 
    554   link = *list;
    555   while (link != NULL)
    556     {
    557       DBusList *next = _dbus_list_get_next_link (list, link);
    558 
    559       free_link (link);
    560 
    561       link = next;
    562     }
    563 
    564   *list = NULL;
    565 }
    566 
    567 /**
    568  * Gets the first link in the list.
    569  * This is a constant-time operation.
    570  *
    571  * @param list address of the list head.
    572  * @returns the first link, or #NULL for an empty list.
    573  */
    574 DBusList*
    575 _dbus_list_get_first_link (DBusList **list)
    576 {
    577   return *list;
    578 }
    579 
    580 /**
    581  * Gets the last link in the list.
    582  * This is a constant-time operation.
    583  *
    584  * @param list address of the list head.
    585  * @returns the last link, or #NULL for an empty list.
    586  */
    587 DBusList*
    588 _dbus_list_get_last_link (DBusList **list)
    589 {
    590   if (*list == NULL)
    591     return NULL;
    592   else
    593     return (*list)->prev;
    594 }
    595 
    596 /**
    597  * Gets the last data in the list.
    598  * This is a constant-time operation.
    599  *
    600  * @param list address of the list head.
    601  * @returns the last data in the list, or #NULL for an empty list.
    602  */
    603 void*
    604 _dbus_list_get_last (DBusList **list)
    605 {
    606   if (*list == NULL)
    607     return NULL;
    608   else
    609     return (*list)->prev->data;
    610 }
    611 
    612 /**
    613  * Gets the first data in the list.
    614  * This is a constant-time operation.
    615  *
    616  * @param list address of the list head.
    617  * @returns the first data in the list, or #NULL for an empty list.
    618  */
    619 void*
    620 _dbus_list_get_first (DBusList **list)
    621 {
    622   if (*list == NULL)
    623     return NULL;
    624   else
    625     return (*list)->data;
    626 }
    627 
    628 /**
    629  * Removes the first link in the list and returns it.  This is a
    630  * constant-time operation.
    631  *
    632  * @param list address of the list head.
    633  * @returns the first link in the list, or #NULL for an empty list.
    634  */
    635 DBusList*
    636 _dbus_list_pop_first_link (DBusList **list)
    637 {
    638   DBusList *link;
    639 
    640   link = _dbus_list_get_first_link (list);
    641   if (link == NULL)
    642     return NULL;
    643 
    644   _dbus_list_unlink (list, link);
    645 
    646   return link;
    647 }
    648 
    649 /**
    650  * Removes the first value in the list and returns it.  This is a
    651  * constant-time operation.
    652  *
    653  * @param list address of the list head.
    654  * @returns the first data in the list, or #NULL for an empty list.
    655  */
    656 void*
    657 _dbus_list_pop_first (DBusList **list)
    658 {
    659   DBusList *link;
    660   void *data;
    661 
    662   link = _dbus_list_get_first_link (list);
    663   if (link == NULL)
    664     return NULL;
    665 
    666   data = link->data;
    667   _dbus_list_remove_link (list, link);
    668 
    669   return data;
    670 }
    671 
    672 /**
    673  * Removes the last value in the list and returns it.  This is a
    674  * constant-time operation.
    675  *
    676  * @param list address of the list head.
    677  * @returns the last data in the list, or #NULL for an empty list.
    678  */
    679 void*
    680 _dbus_list_pop_last (DBusList **list)
    681 {
    682   DBusList *link;
    683   void *data;
    684 
    685   link = _dbus_list_get_last_link (list);
    686   if (link == NULL)
    687     return NULL;
    688 
    689   data = link->data;
    690   _dbus_list_remove_link (list, link);
    691 
    692   return data;
    693 }
    694 
    695 #ifdef DBUS_BUILD_TESTS
    696 /**
    697  * Removes the last link in the list and returns it.  This is a
    698  * constant-time operation.
    699  *
    700  * @param list address of the list head.
    701  * @returns the last link in the list, or #NULL for an empty list.
    702  */
    703 DBusList*
    704 _dbus_list_pop_last_link (DBusList **list)
    705 {
    706   DBusList *link;
    707 
    708   link = _dbus_list_get_last_link (list);
    709   if (link == NULL)
    710     return NULL;
    711 
    712   _dbus_list_unlink (list, link);
    713 
    714   return link;
    715 }
    716 #endif /* DBUS_BUILD_TESTS */
    717 
    718 /**
    719  * Copies a list. This is a linear-time operation.  If there isn't
    720  * enough memory to copy the entire list, the destination list will be
    721  * set to #NULL.
    722  *
    723  * @param list address of the head of the list to copy.
    724  * @param dest address where the copied list should be placed.
    725  * @returns #TRUE on success, #FALSE if not enough memory.
    726  */
    727 dbus_bool_t
    728 _dbus_list_copy (DBusList **list,
    729                  DBusList **dest)
    730 {
    731   DBusList *link;
    732 
    733   _dbus_assert (list != dest);
    734 
    735   *dest = NULL;
    736 
    737   link = *list;
    738   while (link != NULL)
    739     {
    740       if (!_dbus_list_append (dest, link->data))
    741         {
    742           /* free what we have so far */
    743           _dbus_list_clear (dest);
    744           return FALSE;
    745         }
    746 
    747       link = _dbus_list_get_next_link (list, link);
    748     }
    749 
    750   return TRUE;
    751 }
    752 
    753 /**
    754  * Gets the length of a list. This is a linear-time
    755  * operation.
    756  *
    757  * @param list address of the head of the list
    758  * @returns number of elements in the list.
    759  */
    760 int
    761 _dbus_list_get_length (DBusList **list)
    762 {
    763   DBusList *link;
    764   int length;
    765 
    766   length = 0;
    767 
    768   link = *list;
    769   while (link != NULL)
    770     {
    771       ++length;
    772 
    773       link = _dbus_list_get_next_link (list, link);
    774     }
    775 
    776   return length;
    777 }
    778 
    779 /**
    780  * Calls the given function for each element in the list.  The
    781  * function is passed the list element as its first argument, and the
    782  * given data as its second argument.
    783  *
    784  * @param list address of the head of the list.
    785  * @param function function to call for each element.
    786  * @param data extra data for the function.
    787  *
    788  */
    789 void
    790 _dbus_list_foreach (DBusList          **list,
    791                     DBusForeachFunction function,
    792                     void               *data)
    793 {
    794   DBusList *link;
    795 
    796   link = *list;
    797   while (link != NULL)
    798     {
    799       DBusList *next = _dbus_list_get_next_link (list, link);
    800 
    801       (* function) (link->data, data);
    802 
    803       link = next;
    804     }
    805 }
    806 
    807 /**
    808  * Check whether length is exactly one.
    809  *
    810  * @param list the list
    811  * @returns #TRUE if length is exactly one
    812  */
    813 dbus_bool_t
    814 _dbus_list_length_is_one (DBusList **list)
    815 {
    816   return (*list != NULL &&
    817           (*list)->next == *list);
    818 }
    819 
    820 /** @} */
    821 
    822 #ifdef DBUS_BUILD_TESTS
    823 #include "dbus-test.h"
    824 #include <stdio.h>
    825 
    826 static void
    827 verify_list (DBusList **list)
    828 {
    829   DBusList *link;
    830   int length;
    831 
    832   link = *list;
    833 
    834   if (link == NULL)
    835     return;
    836 
    837   if (link->next == link)
    838     {
    839       _dbus_assert (link->prev == link);
    840       _dbus_assert (*list == link);
    841       return;
    842     }
    843 
    844   length = 0;
    845   do
    846     {
    847       length += 1;
    848       _dbus_assert (link->prev->next == link);
    849       _dbus_assert (link->next->prev == link);
    850       link = link->next;
    851     }
    852   while (link != *list);
    853 
    854   _dbus_assert (length == _dbus_list_get_length (list));
    855 
    856   if (length == 1)
    857     _dbus_assert (_dbus_list_length_is_one (list));
    858   else
    859     _dbus_assert (!_dbus_list_length_is_one (list));
    860 }
    861 
    862 static dbus_bool_t
    863 is_ascending_sequence (DBusList **list)
    864 {
    865   DBusList *link;
    866   int prev;
    867 
    868   prev = _DBUS_INT_MIN;
    869 
    870   link = _dbus_list_get_first_link (list);
    871   while (link != NULL)
    872     {
    873       int v = _DBUS_POINTER_TO_INT (link->data);
    874 
    875       if (v <= prev)
    876         return FALSE;
    877 
    878       prev = v;
    879 
    880       link = _dbus_list_get_next_link (list, link);
    881     }
    882 
    883   return TRUE;
    884 }
    885 
    886 static dbus_bool_t
    887 is_descending_sequence (DBusList **list)
    888 {
    889   DBusList *link;
    890   int prev;
    891 
    892   prev = _DBUS_INT_MAX;
    893 
    894   link = _dbus_list_get_first_link (list);
    895   while (link != NULL)
    896     {
    897       int v = _DBUS_POINTER_TO_INT (link->data);
    898 
    899       if (v >= prev)
    900         return FALSE;
    901 
    902       prev = v;
    903 
    904       link = _dbus_list_get_next_link (list, link);
    905     }
    906 
    907   return TRUE;
    908 }
    909 
    910 static dbus_bool_t
    911 all_even_values (DBusList **list)
    912 {
    913   DBusList *link;
    914 
    915   link = _dbus_list_get_first_link (list);
    916   while (link != NULL)
    917     {
    918       int v = _DBUS_POINTER_TO_INT (link->data);
    919 
    920       if ((v % 2) != 0)
    921         return FALSE;
    922 
    923       link = _dbus_list_get_next_link (list, link);
    924     }
    925 
    926   return TRUE;
    927 }
    928 
    929 static dbus_bool_t
    930 all_odd_values (DBusList **list)
    931 {
    932   DBusList *link;
    933 
    934   link = _dbus_list_get_first_link (list);
    935   while (link != NULL)
    936     {
    937       int v = _DBUS_POINTER_TO_INT (link->data);
    938 
    939       if ((v % 2) == 0)
    940         return FALSE;
    941 
    942       link = _dbus_list_get_next_link (list, link);
    943     }
    944 
    945   return TRUE;
    946 }
    947 
    948 static dbus_bool_t
    949 lists_equal (DBusList **list1,
    950              DBusList **list2)
    951 {
    952   DBusList *link1;
    953   DBusList *link2;
    954 
    955   link1 = _dbus_list_get_first_link (list1);
    956   link2 = _dbus_list_get_first_link (list2);
    957   while (link1 && link2)
    958     {
    959       if (link1->data != link2->data)
    960         return FALSE;
    961 
    962       link1 = _dbus_list_get_next_link (list1, link1);
    963       link2 = _dbus_list_get_next_link (list2, link2);
    964     }
    965 
    966   if (link1 || link2)
    967     return FALSE;
    968 
    969   return TRUE;
    970 }
    971 
    972 /**
    973  * @ingroup DBusListInternals
    974  * Unit test for DBusList
    975  * @returns #TRUE on success.
    976  */
    977 dbus_bool_t
    978 _dbus_list_test (void)
    979 {
    980   DBusList *list1;
    981   DBusList *list2;
    982   DBusList *link1;
    983   DBusList *link2;
    984   DBusList *copy1;
    985   DBusList *copy2;
    986   int i;
    987 
    988   list1 = NULL;
    989   list2 = NULL;
    990 
    991   /* Test append and prepend */
    992 
    993   i = 0;
    994   while (i < 10)
    995     {
    996       if (!_dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)))
    997         _dbus_assert_not_reached ("could not allocate for append");
    998 
    999       if (!_dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)))
   1000         _dbus_assert_not_reached ("count not allocate for prepend");
   1001       ++i;
   1002 
   1003       verify_list (&list1);
   1004       verify_list (&list2);
   1005 
   1006       _dbus_assert (_dbus_list_get_length (&list1) == i);
   1007       _dbus_assert (_dbus_list_get_length (&list2) == i);
   1008     }
   1009 
   1010   _dbus_assert (is_ascending_sequence (&list1));
   1011   _dbus_assert (is_descending_sequence (&list2));
   1012 
   1013   /* Test list clear */
   1014   _dbus_list_clear (&list1);
   1015   _dbus_list_clear (&list2);
   1016 
   1017   verify_list (&list1);
   1018   verify_list (&list2);
   1019 
   1020   /* Test get_first, get_last, pop_first, pop_last */
   1021 
   1022   i = 0;
   1023   while (i < 10)
   1024     {
   1025       _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
   1026       _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
   1027       ++i;
   1028     }
   1029 
   1030   --i;
   1031   while (i >= 0)
   1032     {
   1033       void *got_data1;
   1034       void *got_data2;
   1035 
   1036       void *data1;
   1037       void *data2;
   1038 
   1039       got_data1 = _dbus_list_get_last (&list1);
   1040       got_data2 = _dbus_list_get_first (&list2);
   1041 
   1042       data1 = _dbus_list_pop_last (&list1);
   1043       data2 = _dbus_list_pop_first (&list2);
   1044 
   1045       _dbus_assert (got_data1 == data1);
   1046       _dbus_assert (got_data2 == data2);
   1047 
   1048       _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i);
   1049       _dbus_assert (_DBUS_POINTER_TO_INT (data2) == i);
   1050 
   1051       verify_list (&list1);
   1052       verify_list (&list2);
   1053 
   1054       _dbus_assert (is_ascending_sequence (&list1));
   1055       _dbus_assert (is_descending_sequence (&list2));
   1056 
   1057       --i;
   1058     }
   1059 
   1060   _dbus_assert (list1 == NULL);
   1061   _dbus_assert (list2 == NULL);
   1062 
   1063   /* Test get_first_link, get_last_link, pop_first_link, pop_last_link */
   1064 
   1065   i = 0;
   1066   while (i < 10)
   1067     {
   1068       _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
   1069       _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
   1070       ++i;
   1071     }
   1072 
   1073   --i;
   1074   while (i >= 0)
   1075     {
   1076       DBusList *got_link1;
   1077       DBusList *got_link2;
   1078 
   1079       DBusList *link1;
   1080       DBusList *link2;
   1081 
   1082       void *data1;
   1083       void *data2;
   1084 
   1085       got_link1 = _dbus_list_get_last_link (&list1);
   1086       got_link2 = _dbus_list_get_first_link (&list2);
   1087 
   1088       link1 = _dbus_list_pop_last_link (&list1);
   1089       link2 = _dbus_list_pop_first_link (&list2);
   1090 
   1091       _dbus_assert (got_link1 == link1);
   1092       _dbus_assert (got_link2 == link2);
   1093 
   1094       data1 = link1->data;
   1095       data2 = link2->data;
   1096 
   1097       _dbus_list_free_link (link1);
   1098       _dbus_list_free_link (link2);
   1099 
   1100       _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i);
   1101       _dbus_assert (_DBUS_POINTER_TO_INT (data2) == i);
   1102 
   1103       verify_list (&list1);
   1104       verify_list (&list2);
   1105 
   1106       _dbus_assert (is_ascending_sequence (&list1));
   1107       _dbus_assert (is_descending_sequence (&list2));
   1108 
   1109       --i;
   1110     }
   1111 
   1112   _dbus_assert (list1 == NULL);
   1113   _dbus_assert (list2 == NULL);
   1114 
   1115   /* Test iteration */
   1116 
   1117   i = 0;
   1118   while (i < 10)
   1119     {
   1120       _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
   1121       _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
   1122       ++i;
   1123 
   1124       verify_list (&list1);
   1125       verify_list (&list2);
   1126 
   1127       _dbus_assert (_dbus_list_get_length (&list1) == i);
   1128       _dbus_assert (_dbus_list_get_length (&list2) == i);
   1129     }
   1130 
   1131   _dbus_assert (is_ascending_sequence (&list1));
   1132   _dbus_assert (is_descending_sequence (&list2));
   1133 
   1134   --i;
   1135   link2 = _dbus_list_get_first_link (&list2);
   1136   while (link2 != NULL)
   1137     {
   1138       verify_list (&link2); /* pretend this link is the head */
   1139 
   1140       _dbus_assert (_DBUS_POINTER_TO_INT (link2->data) == i);
   1141 
   1142       link2 = _dbus_list_get_next_link (&list2, link2);
   1143       --i;
   1144     }
   1145 
   1146   i = 0;
   1147   link1 = _dbus_list_get_first_link (&list1);
   1148   while (link1 != NULL)
   1149     {
   1150       verify_list (&link1); /* pretend this link is the head */
   1151 
   1152       _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i);
   1153 
   1154       link1 = _dbus_list_get_next_link (&list1, link1);
   1155       ++i;
   1156     }
   1157 
   1158   --i;
   1159   link1 = _dbus_list_get_last_link (&list1);
   1160   while (link1 != NULL)
   1161     {
   1162       verify_list (&link1); /* pretend this link is the head */
   1163 
   1164       _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i);
   1165 
   1166       link1 = _dbus_list_get_prev_link (&list1, link1);
   1167       --i;
   1168     }
   1169 
   1170   _dbus_list_clear (&list1);
   1171   _dbus_list_clear (&list2);
   1172 
   1173   /* Test remove */
   1174 
   1175   i = 0;
   1176   while (i < 10)
   1177     {
   1178       _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
   1179       _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
   1180       ++i;
   1181     }
   1182 
   1183   --i;
   1184   while (i >= 0)
   1185     {
   1186       if ((i % 2) == 0)
   1187         {
   1188           if (!_dbus_list_remove (&list1, _DBUS_INT_TO_POINTER (i)))
   1189             _dbus_assert_not_reached ("element should have been in list");
   1190           if (!_dbus_list_remove (&list2, _DBUS_INT_TO_POINTER (i)))
   1191             _dbus_assert_not_reached ("element should have been in list");
   1192 
   1193           verify_list (&list1);
   1194           verify_list (&list2);
   1195         }
   1196       --i;
   1197     }
   1198 
   1199   _dbus_assert (all_odd_values (&list1));
   1200   _dbus_assert (all_odd_values (&list2));
   1201 
   1202   _dbus_list_clear (&list1);
   1203   _dbus_list_clear (&list2);
   1204 
   1205   /* test removing the other half of the elements */
   1206 
   1207   i = 0;
   1208   while (i < 10)
   1209     {
   1210       _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
   1211       _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
   1212       ++i;
   1213     }
   1214 
   1215   --i;
   1216   while (i >= 0)
   1217     {
   1218       if ((i % 2) != 0)
   1219         {
   1220           if (!_dbus_list_remove (&list1, _DBUS_INT_TO_POINTER (i)))
   1221             _dbus_assert_not_reached ("element should have been in list");
   1222           if (!_dbus_list_remove (&list2, _DBUS_INT_TO_POINTER (i)))
   1223             _dbus_assert_not_reached ("element should have been in list");
   1224 
   1225           verify_list (&list1);
   1226           verify_list (&list2);
   1227         }
   1228       --i;
   1229     }
   1230 
   1231   _dbus_assert (all_even_values (&list1));
   1232   _dbus_assert (all_even_values (&list2));
   1233 
   1234   /* clear list using remove_link */
   1235   while (list1 != NULL)
   1236     {
   1237       _dbus_list_remove_link (&list1, list1);
   1238       verify_list (&list1);
   1239     }
   1240   while (list2 != NULL)
   1241     {
   1242       _dbus_list_remove_link (&list2, list2);
   1243       verify_list (&list2);
   1244     }
   1245 
   1246   /* Test remove link more generally */
   1247   i = 0;
   1248   while (i < 10)
   1249     {
   1250       _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
   1251       _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
   1252       ++i;
   1253     }
   1254 
   1255   --i;
   1256   link2 = _dbus_list_get_first_link (&list2);
   1257   while (link2 != NULL)
   1258     {
   1259       DBusList *next = _dbus_list_get_next_link (&list2, link2);
   1260 
   1261       _dbus_assert (_DBUS_POINTER_TO_INT (link2->data) == i);
   1262 
   1263       if ((i % 2) == 0)
   1264         _dbus_list_remove_link (&list2, link2);
   1265 
   1266       verify_list (&list2);
   1267 
   1268       link2 = next;
   1269       --i;
   1270     }
   1271 
   1272   _dbus_assert (all_odd_values (&list2));
   1273   _dbus_list_clear (&list2);
   1274 
   1275   i = 0;
   1276   link1 = _dbus_list_get_first_link (&list1);
   1277   while (link1 != NULL)
   1278     {
   1279       DBusList *next = _dbus_list_get_next_link (&list1, link1);
   1280 
   1281       _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i);
   1282 
   1283       if ((i % 2) != 0)
   1284         _dbus_list_remove_link (&list1, link1);
   1285 
   1286       verify_list (&list1);
   1287 
   1288       link1 = next;
   1289       ++i;
   1290     }
   1291 
   1292   _dbus_assert (all_even_values (&list1));
   1293   _dbus_list_clear (&list1);
   1294 
   1295   /* Test copying a list */
   1296   i = 0;
   1297   while (i < 10)
   1298     {
   1299       _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
   1300       _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
   1301       ++i;
   1302     }
   1303 
   1304   /* bad pointers, because they are allowed in the copy dest */
   1305   copy1 = _DBUS_INT_TO_POINTER (0x342234);
   1306   copy2 = _DBUS_INT_TO_POINTER (23);
   1307 
   1308   _dbus_list_copy (&list1, &copy1);
   1309   verify_list (&list1);
   1310   verify_list (&copy1);
   1311   _dbus_assert (lists_equal (&list1, &copy1));
   1312 
   1313   _dbus_list_copy (&list2, &copy2);
   1314   verify_list (&list2);
   1315   verify_list (&copy2);
   1316   _dbus_assert (lists_equal (&list2, &copy2));
   1317 
   1318   /* Now test copying empty lists */
   1319   _dbus_list_clear (&list1);
   1320   _dbus_list_clear (&list2);
   1321   _dbus_list_clear (&copy1);
   1322   _dbus_list_clear (&copy2);
   1323 
   1324   /* bad pointers, because they are allowed in the copy dest */
   1325   copy1 = _DBUS_INT_TO_POINTER (0x342234);
   1326   copy2 = _DBUS_INT_TO_POINTER (23);
   1327 
   1328   _dbus_list_copy (&list1, &copy1);
   1329   verify_list (&list1);
   1330   verify_list (&copy1);
   1331   _dbus_assert (lists_equal (&list1, &copy1));
   1332 
   1333   _dbus_list_copy (&list2, &copy2);
   1334   verify_list (&list2);
   1335   verify_list (&copy2);
   1336   _dbus_assert (lists_equal (&list2, &copy2));
   1337 
   1338   _dbus_list_clear (&list1);
   1339   _dbus_list_clear (&list2);
   1340 
   1341   /* insert_before on empty list */
   1342   _dbus_list_insert_before (&list1, NULL,
   1343                             _DBUS_INT_TO_POINTER (0));
   1344   verify_list (&list1);
   1345 
   1346   /* inserting before first element */
   1347   _dbus_list_insert_before (&list1, list1,
   1348                             _DBUS_INT_TO_POINTER (2));
   1349   verify_list (&list1);
   1350   _dbus_assert (is_descending_sequence (&list1));
   1351 
   1352   /* inserting in the middle */
   1353   _dbus_list_insert_before (&list1, list1->next,
   1354                             _DBUS_INT_TO_POINTER (1));
   1355   verify_list (&list1);
   1356   _dbus_assert (is_descending_sequence (&list1));
   1357 
   1358   /* using insert_before to append */
   1359   _dbus_list_insert_before (&list1, NULL,
   1360                             _DBUS_INT_TO_POINTER (-1));
   1361   verify_list (&list1);
   1362   _dbus_assert (is_descending_sequence (&list1));
   1363 
   1364   _dbus_list_clear (&list1);
   1365 
   1366   /* insert_after on empty list */
   1367   _dbus_list_insert_after (&list1, NULL,
   1368                            _DBUS_INT_TO_POINTER (0));
   1369   verify_list (&list1);
   1370 
   1371   /* inserting after first element */
   1372   _dbus_list_insert_after (&list1, list1,
   1373                            _DBUS_INT_TO_POINTER (1));
   1374   verify_list (&list1);
   1375   _dbus_assert (is_ascending_sequence (&list1));
   1376 
   1377   /* inserting at the end */
   1378   _dbus_list_insert_after (&list1, list1->next,
   1379                            _DBUS_INT_TO_POINTER (2));
   1380   verify_list (&list1);
   1381   _dbus_assert (is_ascending_sequence (&list1));
   1382 
   1383   /* using insert_after to prepend */
   1384   _dbus_list_insert_after (&list1, NULL,
   1385                            _DBUS_INT_TO_POINTER (-1));
   1386   verify_list (&list1);
   1387   _dbus_assert (is_ascending_sequence (&list1));
   1388 
   1389   _dbus_list_clear (&list1);
   1390 
   1391   /* using remove_last */
   1392   _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (2));
   1393   _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (1));
   1394   _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (3));
   1395 
   1396   _dbus_list_remove_last (&list1, _DBUS_INT_TO_POINTER (2));
   1397 
   1398   verify_list (&list1);
   1399   _dbus_assert (is_ascending_sequence (&list1));
   1400 
   1401   _dbus_list_clear (&list1);
   1402 
   1403   return TRUE;
   1404 }
   1405 
   1406 #endif
   1407