LCOV - code coverage report
Current view: top level - waltz/h2 - fd_h2_rbuf.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 131 150 87.3 %
Date: 2026-04-01 06:30:45 Functions: 46 204 22.5 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_waltz_h2_fd_h2_rbuf_h
       2             : #define HEADER_fd_src_waltz_h2_fd_h2_rbuf_h
       3             : 
       4             : /* fd_h2_rbuf.h provides a byte oriented unaligend ring buffer. */
       5             : 
       6             : #include "fd_h2_base.h"
       7             : #include "../../util/log/fd_log.h"
       8             : 
       9             : struct fd_h2_rbuf {
      10             :   uchar * buf0;    /* points to first byte of buffer */
      11             :   uchar * buf1;    /* points one past last byte of buffer */
      12             :   uchar * lo;      /* in [buf0,buf1) */
      13             :   uchar * hi;      /* in [buf0,buf1) */
      14             :   ulong   lo_off;
      15             :   ulong   hi_off;
      16             :   ulong   bufsz;
      17             : };
      18             : 
      19             : FD_PROTOTYPES_BEGIN
      20             : 
      21             : /* fd_h2_rbuf_init initializes an h2_rbuf backed by the given buffer.
      22             :    On return, h2_rbuf has a read-write interested in buf.  bufsz has no
      23             :    alignment requirements. */
      24             : 
      25             : static inline fd_h2_rbuf_t *
      26             : fd_h2_rbuf_init( fd_h2_rbuf_t * rbuf,
      27             :                  void *         buf,
      28         282 :                  ulong          bufsz ) {
      29         282 :   *rbuf = (fd_h2_rbuf_t) {
      30         282 :     .buf0  = (uchar *)buf,
      31         282 :     .buf1  = (uchar *)buf+bufsz,
      32         282 :     .lo    = (uchar *)buf,
      33         282 :     .hi    = (uchar *)buf,
      34         282 :     .bufsz = bufsz
      35         282 :   };
      36         282 :   return rbuf;
      37         282 : }
      38             : 
      39             : /* fd_h2_rbuf_used_sz returns the number of unconsumed bytes in rbuf. */
      40             : 
      41             : FD_FN_PURE static inline ulong
      42   500627163 : fd_h2_rbuf_used_sz( fd_h2_rbuf_t const * rbuf ) {
      43   500627163 :   return rbuf->hi_off - rbuf->lo_off;
      44   500627163 : }
      45             : 
      46             : /* fd_h2_rbuf_free_sz returns the number of bytes that can be appended
      47             :    using fd_h2_rbuf_push. */
      48             : 
      49             : FD_FN_PURE static inline ulong
      50   247502892 : fd_h2_rbuf_free_sz( fd_h2_rbuf_t const * rbuf ) {
      51   247502892 :   long used = (long)fd_h2_rbuf_used_sz( rbuf );
      52   247502892 :   return (ulong)fd_long_max( 0L, rbuf->buf1 - rbuf->buf0 - used );
      53   247502892 : }
      54             : 
      55             : /* fd_h2_rbuf_validate_private validates invariants of rbuf. */
      56             : static void
      57             : fd_h2_rbuf_validate_private( fd_h2_rbuf_t * rbuf );
      58             : 
      59             : /* fd_h2_rbuf_push appends a series of newly received bytes into rbuf.
      60             :    Returns chunk_sz.
      61             : 
      62             :    WARNING: The caller must not pass a chunk_sz larger than
      63             :    fd_h2_rbuf_free_sz bytes. */
      64             : 
      65             : static inline void
      66             : fd_h2_rbuf_push( fd_h2_rbuf_t * rbuf,
      67             :                  void const *   chunk,
      68     7502367 :                  ulong          chunk_sz ) {
      69             : #ifdef FD_H2_USE_HANDHOLDING
      70             :   FD_TEST( chunk_sz<=fd_h2_rbuf_free_sz( rbuf ) );
      71             : #endif
      72     7502367 :   uchar * buf0 = rbuf->buf0;
      73     7502367 :   uchar * buf1 = rbuf->buf1;
      74     7502367 :   uchar * lo   = rbuf->lo;
      75     7502367 :   uchar * hi   = rbuf->hi;
      76     7502367 :   rbuf->hi_off += chunk_sz;
      77             : 
      78     7502367 :   if( FD_UNLIKELY( hi+chunk_sz > rbuf->buf1 ) ) {
      79             :     /* Split copy */
      80     1774620 :     if( FD_UNLIKELY( lo>hi ) ) {
      81           0 :       FD_LOG_CRIT(( "rbuf overflow: buf_sz=%lu lo=%ld hi=%ld chunk_sz=%lu",
      82           0 :                     rbuf->bufsz, rbuf->lo-buf0, rbuf->hi-buf0, chunk_sz ));
      83           0 :     }
      84     1774620 :     ulong part1 = (ulong)( buf1-hi        );
      85     1774620 :     ulong part2 = (ulong)( chunk_sz-part1 );
      86     1774620 :     fd_memcpy( hi,                    chunk,         part1 );
      87     1774620 :     fd_memcpy( buf0, (void *)( (ulong)chunk+part1 ), part2 );
      88     1774620 :     rbuf->hi = buf0+part2;
      89     1774620 :     fd_h2_rbuf_validate_private( rbuf );
      90     1774620 :     return;
      91     1774620 :   }
      92             : 
      93             :   /* One-shot copy */
      94     5727747 :   uchar * new_hi = hi+chunk_sz;
      95     5727747 :   if( new_hi==buf1 ) new_hi = buf0;
      96     5727747 :   fd_memcpy( hi, chunk, chunk_sz );
      97     5727747 :   rbuf->hi = new_hi;
      98     5727747 :   fd_h2_rbuf_validate_private( rbuf );
      99     5727747 :   return;
     100     7502367 : }
     101             : 
     102             : /* fd_h2_rbuf_peek_used returns a pointer to the first contiguous
     103             :    fragment of unconsumed data.  *sz is set to the number of contiguous
     104             :    bytes starting at rbuf->lo.  *split_sz is set to the number of bytes
     105             :    that are unconsumed, but in a separate fragment.  The caller may
     106             :    mangle bytes in [retval,retval+sz) if it consumes these bytes
     107             :    immediately afterwards. */
     108             : 
     109             : static inline uchar *
     110             : fd_h2_rbuf_peek_used( fd_h2_rbuf_t * rbuf,
     111             :                       ulong *        sz,
     112    73123704 :                       ulong *        split_sz ) {
     113    73123704 :   ulong used_sz = fd_h2_rbuf_used_sz( rbuf );
     114    73123704 :   uchar * buf0 = rbuf->buf0;
     115    73123704 :   uchar * buf1 = rbuf->buf1;
     116    73123704 :   uchar * lo   = rbuf->lo;
     117    73123704 :   uchar * hi   = rbuf->hi;
     118    73123704 :   uchar * end  = lo+used_sz;
     119             :   /* FIXME make this branchless */
     120    73123704 :   if( end<=buf1 ) {
     121    37615812 :     *sz       = (ulong)( used_sz );
     122    37615812 :     *split_sz = 0UL;
     123    37615812 :   } else {
     124    35507892 :     *sz       = (ulong)( buf1 - lo   );
     125    35507892 :     *split_sz = (ulong)( hi   - buf0 );
     126    35507892 :   }
     127    73123704 :   return lo;
     128    73123704 : }
     129             : 
     130             : /* fd_h2_rbuf_peek_free is like fd_h2_rbuf_peek_used, but refers to the
     131             :    free region. */
     132             : 
     133             : static inline uchar *
     134             : fd_h2_rbuf_peek_free( fd_h2_rbuf_t * rbuf,
     135             :                       ulong *        sz,
     136    60000018 :                       ulong *        split_sz ) {
     137    60000018 :   ulong free_sz = fd_h2_rbuf_free_sz( rbuf );
     138    60000018 :   uchar * buf0 = rbuf->buf0;
     139    60000018 :   uchar * buf1 = rbuf->buf1;
     140    60000018 :   uchar * lo   = rbuf->lo;
     141    60000018 :   uchar * hi   = rbuf->hi;
     142    60000018 :   uchar * end  = hi+free_sz;
     143             :   /* FIXME make this branchless */
     144    60000018 :   if( end<=buf1 ) {
     145    30880788 :     *sz       = (ulong)( free_sz );
     146    30880788 :     *split_sz = 0UL;
     147    30880788 :   } else {
     148    29119230 :     *sz       = (ulong)( buf1 - hi );
     149    29119230 :     *split_sz = (ulong)( lo - buf0 );
     150    29119230 :   }
     151    60000018 :   return hi;
     152    60000018 : }
     153             : 
     154             : /* fd_h2_rbuf_skip frees n bytes from rbuf.  Freeing more bytes than
     155             :    returned by fd_h2_rbuf_used_sz corrupts the buffer state. */
     156             : 
     157             : static inline void
     158             : fd_h2_rbuf_skip( fd_h2_rbuf_t * rbuf,
     159    13123764 :                  ulong          n ) {
     160    13123764 :   uchar * lo    = rbuf->lo;
     161    13123764 :   ulong   bufsz = rbuf->bufsz;
     162    13123764 :   uchar * buf1  = rbuf->buf1;
     163    13123764 :   rbuf->lo_off += n;
     164    13123764 :   lo += n;
     165    13123764 :   if( FD_UNLIKELY( lo>=buf1 ) ) {
     166     3284448 :     lo -= bufsz;
     167     3284448 :   }
     168    13123764 :   rbuf->lo = lo;
     169    13123764 :   fd_h2_rbuf_validate_private( rbuf );
     170    13123764 : }
     171             : 
     172             : /* fd_h2_rbuf_alloc marks the next n free bytes as used. */
     173             : 
     174             : static inline void
     175             : fd_h2_rbuf_alloc( fd_h2_rbuf_t * rbuf,
     176           0 :                    ulong          n ) {
     177           0 :   uchar * hi    = rbuf->hi;
     178           0 :   ulong   bufsz = rbuf->bufsz;
     179           0 :   uchar * buf1  = rbuf->buf1;
     180           0 :   rbuf->hi_off += n;
     181           0 :   hi += n;
     182           0 :   if( FD_UNLIKELY( hi>=buf1 ) ) {
     183           0 :     hi -= bufsz;
     184           0 :   }
     185           0 :   rbuf->hi = hi;
     186           0 :   fd_h2_rbuf_validate_private( rbuf );
     187           0 : }
     188             : 
     189             : /* fd_h2_rbuf_pop consumes n bytes from rbuf.  n is the number of bytes
     190             :    to consume.  n is assumed to be <= fd_h2_rbuf_used(rbuf).  scratch
     191             :    points to scratch memory with space for n bytes.
     192             : 
     193             :    If the bytes are available contiguously in rbuf, returns a pointer to
     194             :    them.  Otherwise, the bytes are copied into scratch.  The returned
     195             :    pointer is valid until the next mutating rbuf operation. */
     196             : 
     197             : static inline uchar *
     198             : fd_h2_rbuf_pop( fd_h2_rbuf_t * rbuf,
     199             :                 uchar *        scratch,
     200     1872021 :                 ulong          n ) {
     201             : #ifdef FD_H2_USE_HANDHOLDING
     202             :   FD_TEST( n<=fd_h2_rbuf_used_sz( rbuf ) );
     203             : #endif
     204     1872021 :   uchar * lo    = rbuf->lo;
     205     1872021 :   uchar * buf0  = rbuf->buf0;
     206     1872021 :   uchar * buf1  = rbuf->buf1;
     207     1872021 :   ulong   bufsz = rbuf->bufsz;
     208     1872021 :   uchar * ret   = lo;
     209     1872021 :   rbuf->lo_off += n;
     210     1872021 :   uchar * end = lo+n;
     211     1872021 :   if( FD_UNLIKELY( (lo+n)>=buf1 ) ) {
     212      466122 :     end -= bufsz;
     213      466122 :   }
     214     1872021 :   if( FD_UNLIKELY( (lo+n)>buf1 ) ) {
     215      441582 :     ulong part0 = (ulong)( buf1-lo );
     216      441582 :     ulong part1 = n-part0;
     217      441582 :     fd_memcpy( scratch,       lo,   part0 );
     218      441582 :     fd_memcpy( scratch+part0, buf0, part1 );
     219      441582 :     ret = scratch;
     220      441582 :   }
     221     1872021 :   rbuf->lo = end;
     222     1872021 :   fd_h2_rbuf_validate_private( rbuf );
     223     1872021 :   return ret;
     224     1872021 : }
     225             : 
     226             : static inline void
     227             : fd_h2_rbuf_pop_copy( fd_h2_rbuf_t * rbuf,
     228             :                      void *         out,
     229         186 :                      ulong          n ) {
     230             : #ifdef FD_H2_USE_HANDHOLDING
     231             :   FD_TEST( n<=fd_h2_rbuf_used_sz( rbuf ) );
     232             : #endif
     233         186 :   uchar * lo    = rbuf->lo;
     234         186 :   uchar * buf0  = rbuf->buf0;
     235         186 :   uchar * buf1  = rbuf->buf1;
     236         186 :   ulong   bufsz = rbuf->bufsz;
     237         186 :   rbuf->lo_off += n;
     238         186 :   uchar * end = lo+n;
     239         186 :   if( FD_UNLIKELY( (lo+n)>=buf1 ) ) {
     240           3 :     end -= bufsz;
     241           3 :   }
     242         186 :   if( FD_UNLIKELY( (lo+n)>buf1 ) ) {
     243           0 :     ulong part0 = (ulong)( buf1-lo );
     244           0 :     ulong part1 = n-part0;
     245           0 :     fd_memcpy(                  out,         lo,   part0 );
     246           0 :     fd_memcpy( (void *)( (ulong)out+part0 ), buf0, part1 );
     247         186 :   } else {
     248         186 :     fd_memcpy( out, lo, n );
     249         186 :   }
     250         186 :   rbuf->lo = end;
     251         186 :   fd_h2_rbuf_validate_private( rbuf );
     252         186 : }
     253             : 
     254             : FD_FN_PURE static inline int
     255         108 : fd_h2_rbuf_is_empty( fd_h2_rbuf_t const * rbuf ) {
     256         108 :   return rbuf->lo_off==rbuf->hi_off;
     257         108 : }
     258             : 
     259             : static void
     260    22498338 : fd_h2_rbuf_validate_private( fd_h2_rbuf_t * rbuf ) {
     261    22498338 : #ifndef FD_H2_USE_HANDHOLDING
     262    22498338 :   (void)rbuf;
     263    22498338 : #endif
     264             : #ifdef FD_H2_USE_HANDHOLDING
     265             :   ulong used = fd_h2_rbuf_used_sz( rbuf );
     266             :   ulong free = fd_h2_rbuf_free_sz( rbuf );
     267             : 
     268             :   if( !( used <= rbuf->bufsz ) ) {
     269             :     FD_LOG_NOTICE(( "used <= rbuf->bufsz failed: rbuf %p used %lu free %lu bufsz %lu", (void *)rbuf, used, free, rbuf->bufsz ));
     270             :   }
     271             :   if( !( free <= rbuf->bufsz ) ) {
     272             :     FD_LOG_NOTICE(( "free <= rbuf->bufsz failed: rbuf %p used %lu free %lu bufsz %lu", (void *)rbuf, used, free, rbuf->bufsz ));
     273             :   }
     274             :   if( !( used + free == rbuf->bufsz ) ) {
     275             :     FD_LOG_NOTICE(( "used + free == rbuf->bufsz failed: rbuf %p used %lu free %lu bufsz %lu", (void *)rbuf, used, free, rbuf->bufsz ));
     276             :   }
     277             :   FD_TEST( used <= rbuf->bufsz );
     278             :   FD_TEST( free <= rbuf->bufsz );
     279             :   FD_TEST( used + free == rbuf->bufsz );
     280             : 
     281             :   ulong used0, used1;
     282             :   uchar * used_p = fd_h2_rbuf_peek_used( rbuf, &used0, &used1 );
     283             :   FD_TEST( used_p == rbuf->lo );
     284             :   FD_TEST( used0 + used1 == used );
     285             : 
     286             :   ulong free0, free1;
     287             :   uchar * free_p = fd_h2_rbuf_peek_free( rbuf, &free0, &free1 );
     288             :   FD_TEST( free_p == rbuf->hi );
     289             :   FD_TEST( free0 + free1 == free );
     290             : #endif /* FD_H2_USE_HANDHOLDING */
     291    22498338 : }
     292             : 
     293             : FD_PROTOTYPES_END
     294             : 
     295             : #endif /* HEADER_fd_src_waltz_h2_fd_h2_rbuf_h */

Generated by: LCOV version 1.14