LCOV - code coverage report
Current view: top level - util/tmpl - fd_vec.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 76 79 96.2 %
Date: 2024-11-13 11:58:15 Functions: 17 18 94.4 %

          Line data    Source code
       1             : /* Declare vectors of bounded run-time maximum size suitable for
       2             :    persistent and IPC usage.  Designed for POD types that have a trivial
       3             :    copy operator. Typical usage:
       4             : 
       5             :      #define VEC_NAME myvec
       6             :      #define VEC_T    myvec_t
       7             :      #include "util/tmpl/fd_vec.c"
       8             : 
       9             :    will declare the following static inline APIs as a header only style
      10             :    library in the compilation unit: 
      11             : 
      12             :      // align/footprint - Return the alignment/footprint required for a
      13             :      // memory region to be used as vector that can hold up to max
      14             :      // events.  footprint returns 0 if max is so large that the
      15             :      // footprint would overflow ULONG_MAX.
      16             :      //
      17             :      // new - Format a memory region pointed to by shmem into a myvec
      18             :      // vector.  Assumes shmem points to a region with the required
      19             :      // alignment and footprint not in use by anything else.  Caller is
      20             :      // not joined on return.  Returns shmem on success or NULL on
      21             :      // failure (e.g. shmem or max are obviously bad).
      22             :      //
      23             :      // join - Join a myvec vector.  Assumes shvec points at a region
      24             :      // formatted as an vector.  Returns a pointer in the caller's
      25             :      // address space to a memory region indexed [0,max) where elements
      26             :      // [0,cnt) are currently in use on success and NULL on failure
      27             :      // (e.g.  shmem is obviously bad).  THIS IS NOT JUST A SIMPLE CAST
      28             :      // OF SHVEC.
      29             :      //
      30             :      // leave - Leave a myvec vector.  Assumes join points to a current
      31             :      // local join.  Returns a pointer to the shared memory region the
      32             :      // join on success and NULL on failure.  THIS IS NOT JUST A SIMPLE
      33             :      // CAST OF JOIN.
      34             :      //
      35             :      // delete - Unformat a memory region used as myvec vector.  Assumes
      36             :      // myvec vector points to a formatted region with no current joins.
      37             :      // Returns a pointer to the unformatted memory region.
      38             : 
      39             :      ulong     myvec_align    ( void      );
      40             :      ulong     myvec_footprint( ulong max );
      41             :      void *    myvec_new      ( void *    shmem, ulong max );
      42             :      myvec_t * myvec_join     ( void *    shvec );
      43             :      void *    myvec_leave    ( myvec_t * join  );
      44             :      void *    myvec_delete   ( void *    shvec );
      45             : 
      46             :      // All the below APIs assume join is a current local join.
      47             : 
      48             :      // myvec_max returns the maximum number of elements in a myvec vector.
      49             :      // myvec_cnt returns the current number of elements, in [0,max]
      50             :      // myvec_free     = max - cnt
      51             :      // myvec_is_empty = (cnt==0)
      52             :      // myvec_is_full  = (cnt==max)
      53             : 
      54             :      ulong myvec_max( myvec_t const * join );
      55             :      ulong myvec_cnt     ( myvec_t const * join );
      56             :      ulong myvec_free    ( myvec_t const * join );
      57             :      int   myvec_is_empty( myvec_t const * join );
      58             :      int   myvec_is_full ( myvec_t const * join );
      59             : 
      60             :      // myvec_expand increases the number of elements in a vector by
      61             :      // delta.  The new elements will be indexed [cnt,cnt+delta) Returns
      62             :      // a pointer to the delta (uninitialized) new elements.  IMPORTANT!
      63             :      // AS THIS IS USED IN HPC CONTEXTS, ASSUMES CALLER KNOWS THERE ARE
      64             :      // DELTA AT LEAST DELTA ELEMENTS FREE (I.E. DELTA IS IN [0,FREE].
      65             :      //
      66             :      // myvec_contract decreases the number of elements in a vector by
      67             :      // delta.  The elements removed are indexed [cnt-delta,cnt).
      68             :      // Returns a pointer to delta removed elements.  IMPORTANT!  AS
      69             :      // THIS IS USED IN HPC CONTEXTS, ASSUMES CALLER KNOWS THERE ARE
      70             :      // DELTA AT LEAST DELTA ELEMENTS PRESENT (I.E.  DELTA IS IN
      71             :      // [0,CNT].
      72             : 
      73             :      myvec_t * myvec_expand  ( myvec_t * join, ulong delta );
      74             :      myvec_t * myvec_contract( myvec_t * join, ulong delta );
      75             : 
      76             :      // myvec_remove removes the element at index by backfilling the
      77             :      // last element into element idx.  This is an O(1) operation.
      78             :      // Returns join.  IMPORTANT!  AS THIS IS USED IN HPC CONTEXTS,
      79             :      // ASSUMES CALLER KNOWS IDX IS A CURRENT ELEMENT.  THAT IS, IDX IS
      80             :      // IN [0,CNT).
      81             : 
      82             :      myvec_t * myvec_remove( myvec_t * join, ulong idx );
      83             :      
      84             :      // myvec_remove_compact remove element at idx by compaction.  While
      85             :      // this is preserves operating, this is an O(cnt-idx-1) operation
      86             :      // and it is very easily to accidentally create O(N^2)
      87             :      // if using compaction.  IMPORTANT!  AS THIS IS USED IN HPC
      88             :      // CONTEXTS, ASSUMES CALLER KNOWS IDX IS A CURRENT ELEMENT.  THAT
      89             :      // IS, IDX IS IN [0,CNT).
      90             : 
      91             :      myvec_t * myvec_remove_compact( myvec_t * join, ulong idx );
      92             : 
      93             :      // TODO: CONSIDER ADDING OTHER APIS LIKE SHUFFLE AND WHAT NOT?
      94             : 
      95             :      You can do this as often as you like in a compilation unit to get
      96             :      different types of vectors.  Since it is all static inline, it is
      97             :      fine to do this in a header too.  Additional options to fine tune
      98             :      this are detailed below. */
      99             : 
     100             : #ifndef VEC_NAME
     101             : #define "Define VEC_NAME"
     102             : #endif
     103             : 
     104             : #ifndef VEC_T
     105             : #define "Define VEC_T"
     106             : #endif
     107             : 
     108             : // TODO: CONSIDER LETTING USER SPECIFY COPY AND MOVE?
     109             : 
     110    27000042 : #define VEC_(n) FD_EXPAND_THEN_CONCAT3(VEC_NAME,_,n)
     111             : 
     112             : struct VEC_(private) {
     113             :   ulong max; /* Arbitrary */
     114             :   ulong cnt; /* In [0,max) */
     115             : };
     116             : 
     117             : typedef struct VEC_(private) VEC_(private_t);
     118             : 
     119             : FD_FN_CONST static inline VEC_(private_t) *
     120     2999994 : VEC_(private)( VEC_T * join ) {
     121     2999994 :   return (VEC_(private_t) *)(((ulong)join) - sizeof(VEC_(private_t)));
     122     2999994 : }
     123             : 
     124             : FD_FN_CONST static inline VEC_(private_t) const *
     125    15000000 : VEC_(private_const)( VEC_T const * join ) {
     126    15000000 :   return (VEC_(private_t) const *)(((ulong)join) - sizeof(VEC_(private_t)));
     127    15000000 : }
     128             : 
     129             : FD_FN_CONST static inline ulong
     130           0 : VEC_(align)( void ) {
     131           0 :   return fd_ulong_max( alignof(VEC_T), 128UL );
     132           0 : }
     133             : 
     134             : FD_FN_CONST static inline ulong
     135          21 : VEC_(private_meta_footprint)( void ) {
     136          21 :   return fd_ulong_align_up( sizeof(VEC_(private_t)), VEC_(align)() );
     137          21 : }
     138             : 
     139             : FD_FN_CONST static inline ulong
     140          12 : VEC_(footprint)( ulong max ) {
     141          12 :   ulong align          = VEC_(align)();
     142          12 :   ulong meta_footprint = VEC_(private_meta_footprint)(); /* Multiple of align */
     143          12 :   ulong data_footprint = fd_ulong_align_up( sizeof(VEC_T)*max, align );
     144          12 :   ulong thresh         = (ULONG_MAX - align - meta_footprint + 1UL) / sizeof(VEC_T);
     145          12 :   return fd_ulong_if( max > thresh, 0UL, meta_footprint + data_footprint );
     146          12 : }
     147             : 
     148             : static inline void *
     149             : VEC_(new)( void * shmem,
     150           6 :            ulong  max ) {
     151             : 
     152           6 :   if( FD_UNLIKELY( !shmem ) ) return NULL;
     153             : 
     154           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, VEC_(align)() ) ) ) return NULL;
     155             : 
     156           3 :   if( FD_UNLIKELY( !VEC_(footprint)( max ) ) ) return NULL;
     157             : 
     158           3 :   VEC_(private_t) * join = VEC_(private)( (VEC_T *)(((ulong)shmem) + VEC_(private_meta_footprint)()) );
     159           3 :   join->max = max;
     160           3 :   join->cnt = 0UL;
     161           3 :   return shmem;
     162           3 : }
     163             : 
     164             : FD_FN_CONST static inline VEC_T *
     165           6 : VEC_(join)( void * shvec ) {
     166             : 
     167           6 :   if( FD_UNLIKELY( !shvec ) ) return NULL;
     168             : 
     169           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shvec, VEC_(align)() ) ) ) return NULL;
     170             : 
     171           3 :   return (VEC_T *)(((ulong)shvec) + VEC_(private_meta_footprint)());
     172           3 : }
     173             : 
     174             : FD_FN_CONST static inline void *
     175           6 : VEC_(leave)( VEC_T * join ) {
     176             : 
     177           6 :   if( FD_UNLIKELY( !join ) ) return NULL;
     178             : 
     179           3 :   return (void *)(((ulong)join) - VEC_(private_meta_footprint)());
     180           6 : }
     181             : 
     182             : FD_FN_CONST static inline void *
     183           6 : VEC_(delete)( void * shvec ) {
     184             : 
     185           6 :   if( FD_UNLIKELY( !shvec ) ) return NULL;
     186             : 
     187           3 :   return shvec;
     188           6 : }
     189             : 
     190     3000000 : FD_FN_PURE static inline ulong VEC_(max)( VEC_T const * join ) { return  VEC_(private_const)( join )->max; }
     191     3000000 : FD_FN_PURE static inline ulong VEC_(cnt)( VEC_T const * join ) { return  VEC_(private_const)( join )->cnt; }
     192             : 
     193             : FD_FN_PURE static inline ulong
     194     3000000 : VEC_(free)( VEC_T const * join ) {
     195     3000000 :   VEC_(private_t) const * vec = VEC_(private_const)( join );
     196     3000000 :   return vec->max - vec->cnt;
     197     3000000 : }
     198             : 
     199     3000000 : FD_FN_PURE static inline int VEC_(is_empty)( VEC_T const * join ) { return !VEC_(private_const)( join )->cnt; }
     200             : 
     201             : FD_FN_PURE static inline int
     202     3000000 : VEC_(is_full) ( VEC_T const * join ) {
     203     3000000 :   VEC_(private_t) const * vec = VEC_(private_const)( join );
     204     3000000 :   return vec->cnt==vec->max;
     205     3000000 : }
     206             : 
     207             : static inline VEC_T *
     208             : VEC_(expand)( VEC_T * join,
     209      749937 :               ulong   delta ) {
     210      749937 :   VEC_(private_t) * vec = VEC_(private)( join );
     211      749937 :   ulong cnt = vec->cnt;
     212      749937 :   vec->cnt = cnt + delta;
     213      749937 :   return join + cnt;
     214      749937 : }
     215             : 
     216             : static inline VEC_T *
     217             : VEC_(contract)( VEC_T * join,
     218      752100 :                 ulong   delta ) {
     219      752100 :   VEC_(private_t) * vec = VEC_(private)( join );
     220      752100 :   ulong cnt = vec->cnt - delta;
     221      752100 :   vec->cnt = cnt;
     222      752100 :   return join + cnt;
     223      752100 : }
     224             : 
     225             : static inline VEC_T *
     226             : VEC_(remove)( VEC_T * join,
     227      748614 :               ulong   idx ) {
     228      748614 :   VEC_(private_t) * vec = VEC_(private)( join );
     229      748614 :   ulong cnt = vec->cnt - 1UL;
     230      748614 :   join[idx] = join[cnt]; /* TODO: Consider letting user decide if self copy is cheaper than testing */
     231      748614 :   vec->cnt = cnt;
     232      748614 :   return join;
     233      748614 : }
     234             : 
     235             : static inline VEC_T *
     236             : VEC_(remove_compact)( VEC_T * join,
     237      749340 :                       ulong   idx ) {
     238      749340 :   VEC_(private_t) * vec = VEC_(private)( join );
     239      749340 :   ulong cnt = vec->cnt - 1UL;
     240   190835202 :   for( ; idx<cnt; idx++ ) join[idx] = join[idx+1UL];
     241      749340 :   vec->cnt = cnt;
     242      749340 :   return join;
     243      749340 : }
     244             : 
     245             : #undef VEC_
     246             : 
     247             : #undef VEC_T
     248             : #undef VEC_NAME
     249             : 

Generated by: LCOV version 1.14