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