LCOV - code coverage report
Current view: top level - util/pod - fd_pod.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 205 222 92.3 %
Date: 2024-11-13 11:58:15 Functions: 92 32181 0.3 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_pod_fd_pod_h
       2             : #define HEADER_fd_src_pod_fd_pod_h
       3             : 
       4             : /* pod is a set of APIs for managing flexible hierarchies of typed
       5             :    key-val pairs.  A pod is a data structure for holds these in memory
       6             :    contiguously and compactly such that it can be easily saved to
       7             :    permanent storage, sent over networks, distributed between different
       8             :    hosts / architectures / address spaces.
       9             : 
      10             :    It is trivial to make a pod.
      11             : 
      12             :    It is trivial to query a pod.
      13             : 
      14             :    It is trivial to import different config file formats into a pod
      15             :    (including JSON, YAML, TOML, etc).
      16             : 
      17             :    It is trivial to serialize / deserialize / save / restore a pod.
      18             : 
      19             :    Multiple value types are supported with builtin coverage of all
      20             :    primitive datatypes.  In particular, a value itself can be a pod and
      21             :    it is easy to lookup deeply nested values in a pod via their key
      22             :    path.  (Essentially, a pod a simple in-memory file system.)
      23             : 
      24             :    As such pods are an incredible useful building blocks for dealing
      25             :    with heterogeneous distributed environment / configuration,
      26             :    checkpointing, etc.
      27             : 
      28             :    The current implementation of POD below assumes little endian
      29             :    architecture and that the platform can reasonably efficient access
      30             :    unaligned primitive types.  These restrictions can be removed if
      31             :    necessary.
      32             : 
      33             :    A pod starts with 3 svw (symmetric-variable-width) encoded ulongs:
      34             : 
      35             :    - max:  The max size of the pod in bytes (including the header)
      36             :    - used: The number of bytes currently used in the pod in bytes
      37             :            (including the header), <= max.
      38             :    - cnt:  The number of key-val pairs in the pod (a key-subpod pair is
      39             :            considered as a single pair from the header POV regardless of
      40             :            the number of keys the subpod might hold).  As a key val pair
      41             :            requires at least 1 byte to represent practically, this is
      42             :            <=used (and more typically << used).
      43             : 
      44             :    Since cnt<=used<=max, the svw encoded size of all these are bounded
      45             :    by the encoded max and we can thus use the same size encoding to
      46             :    facilitate fast operations on encoded headers.
      47             : 
      48             :    This header is followed by cnt key-val pairs.  A pair is represented
      49             :    in a pod as:
      50             : 
      51             :    - key_sz:   strlen(key)+1 to facilitate fast iteration and fast key
      52             :                string ops
      53             :    - key:      key_sz_bytes holds the key cstr, key does not contain a
      54             :                '.' (to facilitate recursive querying), does include the
      55             :                '\0' to facilitate zero-copy user operation /
      56             :                interoperability with standard cstr handling APIs
      57             :    - val_type: 1 byte, a FD_POD_VAL_TYPE_* for extensibility
      58             :    - val_sz:   number of bytes in the pod encoded representation of val
      59             :    - val:      val_sz bytes, interpreted as specified by val_type
      60             : 
      61             :    key_sz and val_sz are both svw encoded.  There are no theoretical
      62             :    restrictions (up to the size of a ulong) on the size of a key or a
      63             :    val. */
      64             : 
      65             : #include "../cstr/fd_cstr.h"
      66             : 
      67             : /* FD_POD_ERR_* gives a number of error codes used by fd_pod APIs. */
      68             : 
      69    43864311 : #define FD_POD_SUCCESS     ( 0) /* Operation was successful */
      70         171 : #define FD_POD_ERR_INVAL   (-1) /* Operation failed because input args were invalid */
      71     1430658 : #define FD_POD_ERR_TYPE    (-2) /* Operation failed because the path contained a key of an unexpected type */
      72     2515368 : #define FD_POD_ERR_RESOLVE (-3) /* Operation failed because the path did not resolve to a key */
      73        6027 : #define FD_POD_ERR_FULL    (-4) /* Operation failed because the pod did not have enough space to complete it */
      74             : 
      75             : /* FD_POD_VAL_TYPE_* gives a type of value stored in a pod key-val pair.
      76             :    These must be in [0,255].  Values in [16,127] are reserved for
      77             :    potentially additional primitive types.  Vales in [128,255] are
      78             :    reserved for user defined types. */
      79             : 
      80   768796590 : #define FD_POD_VAL_TYPE_SUBPOD  ( 0) /* Val is a RAW encoded pod */
      81       99756 : #define FD_POD_VAL_TYPE_BUF     ( 1) /* Val is a RAW encoded buffer */
      82    23125167 : #define FD_POD_VAL_TYPE_CSTR    ( 2) /* Val is a RAW encoded '\0'-terminated string */
      83       98835 : #define FD_POD_VAL_TYPE_CHAR    ( 3) /* Val is a RAW encoded   8-bit char (indeterminant sign) */
      84       99228 : #define FD_POD_VAL_TYPE_SCHAR   ( 4) /* Val is a RAW encoded   8-bit signed int (twos complement) */
      85       99186 : #define FD_POD_VAL_TYPE_SHORT   ( 5) /* Val is a SVW encoded  16-bit signed int (twos complement) */
      86       99453 : #define FD_POD_VAL_TYPE_INT     ( 6) /* Val is a SVW encoded  32-bit signed int (twos complement) */
      87       99522 : #define FD_POD_VAL_TYPE_LONG    ( 7) /* Val is a SVW encoded  64-bit signed int (twos complement) */
      88       99498 : #define FD_POD_VAL_TYPE_INT128  ( 8) /* Val is a SVW encoded 128-bit signed int (twos complement) */
      89      100659 : #define FD_POD_VAL_TYPE_UCHAR   ( 9) /* Val is a RAW encoded   8-bit unsigned int */
      90       99804 : #define FD_POD_VAL_TYPE_USHORT  (10) /* Val is a SVW encoded  16-bit unsigned int */
      91      100842 : #define FD_POD_VAL_TYPE_UINT    (11) /* Val is a SVW encoded  32-bit unsigned int */
      92      100074 : #define FD_POD_VAL_TYPE_ULONG   (12) /* Val is a SVW encoded  64-bit unsigned int */
      93       99021 : #define FD_POD_VAL_TYPE_UINT128 (13) /* Val is a SVW encoded 128-bit unsigned int */
      94      100758 : #define FD_POD_VAL_TYPE_FLOAT   (14) /* Val is a RAW IEEE-754 float  (little endian) */
      95       98511 : #define FD_POD_VAL_TYPE_DOUBLE  (15) /* Val is a RAW IEEE-754 double (little endian) */
      96             : 
      97             : /* FD_POD_VAL_TYPE_CSTR_MAX is the maximum number of bytes (including
      98             :    terminating '\0') required for hold the cstr representation of a
      99             :    value type. */
     100             : 
     101        1488 : #define FD_POD_VAL_TYPE_CSTR_MAX (8UL)
     102             : 
     103             : /* FD_POD_FOOTPRINT_MIN gives the minimum pod byte footprint possible */
     104             : 
     105     4125267 : #define FD_POD_FOOTPRINT_MIN (3UL)
     106             : 
     107             : /* A fd_pod_info_t is used when listing the contents of a pod.  It is
     108             :    not stored explicitly in the pod itself.  The lifetime guarantees of
     109             :    all pointers in an info is that of the pod itself or any invalidating
     110             :    operation on that pod. */
     111             : 
     112             : struct fd_pod_info;
     113             : typedef struct fd_pod_info fd_pod_info_t;
     114             : 
     115             : struct fd_pod_info {
     116             :   ulong           key_sz;   /* Size of key in pod (includes terminating '\0') */
     117             :   char const *    key;      /* Pointer to first byte of this pod key cstr */
     118             :   int             val_type; /* Type of val (in [0,255], a FD_POD_VAL_TYPE_*) */
     119             :   ulong           val_sz;   /* Size of val in bytes (pod encoded form) */
     120             :   void const *    val;      /* Pointer to first byte of val (in pod encoded form).  For a cstr type, if val_sz==0, ignore this and
     121             :                                treat as NULL (FIXME: CONSIDER HANDLING THIS UNDER THE HOOD?).  */
     122             :   fd_pod_info_t * parent;   /* For a recursive listing, NULL if the key is not in a subpod of the pod getting listed.  Otherwise,
     123             :                                points to an (earlier) info with details about the subpod.  For a non-recursive listing or query,
     124             :                                NULL. */
     125             : };
     126             : 
     127             : typedef struct fd_pod_info fd_pod_info_t;
     128             : 
     129             : /* FD_POD_{ALIGN,FOOTPRINT} return the alignment and footprint required
     130             :    for a memory region to be used as a pod.  ALIGN will 1 (no alignment
     131             :    requirements) and FOOTPRINT will be max.  Max is assumed to be at
     132             :    least FD_POD_FOOTPRINT_MIN.  These are provided to facilitate compile
     133             :    time construction and for consistency with other constructors. */
     134             : 
     135             : #define FD_POD_ALIGN            (1UL)
     136             : #define FD_POD_FOOTPRINT( max ) (max)
     137             : 
     138             : FD_PROTOTYPES_BEGIN
     139             : 
     140             : /* Constructors *******************************************************/
     141             : 
     142             : /* fd_pod_{align,footprint,new,join,leave,delete} are the distributed
     143             :    shared memory constructors for a pod and have the usual semantics.
     144             : 
     145             :    Note max is the number of bytes available for the whole pod.
     146             :    Further, there is no actual alignment requirement.  This allows
     147             :    flexibly storing pods into all sorts of places with arbitrary size
     148             :    and alignment constraints.
     149             : 
     150             :    The only practical constraint is a pod can not be squeezed into a
     151             :    region smaller than FD_POD_FOOTPRINT_MIN.  Note further that, from
     152             :    the point of view of distribution, a pod is just a bag of up to max
     153             :    bytes.  Only bytes [0,used) are needed to encode the exact state of
     154             :    pod.  Setting max==used effectively seals up a pod such that no more
     155             :    key-val pairs can be added to it. */
     156             : 
     157           0 : FD_FN_CONST static inline ulong fd_pod_align    ( void      ) { return 1UL; }
     158       30018 : FD_FN_CONST static inline ulong fd_pod_footprint( ulong max ) { return fd_ulong_if( max>=FD_POD_FOOTPRINT_MIN, max, 0UL ); }
     159             : 
     160             : static inline void *
     161             : fd_pod_new( void * shmem,
     162     4090323 :             ulong  max ) {
     163     4090323 :   if( FD_UNLIKELY( !shmem ) ) return NULL;
     164     4090323 :   ulong footprint = fd_pod_footprint( max );
     165     4090323 :   if( FD_UNLIKELY( !footprint ) ) return NULL;
     166     4090323 :   uchar * pod = (uchar *)shmem;
     167     4090323 :   ulong   csz = fd_ulong_svw_enc_sz( max );
     168     4090323 :   fd_ulong_svw_enc_fixed( pod,           csz, max     );
     169     4090323 :   fd_ulong_svw_enc_fixed( pod + csz,     csz, 3UL*csz ); /* used */
     170     4090323 :   fd_ulong_svw_enc_fixed( pod + csz*2UL, csz, 0UL     );
     171     4090323 :   return shmem;
     172     4090323 : }
     173             : 
     174     4090608 : static inline uchar * fd_pod_join  ( void        * shpod ) { return (uchar *)shpod; }
     175         393 : static inline void  * fd_pod_leave ( uchar const * pod   ) { return (void *)pod;    }
     176         108 : static inline void  * fd_pod_delete( void        * shpod ) { return shpod;          }
     177             : 
     178             : /* Accessors **********************************************************/
     179             : 
     180             : /* fd_pod_{max,used,cnt,avail} returns the maximum number of bytes /
     181             :    number of used bytes / number of keys / number of bytes available for
     182             :    storing key-val pairs in the pod.  Assumes pod is a current local
     183             :    join. */
     184             : 
     185             : FD_FN_PURE static inline ulong
     186   167725575 : fd_pod_max( uchar const * pod ) {
     187   167725575 :   ulong csz = fd_ulong_svw_dec_sz( pod );
     188   167725575 :   return fd_ulong_svw_dec_fixed( pod, csz );
     189   167725575 : }
     190             : 
     191             : FD_FN_PURE static inline ulong
     192        3048 : fd_pod_used( uchar const * pod ) {
     193        3048 :   ulong csz = fd_ulong_svw_dec_sz( pod );
     194        3048 :   return fd_ulong_svw_dec_fixed( pod + csz, csz );
     195        3048 : }
     196             : 
     197             : FD_FN_UNUSED FD_FN_PURE static ulong /* Work around -Winline */
     198      939672 : fd_pod_cnt( uchar const * pod ) {
     199      939672 :   ulong csz = fd_ulong_svw_dec_sz( pod );
     200      939672 :   return fd_ulong_svw_dec_fixed( pod + 2UL*csz, csz );
     201      939672 : }
     202             : 
     203             : FD_FN_UNUSED FD_FN_PURE static ulong /* Work around -Winline */
     204        3009 : fd_pod_avail( uchar const * pod ) {
     205        3009 :   ulong csz = fd_ulong_svw_dec_sz( pod );
     206        3009 :   return fd_ulong_svw_dec_fixed( pod, csz ) - fd_ulong_svw_dec_fixed( pod + csz, csz );
     207        3009 : }
     208             : 
     209             : /* fd_pod_list returns the details about the current key-val pairs in
     210             :    the pod.  info is indexed [0,fd_pod_cnt(pod)).  Does not recurse into
     211             :    any subpods in the pod.  E.g. for the pod:
     212             : 
     213             :      int foo 1
     214             :      pod bar {
     215             :        pod baz {
     216             :          int bay 2
     217             :          int bax 3
     218             :        }
     219             :        int baw 4
     220             :      }
     221             :      int bav 5
     222             : 
     223             :    list will return 3 key-val pairs:
     224             : 
     225             :      0: int foo 1       (no parent)
     226             :      1: pod bar { ... } (no parent)
     227             :      2: int bav 5       (no parent)
     228             : 
     229             :    Returns info.  The indices used for the current pairs will be stable
     230             :    for the pod's lifetime or the next invalidating operation.   Returns
     231             :    info on success and NULL on failure (i.e. pod is NULL). */
     232             : 
     233             : fd_pod_info_t *
     234             : fd_pod_list( uchar const   * FD_RESTRICT pod,
     235             :              fd_pod_info_t * FD_RESTRICT info );
     236             : 
     237             : /* fd_pod_cnt_subpod returns the number of subpods in the pod.  Does not
     238             :    recurse into any subpods in the pod.  E.g. for the above example,
     239             :    returns 1.  This operation is O(fd_pod_cnt(pod)) in pod.  NULL
     240             :    returns 0. */
     241             : 
     242             : FD_FN_PURE ulong
     243             : fd_pod_cnt_subpod( uchar const * pod );
     244             : 
     245             : /* fd_pod_list_recursive is the same as fd_pod_list but will depth-first
     246             :    recurse into subpods.  info is indexed [0,fd_pod_cnt_recursive(pod)).
     247             :    E.g. for the above example, list_recursive will return 7 key-val
     248             :    pairs:
     249             : 
     250             :      0: int foo 1       (no parent)
     251             :      1: pod bar { ... } (no parent)
     252             :      2: pod baz { ... } (parent bar)
     253             :      3: int bay 2       (parent baz)
     254             :      4: int bax 3       (parent baz)
     255             :      5: int baw 4       (parent bar)
     256             :      6: int bav 5       (no parent) */
     257             : 
     258             : FD_FN_PURE ulong
     259             : fd_pod_cnt_recursive( uchar const * pod );
     260             : 
     261             : fd_pod_info_t *
     262             : fd_pod_list_recursive( uchar const   * FD_RESTRICT pod,
     263             :                        fd_pod_info_t * FD_RESTRICT info );
     264             : 
     265             : /* fd_pod_query queries the pod for information about path.  Path is a
     266             :    cstr that consists of one or more keys delimited with a '.' such
     267             :    that, for example, the path:
     268             : 
     269             :      "foo.bar.baz"
     270             : 
     271             :    indicates the query should find the key foo in the pod, recurse into
     272             :    the foo's subpod val, find the key bar in the subpod, recurse in
     273             :    bar's subpod val and then find the key baz in the subsubpod and then
     274             :    extract information about baz as requested.  Returns 0 on success or
     275             :    a non-zero (FD_POD_ERR_*) error code on failure:
     276             : 
     277             :      SUCCESS - the query was successful.  If opt_info was non-NULL,
     278             :                *opt_info will contain details about the found key.
     279             :                See fd_pod_info_t for more details.
     280             :      INVAL   - bad input args (e.g. NULL pod and/or NULL path was NULL)
     281             :                opt_info ignored
     282             :      TYPE    - one of the path prefixes resolved to a non-subpod
     283             :                (e.g. "foo.bar" doesn't refer to a subpod)
     284             :                opt_info ignored (FIXME: CONSIDER DETAILS IN OPT_INFO?)
     285             :      RESOLVE - the path did not resolve to a key
     286             :                (e.g. pod doesn't contain a key "foo" or subpod "foo"
     287             :                doesn't contain a key named bar or "foo.bar"
     288             :                doesn't contain a key baz)
     289             :                opt_info ignored (FIXME: CONSIDER DETAILS IN OPT_INFO?)
     290             : 
     291             :    info parent will be NULL (even if path nested) */
     292             : 
     293             : int
     294             : fd_pod_query( uchar const   * FD_RESTRICT pod,
     295             :               char const    * FD_RESTRICT path,
     296             :               fd_pod_info_t * FD_RESTRICT opt_info );
     297             : 
     298             : /* Iterator ***********************************************************/
     299             : 
     300             : /* Typical usage of this iterator:
     301             : 
     302             :    for( fd_pod_iter_t iter = fd_pod_iter_init( pod ); !fd_pod_iter_done( iter ); iter = fd_pod_iter_next( iter ) ) {
     303             :      fd_pod_info_t info = fd_pod_iter_info( iter );
     304             : 
     305             :      ... At this point, info.* contains the usual details about the next
     306             :      ... key-val pair in the pod (info.parent will be NULL).  There is
     307             :      ... no guarantee about the order in which key-val pairs will be
     308             :      ... provided (other than it will be the same for each iteration
     309             :      ... provided the pod itself hasn't been changed and the same order
     310             :      ... given by fd_pod_list).  Iteration does not recurse into any
     311             :      ... subpods.  Assumes the pod will not be changed during the
     312             :      ... iteration.  It is okay to pass NULL for pod to the init (no
     313             :      ... iteration will be done as there are ... no key-val pairs to
     314             :      ... iterate over).
     315             : 
     316             :      ... This process is algorithmically efficient but the
     317             :      ... implementation is not as fast as it could be.  But iterating
     318             :      ... over pods is typically only done during non-critical path
     319             :      ... initialization processes.
     320             :    }
     321             : */
     322             : 
     323             : /* fd_pod_iter_t is an opaque handle for iterating over all the key-val
     324             :    pairs in a pod.  This is exposed here to facilitate inlining iteration
     325             :    operations. */
     326             : 
     327             : struct fd_pod_iter_private {
     328             :   uchar const * cursor;
     329             :   uchar const * stop;
     330             : };
     331             : 
     332             : typedef struct fd_pod_iter_private fd_pod_iter_t;
     333             : 
     334             : /* fd_pod_iter_init starts an iteration over the given pod (pod can be
     335             :    nested inside another pod).  Assumes pod points to the first byte of
     336             :    a well-formed static pod for iteration duration in the caller's local
     337             :    address space or is NULL. */
     338             : 
     339             : FD_FN_UNUSED static fd_pod_iter_t /* Work around -Winline */
     340      457482 : fd_pod_iter_init( uchar const * pod ) {
     341      457482 :   if( FD_UNLIKELY( !pod ) ) { fd_pod_iter_t iter; iter.cursor = NULL; iter.stop = NULL; return iter; }
     342      457479 :   ulong csz = fd_ulong_svw_dec_sz( pod );
     343      457479 :   fd_pod_iter_t iter;
     344      457479 :   iter.cursor = pod + csz*3UL;
     345      457479 :   iter.stop   = pod + fd_ulong_svw_dec_fixed( pod + csz, csz ); /* used */
     346      457479 :   return iter;
     347      457482 : }
     348             : 
     349             : /* fd_pod_iter_done returns 0 if there are more key-val pairs to iterate
     350             :    over or non-zero if not.  Assumes iter was either returned by
     351             :    fd_pod_iter_init or fd_pod_iter_next. */
     352             : 
     353             : static inline int
     354    16818258 : fd_pod_iter_done( fd_pod_iter_t iter ) {
     355    16818258 :   return iter.cursor>=iter.stop;
     356    16818258 : }
     357             : 
     358             : /* fd_pod_iter_next advances the iterator to the next key-val pair in
     359             :    the pod (if any).  Assumes !fd_pod_iter_done(iter). */
     360             : 
     361             : FD_FN_UNUSED static fd_pod_iter_t /* Work around -Winline */
     362    16360776 : fd_pod_iter_next( fd_pod_iter_t iter ) {
     363    16360776 :   uchar const * cursor = iter.cursor;
     364             : 
     365             :   /* Skip over current key */
     366    16360776 :   ulong ksz    = fd_ulong_svw_dec_sz( cursor );
     367    16360776 :   ulong key_sz = fd_ulong_svw_dec_fixed( cursor, ksz );
     368    16360776 :   cursor += ksz + key_sz;
     369             : 
     370             :   /* Skip over current type */
     371    16360776 :   cursor++;
     372             : 
     373             :   /* Skip over current val */
     374    16360776 :   ulong vsz    = fd_ulong_svw_dec_sz( cursor );
     375    16360776 :   ulong val_sz = fd_ulong_svw_dec_fixed( cursor, vsz );
     376    16360776 :   cursor += vsz + val_sz;
     377             : 
     378    16360776 :   iter.cursor = cursor;
     379    16360776 :   return iter;
     380    16360776 : }
     381             : 
     382             : /* fd_pod_iter_info returns information about the current iteration
     383             :    key-val pair.  Assumes !fd_pod_iter_done( iter ).  The usual lifetime
     384             :    restrictions about info.key and info.val apply (which, since the pod
     385             :    is fixed for the iteration duration, mean the lifetime of these
     386             :    pointers is at least the iteration).  info.parent will be NULL. */
     387             : 
     388             : FD_FN_UNUSED static fd_pod_info_t /* Work around -Winline */
     389    16360776 : fd_pod_iter_info( fd_pod_iter_t iter ) {
     390    16360776 :   uchar const * cursor = iter.cursor;
     391             : 
     392    16360776 :   fd_pod_info_t info;
     393             : 
     394             :   /* Unpack key */
     395    16360776 :   ulong ksz     = fd_ulong_svw_dec_sz( cursor );
     396    16360776 :   info.key_sz   = fd_ulong_svw_dec_fixed( cursor, ksz ); cursor += ksz;
     397    16360776 :   info.key      = (char const *)cursor;                  cursor += info.key_sz;
     398             : 
     399             :   /* Unpack type */
     400    16360776 :   info.val_type = (int)cursor[0];                        cursor++;
     401             : 
     402             :   /* Unpack val */
     403    16360776 :   ulong vsz     = fd_ulong_svw_dec_sz( cursor );
     404    16360776 :   info.val_sz   = fd_ulong_svw_dec_fixed( cursor, vsz ); cursor += vsz;
     405    16360776 :   info.val      = (void const *)cursor;                  cursor += info.val_sz;
     406             : 
     407    16360776 :   info.parent   = NULL;
     408             : 
     409    16360776 :   return info;
     410    16360776 : }
     411             : 
     412             : /* Miscellaneous APIs *************************************************/
     413             : 
     414             : /* fd_pod_strerror converts an FD_POD_SUCCESS / FD_POD_ERR_* code into
     415             :    a human readable cstr.  The lifetime of the returned pointer is
     416             :    infinite.  The returned pointer is always to a non-NULL cstr. */
     417             : 
     418             : FD_FN_CONST char const *
     419             : fd_pod_strerror( int err );
     420             : 
     421             : /* fd_pod_reset throws away all key-val pairs in pod.  (This also throws
     422             :    away any key-val pairs in any subpods in the pod.)  Returns pod on
     423             :    success and NULL on failure.
     424             : 
     425             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     426             : 
     427             : static inline uchar *
     428        3003 : fd_pod_reset( uchar * pod ) {
     429        3003 :   if( FD_UNLIKELY( !pod ) ) return NULL;
     430        3003 :   ulong csz = fd_ulong_svw_dec_sz( pod );
     431        3003 :   fd_ulong_svw_enc_fixed( pod + csz,     csz, 3UL*csz ); /* used */
     432        3003 :   fd_ulong_svw_enc_fixed( pod + csz*2UL, csz, 0UL     ); /* cnt */
     433        3003 :   return pod;
     434        3003 : }
     435             : 
     436             : /* fd_pod_resize resizes a pod to the largest possible value <= new_max.
     437             :    Returns the achieved max on success and 0 on failure (pod is NULL,
     438             :    new_max<pod used).  Achieved max is usually new_max but there are
     439             :    rare edge cases.  E.g. pod_max==64, pod_used==64, new_max==65 ... the
     440             :    pod header needs to be expanded by 3 bytes to to accommodate new_max
     441             :    (and potentially wider pod_used and pod_cnt) but that leaves 2 few
     442             :    bytes space to encode the existing pod key-val pairs.
     443             : 
     444             :    The difference between requested new_max and the achieved new_max is
     445             :    typically so small in these edge cases as to be programmatically
     446             :    irrelevant (e.g. there wouldn't be enough room to add additional
     447             :    key-val pairs to the pod for example).  Users can trap if the return
     448             :    value != new_max on return to detect such edge cases if desired
     449             :    though.
     450             : 
     451             :    That is, if the pod points to the first byte of a pod currently held
     452             :    in memory region of new_max bytes in size (where pod used<=new_max),
     453             :    this will adjust pod max to make as much of the new memory region as
     454             :    possible available to the pod for adding new key-val pairs.
     455             : 
     456             :    This operation is O(pod_used) worst case.
     457             : 
     458             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     459             : 
     460             : ulong
     461             : fd_pod_resize( uchar * pod,
     462             :                ulong   new_max );
     463             : 
     464             : /* fd_pod_compact eliminates any internal padding in the pod.  Assumes
     465             :    pod is a current local join.  If full is non-zero, a full compaction
     466             :    is done such that the pod_max is reduced to be equal to pod_used and
     467             :    the pod header is accordingly compacted (otherwise, the pod_max will
     468             :    be unchanged on return).
     469             : 
     470             :    Regardless of full, all subpods will be recursively fully compacted
     471             :    and all cstrs in the pod will have had their padding removed (they
     472             :    will be still be '\0' terminated if originally correctly '\0'
     473             :    terminated).  Returns the compacted size of the pod on success and 0
     474             :    on failure (e.g. pod is NULL).
     475             : 
     476             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION
     477             : 
     478             :    IMPORTANT!  DOING A COMPACT FOLLOWED BY A RESIZE IS NOT GUARANTEED TO
     479             :    RESTORE THESE ORIGINAL OFFSETS. */
     480             : 
     481             : ulong
     482             : fd_pod_compact( uchar * pod,
     483             :                 int     full );
     484             : 
     485             : /* fd_cstr_to_pod_val_type:  Convert a cstr pointed to by cstr into a
     486             :    FD_POD_VAL_TYPE_*.  On success, returns the val type (will be in
     487             :    0:255) and on failure returns a negative value (an FD_POD_ERR_*
     488             :    code). */
     489             : 
     490             : FD_FN_PURE int
     491             : fd_cstr_to_pod_val_type( char const * cstr );
     492             : 
     493             : /* fd_pod_val_type_to_cstr:  Populate the buffer cstr (which has enough
     494             :    room for FD_POD_VAL_TYPE_CSTR_MAX bytes) with the cstr corresponding
     495             :    to val_type (should be in 0:255).  Returns cstr on success and NULL
     496             :    on failure (cstr is untouched on failure). */
     497             : 
     498             : char *
     499             : fd_pod_val_type_to_cstr( int    val_type,
     500             :                          char * cstr );
     501             : 
     502             : /* General alloc APIs *************************************************/
     503             : 
     504             : /* fd_pod_alloc allocates space in the pod for a key at the end of the
     505             :    given path with the given val_type whose encoded size is val_sz.
     506             :    Returns offset in pod where val should be stored (room for val_sz
     507             :    bytes), 0 on failure.  Failure reasons include NULL pod, NULL path,
     508             :    one of the path prefixes resolved to a non-subpod, path is already in
     509             :    the pod, invalid val_type or no room in pod for val_sz.
     510             : 
     511             :    If subpods along the path do not exist, they will be created in the
     512             :    process.
     513             : 
     514             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION
     515             : 
     516             :    IMPORTANT!  In the current implementation, it is possible for one or
     517             :    more subpods along the path to be created and the call to fail.  The
     518             :    last subpod created in a string of such will be empty.
     519             : 
     520             :    Usage with val_types in one of the preexisting FD_POD_VAL_TYPE_*
     521             :    probably should use the specific APIs already provided for these
     522             :    types instead of this.  This is more to support custom user types. */
     523             : 
     524             : ulong
     525             : fd_pod_alloc( uchar      * FD_RESTRICT pod,
     526             :               char const * FD_RESTRICT path,
     527             :               int                      val_type,
     528             :               ulong                    val_sz );
     529             : 
     530             : /* fd_pod_insert is same as the above but also populates the allocated
     531             :    space with the val_sz bytes pointed to by val.  Assumes that val_type
     532             :    / val_sz / val encoding is sensible. */
     533             : 
     534             : FD_FN_UNUSED static ulong /* Work around -Winline */
     535             : fd_pod_insert( uchar      * FD_RESTRICT pod,
     536             :                char const * FD_RESTRICT path,
     537             :                int                      val_type,
     538             :                ulong                    val_sz,
     539      344865 :                void const * FD_RESTRICT val ) {
     540      344865 :   ulong off = fd_pod_alloc( pod, path, val_type, val_sz );
     541      344865 :   if( FD_LIKELY( off ) ) fd_memcpy( pod + off, val, val_sz );
     542      344865 :   return off;
     543      344865 : }
     544             : 
     545             : /* fd_pod_remove removes a key from the pod.  The key is at the end
     546             :    of the given path.  E.g. if path is:
     547             : 
     548             :      "foo.bar.baz"
     549             : 
     550             :    The key "baz" will be remove from subsubpod bar (which in turn is in
     551             :    subpod foo).  The pod and/or any subpods on the path WILL NOT be
     552             :    compacted after remove.
     553             : 
     554             :    If a path ends on a subpod, that subpod and all its keys (and
     555             :    subpods) it might contain will be removed.
     556             : 
     557             :    Currently, if the removal results in any empty subpod, that subpod
     558             :    will be preserved.  (FIXME: CONSIDER OPTION TO REMOVE CREATED EMPTY
     559             :    SUBPODS RECURSIVELY TOO?)
     560             : 
     561             :    Returns a 0 (FD_POD_SUCCESS) on success or a negative value
     562             :    (FD_POD_ERR_*) on failure.  Reasons for failure are:
     563             : 
     564             :      INVAL   - bad input args
     565             :                (e.g. pod or path was NULL)
     566             :      TYPE    - one of the path prefixes resolved to a non-subpod
     567             :                (e.g. "foo.bar" above was had a cstr value)
     568             :      RESOLVE - the path did not resolve to a key
     569             :                (e.g. subsubpod bar did not contain a key baz)
     570             : 
     571             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     572             : 
     573             : int
     574             : fd_pod_remove( uchar      * FD_RESTRICT pod,
     575             :                char const * FD_RESTRICT path );
     576             : 
     577             : /* Specific alloc APIs ************************************************/
     578             : 
     579             : /* fd_pod_alloc_subpod creates a empty subpod at path with space for up
     580             :    to max bytes in the given pod.  Returns offset of subpod within the
     581             :    pod on success (e.g. pod + off is the location of an unjoined pod)
     582             :    and 0 on failure.  The user can add key-val pairs within this subpod
     583             :    as it would any pod with created with max storage.  This offset is
     584             :    valid for the pod's lifetime or an invalidating operation is done on
     585             :    the pod.
     586             : 
     587             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     588             : 
     589             : static inline ulong
     590             : fd_pod_alloc_subpod( uchar      * FD_RESTRICT pod,
     591             :                      char const * FD_RESTRICT path,
     592           0 :                      ulong                    max ) { /* Assumes max>=FD_POD_FOOTPRINT_MIN */
     593           0 :   ulong off = fd_pod_alloc( pod, path, FD_POD_VAL_TYPE_SUBPOD, fd_pod_footprint( max ) );
     594           0 :   if( FD_UNLIKELY( !off ) ) return 0UL;
     595           0 :   fd_pod_new( pod + off, max );
     596           0 :   return off;
     597           0 : }
     598             : 
     599             : /* fd_pod_alloc_buf creates a empty buffer at path with space for up to
     600             :    val_sz bytes in the given pod.  Returns offset of buf on success
     601             :    (e.g. pod + off is the location of first byte of buf) and 0 on
     602             :    failure.  This offset is valid for the pod's lifetime or an
     603             :    invalidating operation is done on the pod.
     604             : 
     605             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     606             : 
     607             : static inline ulong
     608             : fd_pod_alloc_buf( uchar      * FD_RESTRICT pod,
     609             :                   char const * FD_RESTRICT path,
     610           0 :                   ulong                    val_sz ) { /* Bound of final buffer sz */
     611           0 :   return fd_pod_alloc( pod, path, FD_POD_VAL_TYPE_BUF, val_sz );
     612           0 : }
     613             : 
     614             : /* fd_pod_alloc_cstr creates a space for cstr value at path with space
     615             :    for up to val_sz bytes (including terminating '\0').  Returns offset
     616             :    of cstr on success (e.g. pod + off is the location of first byte of
     617             :    cstr) and 0 on failure.  val_sz of 0 indicates that val is the NULL
     618             :    pointer.  This offset is valid for the pod's lifetime or an
     619             :    invalidating operation is done on the pod.
     620             : 
     621             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     622             : 
     623             : static inline ulong
     624             : fd_pod_alloc_cstr( uchar      * FD_RESTRICT pod,
     625             :                    char const * FD_RESTRICT path,
     626           0 :                    ulong                    val_sz ) { /* Bound of final length of cstr, including terminating '\0' */
     627           0 :   return fd_pod_alloc( pod, path, FD_POD_VAL_TYPE_CSTR, val_sz );
     628           0 : }
     629             : 
     630             : /* Specific insert APIs ***********************************************/
     631             : 
     632             : /* fd_pod_insert_subpod inserts the subpod into the pod at the given
     633             :    path.  It is up to the user to do compaction of the subpod and/or
     634             :    overall pod as desired.  Returns offset where subpod inserted, 0 on
     635             :    failure.  This offset is valid for the pod's lifetime or an
     636             :    invalidating operation is done on the pod.
     637             : 
     638             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     639             : 
     640             : static inline ulong
     641             : fd_pod_insert_subpod( uchar       * FD_RESTRICT pod,
     642             :                       char const  * FD_RESTRICT path,
     643           0 :                       uchar const * FD_RESTRICT subpod ) {
     644           0 :   return fd_pod_insert( pod, path, FD_POD_VAL_TYPE_SUBPOD, fd_pod_max( subpod ), subpod );
     645           0 : }
     646             : 
     647             : /* fd_pod_insert_buf inserts the size val_sz buffer val into the pod
     648             :    at the given path.  Returns offset where subpod inserted, 0 on
     649             :    failure.  This offset is valid for the pod's lifetime or an
     650             :    invalidating operation is done on the pod.
     651             : 
     652             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     653             : 
     654             : static inline ulong
     655             : fd_pod_insert_buf( uchar      * FD_RESTRICT pod,
     656             :                    char const * FD_RESTRICT path,
     657             :                    void const * FD_RESTRICT val,
     658       49395 :                    ulong                    val_sz ) {
     659       49395 :   return fd_pod_insert( pod, path, FD_POD_VAL_TYPE_BUF, val_sz, val );
     660       49395 : }
     661             : 
     662             : /* fd_pod_insert_cstr inserts the cstr val into the pod at the given
     663             :    path.  It is fine to insert NULL for val and/or the empty string
     664             :    (they will be recovered as such too).  Returns offset where cstr
     665             :    inserted, 0 on failure.  This offset is valid for the pod's lifetime
     666             :    or an invalidating operation is done on the pod.
     667             : 
     668             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     669             : 
     670             : static inline ulong
     671             : fd_pod_insert_cstr( uchar      * FD_RESTRICT pod,
     672             :                     char const * FD_RESTRICT path,
     673       49254 :                     char const * FD_RESTRICT val ) {
     674       49254 :   return fd_pod_insert( pod, path, FD_POD_VAL_TYPE_CSTR, val ? (strlen( val ) + 1UL) : 0UL, val );
     675       49254 : }
     676             : 
     677             : /* fd_pod_insert_[type] inserts the [type] val into the pod at the given
     678             :    path.  Returns offset where val was inserted, 0 on failure.  The
     679             :    inserted representation might be compressed.  This offset is valid
     680             :    for the pod's lifetime or an invalidating operation is done on the
     681             :    pod.
     682             : 
     683             :    IMPORTANT!  THIS IS AN INVALIDATING OPERATION */
     684             : 
     685             : #define FD_POD_IMPL(type,TYPE)                                                   \
     686             : static inline ulong /* offset where val stored in pod, 0 on failure */           \
     687             : fd_pod_insert_##type( uchar      * FD_RESTRICT pod,                              \
     688             :                       char const * FD_RESTRICT path,                             \
     689      246018 :                       type                     val ) {                           \
     690      246018 :   return fd_pod_insert( pod, path, FD_POD_VAL_TYPE_##TYPE, sizeof(type), &val ); \
     691      246018 : }
     692             : 
     693             : FD_POD_IMPL( char,    CHAR    )
     694             : FD_POD_IMPL( schar,   SCHAR   )
     695             : FD_POD_IMPL( uchar,   UCHAR   )
     696             : FD_POD_IMPL( float,   FLOAT   )
     697             : #if FD_HAS_DOUBLE
     698             : FD_POD_IMPL( double,  DOUBLE  )
     699             : #endif
     700             : 
     701             : #undef FD_POD_IMPL
     702             : 
     703             : #define FD_POD_IMPL(type,TYPE)                                           \
     704             : static inline ulong                                                      \
     705             : fd_pod_insert_##type( uchar      * FD_RESTRICT pod,                      \
     706             :                       char const * FD_RESTRICT path,                     \
     707      148716 :                       type                     val ) {                   \
     708      148716 :   ulong val_sz = fd_ulong_svw_enc_sz( (ulong)val );                      \
     709      148716 :   ulong off = fd_pod_alloc( pod, path, FD_POD_VAL_TYPE_##TYPE, val_sz ); \
     710      148716 :   if( FD_UNLIKELY( !off ) ) return 0UL;                                  \
     711      148716 :   fd_ulong_svw_enc( pod + off, (ulong)val );                             \
     712      112824 :   return off;                                                            \
     713      148716 : }
     714             : 
     715             : FD_POD_IMPL( ushort, USHORT )
     716             : FD_POD_IMPL( uint,   UINT   )
     717             : FD_POD_IMPL( ulong,  ULONG  )
     718             : 
     719             : #undef FD_POD_IMPL
     720             : 
     721             : #define FD_POD_IMPL(type,TYPE)                                           \
     722             : static inline ulong                                                      \
     723             : fd_pod_insert_##type( uchar      * FD_RESTRICT pod,                      \
     724             :                       char const * FD_RESTRICT path,                     \
     725      147336 :                       type                     val ) {                   \
     726      147336 :   ulong zz_val = fd_long_zz_enc( (long)val );                            \
     727      147336 :   ulong val_sz = fd_ulong_svw_enc_sz( zz_val );                          \
     728      147336 :   ulong off = fd_pod_alloc( pod, path, FD_POD_VAL_TYPE_##TYPE, val_sz ); \
     729      147336 :   if( FD_UNLIKELY( !off ) ) return 0UL;                                  \
     730      147336 :   fd_ulong_svw_enc( pod + off, zz_val );                                 \
     731      111930 :   return off;                                                            \
     732      147336 : }
     733             : 
     734             : FD_POD_IMPL( short, SHORT )
     735             : FD_POD_IMPL( int,   INT   )
     736             : FD_POD_IMPL( long,  LONG  )
     737             : 
     738             : #undef FD_POD_IMPL
     739             : 
     740             : #if FD_HAS_INT128
     741             : static inline ulong
     742             : fd_pod_insert_uint128( uchar      * FD_RESTRICT pod,
     743             :                        char const * FD_RESTRICT path,
     744       48945 :                        uint128                  val ) {
     745       48945 :   ulong lo     = (ulong) val;
     746       48945 :   ulong hi     = (ulong)(val>>64);
     747       48945 :   ulong val_sz = fd_ulong_svw_enc_sz( lo ) + fd_ulong_svw_enc_sz( hi );
     748       48945 :   ulong off    = fd_pod_alloc( pod, path, FD_POD_VAL_TYPE_UINT128, val_sz );
     749       48945 :   if( FD_UNLIKELY( !off ) ) return 0UL;
     750       36873 :   fd_ulong_svw_enc( fd_ulong_svw_enc( pod + off, lo ), hi );
     751       36873 :   return off;
     752       48945 : }
     753             : 
     754             : static inline ulong
     755             : fd_pod_insert_int128( uchar      * FD_RESTRICT pod,
     756             :                       char const * FD_RESTRICT path,
     757       49209 :                       int128                   val ) {
     758       49209 :   uint128 zz_val   = fd_int128_zz_enc( val );
     759       49209 :   ulong   lo       = (ulong) zz_val;
     760       49209 :   ulong   hi       = (ulong)(zz_val>>64);
     761       49209 :   ulong   val_sz   = fd_ulong_svw_enc_sz( lo ) + fd_ulong_svw_enc_sz( hi );
     762       49209 :   ulong   off      = fd_pod_alloc( pod, path, FD_POD_VAL_TYPE_INT128, val_sz );
     763       49209 :   if( FD_UNLIKELY( !off ) ) return 0UL;
     764       37161 :   fd_ulong_svw_enc( fd_ulong_svw_enc( pod + off, lo ), hi );
     765       37161 :   return off;
     766       49209 : }
     767             : #endif
     768             : 
     769             : /* Specific query APIs ************************************************/
     770             : 
     771             : /* fd_pod_query_subpod queries for the subpod in pod at path.  Returns a
     772             :    pointer to the pod in the local address space on success or NULL on
     773             :    failure.  The return pointer's lifetime is the pod's local join
     774             :    lifetime or an invalidating operation is done on the pod. */
     775             : 
     776             : FD_FN_UNUSED static uchar const * /* Work around -Winline */
     777             : fd_pod_query_subpod( uchar const * FD_RESTRICT pod,
     778          96 :                      char const  * FD_RESTRICT path ) {
     779          96 :   fd_pod_info_t info[1];
     780          96 :   if( FD_UNLIKELY( fd_pod_query( pod, path, info )        ) ||
     781          96 :       FD_UNLIKELY( info->val_type!=FD_POD_VAL_TYPE_SUBPOD ) ) return NULL;
     782           0 :   return (uchar const *)info->val;
     783          96 : }
     784             : 
     785             : /* fd_pod_query_buf queries for the buffer in pod at path.  Returns the
     786             :    pointer to the buffer in the local address space on success or NULL
     787             :    on failure.  On success, if opt_buf_sz is non-NULL, *opt_buf_sz will
     788             :    have the size of the buffer in bytes on return.  *opt_buf_sz is
     789             :    untouched otherwise.  The return pointer's lifetime is the pod's
     790             :    local join lifetime or an invalidating operation is done on the pod. */
     791             : 
     792             : static inline void const *
     793             : fd_pod_query_buf( uchar const * FD_RESTRICT pod,
     794             :                   char const  * FD_RESTRICT path,
     795       86700 :                   ulong       * FD_RESTRICT opt_buf_sz ) {
     796       86700 :   fd_pod_info_t info[1];
     797       86700 :   if( FD_UNLIKELY( fd_pod_query( pod, path, info )     ) ||
     798       86700 :       FD_UNLIKELY( info->val_type!=FD_POD_VAL_TYPE_BUF ) ) return NULL;
     799       37308 :   if( opt_buf_sz ) *opt_buf_sz = info->val_sz;
     800       37308 :   return info->val;
     801       86700 : }
     802             : 
     803             : /* fd_pod_query_cstr queries for the cstr in pod at path.  Returns the
     804             :    pointer to the cstr in the local address on success or def on
     805             :    failure.  The return pointer's lifetime is the pod's local join
     806             :    lifetime or an invalidating operation is done on the pod. */
     807             : 
     808             : FD_FN_UNUSED FD_FN_PURE static char const * /* Work around -Winline */
     809             : fd_pod_query_cstr( uchar const * FD_RESTRICT pod,
     810             :                    char const  * FD_RESTRICT path,
     811       86538 :                    char const  * FD_RESTRICT def ) {
     812       86538 :   fd_pod_info_t info[1];
     813       86538 :   if( FD_UNLIKELY( fd_pod_query( pod, path, info )      ) ||
     814       86538 :       FD_UNLIKELY( info->val_type!=FD_POD_VAL_TYPE_CSTR ) ) return def;
     815       37317 :   return info->val_sz ? (char const *)info->val : NULL;
     816       86538 : }
     817             : 
     818             : /* fd_pod_query_[type] queries for the [type] in pod at path.  Returns
     819             :    the query result on success or def on failure. */
     820             : 
     821             : #define FD_POD_IMPL(type,TYPE)                                            \
     822             : FD_FN_UNUSED FD_FN_PURE static type /* Work around -Winline */            \
     823             : fd_pod_query_##type( uchar const * FD_RESTRICT pod,                       \
     824             :                      char const  * FD_RESTRICT path,                      \
     825      258921 :                      type                      def ) {                    \
     826      258921 :   fd_pod_info_t info[1];                                                  \
     827      258921 :   if( FD_UNLIKELY( fd_pod_query( pod, path, info )        ) ||            \
     828      258921 :       FD_UNLIKELY( info->val_type!=FD_POD_VAL_TYPE_##TYPE ) ) return def; \
     829      258921 :   return *(type const *)(info->val);                                      \
     830      258921 : }
     831             : 
     832             : FD_POD_IMPL( char,   CHAR   )
     833             : FD_POD_IMPL( schar,  SCHAR  )
     834             : FD_POD_IMPL( uchar,  UCHAR  )
     835             : 
     836             : #undef FD_POD_IMPL
     837             : 
     838             : #define FD_POD_IMPL(type,TYPE)                                            \
     839             : FD_FN_UNUSED FD_FN_PURE static type /* Work around -Winline */            \
     840             : fd_pod_query_##type( uchar const * FD_RESTRICT pod,                       \
     841             :                      char const  * FD_RESTRICT path,                      \
     842      173082 :                      type                      def ) {                    \
     843      173082 :   fd_pod_info_t info[1];                                                  \
     844      173082 :   if( FD_UNLIKELY( fd_pod_query( pod, path, info )        ) ||            \
     845      173082 :       FD_UNLIKELY( info->val_type!=FD_POD_VAL_TYPE_##TYPE ) ) return def; \
     846      173082 :   return FD_LOAD( type, info->val );                                      \
     847      173082 : }
     848             : 
     849             : FD_POD_IMPL( float,  FLOAT  )
     850             : #if FD_HAS_DOUBLE
     851             : FD_POD_IMPL( double, DOUBLE )
     852             : #endif
     853             : 
     854             : #undef FD_POD_IMPL
     855             : 
     856             : #define FD_POD_IMPL(type,TYPE)                                            \
     857             : FD_FN_UNUSED FD_FN_PURE static type /* Work around -Winline */            \
     858             : fd_pod_query_##type( uchar const * FD_RESTRICT pod,                       \
     859             :                      char const  * FD_RESTRICT path,                      \
     860      261435 :                      type                      def ) {                    \
     861      261435 :   fd_pod_info_t info[1];                                                  \
     862      261435 :   if( FD_UNLIKELY( fd_pod_query( pod, path, info )        ) ||            \
     863      261435 :       FD_UNLIKELY( info->val_type!=FD_POD_VAL_TYPE_##TYPE ) ) return def; \
     864      261435 :   ulong u; fd_ulong_svw_dec( (uchar const *)info->val, &u );              \
     865      112836 :   return (type)u;                                                         \
     866      261435 : }
     867             : 
     868             : FD_POD_IMPL( ushort, USHORT )
     869             : FD_POD_IMPL( uint,   UINT   )
     870             : FD_POD_IMPL( ulong,  ULONG  )
     871             : 
     872             : #undef FD_POD_IMPL
     873             : 
     874             : #define FD_POD_IMPL(type,TYPE)                                            \
     875             : FD_FN_UNUSED FD_FN_PURE static type /* Work around -Winline */            \
     876             : fd_pod_query_##type( uchar const * FD_RESTRICT pod,                       \
     877             :                      char const  * FD_RESTRICT path,                      \
     878      258768 :                      type                      def ) {                    \
     879      258768 :   fd_pod_info_t info[1];                                                  \
     880      258768 :   if( FD_UNLIKELY( fd_pod_query( pod, path, info )        ) ||            \
     881      258768 :       FD_UNLIKELY( info->val_type!=FD_POD_VAL_TYPE_##TYPE ) ) return def; \
     882      258768 :   ulong u; fd_ulong_svw_dec( (uchar const *)info->val, &u );              \
     883      111753 :   return (type)fd_long_zz_dec( u );                                       \
     884      258768 : }
     885             : 
     886             : FD_POD_IMPL( short, SHORT )
     887             : FD_POD_IMPL( int,   INT   )
     888             : FD_POD_IMPL( long,  LONG  )
     889             : 
     890             : #undef FD_POD_IMPL
     891             : 
     892             : #if FD_HAS_INT128
     893             : FD_FN_UNUSED FD_FN_PURE static uint128 /* Work around -Winline */
     894             : fd_pod_query_uint128( uchar const * FD_RESTRICT pod,
     895             :                       char const  * FD_RESTRICT path,
     896       85818 :                       uint128                   def ) {
     897       85818 :   fd_pod_info_t info[1];
     898       85818 :   if( FD_UNLIKELY( fd_pod_query( pod, path, info )         ) ||
     899       85818 :       FD_UNLIKELY( info->val_type!=FD_POD_VAL_TYPE_UINT128 ) ) return def;
     900       36885 :   union { ulong w[2]; uint128 u; } tmp;
     901       36885 :   fd_ulong_svw_dec( fd_ulong_svw_dec( (uchar const *)info->val, tmp.w ), tmp.w+1 );
     902       36885 :   return tmp.u;
     903       85818 : }
     904             : 
     905             : FD_FN_UNUSED FD_FN_PURE static int128 /* Work around -Winline */
     906             : fd_pod_query_int128( uchar const * FD_RESTRICT pod,
     907             :                      char const  * FD_RESTRICT path,
     908       86370 :                      int128                    def ) {
     909       86370 :   fd_pod_info_t info[1];
     910       86370 :   if( FD_UNLIKELY( fd_pod_query( pod, path, info )        ) ||
     911       86370 :       FD_UNLIKELY( info->val_type!=FD_POD_VAL_TYPE_INT128 ) ) return def;
     912       37179 :   union { ulong w[2]; uint128 u; } tmp;
     913       37179 :   fd_ulong_svw_dec( fd_ulong_svw_dec( (uchar const *)info->val, tmp.w ), tmp.w+1 );
     914       37179 :   return fd_int128_zz_dec( tmp.u );
     915       86370 : }
     916             : #endif
     917             : 
     918             : FD_PROTOTYPES_END
     919             : 
     920             : #endif /* HEADER_fd_src_pod_fd_pod_h */

Generated by: LCOV version 1.14