LCOV - code coverage report
Current view: top level - util/tmpl - fd_map_giant.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 302 406 74.4 %
Date: 2026-02-26 05:45:35 Functions: 68 120 56.7 %

          Line data    Source code
       1             : /* Generate prototypes, inlines and/or implementations for ultra high
       2             :    performance dynamic key-val maps of gigantic size.  A giant map can
       3             :    be persisting beyond the lifetime of creating process, used
       4             :    concurrently, used IPC, relocated in memory, naively
       5             :    serialized/deserialized and/or moved between hosts.  Memory
       6             :    efficiency and flexible footprint are prioritized.  Elements that are
       7             :    recently used can be optionally moved to the front of the chains to
       8             :    adaptively optimize the maps for recent queries.  Typical usage:
       9             : 
      10             :      struct mymap {
      11             :        ulong key;  // Technically "MAP_KEY_T MAP_KEY;" (default is ulong key), should not be touched by user
      12             :        ulong next; // Technically "ulong     MAP_NEXT;", should not be touched by user
      13             :        ... key and next can be located arbitrarily in struct
      14             :        ... the mapping of a key to an array index is arbitrary but is
      15             :        ... fixed over the lifetime of the key in the map
      16             :      };
      17             : 
      18             :      typedef struct mymap mymap_t;
      19             : 
      20             :      #define MAP_NAME  mymap
      21             :      #define MAP_T     mymap_t
      22             :      #include "tmpl/fd_map_giant.c"
      23             : 
      24             :   will declare the following APIs as a header only style library in the
      25             :   compilation unit:
      26             : 
      27             :     // mymap_{align,footprint} returns alignment and footprint needed
      28             :     // for a memory region to be used as a mymap.  align will be an
      29             :     // integer power-of-two and footprint will be a multiple of align.
      30             :     // footprint will return 0 if key_max requires a footprint that
      31             :     // would overflow 64-bit.  key_max is the maximum number of keys
      32             :     // (elements) the map can hold.
      33             :     //
      34             :     // mymap_new formats a memory region with the appropriate alignment
      35             :     // and footprint whose first byte in the caller's address space is
      36             :     // pointed by shmem.  Returns shmem on success and NULL on failure
      37             :     // (logs details).  Caller is not joined on return.  The map will be
      38             :     // empty.
      39             :     //
      40             :     // mymap_join joins a mymap.  Assumes shmap points at a memory
      41             :     // region formatted as a mymap in the caller's address space.
      42             :     // Returns a handle to the caller's local join on success and NULL
      43             :     // on failure (logs details).  THIS IS NOT A SIMPLE CAST OF SHMAP!
      44             :     // The join can be indexed as a flat array with key_max elements in
      45             :     // the caller's address space.
      46             :     //
      47             :     // mymap_leave leaves a mymap.  Assumes join points to a current
      48             :     // local join.  Returns shmap used on join.  THIS IS NOT A SIMPLE
      49             :     // CASE OF JOIN!
      50             :     //
      51             :     // mymap_delete unformats a memory region used as a mymap.  Assumes
      52             :     // shmap points to a memory region in the caller's local address
      53             :     // space formatted as a mymap, that there are no joins to the mymap
      54             :     // and that any application cleanup of the entries has already been
      55             :     // done.  Returns shmap on success and NULL on failure.
      56             : 
      57             :     ulong     mymap_align    ( void );
      58             :     ulong     mymap_footprint( ulong     key_max );
      59             :     void *    mymap_new      ( void *    shmem, ulong key_max, ulong seed );
      60             :     mymap_t * mymap_join     ( void *    shmap   ); // Indexed [0,key_max)
      61             :     void *    mymap_leave    ( mymap_t * join    );
      62             :     void *    mymap_delete   ( void *    shmap   );
      63             : 
      64             :     // mymap_key_max and mymap_seed return the values used to construct
      65             :     // the map.  They assume join is a current local join.  The values
      66             :     // will be constant for the map lifetime.
      67             : 
      68             :     ulong mymap_key_max( mymap_t const * join );
      69             :     ulong mymap_seed   ( mymap_t const * join );
      70             : 
      71             :     // mymap_key_cnt returns the current number of keys in the map.
      72             :     // Will be in [0,key_max].  mymap_is_full returns 1 if
      73             :     // key_cnt==key_max.  Assumes join is a current local join.  The
      74             :     // values will be constant until the next map insert / remove.
      75             : 
      76             :     ulong mymap_key_cnt( mymap_t const * join );
      77             :     int   mymap_is_full( mymap_t const * join );
      78             : 
      79             :     // mymap_key_{eq,hash,copy} expose the provided
      80             :     // MAP_KEY_{EQ,HASH,COPY} macros as inline functions with strict
      81             :     // semantics.  They assume that the provided pointers are in the
      82             :     // caller's address space to keys that will not be changed
      83             :     // concurrently.  They retain no interest in key on return.
      84             :     //
      85             :     // mymap_key_eq returns 1 if the *k0 and *k1 are equal and 0
      86             :     // otherwise.
      87             :     //
      88             :     // mymap_key_hash returns the hash *key using the hash function
      89             :     // seed.  Should ideally be a random mapping from MAP_KEY_T -> ulong
      90             :     // but this depends on what the user actually passed in for
      91             :     // MAP_HASH.  The seed used by a particular instance of a giant map
      92             :     // can be obtained above.
      93             :     //
      94             :     // mymap_key_copy deep copies *ks into *kd and returns kd.
      95             : 
      96             :     int     mymap_key_eq  ( ulong * k0, ulong * k1       );
      97             :     ulong   mymap_key_hash( ulong * key, ulong seed      );
      98             :     ulong * mymap_key_copy( ulong * kd, ulong const * ks );
      99             : 
     100             :     // mymap_insert inserts the key pointed to by key into the map.
     101             :     // Returns the location in the caller's address space of the element
     102             :     // for key in the map.
     103             :     //
     104             :     // Assumes map is a current local join, key points to a valid key in
     105             :     // the caller's address space, there are no concurrent operations on
     106             :     // the map or key.  The map retains no interest in key.  The
     107             :     // returned element will be valid for the lesser of the lifetime of
     108             :     // the join and until key is removed from the map.
     109             :     //
     110             :     // Critically, as this is used in high performance contexts where
     111             :     // the application already knows this, THE CALLER PROMISES THE KEY
     112             :     // IS NOT IN THE MAP AND THAT THE MAP HAS SPACE FOR KEY.
     113             :     //
     114             :     // This always succeeds (with the above requirements) and returns
     115             :     // non NULL.
     116             : 
     117             :     mymap_t * mymap_insert( mymap_t * join, ulong const * key );
     118             : 
     119             :     // mymap_remove removes the key pointed to by key from the map.  A
     120             :     // pointer in the caller's address space to the former element is
     121             :     // returned to allow additional cleanup of the application fields.
     122             :     // Returns NULL if key is not in the map.
     123             :     //
     124             :     // Assumes map is a current local join, key points to a valid key in
     125             :     // the caller's address space and there are no concurrent operations
     126             :     // on the map or key.  The map retains no interest in key.  Any
     127             :     // returned pointer will be valid for the lesser of the lifetime of
     128             :     // the join and until the next insert.
     129             : 
     130             :     mymap_t * mymap_remove( mymap_t * join, ulong const * key );
     131             : 
     132             :     // mymap_query finds the element for the key pointed to by key in
     133             :     // the map and returns a pointer to it in the caller's address
     134             :     // space.  If key is not found, returns sentinel (usually pass
     135             :     // NULL).
     136             :     //
     137             :     // Assumes map is a current local join, key points to a valid key in
     138             :     // the caller's address space and there are no concurrent operations
     139             :     // on the map or key.  The map retains no interest in key.  On
     140             :     // success, the returned pointer will be valid for the lesser of the
     141             :     // lifetime of join or until key is removed.  On failure, the
     142             :     // returned pointer lifetime will be that of the sentinel.
     143             : 
     144             :     mymap_t * mymap_query( mymap_t * join, ulong const * key, mymap_t * sentinel );
     145             : 
     146             :     // mymap_query_const is the same as mymap_query but supports
     147             :     // concurrent queries so long as there no concurrently running
     148             :     // insert/remove/query operations.  The value fields of the mymap_t
     149             :     // returned by this function can be changed by the application (but
     150             :     // it is up to the application to manage concurrency between
     151             :     // different users modifying the same key).
     152             : 
     153             :     mymap_t const * mymap_query_const( mymap_t const * join, ulong const * key, mymap_t const * sentinel );
     154             : 
     155             :     // mymap_query_safe is the same as mymap_query_const but with
     156             :     // additional safety checks.  If a concurrent write is occurring,
     157             :     // this API will still return a reasonable map entry without
     158             :     // crashing, even if it is wrong.
     159             : 
     160             :     mymap_t const * mymap_query_safe( mymap_t const * join, ulong const * key, mymap_t const * sentinel );
     161             : 
     162             :     // mymap_iter_* allow for iteration over all the keys inserted into
     163             :     // a mymap.  The iteration will be in a random order but the order
     164             :     // will be identical if repeated with no insert/remove/query
     165             :     // operations done in between.  Assumes no concurrent
     166             :     // insert/remove/query operations.  Example usage:
     167             :     //
     168             :     //   for( mymap_t iter = mymap_iter_init( join ); !mymap_iter_done( join, iter ); iter = mymap_iter_next( join, iter ) ) {
     169             :     //     mymap_t * ele = mymap_iter_ele( join, iter );
     170             :     //
     171             :     //     ... process ele here
     172             :     //
     173             :     //     ... IMPORTANT!  It is _okay_ to insert, remove, query or
     174             :     //     ... query_const here.  In particular, if an element is
     175             :     //     ... inserted, it may or may not be covered by this iteration.
     176             :     //     ... If an element is removed that has not already been
     177             :     //     ... iterated over, it will not be iterated over in this
     178             :     //     ... iteration.  It is fine to remove the current item being
     179             :     //     ... iterated over.
     180             :     //
     181             :     //     ... WARNING! While this looks like an O(key_cnt) operation,
     182             :     //     ... technically, this is an O(key_max) operation under the
     183             :     //     ... hood.  As such, use outside critical paths (e.g.
     184             :     //     ... checkpointing), on dense maps (e.g. key_cnt/key_max ~
     185             :     //     ... O(1)) and/or on maps where key_max is small enough not to
     186             :     //     ... matter practically.
     187             :     //   }
     188             : 
     189             :     struct mymap_iter_private { ... internal use only ... };
     190             :     typedef struct mymap_iter_private mymap_iter_t;
     191             : 
     192             :     mymap_iter_t    mymap_iter_init     ( mymap_t const * join, mymap_iter_t iter ); // returns iter, NULL join fine
     193             :     int             mymap_iter_done     ( mymap_t const * join, mymap_iter_t iter ); // returns 1 if no more iterations, 0 o.w.
     194             :     mymap_iter_t    mymap_iter_next     ( mymap_t const * join, mymap_iter_t iter ); // returns next iter value iter
     195             :     mymap_t *       mymap_iter_ele      ( mymap_t *       join, mymap_iter_t iter ); // assumes not done, return non-NULL ele
     196             :     mymap_t const * mymap_iter_ele_const( mymap_t const * join, mymap_iter_t iter ); // assumes not done, return non-NULL ele
     197             : 
     198             :     // mymap_verify returns 0 if the mymap is not obviously corrupt or a
     199             :     // -1 (i.e. ERR_INVAL) if it is obviously corrupt (logs details).
     200             :     // join is the handle of a current local join to mymap.
     201             : 
     202             :     int mymap_verify( mymap_t const * join );
     203             : 
     204             :   You can do this as often as you like in a compilation unit to get
     205             :   different types of gigantic maps.  Variants exist for making header
     206             :   prototypes only and/or implementations if doing a library with
     207             :   multiple compilation units.  Further, options exist to use different
     208             :   hashing functions, comparison functions, etc as detailed below. */
     209             : 
     210             : /* MAP_NAME gives the API prefix to use for map */
     211             : 
     212             : #ifndef MAP_NAME
     213             : #error "Define MAP_NAME"
     214             : #endif
     215             : 
     216             : /* MAP_T is the map element type. */
     217             : 
     218             : #ifndef MAP_T
     219             : #error "Define MAP_T"
     220             : #endif
     221             : 
     222             : /* MAP_KEY_T is the map key type */
     223             : 
     224             : #ifndef MAP_KEY_T
     225             : #define MAP_KEY_T ulong
     226             : #endif
     227             : 
     228             : /* MAP_KEY is the MAP_T key field */
     229             : 
     230             : #ifndef MAP_KEY
     231             : #define MAP_KEY key
     232             : #endif
     233             : 
     234             : /* MAP_NEXT is the MAP_T next field */
     235             : 
     236             : #ifndef MAP_NEXT
     237             : #define MAP_NEXT next
     238             : #endif
     239             : 
     240             : /* MAP_KEY_EQ returns 0/1 if *k0 is the same/different as *k1 */
     241             : 
     242             : #ifndef MAP_KEY_EQ
     243  4148822646 : #define MAP_KEY_EQ(k0,k1) ((*(k0))==(*(k1)))
     244             : #endif
     245             : 
     246             : /* MAP_KEY_HASH maps *key into ulong uniform pseudo randomly. */
     247             : 
     248             : #ifndef MAP_KEY_HASH
     249  5003218794 : #define MAP_KEY_HASH(key,seed) fd_ulong_hash( (*(key)) ^ (seed) )
     250             : #endif
     251             : 
     252             : /* MAP_KEY_COPY copies the contents from *ks to *kd.  Non-POD key types
     253             :    might need to customize this accordingly.  Defaults to the copy
     254             :    operator.  */
     255             : 
     256             : #ifndef MAP_KEY_COPY
     257     9072000 : #define MAP_KEY_COPY(kd,ks) (*(kd))=(*(ks))
     258             : #endif
     259             : 
     260             : /* MAP_MAGIC is the magic number to use for the structure to aid in
     261             :    persistent and or IPC usage. */
     262             : 
     263             : #ifndef MAP_MAGIC
     264           6 : #define MAP_MAGIC (0xf17eda2c3763a900UL) /* firedancer gmap version 0 */
     265             : #endif
     266             : 
     267             : /* 0 - local use only
     268             :    1 - library header declaration
     269             :    2 - library implementation */
     270             : 
     271             : #ifndef MAP_IMPL_STYLE
     272             : #define MAP_IMPL_STYLE 0
     273             : #endif
     274             : 
     275             : /* If MAP_MEMOIZE is defined to non-zero, the MAP_T requires a
     276             :    "hash" field that will hold the value of the MAP_KEY_HASH of the
     277             :    MAP_T's MAP_KEY when the map slot is not empty (undefined otherwise).
     278             :    This is useful for accelerating user operations that might need a
     279             :    hash of the key and for accelerating remove operations.  It is also
     280             :    potentially useful as a way to accelerate slow key comparison
     281             :    operations (see MAP_KEY_EQUAL_IS_SLOW). */
     282             : 
     283             : #ifndef MAP_MEMOIZE
     284             : #define MAP_MEMOIZE 0
     285             : #endif
     286             : 
     287             : /* If MAP_MEMOIZE is non-zero, MAP_HASH is the element member to store the hash in. */
     288             : 
     289             : #ifndef MAP_HASH
     290             : #define MAP_HASH map_hash
     291             : #endif
     292             : 
     293             : /* Implementation *****************************************************/
     294             : 
     295             : /* Constructors and verification logs detail on failure (rest only needs
     296             :    fd_bits.h, consider making logging a compile time option). */
     297             : 
     298             : #include "../log/fd_log.h"
     299             : 
     300 22307243796 : #define MAP_IDX_NULL (~(1UL<<63)) /* 2^63-1 */
     301 29949810018 : #define MAP_(n)      FD_EXPAND_THEN_CONCAT3(MAP_NAME,_,n)
     302             : 
     303             : #if MAP_IMPL_STYLE==0 || MAP_IMPL_STYLE==1 /* need structures and inlines */
     304             : 
     305             : struct MAP_(private) {
     306             : 
     307             :   /* This point is max(128,alignof(MAP_T)) aligned */
     308             : 
     309             :   /* 2 ulong here, index 0 is MAP_MAGIC, index 1 is offset from shmem
     310             :      region to key_max map array below. */
     311             : 
     312             :   /* alignment padding here */
     313             : 
     314             :   /* list_cnt ulong here, indexed [0,list_cnt)
     315             :      list[ list_idx ], idx is in [0,key_max) or MAP_IDX_NULL, tag is used */
     316             : 
     317             :   ulong key_max;    /* yields non-zero footprint, <2^63 */
     318             :   ulong seed;       /* hash seed, arbitrary */
     319             :   ulong list_cnt;   /* == MAP_(private_list_cnt)( key_max ) */
     320             :   ulong key_cnt;    /* in [0,key_max] */
     321             :   ulong free_stack; /* idx is in [0,key_max) or MAP_IDX_NULL, tag is free */
     322             : 
     323             :   /* Elements on the free_stack will have bit 63 of their next field set
     324             :      to facilitate iteration and validation.  Elements in lists will
     325             :      have their bit 63 of their next field clear.  key_max<2^63 ensures
     326             :      no confusion possible with MAP_IDX_NULL though this is more
     327             :      theoretical as ~2^63 keys is impractical physically. */
     328             : 
     329             :   /* This point is max(128,alignof(MAP_T)) aligned */
     330             : 
     331             :   /* key_max MAP_T here, hdr[1] above points here */
     332             : 
     333             : };
     334             : 
     335             : typedef struct MAP_(private) MAP_(private_t);
     336             : 
     337             : typedef ulong MAP_(iter_t);
     338             : 
     339             : FD_PROTOTYPES_BEGIN
     340             : 
     341             : /* map_private_list_cnt returns the number of lists a map with the given
     342             :    key_max should use. */
     343             : 
     344             : FD_FN_CONST static inline ulong
     345    12288030 : MAP_(private_list_cnt)( ulong key_max ) {
     346             :   /* Compute the number of lists as the power of 2 that makes the
     347             :      average chain length between ~1 and ~2 */
     348    12288030 :   ulong list_min = (key_max>>1) + (key_max&1UL); /* list_min = ceil(key_max/2), at most 2^63, computed without overflow */
     349    12288030 :   ulong list_cnt = fd_ulong_pow2_up( list_min ); /* at most 2^63 */
     350    12288030 :   return list_cnt;
     351    12288030 : }
     352             : 
     353             : FD_FN_CONST static inline ulong
     354     6144030 : MAP_(private_meta_footprint)( ulong list_cnt ) {
     355     6144030 :   return fd_ulong_align_up( (2UL + list_cnt)*sizeof(ulong) + sizeof(MAP_(private_t)), fd_ulong_max( 128UL, alignof(MAP_T) ) );
     356     6144030 : }
     357             : 
     358             : /* map_private returns the location of the map private for a current
     359             :    local join.  Assumes join is a current local join.  map_private_const
     360             :    is a const correct version. */
     361             : 
     362             : FD_FN_CONST static inline MAP_(private_t) *
     363  1585152012 : MAP_(private)( MAP_T * join ) {
     364  1585152012 :   return (MAP_(private_t) *)(((ulong)join) - sizeof(MAP_(private_t)));
     365  1585152012 : }
     366             : 
     367             : FD_FN_CONST static inline MAP_(private_t) const *
     368  1863790818 : MAP_(private_const)( MAP_T const * join ) {
     369  1863790818 :   return (MAP_(private_t) const *)(((ulong)join) - sizeof(MAP_(private_t)));
     370  1863790818 : }
     371             : 
     372             : /* map_private_{list,ele}[_const] returns the location in the caller's
     373             :    address space of the map lists and elements.  The _const variants are
     374             :    for const correctness.  Assumes map is valid. */
     375             : 
     376             : FD_FN_PURE static inline ulong *
     377  1585152006 : MAP_(private_list)( MAP_(private_t) * map ) {
     378  1585152006 :   return ((ulong *)map) - map->list_cnt;
     379  1585152006 : }
     380             : 
     381             : FD_FN_PURE static inline ulong const *
     382  1845346800 : MAP_(private_list_const)( MAP_(private_t) const * map ) {
     383  1845346800 :   return ((ulong const *)map) - map->list_cnt;
     384  1845346800 : }
     385             : 
     386             : /* map_private_list_idx returns the index of the list (in [0,list_cnt)
     387             :    that will contain the element corresponding to key (if present at
     388             :    all) for a map with list_cnt elements and seed.  Assumes list_cnt is
     389             :    an integer power-of 2.  Assumes key points to a key is in the
     390             :    caller's address space that will not be changed concurrently.
     391             :    Retains no interest in key on return. */
     392             : 
     393             : FD_FN_PURE static inline ulong
     394             : MAP_(private_list_idx)( MAP_KEY_T const * key,
     395             :                         ulong             seed,
     396  1572864000 :                         ulong             list_cnt ) {
     397  1572864000 :   return (MAP_KEY_HASH( (key), (seed) )) & (list_cnt-1UL);
     398  1572864000 : }
     399             : 
     400             : /* map_private_box_next boxes idx and tag into a map next field value.
     401             :    Assumes idx is in [0,2^63-1==MAP_IDX_NULL] and tag is in [0,1].
     402             : 
     403             :    map_private_unbox_idx unboxes the idx from a map next field value.
     404             :    Return will be in [0,2^63-1==MAP_IDX_NULL].
     405             : 
     406             :    map_private_unbox_tag unboxes the tag from a map next field value.
     407             :    Return will be in [0,1] */
     408             : 
     409   575825754 : FD_FN_CONST static inline ulong MAP_(private_box_next)   ( ulong idx, int tag ) { return idx | (((ulong)tag)<<63); }
     410 11153621112 : FD_FN_CONST static inline ulong MAP_(private_unbox_idx)  ( ulong next )         { return next & MAP_IDX_NULL;      }
     411  7873540614 : FD_FN_CONST static inline int   MAP_(private_unbox_tag)  ( ulong next )         { return (int)(next>>63);          }
     412             : 
     413             : /* map_private_is_null returns 1 if idx is the NULL map idx value
     414             :    and 0 otherwise. */
     415             : 
     416 11147477112 : FD_FN_CONST static inline int   MAP_(private_is_null)( ulong idx ) { return idx==MAP_IDX_NULL; }
     417             : 
     418             : FD_FN_PURE static inline ulong
     419           6 : MAP_(key_max)( MAP_T const * join ) {
     420           6 :   if( FD_UNLIKELY( !join ) ) return 0UL;
     421           6 :   return MAP_(private_const)( join )->key_max;
     422           6 : }
     423             : 
     424             : FD_FN_PURE static inline ulong
     425           6 : MAP_(seed)( MAP_T const * join ) {
     426           6 :   if( FD_UNLIKELY( !join ) ) return 0UL;
     427           6 :   return MAP_(private_const)( join )->seed;
     428           6 : }
     429             : 
     430             : FD_FN_PURE static inline ulong
     431     9216006 : MAP_(key_cnt)( MAP_T const * join ) {
     432     9216006 :   if( FD_UNLIKELY( !join ) ) return 0UL;
     433     9216006 :   return MAP_(private_const)( join )->key_cnt;
     434     9216006 : }
     435             : 
     436             : FD_FN_PURE static inline int
     437     6150000 : MAP_(is_full)( MAP_T const * join ) {
     438     6150000 :   if( FD_UNLIKELY( !join ) ) return 0UL;
     439     6150000 :   MAP_(private_t) const * map = MAP_(private_const)( join );
     440     6150000 :   return MAP_(private_is_null)( MAP_(private_unbox_idx)( map->free_stack ) );
     441     6150000 : }
     442             : 
     443             : FD_FN_PURE static inline int
     444             : MAP_(key_eq)( MAP_KEY_T const * k0,
     445  4148822646 :               MAP_KEY_T const * k1 ) {
     446  4148822646 :   return !!(MAP_KEY_EQ( (k0), (k1) ));
     447  4148822646 : }
     448             : 
     449             : FD_FN_PURE static inline ulong
     450             : MAP_(key_hash)( MAP_KEY_T const * key,
     451     6000000 :                 ulong             seed ) {
     452     6000000 :   return (MAP_KEY_HASH( (key), (seed) ));
     453     6000000 : }
     454             : 
     455             : static inline MAP_KEY_T *
     456             : MAP_(key_copy)( MAP_KEY_T *       kd,
     457     9072000 :                 MAP_KEY_T const * ks ) {
     458     9072000 :   (MAP_KEY_COPY( (kd), (ks) ));
     459     9072000 :   return kd;
     460     9072000 : }
     461             : 
     462             : FD_FN_PURE static inline MAP_(iter_t)
     463     3078000 : MAP_(iter_init)( MAP_T const * join ) {
     464     3078000 :   if( FD_UNLIKELY( !join ) ) return 0UL; /* Debatable */
     465     3078000 :   MAP_(private_t) const * map = MAP_(private_const)( join );
     466     3078000 :   ulong ele_rem = map->key_max;
     467    21242508 :   for( ; ele_rem; ele_rem-- ) if( !MAP_(private_unbox_tag)( join[ ele_rem-1UL ].MAP_NEXT ) ) break;
     468     3078000 :   return ele_rem;
     469     3078000 : }
     470             : 
     471             : FD_FN_CONST static inline int
     472             : MAP_(iter_done)( MAP_T const * join,
     473   791046000 :                  MAP_(iter_t)  ele_rem ) {
     474   791046000 :   (void)join;
     475   791046000 :   return !ele_rem;
     476   791046000 : }
     477             : 
     478             : __attribute__((warn_unused_result))
     479             : FD_FN_PURE static inline MAP_(iter_t)
     480             : MAP_(iter_next)( MAP_T const * join,
     481   787968000 :                  MAP_(iter_t)  ele_rem ) {
     482  1557771492 :   for( ele_rem--; ele_rem; ele_rem-- ) if( !MAP_(private_unbox_tag)( join[ ele_rem-1UL ].MAP_NEXT ) ) break;
     483   787968000 :   return ele_rem;
     484   787968000 : }
     485             : 
     486             : FD_FN_CONST static inline MAP_T *
     487             : MAP_(iter_ele)( MAP_T *      join,
     488   787968000 :                 MAP_(iter_t) ele_rem ) {
     489   787968000 :   return join + ele_rem - 1UL;
     490   787968000 : }
     491             : 
     492             : FD_FN_CONST static inline MAP_T const *
     493             : MAP_(iter_ele_const)( MAP_T const * join,
     494   787968000 :                       MAP_(iter_t)  ele_rem ) {
     495   787968000 :   return join + ele_rem - 1UL;
     496   787968000 : }
     497             : 
     498             : FD_PROTOTYPES_END
     499             : 
     500             : #endif
     501             : 
     502             : #if MAP_IMPL_STYLE==1 /* need prototypes */
     503             : 
     504             : FD_PROTOTYPES_BEGIN
     505             : 
     506             : FD_FN_CONST ulong MAP_(align)    ( void );
     507             : FD_FN_CONST ulong MAP_(footprint)( ulong   key_max );
     508             : void *            MAP_(new)      ( void *  shmem, ulong key_max, ulong seed );
     509             : MAP_T *           MAP_(join)     ( void *  shmap );
     510             : void *            MAP_(leave)    ( MAP_T * join  );
     511             : void *            MAP_(delete)   ( void *  shmap );
     512             : 
     513             : MAP_T *
     514             : MAP_(insert)( MAP_T *           join,
     515             :               MAP_KEY_T const * key );
     516             : 
     517             : MAP_T *
     518             : MAP_(remove)( MAP_T *           join,
     519             :               MAP_KEY_T const * key );
     520             : 
     521             : FD_FN_PURE MAP_T *
     522             : MAP_(query)( MAP_T *           join,
     523             :              MAP_KEY_T const * key,
     524             :              MAP_T *           null );
     525             : 
     526             : FD_FN_PURE MAP_T *
     527             : MAP_(query2)( MAP_T *           join,
     528             :              MAP_KEY_T const * key,
     529             :              MAP_T *           null );
     530             : 
     531             : FD_FN_PURE MAP_T const *
     532             : MAP_(query_const)( MAP_T const *     join,
     533             :                    MAP_KEY_T const * key,
     534             :                    MAP_T const *     null );
     535             : 
     536             : FD_FN_PURE MAP_T const *
     537             : MAP_(query_safe)( MAP_T const *     join,
     538             :                    MAP_KEY_T const * key,
     539             :                    MAP_T const *     null );
     540             : 
     541             : int
     542             : MAP_(verify)( MAP_T const * join );
     543             : 
     544             : MAP_T *
     545             : MAP_(pop_free_ele)( MAP_T * join );
     546             : 
     547             : MAP_T *
     548             : MAP_(push_free_ele)( MAP_T * join,
     549             :                      MAP_T * ele );
     550             : 
     551             : FD_PROTOTYPES_END
     552             : 
     553             : #else /* need implementations */
     554             : 
     555             : #if MAP_IMPL_STYLE==0 /* local only */
     556             : #define MAP_IMPL_STATIC FD_FN_UNUSED static
     557             : #else
     558             : #define MAP_IMPL_STATIC
     559             : #endif
     560             : 
     561             : FD_FN_CONST MAP_IMPL_STATIC ulong
     562     6144090 : MAP_(align)( void ) {
     563     6144090 :   return fd_ulong_max( 128UL, alignof(MAP_T) );
     564     6144090 : }
     565             : 
     566             : FD_FN_CONST MAP_IMPL_STATIC ulong
     567     6144030 : MAP_(footprint)( ulong key_max ) {
     568     6144030 :   ulong align = MAP_(align)();
     569             : 
     570             :   /* memory layout is:
     571             : 
     572             :        2 ulong | pad | list_cnt ulong | map_private_t | key_max map_t | pad
     573             :        <------ meta_footprint, align multiple ------>
     574             :        <------------------ footprint, align multiple -------------------->
     575             : 
     576             :      Noting that list_cnt is in [key_max/2,key_max], footprint is
     577             :      (conservatively) at most:
     578             : 
     579             :        2*sizeof(ulong) + align-1 + key_max*sizeof(ulong) + sizeof(map_private_t) + key_max*sizeof(map_t) + align-1
     580             : 
     581             :      Requiring this to be at most ULONG_MAX (such that no calculations
     582             :      will overflow) yields the below.  We also must have
     583             :      key_max<=2^63-1==MAP_IDX_NULL given how elements are marked. */
     584             : 
     585     6144030 :   ulong key_thresh = fd_ulong_min( (ULONG_MAX - 2UL*(align-1UL) - 2UL*sizeof(ulong) - sizeof(MAP_(private_t))) /
     586     6144030 :                                    (sizeof(MAP_T) + sizeof(ulong)), MAP_IDX_NULL );
     587     6144030 :   if( FD_UNLIKELY( key_max>key_thresh ) ) return 0UL;
     588     6144018 :   ulong list_cnt       = MAP_(private_list_cnt)      ( key_max  );
     589     6144018 :   ulong meta_footprint = MAP_(private_meta_footprint)( list_cnt );
     590     6144018 :   return meta_footprint + fd_ulong_align_up( key_max*sizeof(MAP_T), align );
     591     6144030 : }
     592             : 
     593             : MAP_IMPL_STATIC void *
     594             : MAP_(new)( void * shmem,
     595             :            ulong  key_max,
     596          24 :            ulong  seed ) {
     597          24 :   ulong * hdr = (ulong *)shmem;
     598             : 
     599          24 :   if( FD_UNLIKELY( !hdr ) ) {
     600           6 :     FD_LOG_WARNING(( "NULL shmem" ));
     601           6 :     return NULL;
     602           6 :   }
     603             : 
     604          18 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)hdr, MAP_(align)() ) ) ) {
     605           6 :     FD_LOG_WARNING(( "misaligned shmem" ));
     606           6 :     return NULL;
     607           6 :   }
     608             : 
     609          12 :   ulong footprint = MAP_(footprint)( key_max );
     610          12 :   if( FD_UNLIKELY( !footprint ) ) {
     611           6 :     FD_LOG_WARNING(( "bad key_max" ));
     612           6 :     return NULL;
     613           6 :   }
     614             : 
     615             :   /* Init the metadata */
     616             : 
     617           6 :   ulong list_cnt       = MAP_(private_list_cnt)( key_max );
     618           6 :   ulong meta_footprint = MAP_(private_meta_footprint)( list_cnt );
     619             : 
     620           6 :   MAP_T *           join = (MAP_T *)( ((ulong)shmem) + meta_footprint );
     621           6 :   MAP_(private_t) * map  = MAP_(private)( join );
     622             : 
     623           6 :   map->key_max  = key_max;
     624           6 :   map->seed     = seed;
     625           6 :   map->list_cnt = list_cnt;
     626           6 :   map->key_cnt  = 0UL;
     627             : 
     628             :   /* Init the free stack */
     629             : 
     630           6 :   if( FD_UNLIKELY( !key_max ) ) map->free_stack = MAP_(private_box_next)( MAP_IDX_NULL, 1 );
     631           6 :   else {
     632           6 :     map->free_stack = MAP_(private_box_next)( 0UL, 1 );
     633        3072 :     for( ulong ele_idx=1UL; ele_idx<key_max; ele_idx++ ) join[ ele_idx-1UL ].MAP_NEXT = MAP_(private_box_next)( ele_idx, 1 );
     634           6 :     join[ key_max-1UL ].MAP_NEXT = MAP_(private_box_next)( MAP_IDX_NULL, 1 );
     635           6 :   }
     636             : 
     637             :   /* Set all the lists to null */
     638             : 
     639           6 :   ulong * list = MAP_(private_list)( map );
     640        1542 :   for( ulong list_idx=0UL; list_idx<list_cnt; list_idx++ ) list[ list_idx ] = MAP_(private_box_next)( MAP_IDX_NULL, 0 );
     641             : 
     642           6 :   hdr[1] = meta_footprint;
     643             : 
     644           6 :   FD_COMPILER_MFENCE();
     645           6 :   FD_VOLATILE( hdr[0] ) = MAP_MAGIC;
     646           6 :   FD_COMPILER_MFENCE();
     647             : 
     648           6 :   return hdr;
     649          12 : }
     650             : 
     651             : MAP_IMPL_STATIC MAP_T *
     652          24 : MAP_(join)( void * shmap ) {
     653          24 :   ulong * hdr = (ulong *)shmap;
     654             : 
     655          24 :   if( FD_UNLIKELY( !hdr ) ) {
     656           6 :     FD_LOG_WARNING(( "NULL shmap" ));
     657           6 :     return NULL;
     658           6 :   }
     659             : 
     660          18 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)hdr, MAP_(align)() ) ) ) {
     661           6 :     FD_LOG_WARNING(( "misaligned shmap" ));
     662           6 :     return NULL;
     663           6 :   }
     664             : 
     665          12 :   if( FD_UNLIKELY( hdr[0]!=MAP_MAGIC ) ) {
     666           6 :     FD_LOG_WARNING(( "bad magic" ));
     667           6 :     return NULL;
     668           6 :   }
     669             : 
     670           6 :   return (MAP_T *)(((ulong)shmap) + hdr[1]);
     671          12 : }
     672             : 
     673             : MAP_IMPL_STATIC void *
     674          12 : MAP_(leave)( MAP_T * join ) {
     675             : 
     676          12 :   if( FD_UNLIKELY( !join ) ) {
     677           6 :     FD_LOG_WARNING(( "NULL join" ));
     678           6 :     return NULL;
     679           6 :   }
     680             : 
     681           6 :   return (void *)(((ulong)join) - MAP_(private_meta_footprint)( MAP_(private)( join )->list_cnt ));
     682          12 : }
     683             : 
     684             : MAP_IMPL_STATIC void *
     685          24 : MAP_(delete)( void * shmap ) {
     686          24 :   ulong * hdr = (ulong *)shmap;
     687             : 
     688          24 :   if( FD_UNLIKELY( !hdr ) ) {
     689           6 :     FD_LOG_WARNING(( "NULL shmap" ));
     690           6 :     return NULL;
     691           6 :   }
     692             : 
     693          18 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)hdr, MAP_(align)() ) ) ) {
     694           6 :     FD_LOG_WARNING(( "misaligned shmap" ));
     695           6 :     return NULL;
     696           6 :   }
     697             : 
     698          12 :   if( FD_UNLIKELY( hdr[0]!=MAP_MAGIC ) ) {
     699           6 :     FD_LOG_WARNING(( "bad magic" ));
     700           6 :     return NULL;
     701           6 :   }
     702             : 
     703           6 :   FD_COMPILER_MFENCE();
     704           6 :   FD_VOLATILE( hdr[0] ) = 0UL;
     705           6 :   FD_COMPILER_MFENCE();
     706             : 
     707           6 :   return shmap;
     708          12 : }
     709             : 
     710             : static inline long
     711             : MAP_(verify_key)( MAP_T *           join,
     712             :                   MAP_KEY_T const * key,
     713           0 :                   ulong             cnt ) {
     714           0 : # define MAP_TEST(c) do {                                                        \
     715           0 :     if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: %s", #c )); return -1; } \
     716           0 :   } while(0)
     717           0 : 
     718           0 :   MAP_(private_t) * map = MAP_(private)( join );
     719           0 :   ulong list_idx = MAP_(private_list_idx)( key, map->seed, map->list_cnt );
     720           0 :   ulong key_max  = map->key_max;
     721           0 :   ulong key_cnt  = map->key_cnt;
     722           0 :   ulong ele_idx  = MAP_(private_list)( map )[ MAP_(private_list_idx)( key, map->seed, map->list_cnt ) ];
     723           0 :   while( !MAP_(private_is_null)( ele_idx ) ) {
     724           0 :     MAP_TEST( cnt<key_cnt );
     725           0 :     MAP_TEST( ele_idx<key_max );
     726           0 :     MAP_T const * ele = join + ele_idx;
     727           0 :     MAP_TEST( MAP_(private_list_idx)( &ele->MAP_KEY, map->seed, map->list_cnt )==list_idx );
     728           0 :     cnt++;
     729           0 :     ele_idx  = MAP_(private_unbox_idx)( ele->MAP_NEXT );
     730           0 :     MAP_TEST( !MAP_(private_unbox_tag)( ele->MAP_NEXT ) ); /* Element marked as used */
     731           0 :   }
     732           0 : 
     733           0 : # undef MAP_TEST
     734           0 :   return (long)cnt;;
     735           0 : }
     736             : 
     737             : FD_FN_PURE MAP_IMPL_STATIC MAP_T *
     738             : MAP_(query)( MAP_T *           join,
     739             :              MAP_KEY_T const * key,
     740  1575936000 :              MAP_T *           sentinel ) {
     741  1575936000 :   MAP_(private_t) * map = MAP_(private)( join );
     742             : 
     743             : 
     744             :   /* Find the key */
     745             : 
     746  1575936000 :   ulong hash = MAP_KEY_HASH( (key), (map->seed) );
     747  1575936000 :   ulong * head = MAP_(private_list)( map ) + ( hash & (map->list_cnt-1UL) );
     748  1575936000 :   ulong * cur  = head;
     749  3210248280 :   for(;;) {
     750  3210248280 :     ulong ele_idx = MAP_(private_unbox_idx)( *cur );
     751  3210248280 :     if( FD_UNLIKELY( MAP_(private_is_null)( ele_idx ) ) ) break; /* optimize for found */
     752  2422280280 :     MAP_T * ele = join + ele_idx;
     753  2422280280 :     if(
     754             : #if MAP_MEMOIZE
     755  1211140140 :        hash == ele->MAP_HASH &&
     756             : #endif
     757  1605124140 :       FD_LIKELY( MAP_(key_eq)( key, &ele->MAP_KEY ) ) ) { /* Optimize for found (it is remove after all) */
     758             :       /* Found, move it to the front of the chain. (FIXME: BRANCH PROB? DO BRANCHLESS?) */
     759   787968000 :       if( FD_UNLIKELY( cur!=head ) ) { /* Assume already at head from previous query */
     760   566605140 :         *cur = ele->MAP_NEXT;  /* Already tagged free */
     761   566605140 :         ele->MAP_NEXT = *head; /* Already tagged free */
     762   566605140 :         *head = MAP_(private_box_next)( ele_idx, 0 );
     763   566605140 :       }
     764   787968000 :       return ele;
     765   787968000 :     }
     766  1634312280 :     cur = &ele->MAP_NEXT; /* Retain the pointer to next so we can rewrite it later. */
     767  1634312280 :   }
     768             : 
     769             :   /* Not found */
     770             : 
     771   787968000 :   return sentinel;
     772  1575936000 : }
     773             : 
     774             : FD_FN_PURE MAP_IMPL_STATIC MAP_T *
     775             : MAP_(query2)( MAP_T *           join,
     776             :               MAP_KEY_T const * key,
     777           0 :               MAP_T *           sentinel ) {
     778           0 :   MAP_(private_t) * map = MAP_(private)( join );
     779           0 : 
     780           0 : 
     781           0 :   /* Find the key */
     782           0 : 
     783           0 :   ulong hash = MAP_KEY_HASH( (key), (map->seed) );
     784           0 :   ulong * head = MAP_(private_list)( map ) + ( hash & (map->list_cnt-1UL) );
     785           0 :   ulong * cur  = head;
     786           0 :   for(;;) {
     787           0 :     ulong ele_idx = MAP_(private_unbox_idx)( *cur );
     788           0 :     if( FD_UNLIKELY( MAP_(private_is_null)( ele_idx ) ) ) break; /* optimize for found */
     789           0 :     MAP_T * ele = join + ele_idx;
     790           0 :     if(
     791           0 : #if MAP_MEMOIZE
     792           0 :         hash == ele->MAP_HASH &&
     793           0 : #endif
     794           0 :       FD_LIKELY( MAP_(key_eq)( key, &ele->MAP_KEY ) ) ) { /* Optimize for found (it is remove after all) */
     795           0 :       return ele; /* optimize for found */
     796           0 :     }
     797           0 :     cur = &ele->MAP_NEXT;
     798           0 :   }
     799           0 : 
     800           0 :   /* Not found */
     801           0 : 
     802           0 :   return sentinel;
     803           0 : }
     804             : 
     805             : FD_FN_PURE MAP_IMPL_STATIC MAP_T const *
     806             : MAP_(query_const)( MAP_T const *     join,
     807             :                    MAP_KEY_T const * key,
     808  1839202794 :                    MAP_T const *     sentinel ) {
     809  1839202794 :   MAP_(private_t) const * map = MAP_(private_const)( join );
     810             : 
     811             :   /* Find the key */
     812             : 
     813  1839202794 :   ulong hash = MAP_KEY_HASH( (key), (map->seed) );
     814  1839202794 :   ulong const * head = MAP_(private_list_const)( map ) + ( hash & (map->list_cnt-1UL) );
     815  1839202794 :   ulong const * cur  = head;
     816  3197008218 :   for(;;) {
     817  3197008218 :     ulong ele_idx = MAP_(private_unbox_idx)( *cur );
     818  3197008218 :     if( FD_UNLIKELY( MAP_(private_is_null)( ele_idx ) ) ) break; /* optimize for found */
     819  3193936218 :     MAP_T const * ele = join + ele_idx;
     820  3193936218 :     if(
     821             : #if MAP_MEMOIZE
     822  1596968109 :         hash == ele->MAP_HASH &&
     823             : #endif
     824  2515033506 :       FD_LIKELY( MAP_(key_eq)( key, &ele->MAP_KEY ) ) ) { /* Optimize for found (it is remove after all) */
     825  1836130794 :       return ele; /* optimize for found */
     826  1836130794 :     }
     827  1357805424 :     cur = &ele->MAP_NEXT;
     828  1357805424 :   }
     829             : 
     830             :   /* Not found */
     831             : 
     832     3072000 :   return sentinel;
     833  1839202794 : }
     834             : 
     835             : FD_FN_PURE MAP_IMPL_STATIC MAP_T const *
     836             : MAP_(query_safe)( MAP_T const *     join,
     837             :                   MAP_KEY_T const * key,
     838           0 :                   MAP_T const *     sentinel ) {
     839           0 :   MAP_(private_t) const * map = MAP_(private_const)( join );
     840             : 
     841           0 :   ulong         key_max  = map->key_max;
     842             : 
     843             :   /* Find the key */
     844             : 
     845           0 :   ulong hash = MAP_KEY_HASH( (key), (map->seed) );
     846           0 :   ulong const * head = MAP_(private_list_const)( map ) + ( hash & (map->list_cnt-1UL) );
     847           0 :   ulong const * cur  = head;
     848           0 :   for( ulong i = 0; i < key_max; ++i ) {
     849           0 :     ulong ele_idx = MAP_(private_unbox_idx)( *cur );
     850           0 :     if( FD_UNLIKELY( MAP_(private_is_null)( ele_idx ) || ele_idx >= key_max ) ) break; /* optimize for found */
     851           0 :     MAP_T const * ele = join + ele_idx;
     852           0 :     if(
     853             : #if MAP_MEMOIZE
     854             :         hash == ele->MAP_HASH &&
     855             : #endif
     856           0 :       FD_LIKELY( MAP_(key_eq)( key, &ele->MAP_KEY ) ) ) { /* Optimize for found (it is remove after all) */
     857           0 :       return ele; /* optimize for found */
     858           0 :     }
     859           0 :     cur = &ele->MAP_NEXT;
     860           0 :   }
     861             : 
     862             :   /* Not found */
     863             : 
     864           0 :   return sentinel;
     865           0 : }
     866             : 
     867             : MAP_IMPL_STATIC int
     868     6144006 : MAP_(verify)( MAP_T const * join ) {
     869             : 
     870 14472813600 : # define MAP_TEST(c) do {                                                        \
     871 14472813600 :     if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: %s", #c )); return -1; } \
     872 14472813600 :   } while(0)
     873             : 
     874     6144006 :   MAP_TEST( join );
     875             : 
     876     6144006 :   MAP_(private_t) const * map = MAP_(private_const)( join ); MAP_TEST( map!=NULL );
     877             : 
     878     6144006 :   MAP_TEST( MAP_(footprint)( map->key_max ) );
     879             : 
     880             :   /* seed can be anything as far as map is concerned */
     881             : 
     882     6144006 :   MAP_TEST( map->list_cnt==MAP_(private_list_cnt)( map->key_max ) );
     883     6144006 :   MAP_TEST( map->key_cnt <=map->key_max                           );
     884             : 
     885     6144006 :   ulong         key_max  = map->key_max;
     886     6144006 :   ulong         key_cnt  = map->key_cnt;
     887     6144006 :   ulong         seed     = map->seed;
     888     6144006 :   ulong         list_cnt = map->list_cnt;
     889     6144006 :   ulong const * list     = MAP_(private_list_const)( map ); MAP_TEST( list!=NULL );
     890             : 
     891     6144006 :   ulong free_cnt = key_max - key_cnt;
     892             : 
     893     6144006 :   ulong ele_idx;
     894     6144006 :   ulong cnt;
     895             : 
     896     6144006 :   cnt = 0UL;
     897  1579009542 :   for( ulong list_idx=0UL; list_idx<list_cnt; list_idx++ ) {
     898  1572865536 :     ele_idx =  MAP_(private_unbox_idx)( list[ list_idx ] );
     899  1572865536 :     MAP_TEST( !MAP_(private_unbox_tag)( list[ list_idx ] ) ); /* Head marked as used */
     900  3145729536 :     while( !MAP_(private_is_null)( ele_idx ) ) {
     901  1572864000 :       MAP_TEST( cnt<key_cnt );
     902  1572864000 :       MAP_TEST( ele_idx<key_max );
     903  1572864000 :       MAP_T const * ele = join + ele_idx;
     904             : #if MAP_MEMOIZE
     905   786432000 :       MAP_TEST( ele->MAP_HASH == MAP_KEY_HASH( (&ele->MAP_KEY), (map->seed) ) );
     906   786432000 : #endif
     907  1572864000 :       MAP_TEST( MAP_(private_list_idx)( &ele->MAP_KEY, seed, list_cnt )==list_idx );
     908  1572864000 :       cnt++;
     909  1572864000 :       ele_idx  = MAP_(private_unbox_idx)( ele->MAP_NEXT );
     910  1572864000 :       MAP_TEST( !MAP_(private_unbox_tag)( ele->MAP_NEXT ) ); /* Element marked as used */
     911  1572864000 :     }
     912  1572865536 :   }
     913             : 
     914     6144006 :   MAP_TEST( cnt==key_cnt );
     915             : 
     916     6144006 :   cnt = 0UL;
     917             : 
     918     6144006 :   ele_idx = MAP_(private_unbox_idx)( map->free_stack );
     919     6144006 :   MAP_TEST( MAP_(private_unbox_tag)( map->free_stack ) ); /* Head marked as free */
     920  1579011078 :   while( !MAP_(private_is_null)( ele_idx ) ) {
     921  1572867072 :     MAP_TEST( cnt<free_cnt );
     922  1572867072 :     MAP_TEST( ele_idx<key_max );
     923  1572867072 :     MAP_T const * ele = join + ele_idx;
     924  1572867072 :     cnt++;
     925  1572867072 :     ele_idx = MAP_(private_unbox_idx)( ele->MAP_NEXT );
     926  1572867072 :     MAP_TEST( MAP_(private_unbox_tag)( ele->MAP_NEXT ) ); /* Element marked as free */
     927  1572867072 :   }
     928             : 
     929     6144006 :   MAP_TEST( cnt==free_cnt );
     930             : 
     931  1579008006 :   for( ulong ele_idx=0UL; ele_idx<key_cnt; ele_idx++ ) {
     932  1572864000 :     if( MAP_(private_unbox_tag)( join[ele_idx].MAP_NEXT ) ) continue;
     933  1048162794 :     MAP_TEST( MAP_(query_const)( join, &join[ele_idx].MAP_KEY, NULL )==&join[ele_idx] );
     934  1048162794 :   }
     935             : 
     936     6144006 : # undef MAP_TEST
     937             : 
     938     6144006 :   return 0;
     939     6144006 : }
     940             : 
     941             : MAP_IMPL_STATIC MAP_T *
     942             : MAP_(insert)( MAP_T *           join,
     943     3072000 :               MAP_KEY_T const * key ) {
     944             : # if FD_TMPL_USE_HANDHOLDING
     945             :   if( FD_UNLIKELY( MAP_(key_cnt)( join )>=MAP_(key_max)( join ) ) ) FD_LOG_CRIT(( "map is full" ));
     946             : # endif
     947     3072000 :   MAP_(private_t) * map = MAP_(private)( join );
     948             : 
     949             :   /* Pop the free stack to allocate an element (this is guaranteed to
     950             :      succeed as per contract) */
     951             : 
     952     3072000 :   ulong ele_idx = MAP_(private_unbox_idx)( map->free_stack );
     953     3072000 :   MAP_T * ele = join + ele_idx;
     954     3072000 :   map->free_stack = ele->MAP_NEXT; /* already tagged free */
     955     3072000 :   map->key_cnt++; /* Consider eliminating this to help make completely concurrent lockfree? */
     956             : 
     957             :   /* ... and map the newly allocated element to key (this is also
     958             :      guaranteed to not have collisions as per contract). Note that
     959             :      elements appear in the chain in order of newest to oldest. This
     960             :      property is NECESSARY for an important optimization in
     961             :      fd_funk_rec_query_global. */
     962             : 
     963     3072000 :   ulong hash = MAP_KEY_HASH( (key), (map->seed) );
     964     3072000 :   ulong * head = MAP_(private_list)( map ) + ( hash & (map->list_cnt-1UL) );
     965     3072000 :   MAP_(key_copy)( &ele->MAP_KEY, key );
     966     3072000 :   ele->MAP_NEXT = MAP_(private_box_next)( MAP_(private_unbox_idx)( *head ), 0 );
     967             : # if MAP_MEMOIZE
     968     1536000 :   ele->MAP_HASH = hash;
     969             : # endif
     970     3072000 :   *head = MAP_(private_box_next)( ele_idx, 0 );
     971     3072000 :   return ele;
     972     3072000 : }
     973             : 
     974             : MAP_IMPL_STATIC MAP_T *
     975           0 : MAP_(pop_free_ele)( MAP_T * join ) {
     976           0 : # if FD_TMPL_USE_HANDHOLDING
     977           0 :   if( FD_UNLIKELY( !MAP_(key_cnt)( join ) ) ) FD_LOG_CRIT(( "map is empty" ));
     978           0 : # endif
     979           0 :   MAP_(private_t) * map = MAP_(private)( join );
     980           0 : 
     981           0 :   /* Pop the free stack to allocate an element (this is guaranteed to
     982           0 :      succeed as per contract) */
     983           0 : 
     984           0 :   ulong ele_idx = MAP_(private_unbox_idx)( map->free_stack );
     985           0 :   MAP_T * ele = join + ele_idx;
     986           0 :   map->free_stack = ele->MAP_NEXT; /* already tagged free */
     987           0 :   return ele;
     988           0 : }
     989             : 
     990             : MAP_IMPL_STATIC MAP_T *
     991             : MAP_(push_free_ele)( MAP_T * join,
     992           0 :                      MAP_T * ele ) {
     993           0 :   MAP_(private_t) * map = MAP_(private)( join );
     994           0 : 
     995           0 :   ulong ele_idx = (ulong)(ele - join);
     996           0 : 
     997           0 :   ele->MAP_NEXT = map->free_stack; /* already tagged free */
     998           0 :   map->free_stack = MAP_(private_box_next)( ele_idx, 1 );
     999           0 :   return ele;
    1000           0 : }
    1001             : 
    1002             : MAP_IMPL_STATIC MAP_T *
    1003             : MAP_(insert_free_ele)( MAP_T *           join,
    1004             :                        MAP_T *           ele,
    1005           0 :                        MAP_KEY_T const * key ) {
    1006           0 :   MAP_(private_t) * map = MAP_(private)( join );
    1007           0 :   /* Map the allocated element to key (this is also
    1008           0 :      guaranteed to not have collisions as per contract). */
    1009           0 : 
    1010           0 :   ulong ele_idx = (ulong)(ele - join);
    1011           0 : 
    1012           0 :   ulong * head = MAP_(private_list)( map ) + MAP_(private_list_idx)( key, map->seed, map->list_cnt );
    1013           0 :   MAP_(key_copy)( &ele->MAP_KEY, key );
    1014           0 :   ele->MAP_NEXT = MAP_(private_box_next)( MAP_(private_unbox_idx)( *head ), 0 );
    1015           0 :   *head = MAP_(private_box_next)( ele_idx, 0 );
    1016           0 :   return ele;
    1017           0 : }
    1018             : 
    1019             : MAP_IMPL_STATIC MAP_T *
    1020             : MAP_(remove)( MAP_T *           join,
    1021     6144000 :               MAP_KEY_T const * key ) {
    1022     6144000 :   MAP_(private_t) * map = MAP_(private)( join );
    1023             : 
    1024             : 
    1025             :   /* Find the key */
    1026             : 
    1027     6144000 :   ulong hash = MAP_KEY_HASH( (key), (map->seed) );
    1028     6144000 :   ulong * head = MAP_(private_list)( map ) + ( hash & (map->list_cnt-1UL) );
    1029     6144000 :   ulong * cur  = head;
    1030     9330000 :   for(;;) {
    1031     9330000 :     ulong ele_idx = MAP_(private_unbox_idx)( *cur );
    1032     9330000 :     if( FD_UNLIKELY( MAP_(private_is_null)( ele_idx ) ) ) break;
    1033     6258000 :     MAP_T * ele = join + ele_idx;
    1034     6258000 :     if(
    1035             : #if MAP_MEMOIZE
    1036     3129000 :        hash == ele->MAP_HASH &&
    1037             : #endif
    1038     4665000 :       FD_LIKELY( MAP_(key_eq)( key, &ele->MAP_KEY ) ) ) { /* Optimize for found (it is remove after all) */
    1039             :       /* Found, remove the mapping and push it to free stack. */
    1040     3072000 :       *cur = ele->MAP_NEXT; /* already tagged empty */
    1041     3072000 :       ele->MAP_NEXT = map->free_stack; /* already tagged free */
    1042     3072000 :       map->free_stack = MAP_(private_box_next)( ele_idx, 1 );
    1043     3072000 :       map->key_cnt--;
    1044     3072000 :       return ele;
    1045     3072000 :     }
    1046     3186000 :     cur = &ele->MAP_NEXT; /* Retain the pointer to next so we can rewrite it later. */
    1047     3186000 :   }
    1048             : 
    1049             :   /* Not found */
    1050     3072000 :   return NULL;
    1051     6144000 : }
    1052             : 
    1053             : #undef MAP_IMPL_STATIC
    1054             : 
    1055             : #endif
    1056             : 
    1057             : #undef MAP_
    1058             : #undef MAP_IDX_NULL
    1059             : 
    1060             : #undef MAP_IMPL_STYLE
    1061             : #undef MAP_MAGIC
    1062             : #undef MAP_KEY_COPY
    1063             : #undef MAP_KEY_HASH
    1064             : #undef MAP_KEY_EQ
    1065             : #undef MAP_NEXT
    1066             : #undef MAP_KEY
    1067             : #undef MAP_KEY_T
    1068             : #undef MAP_T
    1069             : #undef MAP_NAME
    1070             : #undef MAP_MEMOIZE
    1071             : #undef MAP_HASH

Generated by: LCOV version 1.14