LCOV - code coverage report
Current view: top level - flamenco/types - fd_bincode.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 99 305 32.5 %
Date: 2025-12-21 05:09:38 Functions: 17 15570 0.1 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_types_fd_bincode_h
       2             : #define HEADER_fd_src_flamenco_types_fd_bincode_h
       3             : 
       4             : #include "../../util/fd_util.h"
       5             : 
       6             : /* Context argument used for encoding */
       7             : struct fd_bincode_encode_ctx {
       8             :   /* Current position in data buffer */
       9             :   void * data;
      10             :   /* End of buffer */
      11             :   void * dataend;
      12             : };
      13             : typedef struct fd_bincode_encode_ctx fd_bincode_encode_ctx_t;
      14             : 
      15             : /* Context argument used for decoding */
      16             : struct fd_bincode_decode_ctx {
      17             :   /* Current position in data buffer */
      18             :   void const * data;
      19             :   /* End of buffer */
      20             :   void const * dataend;
      21             : };
      22             : typedef struct fd_bincode_decode_ctx fd_bincode_decode_ctx_t;
      23             : 
      24       53889 : #define FD_BINCODE_SUCCESS         (    0)
      25           0 : #define FD_BINCODE_ERR_UNDERFLOW   (-1001) /* Attempted to read past end of buffer */
      26           6 : #define FD_BINCODE_ERR_OVERFLOW    (-1002) /* Attempted to write past end of buffer */
      27           0 : #define FD_BINCODE_ERR_ENCODING    (-1003) /* Invalid encoding */
      28             : 
      29             : #define FD_BINCODE_PRIMITIVE_STUBS( name, type ) \
      30             :   static inline int \
      31             :   fd_bincode_##name##_decode( type *                    self, \
      32         504 :                               fd_bincode_decode_ctx_t * ctx ) { \
      33         504 :     uchar const * ptr = (uchar const *) ctx->data; \
      34         504 :     if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
      35         504 :       return FD_BINCODE_ERR_UNDERFLOW; \
      36         504 :     memcpy( self, ptr, sizeof(type) );  /* unaligned */ \
      37         504 :     ctx->data = ptr + sizeof(type); \
      38         504 :     return FD_BINCODE_SUCCESS; \
      39         504 :   } \
      40             :   static inline int \
      41       49206 :   fd_bincode_##name##_decode_footprint( fd_bincode_decode_ctx_t * ctx ) { \
      42       49206 :     uchar const * ptr = (uchar const *) ctx->data; \
      43       49206 :     if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
      44       49206 :       return FD_BINCODE_ERR_UNDERFLOW; \
      45       49206 :     ctx->data = ptr + sizeof(type); \
      46       49206 :     return FD_BINCODE_SUCCESS; \
      47       49206 :   } \
      48             :   static inline void \
      49             :   fd_bincode_##name##_decode_unsafe( type *                    self, \
      50       34551 :                                      fd_bincode_decode_ctx_t * ctx ) { \
      51       34551 :     uchar const * ptr = (uchar const *) ctx->data; \
      52       34551 :     memcpy( self, ptr, sizeof(type) );  /* unaligned */ \
      53       34551 :     ctx->data = ptr + sizeof(type); \
      54       34551 :   } \
      55             :   static inline int \
      56             :   fd_bincode_##name##_encode( type                      self, \
      57        1752 :                               fd_bincode_encode_ctx_t * ctx ) { \
      58        1752 :     uchar * ptr = (uchar *)ctx->data; \
      59        1752 :     if ( FD_UNLIKELY((void *)(ptr + sizeof(type)) > ctx->dataend ) ) \
      60        1752 :       return FD_BINCODE_ERR_OVERFLOW; \
      61        1752 :     memcpy( ptr, &self, sizeof(type) );  /* unaligned */ \
      62        1749 :     ctx->data = ptr + sizeof(type); \
      63        1749 :     return FD_BINCODE_SUCCESS; \
      64        1752 :   }
      65             : 
      66             : /* fd_w_u128 is a wrapped "uint128" type providing basic 128-bit
      67             :    unsigned int functionality to fd_types, even if the compile target
      68             :    does not natively support uint128. */
      69             : 
      70             : union __attribute__((aligned(16))) fd_w_u128 {
      71             :   uchar   uc[16];
      72             :   ulong   ul[2];
      73             : # if FD_HAS_INT128
      74             :   uint128 ud;
      75             : # endif
      76             : };
      77             : 
      78             : typedef union fd_w_u128 fd_w_u128_t;
      79             : 
      80             : FD_BINCODE_PRIMITIVE_STUBS( uint8,   uchar       )
      81             : FD_BINCODE_PRIMITIVE_STUBS( uint16,  ushort      )
      82             : FD_BINCODE_PRIMITIVE_STUBS( uint32,  uint        )
      83             : FD_BINCODE_PRIMITIVE_STUBS( uint64,  ulong       )
      84             : FD_BINCODE_PRIMITIVE_STUBS( int64,   long        )
      85             : FD_BINCODE_PRIMITIVE_STUBS( uint128, fd_w_u128_t )
      86             : FD_BINCODE_PRIMITIVE_STUBS( double,  double      )
      87             : 
      88             : static inline int
      89             : fd_bincode_bool_decode( uchar *                   self,
      90           3 :                         fd_bincode_decode_ctx_t * ctx ) {
      91             : 
      92           3 :   uchar const * ptr = (uchar const *)ctx->data;
      93           3 :   if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
      94           0 :     return FD_BINCODE_ERR_UNDERFLOW;
      95             : 
      96           3 :   if( FD_UNLIKELY( *ptr & (~1U) ) )
      97           0 :     return FD_BINCODE_ERR_ENCODING;
      98             : 
      99           3 :   *self = *ptr;
     100           3 :   ctx->data = ptr + 1;
     101             : 
     102           3 :   return FD_BINCODE_SUCCESS;
     103           3 : }
     104             : 
     105             : static inline int
     106           6 : fd_bincode_bool_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
     107             : 
     108           6 :   uchar const * ptr = (uchar const *)ctx->data;
     109           6 :   if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
     110           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     111             : 
     112           6 :   if( FD_UNLIKELY( *ptr & (~1U) ) )
     113           0 :     return FD_BINCODE_ERR_ENCODING;
     114             : 
     115           6 :   ctx->data = ptr + 1;
     116             : 
     117           6 :   return FD_BINCODE_SUCCESS;
     118           6 : }
     119             : 
     120             : static inline void
     121             : fd_bincode_bool_decode_unsafe( uchar *                   self,
     122           0 :                                fd_bincode_decode_ctx_t * ctx ) {
     123           0 :   fd_bincode_uint8_decode_unsafe( self, ctx );
     124           0 : }
     125             : 
     126             : static inline int
     127             : fd_bincode_bool_encode( uchar                     self,
     128         195 :                         fd_bincode_encode_ctx_t * ctx ) {
     129             : 
     130         195 :   uchar * ptr = (uchar *)ctx->data;
     131         195 :   if ( FD_UNLIKELY( (void *)(ptr + 1) > ctx->dataend ) )
     132           0 :     return FD_BINCODE_ERR_OVERFLOW;
     133             : 
     134         195 :   *ptr = !!self;
     135         195 :   ctx->data = ptr + 1;
     136             : 
     137         195 :   return FD_BINCODE_SUCCESS;
     138         195 : }
     139             : 
     140             : static inline int
     141             : fd_bincode_bytes_decode( uchar *                   self,
     142             :                          ulong                     len,
     143           0 :                          fd_bincode_decode_ctx_t * ctx ) {
     144           0 :   uchar * ptr = (uchar *) ctx->data;
     145           0 :   if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) // Get wrap-around case right
     146           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     147           0 : 
     148           0 :   fd_memcpy(self, ptr, len);
     149           0 :   ctx->data = ptr + len;
     150           0 : 
     151           0 :   return FD_BINCODE_SUCCESS;
     152           0 : }
     153             : 
     154             : static inline int
     155             : fd_bincode_bytes_decode_footprint( ulong                     len,
     156         462 :                                    fd_bincode_decode_ctx_t * ctx ) {
     157         462 :   uchar * ptr = (uchar *) ctx->data;
     158         462 :   if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) { // Get wrap-around case right
     159           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     160           0 :   }
     161             : 
     162         462 :   ctx->data = ptr + len;
     163             : 
     164         462 :   return FD_BINCODE_SUCCESS;
     165         462 : }
     166             : 
     167             : static inline void
     168             : fd_bincode_bytes_decode_unsafe( uchar *                   self,
     169             :                                 ulong                     len,
     170       33975 :                                 fd_bincode_decode_ctx_t * ctx ) {
     171       33975 :   uchar * ptr = (uchar *) ctx->data;
     172       33975 :   fd_memcpy(self, ptr, len);
     173       33975 :   ctx->data = ptr + len;
     174       33975 : }
     175             : 
     176             : static inline int
     177             : fd_bincode_bytes_encode( uchar const *             self,
     178             :                          ulong                     len,
     179         786 :                          fd_bincode_encode_ctx_t * ctx ) {
     180         786 :   fd_msan_check( self, len );
     181             : 
     182         786 :   uchar * ptr = (uchar *)ctx->data;
     183         786 :   if( FD_UNLIKELY( (void *)( ptr+len ) > ctx->dataend ) )
     184           0 :     return FD_BINCODE_ERR_OVERFLOW;
     185             : 
     186         786 :   fd_memcpy( ptr, self, len );
     187         786 :   ctx->data = ptr + len;
     188             : 
     189         786 :   return FD_BINCODE_SUCCESS;
     190         786 : }
     191             : 
     192             : /* Alternate versions of fd_cu16_dec to make the function signature more consistent with the
     193             :    other fd_bincode_decode functions.  */
     194             : static inline int
     195             : fd_bincode_compact_u16_decode( ushort *                  self,
     196           0 :                                fd_bincode_decode_ctx_t * ctx ) {
     197           0 :   const uchar * ptr = (const uchar*) ctx->data;
     198           0 :   if( FD_UNLIKELY( ptr==NULL ) ) {
     199           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     200           0 :   }
     201             : 
     202           0 :   if( FD_LIKELY( (void *) (ptr + 1) <= ctx->dataend && !(0x80U & ptr[0]) ) ) {
     203           0 :     *self = (ushort)ptr[0];
     204           0 :     ctx->data = ptr + 1;
     205           0 :     return FD_BINCODE_SUCCESS;
     206           0 :   }
     207             : 
     208           0 :   if( FD_LIKELY( (void *) (ptr + 2) <= ctx->dataend && !(0x80U & ptr[1]) ) ) {
     209           0 :     if( FD_UNLIKELY( !ptr[1] ) ) /* Detect non-minimal encoding */
     210           0 :       return FD_BINCODE_ERR_ENCODING;
     211           0 :     *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
     212           0 :     ctx->data = ptr + 2;
     213           0 :     return FD_BINCODE_SUCCESS;
     214           0 :   }
     215             : 
     216           0 :   if( FD_LIKELY( (void *) (ptr + 3) <= ctx->dataend && !(0xFCU & ptr[2]) ) ) {
     217           0 :     if( FD_UNLIKELY( !ptr[2] ) ) /* Detect non-minimal encoding */
     218           0 :       return FD_BINCODE_ERR_ENCODING;
     219           0 :     *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
     220           0 :     ctx->data = ptr + 3;
     221           0 :     return FD_BINCODE_SUCCESS;
     222           0 :   }
     223             : 
     224           0 :   return FD_BINCODE_ERR_UNDERFLOW;
     225           0 : }
     226             : 
     227             : static inline void
     228             : fd_bincode_compact_u16_decode_unsafe( ushort *                  self,
     229           0 :                                       fd_bincode_decode_ctx_t * ctx ) {
     230           0 :   const uchar * ptr = (const uchar*) ctx->data;
     231             : 
     232           0 :   if( !(0x80U & ptr[0]) ) {
     233           0 :     *self = (ushort)ptr[0];
     234           0 :     ctx->data = ptr + 1;
     235           0 :     return;
     236           0 :   }
     237             : 
     238           0 :   if( !(0x80U & ptr[1]) ) {
     239           0 :     *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
     240           0 :     ctx->data = ptr + 2;
     241           0 :     return;
     242           0 :   }
     243             : 
     244           0 :   *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
     245           0 :   ctx->data = ptr + 3;
     246           0 : }
     247             : 
     248             : static inline int
     249             : fd_bincode_compact_u16_encode( ushort const *            self,
     250          12 :                                fd_bincode_encode_ctx_t * ctx ) {
     251          12 :   uchar * ptr = (uchar*) ctx->data;
     252          12 :   ulong val = *self;
     253             : 
     254          12 :   if ( val < 0x80UL ) {
     255          12 :     if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
     256           0 :       return FD_BINCODE_ERR_OVERFLOW;
     257          12 :     *ptr = (uchar)val;
     258          12 :     ctx->data = ptr + 1;
     259          12 :     return FD_BINCODE_SUCCESS;
     260          12 :   }
     261             : 
     262           0 :   else if ( val < 0x4000UL ) {
     263           0 :     if ( FD_UNLIKELY((void *) (ptr + 2) > ctx->dataend ) )
     264           0 :       return FD_BINCODE_ERR_OVERFLOW;
     265           0 :     ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
     266           0 :     ptr[1] = (uchar)(val>>7);
     267           0 :     ctx->data = ptr + 2;
     268           0 :     return FD_BINCODE_SUCCESS;
     269           0 :   }
     270             : 
     271           0 :   else {
     272           0 :     if ( FD_UNLIKELY((void *) (ptr + 3) > ctx->dataend ) )
     273           0 :       return FD_BINCODE_ERR_OVERFLOW;
     274           0 :     ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
     275           0 :     ptr[1] = (uchar)(((val>>7)&0x7FUL)|0x80UL);
     276           0 :     ptr[2] = (uchar)(val>>14);
     277           0 :     ctx->data = ptr + 3;
     278           0 :     return FD_BINCODE_SUCCESS;
     279           0 :   }
     280          12 : }
     281             : 
     282             : static inline ulong
     283           0 : fd_bincode_compact_u16_size( ushort const * self ) {
     284           0 :   ulong val = *self;
     285             : 
     286           0 :   if ( val < 0x80UL ) {
     287           0 :     return 1;
     288           0 :   }
     289           0 :   else if ( val < 0x4000UL ) {
     290           0 :     return 2;
     291           0 :   }
     292           0 :   else {
     293           0 :     return 3;
     294           0 :   }
     295           0 : }
     296             : 
     297             : /* Decodes an integer encoded using the serde_varint algorithm:
     298             :    https://github.com/solana-labs/solana/blob/master/sdk/program/src/serde_varint.rs
     299             : 
     300             :    A variable number of bytes could have been used to encode the integer.
     301             :    The most significant bit of each byte indicates if more bytes have been used, so we keep consuming until
     302             :    we reach a byte where the most significant bit is 0.
     303             : */
     304             : static inline int
     305             : fd_bincode_varint_decode( ulong *                   self,
     306           0 :                           fd_bincode_decode_ctx_t * ctx ) {
     307           0 :   ulong out   = 0UL;
     308           0 :   uint  shift = 0U;
     309           0 : 
     310           0 :   while( FD_LIKELY( shift < 64U ) ) {
     311           0 : 
     312           0 :     if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
     313           0 :       return FD_BINCODE_ERR_UNDERFLOW;
     314           0 : 
     315           0 :     uint byte = *(uchar const *)ctx->data;
     316           0 :     ctx->data = (uchar const *)ctx->data + 1;
     317           0 :     out |= (byte & 0x7FUL) << shift;
     318           0 : 
     319           0 :     if( (byte & 0x80U) == 0U ) {
     320           0 :       if( (out>>shift) != byte )
     321           0 :         return FD_BINCODE_ERR_ENCODING;
     322           0 :       if( byte==0U && (shift!=0U || out!=0UL) )
     323           0 :         return FD_BINCODE_ERR_ENCODING;
     324           0 :       *self = out;
     325           0 :       return FD_BINCODE_SUCCESS;
     326           0 :     }
     327           0 : 
     328           0 :     shift += 7U;
     329           0 : 
     330           0 :   }
     331           0 : 
     332           0 :   return FD_BINCODE_ERR_ENCODING;
     333           0 : }
     334             : 
     335             : static inline int
     336           0 : fd_bincode_varint_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
     337           0 :   ulong out   = 0UL;
     338           0 :   uint  shift = 0U;
     339             : 
     340           0 :   while( FD_LIKELY( shift < 64U ) ) {
     341             : 
     342           0 :     if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
     343           0 :       return FD_BINCODE_ERR_UNDERFLOW;
     344             : 
     345           0 :     uint byte = *(uchar const *)ctx->data;
     346           0 :     ctx->data = (uchar const *)ctx->data + 1;
     347           0 :     out |= (byte & 0x7FUL) << shift;
     348             : 
     349           0 :     if( (byte & 0x80U) == 0U ) {
     350           0 :       if( (out>>shift) != byte )
     351           0 :         return FD_BINCODE_ERR_ENCODING;
     352           0 :       if( byte==0U && (shift!=0U || out!=0UL) )
     353           0 :         return FD_BINCODE_ERR_ENCODING;
     354           0 :       return FD_BINCODE_SUCCESS;
     355           0 :     }
     356             : 
     357           0 :     shift += 7U;
     358             : 
     359           0 :   }
     360             : 
     361           0 :   return FD_BINCODE_ERR_ENCODING;
     362           0 : }
     363             : 
     364             : static inline void
     365             : fd_bincode_varint_decode_unsafe( ulong *                   self,
     366           0 :                                  fd_bincode_decode_ctx_t * ctx ) {
     367           0 :   ulong out   = 0UL;
     368           0 :   uint  shift = 0U;
     369             : 
     370           0 :   for(;;) {
     371           0 :     uint byte = *(uchar const *)ctx->data;
     372           0 :     ctx->data = (uchar const *)ctx->data + 1;
     373           0 :     out |= (byte & 0x7FUL) << shift;
     374             : 
     375           0 :     if( (byte & 0x80U) == 0U ) {
     376           0 :       *self = out;
     377           0 :       return;
     378           0 :     }
     379             : 
     380           0 :     shift += 7U;
     381           0 :   }
     382           0 : }
     383             : 
     384             : static inline int
     385             : fd_bincode_varint_encode( ulong                     val,
     386           0 :                           fd_bincode_encode_ctx_t * ctx ) {
     387           0 :   uchar * ptr = (uchar *) ctx->data;
     388           0 :   while (1) {
     389           0 :     if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
     390           0 :       return FD_BINCODE_ERR_OVERFLOW;
     391           0 :     if ( val < 0x80UL ) {
     392           0 :       *(ptr++) = (uchar)val;
     393           0 :       ctx->data = ptr;
     394           0 :       return FD_BINCODE_SUCCESS;
     395           0 :     }
     396           0 :     *(ptr++) = (uchar)((val&0x7FUL)|0x80UL);
     397           0 :     val >>= 7;
     398           0 :   }
     399           0 : }
     400             : 
     401             : static inline ulong
     402           0 : fd_bincode_varint_size( ulong val ) {
     403           0 :   ulong sz = 0;
     404           0 :   while (1) {
     405           0 :     if ( val < 0x80UL ) {
     406           0 :       return sz+1;
     407           0 :     }
     408           0 :     sz++;
     409           0 :     val >>= 7;
     410           0 :   }
     411           0 : }
     412             : 
     413             : /* Convenience API for deserializing with common allocators */
     414             : 
     415             : /* fd_bincode_decode_spad decodes a bincode type.  The result is
     416             :    allocated into a spad on success.  On failure, no spad allocations
     417             :    are made.
     418             : 
     419             :    fd_bincode_decode1_spad optionally outputs the number of bytes read
     420             :    to *psz. */
     421             : 
     422             : #define fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, psz )  \
     423           0 :   __extension__({                                                      \
     424           0 :     fd_spad_t *  const spad_   = (spad);                               \
     425           0 :     void const * const buf_    = (buf);                                \
     426           0 :     ulong        const buf_sz_ = (buf_sz);                             \
     427           0 :     int *              perr_   = (perr);                               \
     428           0 :     ulong *            psz_    = (psz);                                \
     429           0 :     fd_bincode_decode_ctx_t ctx = {0};                                 \
     430           0 :     if( perr_ ) *perr_ = -1;                                           \
     431           0 :     ctx.data    = (void const *)( buf_ );                              \
     432           0 :     ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ );         \
     433           0 :     ulong total_sz = 0UL;                                              \
     434           0 :     int err = fd_##type##_decode_footprint( &ctx, &total_sz );         \
     435           0 :     fd_##type##_t * out = NULL;                                        \
     436           0 :     if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) {                       \
     437           0 :       ulong align = fd_##type##_align();                               \
     438           0 :       void * mem = fd_spad_alloc( spad_, align, total_sz );            \
     439           0 :       if( FD_UNLIKELY( !mem ) ) {                                      \
     440           0 :         FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in spad)", align-1UL, total_sz, fd_spad_mem_free( spad_ ) )); \
     441           0 :       }                                                                \
     442           0 :       out = fd_##type##_decode( mem, &ctx );                           \
     443           0 :       if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_;                \
     444           0 :     }                                                                  \
     445           0 :     if( perr_ ) *perr_ = err;                                          \
     446           0 :     out;                                                               \
     447           0 :   })
     448             : 
     449             : #define fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, psz )  \
     450             :   __extension__({                                                             \
     451             :     fd_spad_t *  const spad_   = (spad);                                      \
     452             :     void const * const buf_    = (buf);                                       \
     453             :     ulong        const buf_sz_ = (buf_sz);                                    \
     454             :     int *              perr_   = (perr);                                      \
     455             :     ulong *            psz_    = (psz);                                       \
     456             :     fd_bincode_decode_ctx_t ctx = {0};                                        \
     457             :     if( perr_ ) *perr_ = -1;                                                  \
     458             :     ctx.data    = (void const *)( buf_ );                                     \
     459             :     ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ );                \
     460             :     ulong total_sz = 0UL;                                                     \
     461             :     int err = fd_##type##_decode_footprint( &ctx, &total_sz );                \
     462             :     fd_##type##_global_t * out = NULL;                                        \
     463             :     if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) {                              \
     464             :       ulong align = fd_##type##_align();                                      \
     465             :       void * mem = fd_spad_alloc( spad_, align, total_sz );                   \
     466             :       if( FD_UNLIKELY( !mem ) ) {                                             \
     467             :         FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in spad)", align-1UL, total_sz, fd_spad_mem_free( spad_ ) )); \
     468             :       }                                                                       \
     469             :       out = fd_##type##_decode_global( mem, &ctx );                           \
     470             :       if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_;                       \
     471             :     }                                                                         \
     472             :     if( perr_ ) *perr_ = err;                                                 \
     473             :     out;                                                                      \
     474             :   })
     475             : 
     476             : #define fd_bincode_decode_spad( type, spad, buf, buf_sz, perr ) \
     477           0 :   fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, NULL )
     478             : 
     479             : #define fd_bincode_decode_spad_global( type, spad, buf, buf_sz, perr ) \
     480             :   fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, NULL )
     481             : 
     482             : /* fd_bincode_decode_scratch decodes a bincode type.  The result is
     483             :    allocated into the thread's scratch region on success.  On failure,
     484             :    no allocations are made. */
     485             : 
     486             : #define fd_bincode_decode1_scratch( type, buf, buf_sz, perr, psz )     \
     487             :   __extension__({                                                      \
     488             :     void const * const buf_    = (buf);                                \
     489             :     ulong        const buf_sz_ = (buf_sz);                             \
     490             :     int *              perr_   = (perr);                               \
     491             :     ulong *            psz_    = (psz);                                \
     492             :     fd_bincode_decode_ctx_t ctx = {0};                                 \
     493             :     if( perr_ ) *perr_ = -1;                                           \
     494             :     ctx.data    = (void const *)( buf_ );                              \
     495             :     ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ );         \
     496             :     ulong total_sz = 0UL;                                              \
     497             :     int err = fd_##type##_decode_footprint( &ctx, &total_sz );         \
     498             :     fd_##type##_t * out = NULL;                                        \
     499             :     if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) {                       \
     500             :       ulong align = fd_##type##_align();                               \
     501             :       if( FD_UNLIKELY( !fd_scratch_alloc_is_safe( align, total_sz ) ) ) { \
     502             :         FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in scratch region)", align-1UL, total_sz, fd_scratch_free() )); \
     503             :       }                                                                \
     504             :       void * mem = fd_scratch_alloc( align, total_sz );                \
     505             :       out = fd_##type##_decode( mem, &ctx );                           \
     506             :       if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_;                \
     507             :     }                                                                  \
     508             :     if( perr_ ) *perr_ = err;                                          \
     509             :     out;                                                               \
     510             :   })
     511             : 
     512             : #define fd_bincode_decode_scratch( type, buf, buf_sz, perr ) \
     513             :   fd_bincode_decode1_scratch( type, buf, buf_sz, perr, NULL )
     514             : 
     515             : /* fd_bincode_decode_static decodes a statically-sized bincode type.
     516             : 
     517             :    Example usage:
     518             : 
     519             :    fd_epoch_schedule_t es[1]; int err;
     520             :    if( FD_UNLIKELY( fd_bincode_decode_static( epoch_schedule, es, buf, bufsz, &err ) ) ) {
     521             :      ... parse fail ...
     522             :      return;
     523             :    }
     524             :    ... parse success ... */
     525             : 
     526             : #define fd_bincode_decode_static1( type, suffix, out, buf, buf_sz, perr ) \
     527          30 :   __extension__({                                                      \
     528          30 :     void const * const buf_    = (buf);                                \
     529          48 :     ulong        const buf_sz_ = (buf_sz);                             \
     530          30 :     int *              perr_   = (perr);                               \
     531          30 :     fd_##type##suffix##_t *    res     = NULL;                         \
     532          30 :     fd_bincode_decode_ctx_t ctx = {0};                                 \
     533          30 :     ctx.data    = (void const *)( buf_ );                              \
     534          30 :     ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ );         \
     535          30 :     ulong total_sz = 0UL;                                              \
     536          30 :     int err = fd_##type##_decode_footprint( &ctx, &total_sz );         \
     537          30 :     if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) {                       \
     538          30 :       res = fd_##type##_decode##suffix( (out), &ctx );                 \
     539          30 :     }                                                                  \
     540          30 :     if( perr_ ) *perr_ = err;                                          \
     541          30 :     res;                                                               \
     542          30 :   })
     543             : 
     544             : #define fd_bincode_decode_static( t,o,b,s,p ) \
     545          30 :   fd_bincode_decode_static1( t, , o, b, s, p )
     546             : 
     547             : #define fd_bincode_decode_static_global( t,o,b,s,p ) \
     548             :   fd_bincode_decode_static1( t, _global, o, b, s, p )
     549             : 
     550             : #define fd_bincode_decode_static_limited_deserialize( type, out, buf, buf_sz, limit, perr ) \
     551          24 :   fd_bincode_decode_static( type, out, buf, buf_sz>limit ? limit : buf_sz, perr )
     552             : 
     553             : #endif /* HEADER_fd_src_flamenco_types_fd_bincode_h */

Generated by: LCOV version 1.14