LCOV - code coverage report
Current view: top level - util/tmpl - fd_map.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 95 98 96.9 %
Date: 2025-08-05 05:04:49 Functions: 150 4320 3.5 %

          Line data    Source code
       1             : /* Declare ultra high performance dynamic key-val maps of bounded
       2             :    compile time size.  Typical usage:
       3             : 
       4             :      struct mymap {
       5             :        ulong key;  // Technically "MAP_KEY_T  MAP_KEY;"  (default is ulong key)
       6             :        uint  hash; // Technically "MAP_HASH_T MAP_HASH;" (default is uint  hash), ==mymap_hash(key)
       7             :        ... key and hash can be located arbitrarily in struct
       8             :        ... hash is not required if MAP_MEMOIZE is zero
       9             :        ... the rest of the struct is POD state/values associated with key
      10             :        ... the mapping of a key to a map slot is arbitrary and might
      11             :        ... change over the lifetime of the key
      12             :      };
      13             : 
      14             :      typedef struct mymap mymap_t;
      15             : 
      16             :      #define MAP_NAME        mymap
      17             :      #define MAP_T           mymap_t
      18             :      #define MAP_LG_SLOT_CNT 12
      19             :      #include "util/tmpl/fd_map.c"
      20             : 
      21             :   will declare the following static inline APIs as a header only style
      22             :   library in the compilation unit:
      23             : 
      24             :     // align/footprint - Return the alignment/footprint required for a
      25             :     // memory region to be used as mymap.
      26             :     //
      27             :     // new - Format a memory region pointed to by shmem into a mymap.
      28             :     // Assumes shmem points to a region with the required alignment and
      29             :     // footprint not in use by anything else.  Caller is not joined on
      30             :     // return.  Returns shmem.
      31             :     //
      32             :     // join - Join a mymap.  Assumes shmap points at a region formatted
      33             :     // as a mymap.  Returns a handle of the callers join.
      34             :     //
      35             :     // leave - Leave a mymap.  Assumes mymap points to a current join.
      36             :     // Returns a pointer to the shared memory region the join.
      37             :     //
      38             :     // delete - Unformat a memory region used as a mymap.  Assumes
      39             :     // shmymap points to a formatted region with no current joins.
      40             :     // Returns a pointer to the unformatted memory region.
      41             : 
      42             :     ulong     mymap_align    ( void              );
      43             :     ulong     mymap_footprint( void              );
      44             :     void *    mymap_new      ( void *    shmem   );
      45             :     mymap_t * mymap_join     ( void *    shmymap );
      46             :     void *    mymap_leave    ( mymap_t * mymap   );
      47             :     void *    mymap_delete   ( void *    shmymap );
      48             : 
      49             :     // Return the maximum number of keys that can be inserted into a
      50             :     // mymap.  The mymap will become increasingly inefficient the more
      51             :     // keys there are.  Recommend not using more than around half this
      52             :     // value.
      53             : 
      54             :     ulong mymap_key_max( void ); // == 2^MAP_LG_SLOT_CNT - 1
      55             : 
      56             :     // Return the number of slots in a mymap.  This is to facilitate
      57             :     // iterating / listing all contents of a mymap (this process is not
      58             :     // algorithmically ideal for a sparse mymap).  E.g.
      59             :     // mymap[slot_idx].key for slot_idx in [0,mymap_slot_cnt()] when
      60             :     // key!=0 is the set of all current key-vals in the mymap.
      61             : 
      62             :     ulong mymap_slot_cnt( void ); // == 2^MAP_LG_SLOT_CNT
      63             : 
      64             :     // Returns the index of the slot (allows communicating locations of
      65             :     // map entries between users of mymap in different address spaces).
      66             :     // Might imply a division (probably via magic multiply) if
      67             :     // sizeof(mymap_t) is not a power of two (as such, power-of-2
      68             :     // sizeof(mymap_t) have good Feng Shui).  Assumes that mymap is a
      69             :     // current join and slot points to a slot in that join.
      70             : 
      71             :     ulong mymap_slot_idx( mymap_t const * mymap, mymap_t const * slot );
      72             : 
      73             :     // Returns the "null" key, which is the canonical key that will
      74             :     // never be inserted (typically zero).
      75             : 
      76             :     ulong mymap_key_null( void ); // == MAP_KEY_NULL
      77             : 
      78             :     // Return the 1/0 if key is a key that will never/might be inserted.
      79             : 
      80             :     int mymap_key_inval( ulong key );
      81             : 
      82             :     // Return the 1/0 if k0 and k1 are keys that are the same
      83             : 
      84             :     int mymap_key_equal( ulong k0, ulong k1 );
      85             : 
      86             :     // Return the hash of key used by the map.  Should ideally be a
      87             :     // random mapping from MAP_KEY_T -> MAP_HASH_T.
      88             : 
      89             :     uint mymap_key_hash( ulong key );
      90             : 
      91             :     // Insert key into the map, fast O(1).  Returns a pointer to the map
      92             :     // the entry with key on success and NULL on failure (i.e. key is
      93             :     // already in the map).  The returned pointer lifetime is until
      94             :     // _any_ map remove or map leave.  The caller should not change the
      95             :     // values in key or hash but is free to modify other fields in the
      96             :     // entry on return.  Assumes map is a current join, there are less
      97             :     // than mymap_key_max() keys in the map and key is not a value that
      98             :     // will never be inserted.
      99             : 
     100             :     mymap_t * mymap_insert( mymap_t * map, ulong key );
     101             : 
     102             :     // Remove entry from map, fast O(1).  Assumes map is a current join
     103             :     // and that entry points to a full entry currently in the map.  When
     104             :     // the function returns, the entry pointed to by entry may be
     105             :     // clobbered.
     106             :     // Removal performance very slightly more optimal if sizeof(mymap_t)
     107             :     // is a power of two.
     108             : 
     109             :     void mymap_remove( mymap_t * map, mymap_t * entry );
     110             : 
     111             :     // Remove all entries from the map. O(map size).
     112             : 
     113             :     void mymap_clear( mymap_t * map );
     114             : 
     115             :     // Query map for key, fast O(1).  Returns a pointer to the map slot
     116             :     // holding key or null if key not in map.  The returned pointer
     117             :     // lifetime is until the next map remove or map leave.  The caller
     118             :     // should not change key or hash but is free to modify other fields
     119             :     // in the entry.  Assumes map is a current join and that key is
     120             :     // non-zero.  mymap_query_const is a const correct version.
     121             : 
     122             :     mymap_t *       mymap_query      ( mymap_t *       map, ulong key, mymap_t *       null );
     123             :     mymap_t const * mymap_query_const( mymap_t const * map, ulong key, mymap_t const * null );
     124             : 
     125             :   You can do this as often as you like in a compilation unit to get
     126             :   different types of maps.  Since it is all static inline, it is fine
     127             :   to do this in a header too.  Further, options exist to use different
     128             :   hashing functions, variable length keys, etc as detailed below.
     129             : 
     130             :   For use with non-POD C++ structs, map_new assumes that a slot can be
     131             :   initialized to empty by assigning its key to MAP_KEY_NULL.  Map insert
     132             :   will use MAP_KEY_MOVE to move the user provided key into the slot key
     133             :   value.  Map remove will MAP_MOVE slots as necessary to preserve their
     134             :   probe sequences and assumes the user has already cleaned up the entry
     135             :   to remove enough so that all that needs to be done to eliminate the
     136             :   entry from the map is assign the entry's key to MAP_KEY_NULL.
     137             : 
     138             :     mymap_t * slot = mymap_insert( map, cxx_key );
     139             :     if( FD_UNLIKELY( !slot ) ) ... handle failure (cxx_key was not moved)
     140             :     else {
     141             :       ... mymap_insert did a MAP_KEY_MOVE of cxx_key into slot->key
     142             :       ... clean cxx_key's shell here as necessary here
     143             :       ... initialize other slot fields as necessary
     144             :     }
     145             : 
     146             :   and on removal:
     147             : 
     148             :     ... clean up other slot fields as necessary
     149             :     ... clean up slot->key as necessary
     150             :     mymap_remove( map, slot );
     151             :     ... the mapping of keys to map slots might have been changed by the
     152             :     ... mymap_remove.  Any motion of slots was done via:
     153             :     ... MAP_MOVE( dst_slot, src_slot )
     154             : 
     155             :   fd_map align and footprint are declaration friendly.  E.g.
     156             : 
     157             :     mymap_t map[ ... map slot cnt ... ];
     158             : 
     159             :   will have the appropriate alignment and footprint for a mymap_t map. */
     160             : 
     161             : #include "../bits/fd_bits.h"
     162             : 
     163             : #ifndef MAP_NAME
     164             : #error "Define MAP_NAME"
     165             : #endif
     166             : 
     167             : /* A MAP_T should be something reasonable to shallow copy with the
     168             :    fields described above. */
     169             : 
     170             : #ifndef MAP_T
     171             : #error "Define MAP_T struct"
     172             : #endif
     173             : 
     174             : /* MAP_HASH_T should be an unsigned integral type. */
     175             : 
     176             : #ifndef MAP_HASH_T
     177  1845481656 : #define MAP_HASH_T uint
     178             : #endif
     179             : 
     180             : /* MAP_HASH is the MAP_T hash field name.  Defaults to hash. */
     181             : 
     182             : #ifndef MAP_HASH
     183        6906 : #define MAP_HASH hash
     184             : #endif
     185             : 
     186             : /* MAP_LG_SLOT_CNT is the log2 of the number of slots in the map. */
     187             : 
     188             : #ifndef MAP_LG_SLOT_CNT
     189             : #error "Define MAP_LG_SLOT_CNT, should be at least 1 and much less than 63"
     190             : #endif
     191             : 
     192             : /* MAP_KEY_T should be something reasonable to pass to a static inline
     193             :    by value, assign to MAP_KEY_NULL, compare for equality and copy.
     194             :    E.g. a uint, ulong, __m128i, etc. */
     195             : 
     196             : #ifndef MAP_KEY_T
     197   433553730 : #define MAP_KEY_T ulong
     198             : #else
     199             : #if !defined(MAP_KEY_NULL) || !defined(MAP_KEY_INVAL) || !defined(MAP_KEY_EQUAL) || !defined(MAP_KEY_EQUAL_IS_SLOW) || !defined(MAP_KEY_HASH)
     200             : #error "Define MAP_KEY_NULL, MAP_KEY_INVAL, MAP_KEY_EQUAL, MAP_KEY_EQUAL_IS_SLOW, and MAP_KEY_HASH if using a custom MAP_KEY_T"
     201             : #endif
     202             : #endif
     203             : 
     204             : /* MAP_KEY is the MAP_T key field name.  Defaults to key. */
     205             : 
     206             : #ifndef MAP_KEY
     207  5060627703 : #define MAP_KEY key
     208             : #endif
     209             : 
     210             : #ifndef MAP_KEY_NULL
     211             : #if defined(MAP_KEY_INVAL)
     212             : #error "MAP_KEY_INVAL is defined but MAP_KEY_NULL is not"
     213             : #endif
     214             : #endif
     215             : 
     216             : #ifndef MAP_KEY_INVAL
     217             : #if defined(MAP_KEY_NULL)
     218             : #error "MAP_KEY_NULL is defined but MAP_KEY_INVAL is not"
     219             : #endif
     220             : #endif
     221             : 
     222             : /* MAP_KEY_NULL is a key that will never be inserted. */
     223             : 
     224             : #ifndef MAP_KEY_NULL
     225      530850 : #define MAP_KEY_NULL 0UL
     226             : #endif
     227             : 
     228             : /* MAP_KEY_INVAL returns 1 if k0 is key that will never be inserted
     229             :    and zero otherwise.  Note that MAP_KEY_INVAL( MAP_KEY_NULL ) should
     230             :    be true.  This should be generally fast. */
     231             : 
     232             : #ifndef MAP_KEY_INVAL
     233   433545702 : #define MAP_KEY_INVAL(k) !(k)
     234             : #endif
     235             : 
     236             : /* MAP_KEY_EQUAL returns 0/1 if k0 is the same/different.  Note that
     237             :    this function may also be called with MAP_KEY_NULL. */
     238             : 
     239             : #ifndef MAP_KEY_EQUAL
     240   470285517 : #define MAP_KEY_EQUAL(k0,k1) (k0)==(k1)
     241             : #endif
     242             : 
     243             : /* If MAP_KEY_EQUAL_IS_SLOW is slow (e.g. variable length string
     244             :    compare, large buffer compares, etc), set MAP_KEY_EQUAL_IS_SLOW to
     245             :    non-zero.  Then, if MAP_MEMOIZE (below) is set, precomputed key hashes
     246             :    will be used accelerate key insert and key query. */
     247             : 
     248             : #ifndef MAP_KEY_EQUAL_IS_SLOW
     249             : #define MAP_KEY_EQUAL_IS_SLOW 0
     250             : #endif
     251             : 
     252             : /* MAP_KEY_HASH takes a key and maps it into MAP_HASH_T uniform pseudo
     253             :    randomly. */
     254             : 
     255             : #ifndef MAP_KEY_HASH
     256   121091733 : #define MAP_KEY_HASH(key) (MAP_HASH_T)fd_ulong_hash( key )
     257             : #endif
     258             : 
     259             : /* MAP_KEY_MOVE moves the contents from src to dst.  Non-POD key types
     260             :    need to customize this accordingly (and handle the case of
     261             :    ks==MAP_KEY_NULL).  Defaults to shallow copy. */
     262             : 
     263             : #ifndef MAP_KEY_MOVE
     264  1603471896 : #define MAP_KEY_MOVE(kd,ks) (kd)=(ks)
     265             : #endif
     266             : 
     267             : /* MAP_MOVE moves the contents of a MAP_T from src to dst.  Non-POD key
     268             :    types need to customize this accordingly.  Defaults to shallow copy. */
     269             : 
     270             : #ifndef MAP_MOVE
     271      374472 : #define MAP_MOVE(d,s) (d)=(s)
     272             : #endif
     273             : 
     274             : /* If MAP_MEMOIZE is defined to non-zero, the MAP_T requires a hash
     275             :    field that will hold the value of the MAP_KEY_HASH of the MAP_T's key
     276             :    field when the map slot is not empty (undefined otherwise).  This is
     277             :    useful for accelerating user operations that might need a hash of the
     278             :    key and for accelerating remove operations.  It is also potentially
     279             :    useful as a way to accelerate slow key comparison operations (see
     280             :    MAP_KEY_EQUAL_IS_SLOW). */
     281             : 
     282             : #ifndef MAP_MEMOIZE
     283             : #define MAP_MEMOIZE 1
     284             : #endif
     285             : 
     286             : /* MAP_QUERY_OPT allows the user to specify how the map query function
     287             :    should be optimized.
     288             :      0 -> optimize for low fill ratio
     289             :      1 -> optimize for low fill ratio and extremely rare query failure
     290             :      2 -> optimize for low fill ratio and extremely rare query success */
     291             : 
     292             : #ifndef MAP_QUERY_OPT
     293             : #define MAP_QUERY_OPT 0
     294             : #endif
     295             : 
     296             : #if FD_TMPL_USE_HANDHOLDING
     297             : #include "../log/fd_log.h"
     298             : #endif
     299             : 
     300             : /* Implementation *****************************************************/
     301             : 
     302 10039320411 : #define MAP_(n)       FD_EXPAND_THEN_CONCAT3(MAP_NAME,_,n)
     303  4014772635 : #define MAP_SLOT_CNT  (1UL<<(MAP_LG_SLOT_CNT))
     304  4013489988 : #define MAP_SLOT_MASK (MAP_SLOT_CNT-1UL)
     305             : 
     306             : FD_PROTOTYPES_BEGIN
     307             : 
     308             : /* Private APIs *******************************************************/
     309             : 
     310             : /* Get the linear probing starting slot for a key and the slot to probe
     311             :    after a given slot */
     312             : 
     313  1845491580 : FD_FN_CONST static inline ulong MAP_(private_start)( MAP_HASH_T hash ) { return (ulong)(hash & (MAP_HASH_T)MAP_SLOT_MASK); }
     314  2167997406 : FD_FN_CONST static inline ulong MAP_(private_next) ( ulong      slot ) { return (++slot) & MAP_SLOT_MASK; }
     315             : 
     316             : /* Public APIS ********************************************************/
     317             : 
     318        7716 : FD_FN_CONST static inline ulong MAP_(align)    ( void ) { return alignof(MAP_T); }
     319        8493 : FD_FN_CONST static inline ulong MAP_(footprint)( void ) { return sizeof(MAP_T)*MAP_SLOT_CNT; }
     320             : 
     321             : static inline void *
     322        8553 : MAP_(new)( void *  shmem ) {
     323             : # if FD_TMPL_USE_HANDHOLDING
     324             :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, MAP_(align)() ) ) ) FD_LOG_CRIT(( "unaligned shmem" ));
     325             : # endif
     326        8553 :   MAP_T * map = (MAP_T *)shmem;
     327     1269129 :   for( ulong slot_idx=0UL; slot_idx<MAP_SLOT_CNT; slot_idx++ ) map[ slot_idx ].MAP_KEY = (MAP_KEY_NULL);
     328        8553 :   return map;
     329        8553 : }
     330             : 
     331    69459217 : static inline MAP_T * MAP_(join)  ( void *  shmap ) { return (MAP_T *)shmap; }
     332    69459166 : static inline void *  MAP_(leave) ( MAP_T * map   ) { return map; }
     333        7686 : static inline void *  MAP_(delete)( void *  shmap ) { return shmap; }
     334             : 
     335        1002 : FD_FN_CONST static inline ulong MAP_(key_max) ( void ) { return MAP_SLOT_MASK; }
     336        1542 : FD_FN_CONST static inline ulong MAP_(slot_cnt)( void ) { return MAP_SLOT_CNT;  }
     337             : 
     338             : FD_FN_CONST static inline ulong
     339  1603467471 : MAP_(slot_idx)( MAP_T const * map, MAP_T const * entry ) {
     340             : # if FD_TMPL_USE_HANDHOLDING
     341             :   if( FD_UNLIKELY( ((ulong)(entry-map)>=MAP_SLOT_CNT) | (map>entry) ) ) FD_LOG_CRIT(( "index out of bounds" ));
     342             : # endif
     343  1603467471 :   return (ulong)(entry-map);
     344  1603467471 : }
     345             : 
     346        1551 : FD_FN_CONST static inline MAP_KEY_T MAP_(key_null)( void ) { return (MAP_KEY_NULL); }
     347             : 
     348             : /* These are FD_FN_PURE instead of FD_FN_CONST in case a non-POD
     349             :    MAP_KEY_T.  FIXME: CONSIDER LETTING THE COMPILER SORT THIS OUT? */
     350             : 
     351  5493587073 : FD_FN_PURE static inline int MAP_(key_inval)( MAP_KEY_T k0               ) { return (MAP_KEY_INVAL(k0)); }
     352   598769574 : FD_FN_PURE static inline int MAP_(key_equal)( MAP_KEY_T k0, MAP_KEY_T k1 ) { return (MAP_KEY_EQUAL(k0,k1)); }
     353             : 
     354  1845491580 : FD_FN_PURE static inline MAP_HASH_T MAP_(key_hash)( MAP_KEY_T key ) { return (MAP_KEY_HASH(key)); }
     355             : 
     356             : FD_FN_UNUSED static MAP_T * /* Work around -Winline */
     357             : MAP_(insert)( MAP_T *   map,
     358  1603722738 :               MAP_KEY_T key ) {
     359             : # if FD_TMPL_USE_HANDHOLDING
     360             :   if( FD_UNLIKELY( MAP_(key_inval)( key ) ) ) FD_LOG_CRIT(( "invalid key" ));
     361             : # endif
     362  1603722738 :   MAP_HASH_T hash = MAP_(key_hash)( key );
     363  1603722738 :   ulong slot = MAP_(private_start)( hash );
     364  1603722738 :   MAP_T * m;
     365  1737524886 :   for(;;) {
     366  1737524886 :     m = map + slot;
     367  1737524886 :     MAP_KEY_T map_key = m->MAP_KEY;
     368  1737524886 :     if( FD_LIKELY( MAP_(key_inval)( map_key ) ) ) break; /* Optimize for not found */
     369             : #   if MAP_MEMOIZE && MAP_KEY_EQUAL_IS_SLOW          /* ... and then for searching */
     370        1296 :     if( FD_UNLIKELY( m->MAP_HASH==hash && MAP_(key_equal)( map_key, key ) ) ) return NULL;
     371             : #   else
     372   134051694 :     if( FD_UNLIKELY( MAP_(key_equal)( map_key, key ) ) ) return NULL;
     373   133800855 : #   endif
     374   133802148 :     slot = MAP_(private_next)( slot );
     375   133802148 :   }
     376  1603471896 :   MAP_KEY_MOVE( m->MAP_KEY, key );
     377             : # if MAP_MEMOIZE
     378        5712 :   m->MAP_HASH = hash;
     379             : # endif
     380  1603471896 :   return m;
     381  1603722738 : }
     382             : 
     383             : static inline void
     384             : MAP_(remove)( MAP_T * map,
     385  1603465935 :               MAP_T * entry ) {
     386  1603465935 :   ulong slot = MAP_(slot_idx)( map, entry );
     387             : 
     388  1603840407 :   for(;;) {
     389             : 
     390             :     /* Make a hole at slot */
     391             : 
     392  1603840407 :     map[slot].MAP_KEY = (MAP_KEY_NULL);
     393  1603840407 :     ulong hole = slot;
     394             : 
     395             :     /* The creation of a hole at slot might have disrupted the probe
     396             :        sequence involving the keys in any contiguously occupied map
     397             :        entry after slot. */
     398             : 
     399  1727328339 :     for(;;) {
     400  1727328339 :       slot = MAP_(private_next)( slot );
     401             : 
     402             :       /* At this point, map entries (hole,slot) (cyclic) are occupied
     403             :          and the probe sequence for these has been confirmed to be
     404             :          intact.  If slot is empty, then all probe sequences are intact. */
     405             : 
     406  1727328339 :       MAP_KEY_T key = map[slot].MAP_KEY;
     407  1727328339 :       if( MAP_(key_inval)(key) ) return;
     408             : 
     409             :       /* slot is occupied.  If a probe looking for the key at slot does
     410             :          not start its scan in (hole,slot] (cyclic), its scan will fail
     411             :          erroneously due to the hole just made.  In this case, we move
     412             :          slot to hole to restore the probe sequence for the key at slot
     413             :          and then make a new hole at slot.  As the new hole could break
     414             :          the other probe sequences, we start over on the new hole. */
     415             : 
     416             : #     if MAP_MEMOIZE
     417           0 :       MAP_HASH_T hash = map[slot].MAP_HASH;
     418             : #     else
     419   123862404 :       MAP_HASH_T hash = MAP_(key_hash)( key );
     420             : #     endif
     421   123862404 :       ulong start = MAP_(private_start)( hash );
     422   123862404 :       if( !(((hole<start) & (start<=slot)) | ((hole>slot) & ((hole<start) | (start<=slot)))) ) break;
     423   123862404 :     }
     424             : 
     425      374472 :     MAP_MOVE( map[hole], map[slot] );
     426      374472 :   }
     427             :   /* never get here */
     428  1603465935 : }
     429             : 
     430             : static inline void
     431          27 : MAP_(clear)( MAP_T * map ) {
     432        3483 :   for( ulong slot_idx=0UL; slot_idx<MAP_SLOT_CNT; slot_idx++ ) map[ slot_idx ].MAP_KEY = (MAP_KEY_NULL);
     433          27 : }
     434             : 
     435             : FD_FN_PURE FD_FN_UNUSED static MAP_T * /* Work around -Winline */
     436             : MAP_(query)( MAP_T *   map,
     437             :              MAP_KEY_T key,
     438   117906438 :              MAP_T *   null ) {
     439             : # if FD_TMPL_USE_HANDHOLDING
     440             :   if( FD_UNLIKELY( MAP_(key_inval)( key ) ) ) FD_LOG_CRIT(( "invalid key" ));
     441             : # endif
     442   117906438 :   MAP_HASH_T hash = MAP_(key_hash)( key );
     443   117906438 :   ulong slot = MAP_(private_start)( hash );
     444   117906438 :   MAP_T * m;
     445   424773357 :   for(;;) {
     446   424773357 :     m = map + slot;
     447   424773357 :     MAP_KEY_T map_key = m->MAP_KEY;
     448             : 
     449             : #   if MAP_MEMOIZE && MAP_KEY_EQUAL_IS_SLOW
     450        2706 : #   define MAP_IMPL_QUERY_FOUND (hash==m->MAP_HASH && MAP_(key_equal)( map_key, key ))
     451             : #   else
     452   424770387 : #   define MAP_IMPL_QUERY_FOUND MAP_(key_equal)( map_key, key )
     453             : #   endif
     454             : 
     455             : #   if MAP_QUERY_OPT==0
     456   424773093 :     int found = MAP_IMPL_QUERY_FOUND;
     457   424773093 :     int empty = MAP_(key_inval)( map_key );
     458             :     int done  = found | empty;
     459   424773093 :     if( empty ) m = null; /* cmov */
     460   424773093 :     FD_COMPILER_FORGET( done );
     461   424773093 :     if( FD_LIKELY( done ) ) break;
     462             : #   elif MAP_QUERY_OPT==1
     463           0 :     if( FD_LIKELY( MAP_IMPL_QUERY_FOUND       ) ) break;
     464           0 :     if( FD_LIKELY( MAP_(key_inval)( map_key ) ) ) return null;
     465             : #   else
     466         264 :     if( FD_LIKELY( MAP_(key_inval)( map_key ) ) ) return null;
     467         243 :     if( FD_LIKELY( MAP_IMPL_QUERY_FOUND       ) ) break;
     468         204 : #   endif
     469             : 
     470         204 : #   undef MAP_IMPL_QUERY_FOUND
     471             : 
     472   306866919 :     slot = MAP_(private_next)( slot );
     473   306866919 :   }
     474          39 :   return m;
     475   117906438 : }
     476             : 
     477             : FD_FN_PURE static inline MAP_T const *
     478             : MAP_(query_const)( MAP_T const * map,
     479             :                    MAP_KEY_T     key,
     480         231 :                    MAP_T const * null ) {
     481         231 :   return (MAP_T const *)MAP_(query)( (MAP_T *)map, key, (MAP_T *)null ); /* query doesn't actual change any memory */
     482         231 : }
     483             : 
     484             : FD_PROTOTYPES_END
     485             : 
     486             : #undef MAP_SLOT_MASK
     487             : #undef MAP_SLOT_CNT
     488             : #undef MAP_
     489             : 
     490             : /* End implementation *************************************************/
     491             : 
     492             : #undef MAP_QUERY_OPT
     493             : #undef MAP_MEMOIZE
     494             : #undef MAP_MOVE
     495             : #undef MAP_KEY_MOVE
     496             : #undef MAP_KEY_HASH
     497             : #undef MAP_KEY_EQUAL_IS_SLOW
     498             : #undef MAP_KEY_EQUAL
     499             : #undef MAP_KEY_INVAL
     500             : #undef MAP_KEY_NULL
     501             : #undef MAP_KEY
     502             : #undef MAP_KEY_T
     503             : #undef MAP_LG_SLOT_CNT
     504             : #undef MAP_HASH
     505             : #undef MAP_HASH_T
     506             : #undef MAP_T
     507             : #undef MAP_NAME
     508             : 

Generated by: LCOV version 1.14