root/opal/mca/pmix/pmix4x/pmix/src/class/pmix_list.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. pmix_list_is_empty
  2. pmix_list_get_first
  3. pmix_list_get_last
  4. pmix_list_get_begin
  5. pmix_list_get_end
  6. pmix_list_get_size
  7. _pmix_list_append
  8. pmix_list_prepend
  9. pmix_list_remove_first
  10. pmix_list_remove_last
  11. pmix_list_insert_pos

   1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
   2  /*
   3  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   4  *                         University Research and Technology
   5  *                         Corporation.  All rights reserved.
   6  * Copyright (c) 2004-2006 The University of Tennessee and The University
   7  *                         of Tennessee Research Foundation.  All rights
   8  *                         reserved.
   9  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
  10  *                         University of Stuttgart.  All rights reserved.
  11  * Copyright (c) 2004-2005 The Regents of the University of California.
  12  *                         All rights reserved.
  13  * Copyright (c) 2007      Voltaire All rights reserved.
  14  * Copyright (c) 2013      Los Alamos National Security, LLC. All rights
  15  *                         reserved.
  16  * Copyright (c) 2013-2018 Intel, Inc.  All rights reserved.
  17  * $COPYRIGHT$
  18  *
  19  * Additional copyrights may follow
  20  *
  21  * $HEADER$
  22  */
  23 /**
  24  * @file
  25  *
  26  * The pmix_list_t interface is used to provide a generic
  27  * doubly-linked list container for PMIx.  It was inspired by (but
  28  * is slightly different than) the Standard Template Library (STL)
  29  * std::list class.  One notable difference from std::list is that
  30  * when an pmix_list_t is destroyed, all of the pmix_list_item_t
  31  * objects that it contains are orphaned -- they are \em not
  32  * destroyed.
  33  *
  34  * The general idea is that pmix_list_item_t objects can be put on an
  35  * pmix_list_t.  Hence, you create a new type that derives from
  36  * pmix_list_item_t; this new type can then be used with pmix_list_t
  37  * containers.
  38  *
  39  * NOTE: pmix_list_item_t instances can only be on \em one list at a
  40  * time.  Specifically, if you add an pmix_list_item_t to one list,
  41  * and then add it to another list (without first removing it from the
  42  * first list), you will effectively be hosing the first list.  You
  43  * have been warned.
  44  *
  45  * If PMIX_ENABLE_DEBUG is true, a bunch of checks occur, including
  46  * some spot checks for a debugging reference count in an attempt to
  47  * ensure that an pmix_list_item_t is only one *one* list at a time.
  48  * Given the highly concurrent nature of this class, these spot checks
  49  * cannot guarantee that an item is only one list at a time.
  50  * Specifically, since it is a desirable attribute of this class to
  51  * not use locks for normal operations, it is possible that two
  52  * threads may [erroneously] modify an pmix_list_item_t concurrently.
  53  *
  54  * The only way to guarantee that a debugging reference count is valid
  55  * for the duration of an operation is to lock the item_t during the
  56  * operation.  But this fundamentally changes the desirable attribute
  57  * of this class (i.e., no locks).  So all we can do is spot-check the
  58  * reference count in a bunch of places and check that it is still the
  59  * value that we think it should be.  But this doesn't mean that you
  60  * can run into "unlucky" cases where two threads are concurrently
  61  * modifying an item_t, but all the spot checks still return the
  62  * "right" values.  All we can do is hope that we have enough spot
  63  * checks to statistically drive down the possibility of the unlucky
  64  * cases happening.
  65  */
  66 
  67 #ifndef PMIX_LIST_H
  68 #define PMIX_LIST_H
  69 
  70 #include <src/include/pmix_config.h>
  71 #include <stdio.h>
  72 #include <stdlib.h>
  73 #if HAVE_STDBOOL_H
  74 #include <stdbool.h>
  75 #endif
  76 
  77 #include "src/class/pmix_object.h"
  78 
  79 BEGIN_C_DECLS
  80 
  81 /**
  82  * \internal
  83  *
  84  * The class for the list container.
  85  */
  86 PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_list_t);
  87 /**
  88  * \internal
  89  *
  90  * Base class for items that are put in list (pmix_list_t) containers.
  91  */
  92 PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_list_item_t);
  93 
  94 
  95 /**
  96  * \internal
  97  *
  98  * Struct of an pmix_list_item_t
  99  */
 100 struct pmix_list_item_t
 101 {
 102     pmix_object_t super;
 103     /**< Generic parent class for all PMIx objects */
 104     volatile struct pmix_list_item_t *pmix_list_next;
 105     /**< Pointer to next list item */
 106     volatile struct pmix_list_item_t *pmix_list_prev;
 107     /**< Pointer to previous list item */
 108     int32_t item_free;
 109 
 110 #if PMIX_ENABLE_DEBUG
 111     /** Atomic reference count for debugging */
 112     pmix_atomic_int32_t pmix_list_item_refcount;
 113     /** The list this item belong to */
 114     volatile struct pmix_list_t* pmix_list_item_belong_to;
 115 #endif
 116 };
 117 /**
 118  * Base type for items that are put in a list (pmix_list_t) containers.
 119  */
 120 typedef struct pmix_list_item_t pmix_list_item_t;
 121 
 122 
 123 /**
 124  * Get the next item in a list.
 125  *
 126  * @param item A list item.
 127  *
 128  * @returns The next item in the list
 129  */
 130 #define pmix_list_get_next(item) \
 131     ((item) ? ((pmix_list_item_t*) ((pmix_list_item_t*)(item))->pmix_list_next) : NULL)
 132 
 133 /**
 134  * Get the next item in a list.
 135  *
 136  * @param item A list item.
 137  *
 138  * @returns The next item in the list
 139  */
 140 #define pmix_list_get_prev(item) \
 141     ((item) ? ((pmix_list_item_t*) ((pmix_list_item_t*)(item))->pmix_list_prev) : NULL)
 142 
 143 
 144 /**
 145  * \internal
 146  *
 147  * Struct of an pmix_list_t
 148  */
 149 struct pmix_list_t
 150 {
 151     pmix_object_t       super;
 152     /**< Generic parent class for all PMIx objects */
 153     pmix_list_item_t    pmix_list_sentinel;
 154     /**< Head and tail item of the list */
 155     volatile size_t     pmix_list_length;
 156     /**< Quick reference to the number of items in the list */
 157 };
 158 /**
 159  * List container type.
 160  */
 161 typedef struct pmix_list_t pmix_list_t;
 162 
 163 /** Cleanly destruct a list
 164  *
 165  * The pmix_list_t destructor doesn't release the items on the
 166  * list - so provide two convenience macros that do so and then
 167  * destruct/release the list object itself
 168  *
 169  * @param[in] list List to destruct or release
 170  */
 171 #define PMIX_LIST_DESTRUCT(list)                                \
 172     do {                                                        \
 173         pmix_list_item_t *it;                                   \
 174         while (NULL != (it = pmix_list_remove_first(list))) {   \
 175             PMIX_RELEASE(it);                                    \
 176         }                                                       \
 177         PMIX_DESTRUCT(list);                                     \
 178     } while (0)
 179 
 180 #define PMIX_LIST_RELEASE(list)                                 \
 181     do {                                                        \
 182         pmix_list_item_t *it;                                   \
 183         while (NULL != (it = pmix_list_remove_first(list))) {   \
 184             PMIX_RELEASE(it);                                    \
 185         }                                                       \
 186         PMIX_RELEASE(list);                                      \
 187     } while (0)
 188 
 189 
 190 /**
 191  * Loop over a list.
 192  *
 193  * @param[in] item Storage for each item
 194  * @param[in] list List to iterate over
 195  * @param[in] type Type of each list item
 196  *
 197  * This macro provides a simple way to loop over the items in an pmix_list_t. It
 198  * is not safe to call pmix_list_remove_item from within the loop.
 199  *
 200  * Example Usage:
 201  *
 202  * class_foo_t *foo;
 203  * pmix_list_foreach(foo, list, class_foo_t) {
 204  *    do something;
 205  * }
 206  */
 207 #define PMIX_LIST_FOREACH(item, list, type)                             \
 208   for (item = (type *) (list)->pmix_list_sentinel.pmix_list_next ;      \
 209        item != (type *) &(list)->pmix_list_sentinel ;                   \
 210        item = (type *) ((pmix_list_item_t *) (item))->pmix_list_next)
 211 
 212 /**
 213  * Loop over a list in reverse.
 214  *
 215  * @param[in] item Storage for each item
 216  * @param[in] list List to iterate over
 217  * @param[in] type Type of each list item
 218  *
 219  * This macro provides a simple way to loop over the items in an pmix_list_t. It
 220  * is not safe to call pmix_list_remove_item from within the loop.
 221  *
 222  * Example Usage:
 223  *
 224  * class_foo_t *foo;
 225  * pmix_list_foreach(foo, list, class_foo_t) {
 226  *    do something;
 227  * }
 228  */
 229 #define PMIX_LIST_FOREACH_REV(item, list, type)                         \
 230   for (item = (type *) (list)->pmix_list_sentinel.pmix_list_prev ;      \
 231        item != (type *) &(list)->pmix_list_sentinel ;                   \
 232        item = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev)
 233 
 234 /**
 235  * Loop over a list in a *safe* way
 236  *
 237  * @param[in] item Storage for each item
 238  * @param[in] next Storage for next item
 239  * @param[in] list List to iterate over
 240  * @param[in] type Type of each list item
 241  *
 242  * This macro provides a simple way to loop over the items in an pmix_list_t. It
 243  * is safe to call pmix_list_remove_item(list, item) from within the loop.
 244  *
 245  * Example Usage:
 246  *
 247  * class_foo_t *foo, *next;
 248  * pmix_list_foreach_safe(foo, next, list, class_foo_t) {
 249  *    do something;
 250  *    pmix_list_remove_item (list, (pmix_list_item_t *) foo);
 251  * }
 252  */
 253 #define PMIX_LIST_FOREACH_SAFE(item, next, list, type)                  \
 254   for (item = (type *) (list)->pmix_list_sentinel.pmix_list_next,       \
 255          next = (type *) ((pmix_list_item_t *) (item))->pmix_list_next ;\
 256        item != (type *) &(list)->pmix_list_sentinel ;                   \
 257        item = next, next = (type *) ((pmix_list_item_t *) (item))->pmix_list_next)
 258 
 259 /**
 260  * Loop over a list in a *safe* way
 261  *
 262  * @param[in] item Storage for each item
 263  * @param[in] next Storage for next item
 264  * @param[in] list List to iterate over
 265  * @param[in] type Type of each list item
 266  *
 267  * This macro provides a simple way to loop over the items in an pmix_list_t. If
 268  * is safe to call pmix_list_remove_item(list, item) from within the loop.
 269  *
 270  * Example Usage:
 271  *
 272  * class_foo_t *foo, *next;
 273  * pmix_list_foreach_safe(foo, next, list, class_foo_t) {
 274  *    do something;
 275  *    pmix_list_remove_item (list, (pmix_list_item_t *) foo);
 276  * }
 277  */
 278 #define PMIX_LIST_FOREACH_SAFE_REV(item, prev, list, type)              \
 279   for (item = (type *) (list)->pmix_list_sentinel.pmix_list_prev,       \
 280          prev = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev ;\
 281        item != (type *) &(list)->pmix_list_sentinel ;                   \
 282        item = prev, prev = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev)
 283 
 284 
 285 /**
 286  * Check for empty list
 287  *
 288  * @param list The list container
 289  *
 290  * @returns true if list's size is 0, false otherwise
 291  *
 292  * This is an O(1) operation.
 293  *
 294  * This is an inlined function in compilers that support inlining,
 295  * so it's usually a cheap operation.
 296  */
 297 static inline bool pmix_list_is_empty(pmix_list_t* list)
 298 {
 299     return (list->pmix_list_sentinel.pmix_list_next ==
 300         &(list->pmix_list_sentinel) ? true : false);
 301 }
 302 
 303 
 304 /**
 305  * Return the first item on the list (does not remove it).
 306  *
 307  * @param list The list container
 308  *
 309  * @returns A pointer to the first item on the list
 310  *
 311  * This is an O(1) operation to return the first item on the list.  It
 312  * should be compared against the returned value from
 313  * pmix_list_get_end() to ensure that the list is not empty.
 314  *
 315  * This is an inlined function in compilers that support inlining, so
 316  * it's usually a cheap operation.
 317  */
 318 static inline pmix_list_item_t* pmix_list_get_first(pmix_list_t* list)
 319 {
 320     pmix_list_item_t* item = (pmix_list_item_t*)list->pmix_list_sentinel.pmix_list_next;
 321 #if PMIX_ENABLE_DEBUG
 322     /* Spot check: ensure that the first item is only on one list */
 323 
 324     assert(1 == item->pmix_list_item_refcount);
 325     assert( list == item->pmix_list_item_belong_to );
 326 #endif
 327 
 328     return item;
 329 }
 330 
 331 /**
 332  * Return the last item on the list (does not remove it).
 333  *
 334  * @param list The list container
 335  *
 336  * @returns A pointer to the last item on the list
 337  *
 338  * This is an O(1) operation to return the last item on the list.  It
 339  * should be compared against the returned value from
 340  * pmix_list_get_begin() to ensure that the list is not empty.
 341  *
 342  * This is an inlined function in compilers that support inlining, so
 343  * it's usually a cheap operation.
 344  */
 345 static inline pmix_list_item_t* pmix_list_get_last(pmix_list_t* list)
 346 {
 347     pmix_list_item_t* item = (pmix_list_item_t *)list->pmix_list_sentinel.pmix_list_prev;
 348 #if PMIX_ENABLE_DEBUG
 349     /* Spot check: ensure that the last item is only on one list */
 350 
 351     assert( 1 == item->pmix_list_item_refcount );
 352     assert( list == item->pmix_list_item_belong_to );
 353 #endif
 354 
 355     return item;
 356 }
 357 
 358 /**
 359  * Return the beginning of the list; an invalid list entry suitable
 360  * for comparison only.
 361  *
 362  * @param list The list container
 363  *
 364  * @returns A pointer to the beginning of the list.
 365  *
 366  * This is an O(1) operation to return the beginning of the list.
 367  * Similar to the STL, this is a special invalid list item -- it
 368  * should \em not be used for storage.  It is only suitable for
 369  * comparison to other items in the list to see if they are valid or
 370  * not; it's ususally used when iterating through the items in a list.
 371  *
 372  * This is an inlined function in compilers that support inlining, so
 373  * it's usually a cheap operation.
 374  */
 375 static inline pmix_list_item_t* pmix_list_get_begin(pmix_list_t* list)
 376 {
 377     return &(list->pmix_list_sentinel);
 378 }
 379 
 380 /**
 381  * Return the end of the list; an invalid list entry suitable for
 382  * comparison only.
 383  *
 384  * @param list The list container
 385  *
 386  * @returns A pointer to the end of the list.
 387  *
 388  * This is an O(1) operation to return the end of the list.
 389  * Similar to the STL, this is a special invalid list item -- it
 390  * should \em not be used for storage.  It is only suitable for
 391  * comparison to other items in the list to see if they are valid or
 392  * not; it's ususally used when iterating through the items in a list.
 393  *
 394  * This is an inlined function in compilers that support inlining, so
 395  * it's usually a cheap operation.
 396  */
 397 static inline pmix_list_item_t* pmix_list_get_end(pmix_list_t* list)
 398 {
 399     return &(list->pmix_list_sentinel);
 400 }
 401 
 402 
 403 /**
 404  * Return the number of items in a list
 405  *
 406  * @param list The list container
 407  *
 408  * @returns The size of the list (size_t)
 409  *
 410  * This is an O(1) lookup to return the size of the list.
 411  *
 412  * This is an inlined function in compilers that support inlining, so
 413  * it's usually a cheap operation.
 414  *
 415  * \warning The size of the list is cached as part of the list.  In
 416  * the future, calling \c pmix_list_splice or \c pmix_list_join may
 417  * result in this function recomputing the list size, which would be
 418  * an O(N) operation.  If \c pmix_list_splice or \c pmix_list_join is
 419  * never called on the specified list, this function will always be
 420  * O(1).
 421  */
 422 static inline size_t pmix_list_get_size(pmix_list_t* list)
 423 {
 424 #if PMIX_ENABLE_DEBUG && 0
 425     /* not sure if we really want this running in devel, as it does
 426      * slow things down.  Wanted for development of splice / join to
 427      * make sure length was reset properly
 428      */
 429     size_t check_len = 0;
 430     pmix_list_item_t *item;
 431 
 432     for (item = pmix_list_get_first(list) ;
 433          item != pmix_list_get_end(list) ;
 434          item = pmix_list_get_next(item)) {
 435         check_len++;
 436     }
 437 
 438     if (check_len != list->pmix_list_length) {
 439         fprintf(stderr," Error :: pmix_list_get_size - pmix_list_length does not match actual list length\n");
 440         fflush(stderr);
 441         abort();
 442     }
 443 #endif
 444 
 445     return list->pmix_list_length;
 446 }
 447 
 448 
 449 /**
 450  * Remove an item from a list.
 451  *
 452  * @param list The list container
 453  * @param item The item to remove
 454  *
 455  * @returns A pointer to the item on the list previous to the one
 456  * that was removed.
 457  *
 458  * This is an O(1) operation to remove an item from the list.  The
 459  * forward / reverse pointers in the list are updated and the item is
 460  * removed.  The list item that is returned is now "owned" by the
 461  * caller -- they are responsible for PMIX_RELEASE()'ing it.
 462  *
 463  * If debugging is enabled (specifically, if --enable-debug was used
 464  * to configure PMIx), this is an O(N) operation because it checks
 465  * to see if the item is actually in the list first.
 466  *
 467  * This is an inlined function in compilers that support inlining, so
 468  * it's usually a cheap operation.
 469  */
 470 static inline pmix_list_item_t *pmix_list_remove_item
 471   (pmix_list_t *list, pmix_list_item_t *item)
 472 {
 473 #if PMIX_ENABLE_DEBUG
 474     pmix_list_item_t *item_ptr;
 475     bool found = false;
 476 
 477     /* check to see that the item is in the list */
 478     for (item_ptr = pmix_list_get_first(list);
 479             item_ptr != pmix_list_get_end(list);
 480             item_ptr = (pmix_list_item_t *)(item_ptr->pmix_list_next)) {
 481         if (item_ptr == (pmix_list_item_t *) item) {
 482             found = true;
 483             break;
 484         }
 485     }
 486     if (!found) {
 487         fprintf(stderr," Warning :: pmix_list_remove_item - the item %p is not on the list %p \n",(void*) item, (void*) list);
 488         fflush(stderr);
 489         return (pmix_list_item_t *)NULL;
 490     }
 491 
 492     assert( list == item->pmix_list_item_belong_to );
 493 #endif
 494 
 495     /* reset next pointer of previous element */
 496     item->pmix_list_prev->pmix_list_next=item->pmix_list_next;
 497 
 498     /* reset previous pointer of next element */
 499     item->pmix_list_next->pmix_list_prev=item->pmix_list_prev;
 500 
 501     list->pmix_list_length--;
 502 
 503 #if PMIX_ENABLE_DEBUG
 504     /* Spot check: ensure that this item is still only on one list */
 505 
 506     item->pmix_list_item_refcount -= 1;
 507     assert(0 == item->pmix_list_item_refcount);
 508     item->pmix_list_item_belong_to = NULL;
 509 #endif
 510 
 511     return (pmix_list_item_t *)item->pmix_list_prev;
 512 }
 513 
 514 
 515 /**
 516  * Append an item to the end of the list.
 517  *
 518  * @param list The list container
 519  * @param item The item to append
 520  *
 521  * This is an O(1) operation to append an item to the end of a list.
 522  * The pmix_list_item_t is not PMIX_RETAIN()'ed; it is assumed that
 523  * "ownership" of the item is passed from the caller to the list.
 524  *
 525  * This is an inlined function in compilers that support inlining, so
 526  * it's usually a cheap operation.
 527  */
 528 
 529 #if PMIX_ENABLE_DEBUG
 530 #define pmix_list_append(l,i) \
 531 _pmix_list_append(l,i,__FILE__,__LINE__)
 532 #else
 533 #define pmix_list_append(l,i) \
 534 _pmix_list_append(l,i)
 535 #endif  /* PMIX_ENABLE_DEBUG */
 536 
 537 static inline void _pmix_list_append(pmix_list_t *list, pmix_list_item_t *item
 538 #if PMIX_ENABLE_DEBUG
 539                                      , const char* FILE_NAME, int LINENO
 540 #endif  /* PMIX_ENABLE_DEBUG */
 541                                      )
 542 {
 543     pmix_list_item_t* sentinel = &(list->pmix_list_sentinel);
 544 #if PMIX_ENABLE_DEBUG
 545   /* Spot check: ensure that this item is previously on no lists */
 546 
 547   assert(0 == item->pmix_list_item_refcount);
 548   assert( NULL == item->pmix_list_item_belong_to );
 549   item->super.cls_init_file_name = FILE_NAME;
 550   item->super.cls_init_lineno    = LINENO;
 551 #endif
 552 
 553   /* set new element's previous pointer */
 554   item->pmix_list_prev = sentinel->pmix_list_prev;
 555 
 556   /* reset previous pointer on current last element */
 557   sentinel->pmix_list_prev->pmix_list_next = item;
 558 
 559   /* reset new element's next pointer */
 560   item->pmix_list_next = sentinel;
 561 
 562   /* reset the list's tail element previous pointer */
 563   sentinel->pmix_list_prev = item;
 564 
 565   /* increment list element counter */
 566   list->pmix_list_length++;
 567 
 568 #if PMIX_ENABLE_DEBUG
 569   /* Spot check: ensure this item is only on the list that we just
 570      appended it to */
 571 
 572   item->pmix_list_item_refcount += 1;
 573   assert(1 == item->pmix_list_item_refcount);
 574   item->pmix_list_item_belong_to = list;
 575 #endif
 576 }
 577 
 578 
 579 /**
 580  * Prepend an item to the beginning of the list.
 581  *
 582  * @param list The list container
 583  * @param item The item to prepend
 584  *
 585  * This is an O(1) operation to prepend an item to the beginning of a
 586  * list.  The pmix_list_item_t is not PMIX_RETAIN()'ed; it is assumed
 587  * that "ownership" of the item is passed from the caller to the list.
 588  *
 589  * This is an inlined function in compilers that support inlining, so
 590  * it's usually a cheap operation.
 591  */
 592 static inline void pmix_list_prepend(pmix_list_t *list,
 593                                      pmix_list_item_t *item)
 594 {
 595     pmix_list_item_t* sentinel = &(list->pmix_list_sentinel);
 596 #if PMIX_ENABLE_DEBUG
 597   /* Spot check: ensure that this item is previously on no lists */
 598 
 599   assert(0 == item->pmix_list_item_refcount);
 600   assert( NULL == item->pmix_list_item_belong_to );
 601 #endif
 602 
 603   /* reset item's next pointer */
 604   item->pmix_list_next = sentinel->pmix_list_next;
 605 
 606   /* reset item's previous pointer */
 607   item->pmix_list_prev = sentinel;
 608 
 609   /* reset previous first element's previous poiner */
 610   sentinel->pmix_list_next->pmix_list_prev = item;
 611 
 612   /* reset head's next pointer */
 613   sentinel->pmix_list_next = item;
 614 
 615   /* increment list element counter */
 616   list->pmix_list_length++;
 617 
 618 #if PMIX_ENABLE_DEBUG
 619   /* Spot check: ensure this item is only on the list that we just
 620      prepended it to */
 621 
 622   item->pmix_list_item_refcount += 1;
 623   assert(1 == item->pmix_list_item_refcount);
 624   item->pmix_list_item_belong_to = list;
 625 #endif
 626 }
 627 
 628 
 629 /**
 630  * Remove the first item from the list and return it.
 631  *
 632  * @param list The list container
 633  *
 634  * @returns The first item on the list.  If the list is empty,
 635  * NULL will be returned
 636  *
 637  * This is an O(1) operation to return the first item on the list.  If
 638  * the list is not empty, a pointer to the first item in the list will
 639  * be returned.  Ownership of the item is transferred from the list to
 640  * the caller; no calls to PMIX_RETAIN() or PMIX_RELEASE() are invoked.
 641  *
 642  * This is an inlined function in compilers that support inlining, so
 643  * it's usually a cheap operation.
 644  */
 645 static inline pmix_list_item_t *pmix_list_remove_first(pmix_list_t *list)
 646 {
 647   /*  Removes and returns first item on list.
 648       Caller now owns the item and should release the item
 649       when caller is done with it.
 650   */
 651   volatile pmix_list_item_t *item;
 652   if ( 0 == list->pmix_list_length ) {
 653     return (pmix_list_item_t *)NULL;
 654   }
 655 
 656 #if PMIX_ENABLE_DEBUG
 657   /* Spot check: ensure that the first item is only on this list */
 658 
 659   assert(1 == list->pmix_list_sentinel.pmix_list_next->pmix_list_item_refcount);
 660 #endif
 661 
 662   /* reset list length counter */
 663   list->pmix_list_length--;
 664 
 665   /* get pointer to first element on the list */
 666   item = list->pmix_list_sentinel.pmix_list_next;
 667 
 668   /* reset previous pointer of next item on the list */
 669   item->pmix_list_next->pmix_list_prev = item->pmix_list_prev;
 670 
 671   /* reset the head next pointer */
 672   list->pmix_list_sentinel.pmix_list_next = item->pmix_list_next;
 673 
 674 #if PMIX_ENABLE_DEBUG
 675   assert( list == item->pmix_list_item_belong_to );
 676   item->pmix_list_item_belong_to = NULL;
 677   item->pmix_list_prev=(pmix_list_item_t *)NULL;
 678   item->pmix_list_next=(pmix_list_item_t *)NULL;
 679 
 680   /* Spot check: ensure that the item we're returning is now on no
 681      lists */
 682 
 683   item->pmix_list_item_refcount -= 1;
 684   assert(0 == item->pmix_list_item_refcount);
 685 #endif
 686 
 687   return (pmix_list_item_t *) item;
 688 }
 689 
 690 
 691 /**
 692  * Remove the last item from the list and return it.
 693  *
 694  * @param list The list container
 695  *
 696  * @returns The last item on the list.  If the list is empty,
 697  * NULL will be returned
 698  *
 699  * This is an O(1) operation to return the last item on the list.  If
 700  * the list is not empty, a pointer to the last item in the list will
 701  * be returned.  Ownership of the item is transferred from the list to
 702  * the caller; no calls to PMIX_RETAIN() or PMIX_RELEASE() are invoked.
 703  *
 704  * This is an inlined function in compilers that support inlining, so
 705  * it's usually a cheap operation.
 706  */
 707 static inline pmix_list_item_t *pmix_list_remove_last(pmix_list_t *list)
 708 {
 709   /*  Removes, releases and returns last item on list.
 710       Caller now owns the item and should release the item
 711       when caller is done with it.
 712   */
 713   volatile pmix_list_item_t  *item;
 714   if ( 0 == list->pmix_list_length ) {
 715       return (pmix_list_item_t *)NULL;
 716   }
 717 
 718 #if PMIX_ENABLE_DEBUG
 719   /* Spot check: ensure that the first item is only on this list */
 720 
 721   assert(1 == list->pmix_list_sentinel.pmix_list_prev->pmix_list_item_refcount);
 722 #endif
 723 
 724   /* reset list length counter */
 725   list->pmix_list_length--;
 726 
 727   /* get item */
 728   item = list->pmix_list_sentinel.pmix_list_prev;
 729 
 730   /* reset previous pointer on next to last pointer */
 731   item->pmix_list_prev->pmix_list_next = item->pmix_list_next;
 732 
 733   /* reset tail's previous pointer */
 734   list->pmix_list_sentinel.pmix_list_prev = item->pmix_list_prev;
 735 
 736 #if PMIX_ENABLE_DEBUG
 737   assert( list == item->pmix_list_item_belong_to );
 738   item->pmix_list_next = item->pmix_list_prev = (pmix_list_item_t *)NULL;
 739 
 740   /* Spot check: ensure that the item we're returning is now on no
 741      lists */
 742 
 743   item->pmix_list_item_refcount -= 1;
 744   assert(0 == item->pmix_list_item_refcount);
 745   item->pmix_list_item_belong_to = NULL;
 746 #endif
 747 
 748   return (pmix_list_item_t *) item;
 749 }
 750 
 751   /**
 752    * Add an item to the list before a given element
 753    *
 754    * @param list The list container
 755    * @param pos List element to insert \c item before
 756    * @param item The item to insert
 757    *
 758    * Inserts \c item before \c pos.  This is an O(1) operation.
 759    */
 760 static inline void pmix_list_insert_pos(pmix_list_t *list, pmix_list_item_t *pos,
 761                                         pmix_list_item_t *item)
 762 {
 763 #if PMIX_ENABLE_DEBUG
 764     /* Spot check: ensure that the item we're insertting is currently
 765        not on any list */
 766 
 767     assert(0 == item->pmix_list_item_refcount);
 768     assert( NULL == item->pmix_list_item_belong_to );
 769 #endif
 770 
 771     /* point item at the existing elements */
 772     item->pmix_list_next = pos;
 773     item->pmix_list_prev = pos->pmix_list_prev;
 774 
 775     /* splice into the list */
 776     pos->pmix_list_prev->pmix_list_next = item;
 777     pos->pmix_list_prev = item;
 778 
 779     /* reset list length counter */
 780     list->pmix_list_length++;
 781 
 782 #if PMIX_ENABLE_DEBUG
 783     /* Spot check: double check that this item is only on the list
 784        that we just added it to */
 785 
 786     item->pmix_list_item_refcount += 1;
 787     assert(1 == item->pmix_list_item_refcount);
 788     item->pmix_list_item_belong_to = list;
 789 #endif
 790 }
 791 
 792   /**
 793    * Add an item to the list at a specific index location in the list.
 794    *
 795    * @param list The list container
 796    * @param item The item to insert
 797    * @param index Location to add the item
 798    *
 799    * @returns true if insertion succeeded; otherwise false
 800    *
 801    * This is potentially an O(N) operation to traverse down to the
 802    * correct location in the list and add an item.
 803    *
 804    * Example: if idx = 2 and list = item1->item2->item3->item4, then
 805    * after insert, list = item1->item2->item->item3->item4.
 806    *
 807    * If index is greater than the length of the list, no action is
 808    * performed and false is returned.
 809    */
 810   bool pmix_list_insert(pmix_list_t *list, pmix_list_item_t *item,
 811                                       long long idx);
 812 
 813 
 814     /**
 815      * Join a list into another list
 816      *
 817      * @param thislist List container for list being operated on
 818      * @param pos List item in \c thislist marking the position before
 819      *              which items are inserted
 820      * @param xlist List container for list being spliced from
 821      *
 822      * Join a list into another list.  All of the elements of \c xlist
 823      * are inserted before \c pos and removed from \c xlist.
 824      *
 825      * This operation is an O(1) operation.  Both \c thislist and \c
 826      * xlist must be valid list containsers.  \c xlist will be empty
 827      * but valid after the call.  All pointers to \c pmix_list_item_t
 828      * containers remain valid, including those that point to elements
 829      * in \c xlist.
 830      */
 831     void pmix_list_join(pmix_list_t *thislist, pmix_list_item_t *pos,
 832                                       pmix_list_t *xlist);
 833 
 834 
 835     /**
 836      * Splice a list into another list
 837      *
 838      * @param thislist List container for list being operated on
 839      * @param pos List item in \c thislist marking the position before
 840      *             which items are inserted
 841      * @param xlist List container for list being spliced from
 842      * @param first List item in \c xlist marking the start of elements
 843      *             to be copied into \c thislist
 844      * @param last List item in \c xlist marking the end of elements
 845      * to be copied into \c thislist
 846      *
 847      * Splice a subset of a list into another list.  The \c [first,
 848      * last) elements of \c xlist are moved into \c thislist,
 849      * inserting them before \c pos.  \c pos must be a valid iterator
 850      * in \c thislist and \c [first, last) must be a valid range in \c
 851      * xlist.  \c postition must not be in the range \c [first, last).
 852      * It is, however, valid for \c xlist and \c thislist to be the
 853      * same list.
 854      *
 855      * This is an O(N) operation because the length of both lists must
 856      * be recomputed.
 857      */
 858     void pmix_list_splice(pmix_list_t *thislist, pmix_list_item_t *pos,
 859                                         pmix_list_t *xlist, pmix_list_item_t *first,
 860                                         pmix_list_item_t *last);
 861 
 862     /**
 863      * Comparison function for pmix_list_sort(), below.
 864      *
 865      * @param a Pointer to a pointer to an pmix_list_item_t.
 866      * Explanation below.
 867      * @param b Pointer to a pointer to an pmix_list_item_t.
 868      * Explanation below.
 869      * @retval 1 if \em a is greater than \em b
 870      * @retval 0 if \em a is equal to \em b
 871      * @retval 11 if \em a is less than \em b
 872      *
 873      * This function is invoked by qsort(3) from within
 874      * pmix_list_sort().  It is important to understand what
 875      * pmix_list_sort() does before invoking qsort, so go read that
 876      * documentation first.
 877      *
 878      * The important thing to realize here is that a and b will be \em
 879      * double pointers to the items that you need to compare.  Here's
 880      * a sample compare function to illustrate this point:
 881      */
 882     typedef int (*pmix_list_item_compare_fn_t)(pmix_list_item_t **a,
 883                                                pmix_list_item_t **b);
 884 
 885     /**
 886      * Sort a list with a provided compare function.
 887      *
 888      * @param list The list to sort
 889      * @param compare Compare function
 890      *
 891      * Put crassly, this function's complexity is O(N) + O(log(N)).
 892      * Its algorithm is:
 893      *
 894      * - remove every item from the list and put the corresponding
 895      *    (pmix_list_item_t*)'s in an array
 896      * - call qsort(3) with that array and your compare function
 897      * - re-add every element of the now-sorted array to the list
 898      *
 899      * The resulting list is now ordered.  Note, however, that since
 900      * an array of pointers is sorted, the comparison function must do
 901      * a double de-reference to get to the actual pmix_list_item_t (or
 902      * whatever the underlying type is).  See the documentation of
 903      * pmix_list_item_compare_fn_t for an example).
 904      */
 905     int pmix_list_sort(pmix_list_t* list, pmix_list_item_compare_fn_t compare);
 906 
 907 END_C_DECLS
 908 
 909 #endif /* PMIX_LIST_H */

/* [<][>][^][v][top][bottom][index][help] */