LCOV - code coverage report
Current view: top level - util/tmpl - fd_slist.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 197 201 98.0 %
Date: 2025-09-19 04:41:14 Functions: 77 108 71.3 %

          Line data    Source code
       1             : /* Generate prototypes, inlines and/or implementations for HPC slingly
       2             :    linked lists.  A slist can store a practically unbounded number of
       3             :    elements.  Typical slist operations are generally a fast O(1) time
       4             :    and slist element memory overhead is a small O(1) space.
       5             : 
       6             :    This API is designed for ultra tight coupling with pools, treaps,
       7             :    heaps, maps, dlists, etc.  Likewise, a slist can be persisted beyond
       8             :    the lifetime of the creating process, used concurrently in many
       9             :    common operations, used inter-process, relocated in memory, naively
      10             :    serialized/deserialized, moved between hosts, supports index
      11             :    compression for cache and memory bandwidth efficiency, etc.
      12             : 
      13             :    Memory efficiency and flexible footprint are prioritized.
      14             : 
      15             :    Typical usage:
      16             : 
      17             :      struct myele {
      18             :        ulong next; // Technically "SLIST_IDX_T SLIST_NEXT" (default is ulong next), do not modify while element is in the slist
      19             :        ... next can be located arbitrarily in the element and can be
      20             :        ... reused for other purposes when the element is not in a slist.
      21             :        ... An element should not be moved / released while an element is
      22             :        ... in a slist
      23             :      };
      24             : 
      25             :      typedef struct myele myele_t;
      26             : 
      27             :      #define SLIST_NAME  myslist
      28             :      #define SLIST_ELE_T myele_t
      29             :      #include "tmpl/fd_slist.c"
      30             : 
      31             :    will declare the following APIs as a header only style library in the
      32             :    compilation unit:
      33             : 
      34             :      // myslist_ele_max returns the theoretical maximum number of
      35             :      // elements that can be held in a myslist.
      36             : 
      37             :      ulong myslist_ele_max( void );
      38             : 
      39             :      // myslist_{align,footprint} returns the alignment and footprint
      40             :      // needed for a memory region to be used as a myslist.  align will
      41             :      // be an integer power-of-two and footprint will be a multiple of
      42             :      // align.  The values will be compile-time declaration friendly
      43             :      // (e.g. "myslist_t mem[1];" will have the correct alignment and
      44             :      // footprint and not be larger than 4096).
      45             :      //
      46             :      // myslist_new formats a memory region with the appropriate
      47             :      // alignment and footprint whose first byte in the caller's address
      48             :      // space is pointed to by shmem as a myslist.  Returns shmem on
      49             :      // success and NULL on failure (logs details).  Caller is not
      50             :      // joined on return.  The slist will be empty.
      51             :      //
      52             :      // myslist_join joins a myslist.  Assumes shslist points at a
      53             :      // memory region formatted as a myslist in the caller's address
      54             :      // space.  Returns a handle to the caller's local join on success
      55             :      // and NULL on failure (logs details).  Do not assume this is a
      56             :      // simple cast of shslist!
      57             :      //
      58             :      // myslist_leave leaves a myslist.  Assumes join points to a
      59             :      // current local join.  Returns shslist used on join.  Do not
      60             :      // assume this is a simple cast of join!
      61             :      //
      62             :      // myslist_delete unformats a memory region used as a myslist.
      63             :      // Assumes shslist points to a memory region in the caller's local
      64             :      // address space formatted as a myslist, that there are no joins to
      65             :      // the myslist and that any application cleanup of the entries has
      66             :      // already been done.  Returns shslist on success and NULL on
      67             :      // failure.
      68             : 
      69             :      ulong       myslist_align    ( void );
      70             :      ulong       myslist_footprint( void );
      71             :      void *      myslist_new      ( void *      shmem   );
      72             :      myslist_t * myslist_join     ( void *      shslist );
      73             :      void *      myslist_leave    ( myslist_t * join    );
      74             :      void *      myslist_delete   ( void *      shslist );
      75             : 
      76             :      // The below APIs assume join is a current local join to a myslist
      77             :      // and pool is a current local join to the element storage backing
      78             :      // the slist.
      79             :      //
      80             :      // myslist_is_empty returns 1 if the slist is empty and 0
      81             :      // otherwise.
      82             :      //
      83             :      // myslist_idx_peek_{head,tail} returns the pool index of the
      84             :      // slist's {head,tail}.  Assumes slist is not empty.
      85             : 
      86             :      int myslist_is_empty( myslist_t const * join, myele_t const * pool );
      87             : 
      88             :      ulong myslist_idx_peek_head( myslist_t const * join, myele_t const * pool );
      89             :      ulong myslist_idx_peek_tail( myslist_t const * join, myele_t const * pool );
      90             : 
      91             :      // myslist_idx_push_{head,tail} pushes the pool element whose index
      92             :      // is ele_idx to the slist's {head,tail} and returns join.  Assumes
      93             :      // ele_idx valid and not already in the slist.
      94             :      /
      95             :      // myslist_idx_pop_head pops the pool element at the slist's head
      96             :      // and returns its pool index.  Assumes slist is not empty.
      97             :      //
      98             :      // myslist_idx_insert_after inserts the pool element whose index is
      99             :      // ele_idx into the slist immediately after the pool element whose
     100             :      // index is prev_idx and returns join.  Assumes ele_idx is valid
     101             :      // and not already in the slist and prev_idx is already in the
     102             :      // slist.
     103             : 
     104             :      myslist_t * myslist_idx_push_head    ( myslist_t * join, ulong ele_idx,                 myele_t * pool );
     105             :      myslist_t * myslist_idx_push_tail    ( myslist_t * join, ulong ele_idx,                 myele_t * pool );
     106             :      ulong       myslist_idx_pop_head     ( myslist_t * join,                                myele_t * pool );
     107             :      myslist_t * myslist_idx_insert_after ( myslist_t * join, ulong ele_idx, ulong prev_idx, myele_t * pool );
     108             : 
     109             :      // myslist_remove_all removes all elements from the slist and
     110             :      // returns join.  It is the caller's responsibility to release all
     111             :      // elements to the pool as might be necessary.
     112             : 
     113             :      myslist_t * myslist_remove_all( myslist_t * join, myele_t * pool );
     114             : 
     115             :      // myslist_iter_* support fast ordered forward (head to tail)
     116             :      // iteration over all the elements in a slist.  Example usage:
     117             :      //
     118             :      //   for( myslist_iter_t iter = myslist_iter_init( join, pool );
     119             :      //        !myslist_iter_done( iter, join, pool );
     120             :      //        iter = myslist_iter_next( iter, join, pool ) ) {
     121             :      //     ulong ele_idx = myslist_iter_idx( iter, join, pool );
     122             :      //
     123             :      //     ... process element here
     124             :      //
     125             :      //     ... IMPORTANT!  It is generally safe to insert elements
     126             :      //     ... here (though they might not be covered by this
     127             :      //     ... iteration).  It is also generally safe to remove any
     128             :      //     ... element but the current element here (the removed
     129             :      //     ... element might have already been iterated over).  It is
     130             :      //     ... straightforward to make a variant of this iterator
     131             :      //     ... that would support removing the current element here
     132             :      //     ... if desired.
     133             :      //   }
     134             : 
     135             :      struct myslist_iter_private { ... internal use only ... };
     136             :      typedef struct myslist_iter_private myslist_iter_t;
     137             : 
     138             :      myslist_iter_t  myslist_iter_fwd_init(                      myslist_t const * join, myele_t const * pool );
     139             :      int             myslist_iter_done    ( myslist_iter_t iter, myslist_t const * join, myele_t const * pool );
     140             :      myslist_iter_t  myslist_iter_fwd_next( myslist_iter_t iter, myslist_t const * join, myele_t const * pool ); // assumes !done
     141             :      ulong           myslist_iter_idx     ( myslist_iter_t iter, myslist_t const * join, myele_t const * pool ); // assumes !done
     142             : 
     143             :      // myslist_verify returns 0 if the myslist is not obviously corrupt
     144             :      // or -1 (i.e. ERR_INVAL) otherwise (logs details).
     145             : 
     146             :      int
     147             :      myslist_verify( myslist_t const * join,    // Current local join to a myslist.
     148             :                      ulong             ele_cnt, // Element storage size, in [0,myslist_ele_max()]
     149             :                      myele_t const *   pool );  // Current local join to element storage, indexed [0,ele_cnt)
     150             : 
     151             :      // The above APIs have helpers that operate purely in the caller's
     152             :      // local address space when applicable.  The various elements
     153             :      // passed to / returned from these functions should be / will be
     154             :      // from the slist's underlying pool.
     155             : 
     156             :      myele_t * myslist_ele_peek_head( myslist_t const * join, myele_t * pool );
     157             :      myele_t * myslist_ele_peek_tail( myslist_t const * join, myele_t * pool );
     158             : 
     159             :      myslist_t * myslist_ele_push_head    ( myslist_t * join, myele_t * ele,                 myele_t * pool );
     160             :      myslist_t * myslist_ele_push_tail    ( myslist_t * join, myele_t * ele,                 myele_t * pool );
     161             :      myele_t *   myslist_ele_pop_head     ( myslist_t * join,                                myele_t * pool );
     162             :      myslist_t * myslist_ele_insert_after ( myslist_t * join, myele_t * ele, myele_t * prev, myele_t * pool );
     163             : 
     164             :      myele_t * myslist_iter_ele( myslist_iter_t iter, myslist_t const * join, myele_t * pool );
     165             : 
     166             :      // ... and const correct helpers when applicable
     167             : 
     168             :      myele_t const * myslist_ele_peek_head_const( myslist_t const * join, myele_t const * pool );
     169             :      myele_t const * myslist_ele_peek_tail_const( myslist_t const * join, myele_t const * pool );
     170             : 
     171             :      myele_t const * myslist_iter_ele_const( myslist_iter_t iter, myslist_t const * join, myele_t const * pool );
     172             : 
     173             :    You can do this as often as you like in a compilation unit to get
     174             :    different types of slists.  Variants exist for making header
     175             :    prototypes only and/or implementations only if making a library for
     176             :    use across multiple compilation units.  Further, options exist to use
     177             :    different hashing functions, comparison functions, etc as detailed
     178             :    below. */
     179             : 
     180             : /* TODO: DOC CONCURRENCY REQUIREMENTS */
     181             : 
     182             : /* SLIST_NAME gives the API prefix to use for a slist */
     183             : 
     184             : #ifndef SLIST_NAME
     185             : #error "Define SLIST_NAME"
     186             : #endif
     187             : 
     188             : /* SLIST_ELE_T is the slist element type. */
     189             : 
     190             : #ifndef SLIST_ELE_T
     191             : #error "Define SLIST_ELE_T"
     192             : #endif
     193             : 
     194             : /* SLIST_IDX_T is the type used for the prev and next fields in the
     195             :    SLIST_ELE_T.  Should be a primitive unsigned integer type.  Defaults
     196             :    to ulong.  A slist can't use element memory regions with more
     197             :    elements than the maximum value that can be represented by a
     198             :    SLIST_IDX_T.  (E.g. if ushort, the maximum size element store
     199             :    supported by the slist is 65535 elements.) */
     200             : 
     201             : #ifndef SLIST_IDX_T
     202             : #define SLIST_IDX_T ulong
     203             : #endif
     204             : 
     205             : /* SLIST_NEXT is the SLIST_ELE_T next field */
     206             : 
     207             : #ifndef SLIST_NEXT
     208             : #define SLIST_NEXT next
     209             : #endif
     210             : 
     211             : /* SLIST_MAGIC is the magic number to use for the structure to aid in
     212             :    persistent and/or IPC usage. */
     213             : 
     214             : #ifndef SLIST_MAGIC
     215        9033 : #define SLIST_MAGIC (0xf17eda2c37371570UL) /* firedancer slist version 0 */
     216             : #endif
     217             : 
     218             : /* 0 - local use only
     219             :    1 - library header declaration
     220             :    2 - library implementation */
     221             : 
     222             : #ifndef SLIST_IMPL_STYLE
     223             : #define SLIST_IMPL_STYLE 0
     224             : #endif
     225             : 
     226             : #if FD_TMPL_USE_HANDHOLDING
     227             : #include "../log/fd_log.h"
     228             : #endif
     229             : 
     230             : /* Implementation *****************************************************/
     231             : 
     232             : /* Constructors and verification log details on failure (rest only needs
     233             :    fd_bits.h, consider making logging a compile time option). */
     234             : 
     235 45496088043 : #define SLIST_(n) FD_EXPAND_THEN_CONCAT3(SLIST_NAME,_,n)
     236             : 
     237             : #if SLIST_IMPL_STYLE==0 || SLIST_IMPL_STYLE==1 /* need structures and inlines */
     238             : 
     239             : struct SLIST_(private) {
     240             : 
     241             :   /* join points here */
     242             : 
     243             :   ulong       magic; /* == SLIST_MAGIC */
     244             :   SLIST_IDX_T head;  /* index of first list element (or idx_null if empty list) */
     245             :   SLIST_IDX_T tail;  /* index of last  list element (or idx_null if empty list) */
     246             : };
     247             : 
     248             : typedef struct SLIST_(private) SLIST_(private_t);
     249             : 
     250             : typedef SLIST_(private_t) SLIST_(t);
     251             : 
     252             : typedef ulong SLIST_(iter_t);
     253             : 
     254             : FD_PROTOTYPES_BEGIN
     255             : 
     256             : /* slist_private returns the location of the slist header for a current
     257             :    local join.  Assumes join is a current local join.
     258             :    slist_private_const is a const correct version. */
     259             : 
     260             : FD_FN_CONST static inline SLIST_(private_t) *
     261   375011145 : SLIST_(private)( SLIST_(t) * join ) {
     262   375011145 :   return (SLIST_(private_t) *)join;
     263   375011145 : }
     264             : 
     265             : FD_FN_CONST static inline SLIST_(private_t) const *
     266 13685737875 : SLIST_(private_const)( SLIST_(t) const * join ) {
     267 13685737875 :   return (SLIST_(private_t) const *)join;
     268 13685737875 : }
     269             : 
     270             : /* slist_private_{cidx,idx} compress / decompress 64-bit in-register
     271             :    indices to/from their in-memory representations. */
     272             : 
     273   937545990 : FD_FN_CONST static inline SLIST_IDX_T SLIST_(private_cidx)( ulong       idx  ) { return (SLIST_IDX_T)idx;  }
     274 17060946987 : FD_FN_CONST static inline ulong       SLIST_(private_idx) ( SLIST_IDX_T cidx ) { return (ulong)      cidx; }
     275             : 
     276             : /* slist_private_idx_null returns the element storage index that
     277             :    represents NULL. */
     278             : 
     279   437603241 : FD_FN_CONST static inline ulong SLIST_(private_idx_null)( void ) { return (ulong)(SLIST_IDX_T)~0UL; }
     280             : 
     281             : /* slist_private_idx_is_null returns 1 if idx is the NULL slist index
     282             :    and 0 otherwise. */
     283             : 
     284  5437552284 : FD_FN_CONST static inline int SLIST_(private_idx_is_null)( ulong idx ) { return idx==(ulong)(SLIST_IDX_T)~0UL; }
     285             : 
     286   187540266 : FD_FN_CONST static ulong SLIST_(ele_max)( void ) { return (ulong)(SLIST_IDX_T)~0UL; }
     287             : 
     288             : FD_FN_PURE static inline int
     289             : SLIST_(is_empty)( SLIST_(t) const *   join,
     290  1874929434 :                   SLIST_ELE_T const * pool ) {
     291  1874929434 :   (void)pool;
     292  1874929434 :   return SLIST_(private_idx_is_null)( SLIST_(private_idx)( SLIST_(private_const)( join )->head ) );
     293  1874929434 : }
     294             : 
     295             : FD_FN_PURE static inline ulong
     296             : SLIST_(idx_peek_head)( SLIST_(t) const *   join,
     297  5624469645 :                        SLIST_ELE_T const * pool ) {
     298  5624469645 :   (void)pool;
     299             : # if FD_TMPL_USE_HANDHOLDING
     300             :   if( FD_UNLIKELY( SLIST_(is_empty)( join, pool ) ) ) FD_LOG_CRIT(( "cannot peek on empty slist" ));
     301             : # endif
     302  5624469645 :   return SLIST_(private_idx)( SLIST_(private_const)( join )->head );
     303  5624469645 : }
     304             : 
     305             : FD_FN_PURE static inline ulong
     306             : SLIST_(idx_peek_tail)( SLIST_(t) const *   join,
     307  5623879311 :                        SLIST_ELE_T const * pool ) {
     308  5623879311 :   (void)pool;
     309             : # if FD_TMPL_USE_HANDHOLDING
     310             :   if( FD_UNLIKELY( SLIST_(is_empty)( join, pool ) ) ) FD_LOG_CRIT(( "cannot peek on empty slist" ));
     311             : # endif
     312  5623879311 :   return SLIST_(private_idx)( SLIST_(private_const)( join )->tail );
     313  5623879311 : }
     314             : 
     315             : static inline SLIST_(t) *
     316             : SLIST_(idx_push_head)( SLIST_(t) *   join,
     317             :                        ulong         ele_idx,
     318    62499201 :                        SLIST_ELE_T * pool ) {
     319    62499201 :   SLIST_(private_t) * slist = SLIST_(private)( join );
     320             : 
     321    62499201 :   ulong head_idx = SLIST_(private_idx)( slist->head );
     322             : 
     323    62499201 :   pool[ ele_idx ].SLIST_NEXT = SLIST_(private_cidx)( head_idx );
     324             : 
     325    62499201 :   SLIST_IDX_T dummy[1];
     326    62499201 :   *fd_ptr_if( !SLIST_(private_idx_is_null)( head_idx ), dummy+0, &slist->tail ) =
     327    62499201 :     SLIST_(private_cidx)( ele_idx );
     328             : 
     329    62499201 :   slist->head = SLIST_(private_cidx)( ele_idx );
     330    62499201 :   return join;
     331    62499201 : }
     332             : 
     333             : static inline SLIST_(t) *
     334             : SLIST_(idx_push_tail)( SLIST_(t) *   join,
     335             :                        ulong         ele_idx,
     336    62539374 :                        SLIST_ELE_T * pool ) {
     337    62539374 :   SLIST_(private_t) * slist = SLIST_(private)( join );
     338             : 
     339    62539374 :   ulong tail_idx = SLIST_(private_idx)( slist->tail );
     340             : 
     341    62539374 :   pool[ ele_idx ].SLIST_NEXT = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
     342             : 
     343    62539374 :   *fd_ptr_if( !SLIST_(private_idx_is_null)( tail_idx ), &pool[ tail_idx ].SLIST_NEXT, &slist->head ) =
     344    62539374 :     SLIST_(private_cidx)( ele_idx );
     345             : 
     346    62539374 :   slist->tail = SLIST_(private_cidx)( ele_idx );
     347    62539374 :   return join;
     348    62539374 : }
     349             : 
     350             : static inline ulong
     351             : SLIST_(idx_pop_head)( SLIST_(t) *   join,
     352   187505484 :                       SLIST_ELE_T * pool ) {
     353             : # if FD_TMPL_USE_HANDHOLDING
     354             :   if( FD_UNLIKELY( SLIST_(is_empty)( join, pool ) ) ) FD_LOG_CRIT(( "cannot pop from empty slist" ));
     355             : # endif
     356   187505484 :   SLIST_(private_t) * slist = SLIST_(private)( join );
     357             : 
     358   187505484 :   ulong ele_idx  = SLIST_(private_idx)( slist->head ); /* Not NULL as per contract */
     359   187505484 :   ulong next_idx = SLIST_(private_idx)( pool[ ele_idx ].SLIST_NEXT );
     360             : 
     361   187505484 :   SLIST_IDX_T dummy[1];
     362   187505484 :   *fd_ptr_if( !SLIST_(private_idx_is_null)( next_idx ), dummy+0, &slist->tail ) =
     363   187505484 :     SLIST_(private_cidx)( SLIST_(private_idx_null)() );
     364             : 
     365   187505484 :   slist->head = SLIST_(private_cidx)( next_idx );
     366   187505484 :   return ele_idx;
     367   187505484 : }
     368             : 
     369             : static inline SLIST_(t) *
     370             : SLIST_(idx_insert_after)( SLIST_(t) *   join,
     371             :                           ulong         ele_idx,
     372             :                           ulong         prev_idx,
     373    62467059 :                           SLIST_ELE_T * pool ) {
     374    62467059 :   ulong next_idx = SLIST_(private_idx)( pool[ prev_idx ].SLIST_NEXT );
     375             : 
     376    62467059 :   pool[ ele_idx ].SLIST_NEXT = SLIST_(private_cidx)( next_idx );
     377             : 
     378    62467059 :   pool[ prev_idx ].SLIST_NEXT = SLIST_(private_cidx)( ele_idx );
     379             : 
     380    62467059 :   SLIST_IDX_T dummy[1];
     381    62467059 :   *fd_ptr_if( !SLIST_(private_idx_is_null)( next_idx ), dummy+0, &SLIST_(private)( join )->tail ) =
     382    62467059 :     SLIST_(private_cidx)( ele_idx );
     383             : 
     384    62467059 :   return join;
     385    62467059 : }
     386             : 
     387             : static inline SLIST_(t) *
     388             : SLIST_(remove_all)( SLIST_(t) *   join,
     389          27 :                     SLIST_ELE_T * pool ) {
     390          27 :   (void)pool;
     391          27 :   SLIST_(private_t) * slist = SLIST_(private)( join );
     392          27 :   slist->head = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
     393          27 :   slist->tail = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
     394          27 :   return join;
     395          27 : }
     396             : 
     397             : FD_FN_PURE static inline SLIST_(iter_t)
     398             : SLIST_(iter_init)( SLIST_(t) const *   join,
     399   374919222 :                        SLIST_ELE_T const * pool ) {
     400   374919222 :   (void)pool;
     401   374919222 :   return SLIST_(private_idx)( SLIST_(private_const)( join )->head );
     402   374919222 : }
     403             : 
     404             : FD_FN_CONST static inline int
     405             : SLIST_(iter_done)( SLIST_(iter_t)      iter,
     406             :                    SLIST_(t) const *   join,
     407  1593543513 :                    SLIST_ELE_T const * pool ) {
     408  1593543513 :   (void)join; (void)pool;
     409  1593543513 :   return SLIST_(private_idx_is_null)( iter );
     410  1593543513 : }
     411             : 
     412             : FD_FN_PURE static inline SLIST_(iter_t)
     413             : SLIST_(iter_next)( SLIST_(iter_t)      iter,
     414             :                        SLIST_(t) const *   join,
     415  1218624291 :                        SLIST_ELE_T const * pool ) {
     416  1218624291 :   (void)join;
     417  1218624291 :   return SLIST_(private_idx)( pool[ iter ].SLIST_NEXT );
     418  1218624291 : }
     419             : 
     420             : FD_FN_CONST static inline ulong
     421             : SLIST_(iter_idx)( SLIST_(iter_t)      iter,
     422             :                   SLIST_(t) const *   join,
     423   187489653 :                   SLIST_ELE_T const * pool ) {
     424   187489653 :   (void)join; (void)pool;
     425   187489653 :   return iter;
     426   187489653 : }
     427             : 
     428             : FD_FN_PURE static inline SLIST_ELE_T *
     429             : SLIST_(ele_peek_head)( SLIST_(t) const * join,
     430  1875216795 :                        SLIST_ELE_T *     pool ) {
     431  1875216795 :   return pool + SLIST_(idx_peek_head)( join, pool );
     432  1875216795 : }
     433             : 
     434             : FD_FN_PURE static inline SLIST_ELE_T const *
     435             : SLIST_(ele_peek_head_const)( SLIST_(t) const *   join,
     436  1874626416 :                              SLIST_ELE_T const * pool ) {
     437  1874626416 :   return pool + SLIST_(idx_peek_head)( join, pool );
     438  1874626416 : }
     439             : 
     440             : FD_FN_PURE static inline SLIST_ELE_T *
     441             : SLIST_(ele_peek_tail)( SLIST_(t) const * join,
     442  1874626479 :                        SLIST_ELE_T *     pool ) {
     443  1874626479 :   return pool + SLIST_(idx_peek_tail)( join, pool );
     444  1874626479 : }
     445             : 
     446             : FD_FN_PURE static inline SLIST_ELE_T const *
     447             : SLIST_(ele_peek_tail_const)( SLIST_(t) const *   join,
     448  1874626416 :                              SLIST_ELE_T const * pool ) {
     449  1874626416 :   return pool + SLIST_(idx_peek_tail)( join, pool );
     450  1874626416 : }
     451             : 
     452             : static inline SLIST_(t) *
     453             : SLIST_(ele_push_head)( SLIST_(t) *   join,
     454             :                        SLIST_ELE_T * ele,
     455    31246809 :                        SLIST_ELE_T * pool ) {
     456    31246809 :   return SLIST_(idx_push_head)( join, (ulong)(ele-pool), pool );
     457    31246809 : }
     458             : 
     459             : static inline SLIST_(t) *
     460             : SLIST_(ele_push_tail)( SLIST_(t) *   join,
     461             :                        SLIST_ELE_T * ele,
     462    31284390 :                        SLIST_ELE_T * pool ) {
     463    31284390 :   return SLIST_(idx_push_tail)( join, (ulong)(ele-pool), pool );
     464    31284390 : }
     465             : 
     466             : static inline SLIST_ELE_T *
     467             : SLIST_(ele_pop_head)( SLIST_(t) *   join,
     468    93740538 :                       SLIST_ELE_T * pool ) {
     469    93740538 :   return pool + SLIST_(idx_pop_head)( join, pool );
     470    93740538 : }
     471             : 
     472             : static inline SLIST_(t) *
     473             : SLIST_(ele_insert_after)( SLIST_(t) *   join,
     474             :                           SLIST_ELE_T * ele,
     475             :                           SLIST_ELE_T * prev,
     476    31229655 :                           SLIST_ELE_T * pool ) {
     477    31229655 :   return SLIST_(idx_insert_after)( join, (ulong)(ele-pool), (ulong)(prev-pool), pool );
     478    31229655 : }
     479             : 
     480             : FD_FN_CONST static inline SLIST_ELE_T *
     481             : SLIST_(iter_ele)( SLIST_(iter_t)    iter,
     482             :                   SLIST_(t) const * join,
     483   187429599 :                   SLIST_ELE_T *     pool ) {
     484   187429599 :   (void)join;
     485   187429599 :   return pool + iter;
     486   187429599 : }
     487             : 
     488             : FD_FN_CONST static inline SLIST_ELE_T const *
     489             : SLIST_(iter_ele_const)( SLIST_(iter_t)      iter,
     490             :                         SLIST_(t) const *   join,
     491           0 :                         SLIST_ELE_T const * pool ) {
     492           0 :   (void)join;
     493           0 :   return pool + iter;
     494           0 : }
     495             : 
     496             : FD_PROTOTYPES_END
     497             : 
     498             : #endif
     499             : 
     500             : #if SLIST_IMPL_STYLE==1 /* need prototypes */
     501             : 
     502             : FD_PROTOTYPES_BEGIN
     503             : 
     504             : FD_FN_CONST ulong SLIST_(align)    ( void                );
     505             : FD_FN_CONST ulong SLIST_(footprint)( void                );
     506             : void *            SLIST_(new)      ( void *      shmem   );
     507             : SLIST_(t) *       SLIST_(join)     ( void *      shslist );
     508             : void *            SLIST_(leave)    ( SLIST_(t) * join    );
     509             : void *            SLIST_(delete)   ( void *      shslist );
     510             : 
     511             : int
     512             : SLIST_(verify)( SLIST_(t) const *   join,
     513             :                 ulong               ele_cnt,
     514             :                 SLIST_ELE_T const * pool );
     515             : 
     516             : FD_PROTOTYPES_END
     517             : 
     518             : #else /* need implementations */
     519             : 
     520             : #if SLIST_IMPL_STYLE==0 /* local only */
     521             : #define SLIST_IMPL_STATIC FD_FN_UNUSED static
     522             : #else
     523             : #define SLIST_IMPL_STATIC
     524             : #endif
     525             : 
     526             : FD_PROTOTYPES_BEGIN
     527             : 
     528       27114 : FD_FN_CONST SLIST_IMPL_STATIC ulong SLIST_(align)    ( void ) { return alignof(SLIST_(t)); }
     529           3 : FD_FN_CONST SLIST_IMPL_STATIC ulong SLIST_(footprint)( void ) { return sizeof( SLIST_(t)); }
     530             : 
     531             : SLIST_IMPL_STATIC void *
     532        9039 : SLIST_(new)( void * shmem ) {
     533             : 
     534        9039 :   if( FD_UNLIKELY( !shmem ) ) {
     535           3 :     FD_LOG_WARNING(( "NULL shmem" ));
     536           3 :     return NULL;
     537           3 :   }
     538             : 
     539        9036 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, SLIST_(align)() ) ) ) {
     540           3 :     FD_LOG_WARNING(( "misaligned shmem" ));
     541           3 :     return NULL;
     542           3 :   }
     543             : 
     544             :   // Note: Guaranteed non-zero and not otherwise used
     545             : //ulong footprint = SLIST_(footprint)();
     546             : //if( FD_UNLIKELY( !footprint ) ) {
     547             : //  FD_LOG_WARNING(( "bad footprint" ));
     548             : //  return NULL;
     549             : //}
     550             : 
     551        9033 :   SLIST_(private_t) * slist = (SLIST_(private_t) *)shmem;
     552             : 
     553        9033 :   slist->head = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
     554        9033 :   slist->tail = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
     555             : 
     556        9033 :   FD_COMPILER_MFENCE();
     557        9033 :   FD_VOLATILE( slist->magic ) = SLIST_MAGIC;
     558        9033 :   FD_COMPILER_MFENCE();
     559             : 
     560        9033 :   return shmem;
     561        9036 : }
     562             : 
     563             : SLIST_IMPL_STATIC SLIST_(t) *
     564        9042 : SLIST_(join)( void * shslist ) {
     565        9042 :   SLIST_(private_t) * slist = (SLIST_(private_t) *)shslist;
     566             : 
     567        9042 :   if( FD_UNLIKELY( !slist ) ) {
     568           3 :     FD_LOG_WARNING(( "NULL shslist" ));
     569           3 :     return NULL;
     570           3 :   }
     571             : 
     572        9039 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)slist, SLIST_(align)() ) ) ) {
     573           3 :     FD_LOG_WARNING(( "misaligned shslist" ));
     574           3 :     return NULL;
     575           3 :   }
     576             : 
     577        9036 :   if( FD_UNLIKELY( slist->magic!=SLIST_MAGIC ) ) {
     578           3 :     FD_LOG_WARNING(( "bad magic" ));
     579           3 :     return NULL;
     580           3 :   }
     581             : 
     582        9033 :   return (SLIST_(t) *)slist;
     583        9036 : }
     584             : 
     585             : SLIST_IMPL_STATIC void *
     586        9033 : SLIST_(leave)( SLIST_(t) * join ) {
     587             : 
     588        9033 :   if( FD_UNLIKELY( !join ) ) {
     589           3 :     FD_LOG_WARNING(( "NULL join" ));
     590           3 :     return NULL;
     591           3 :   }
     592             : 
     593        9030 :   return (void *)join;
     594        9033 : }
     595             : 
     596             : SLIST_IMPL_STATIC void *
     597        9039 : SLIST_(delete)( void * shslist ) {
     598        9039 :   SLIST_(private_t) * slist = (SLIST_(private_t) *)shslist;
     599             : 
     600        9039 :   if( FD_UNLIKELY( !slist ) ) {
     601           3 :     FD_LOG_WARNING(( "NULL shslist" ));
     602           3 :     return NULL;
     603           3 :   }
     604             : 
     605        9036 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)slist, SLIST_(align)() ) ) ) {
     606           3 :     FD_LOG_WARNING(( "misaligned shslist" ));
     607           3 :     return NULL;
     608           3 :   }
     609             : 
     610        9033 :   if( FD_UNLIKELY( slist->magic!=SLIST_MAGIC ) ) {
     611           3 :     FD_LOG_WARNING(( "bad magic" ));
     612           3 :     return NULL;
     613           3 :   }
     614             : 
     615        9030 :   FD_COMPILER_MFENCE();
     616        9030 :   FD_VOLATILE( slist->magic ) = 0UL;
     617        9030 :   FD_COMPILER_MFENCE();
     618             : 
     619        9030 :   return shslist;
     620        9033 : }
     621             : 
     622             : SLIST_IMPL_STATIC int
     623             : SLIST_(verify)( SLIST_(t) const *   join,
     624             :                 ulong               ele_cnt,
     625   187540263 :                 SLIST_ELE_T const * pool ) {
     626             : 
     627  3750757227 : # define SLIST_TEST(c) do {                                                      \
     628  3750757227 :     if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: %s", #c )); return -1; } \
     629  3750757227 :   } while(0)
     630             : 
     631             :   /* Validate input args */
     632             : 
     633   187540263 :   SLIST_TEST( join                       );
     634   187540263 :   SLIST_TEST( ele_cnt<=SLIST_(ele_max)() );
     635   187540263 :   SLIST_TEST( (!!pool) | (!ele_cnt)      );
     636             : 
     637             :   /* Iterate forward through the slist, validating as we go */
     638             : 
     639   187540263 :   SLIST_(private_t) const * slist = SLIST_(private_const)( join );
     640             : 
     641   187540263 :   SLIST_TEST( slist->magic==SLIST_MAGIC );
     642             : 
     643   187540263 :   ulong rem      = ele_cnt;
     644   187540263 :   ulong prev_idx = SLIST_(private_idx_null)();
     645   187540263 :   ulong ele_idx  = SLIST_(private_idx)( slist->head );
     646  1594068219 :   while( !SLIST_(private_idx_is_null)( ele_idx ) ) {
     647             : 
     648             :     /* Visit ele_idx */
     649             : 
     650  1406527956 :     SLIST_TEST( rem ); rem--;                                                  /* Test for cycles */
     651  1406527956 :     SLIST_TEST( ele_idx<ele_cnt );                                             /* Test valid ele_idx */
     652             : 
     653             :     /* Advance to next element */
     654             : 
     655  1406527956 :     prev_idx = ele_idx;
     656  1406527956 :     ele_idx  = SLIST_(private_idx)( pool[ ele_idx ].SLIST_NEXT );
     657  1406527956 :   }
     658             : 
     659   187540263 :   SLIST_TEST( SLIST_(private_idx)( slist->tail )==prev_idx );
     660             : 
     661   187540263 : # undef SLIST_TEST
     662             : 
     663   187540263 :   return 0;
     664   187540263 : }
     665             : 
     666             : FD_PROTOTYPES_END
     667             : 
     668             : #undef SLIST_IMPL_STATIC
     669             : 
     670             : #endif
     671             : 
     672             : #undef SLIST_
     673             : 
     674             : #undef SLIST_IMPL_STYLE
     675             : #undef SLIST_MAGIC
     676             : #undef SLIST_NEXT
     677             : #undef SLIST_IDX_T
     678             : #undef SLIST_ELE_T
     679             : #undef SLIST_NAME

Generated by: LCOV version 1.14