LCOV - code coverage report
Current view: top level - util/tmpl - fd_treap.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 507 569 89.1 %
Date: 2025-10-13 04:42:14 Functions: 204 11116 1.8 %

          Line data    Source code
       1             : /* Generate prototypes, inlines and implementations for ultra high
       2             :    performance treaps.  A treap hybrid of a binary search tree and heap
       3             :    such that it will well-balanced on average statistically.
       4             : 
       5             :    It is not as well-balanced theoretically as more complex
       6             :    non-randomized balancing tree algorithms (e.g. red-black trees, AVL
       7             :    trees, etc).  But it is often better in practice as it is much
       8             :    simpler (i.e. amenable for ultra high performance and small code
       9             :    footprint implementation) and very adaptable (e.g. easy to tweak to
      10             :    support adaptive queries like a splay tree, etc).  Additionally,
      11             :    there are a bunch of tricks in the below to optimize this much
      12             :    further than textbook implementations (those tend to miss a lot of
      13             :    practical opportunities including eliminating the cost of random
      14             :    number generation during operations).
      15             : 
      16             :    This API is designed for ultra tight coupling with pools, maps, other
      17             :    treaps, etc.  Likewise, a treap can be persisted beyond the lifetime
      18             :    of creating process, used concurrently in many common operations,
      19             :    used inter-process, relocated in memory, naively
      20             :    serialized/deserialized, moved between hosts, supports index
      21             :    compression for cache and memory bandwidth efficiency, etc.
      22             : 
      23             :    Typical usage:
      24             : 
      25             :      struct myele {
      26             : 
      27             :        ... Each field below can be located arbitrarily in the struct
      28             : 
      29             :        ulong parent; // Technically "TREAP_IDX_T TREAP_PARENT;" (default is ulong parent), similarly for left, right, and prio.
      30             :        ulong left;   // parent, left and right managed by the treap when a myele is in the treap.  prio is constant while in a
      31             :        ulong right;  // treap.  Further, all these can be used arbitrarily when not in treap (this includes perhaps using an
      32             :        ulong prio;   // anonymous union and/or bit fields for even more flexibility).  Additional considerations for prio below.
      33             : 
      34             :        // if TREAP_OPTIMIZE_ITERATION is set to 1, the following two
      35             :        // fields are also needed:
      36             :        ulong next;  // Similarly to above, technically TREAP_IDX_T TREAP_NEXT, TREAP_PREV.  These fields are treap-managed when
      37             :        ulong prev;  // a myele is in the treap and can be used arbitrarily when not.
      38             : 
      39             : 
      40             :        ... Generally speaking, this treap implement is agnostic to how
      41             :        ... the user manages treap priorities.  The algorithmic costs
      42             :        ... below assume that priorities are random though.
      43             : 
      44             :        ... For stock usage cases, the most optimal handling of prio is
      45             :        ... to initialize the prio field exactly once when the myele
      46             :        ... storage is first created with random values and then leave it
      47             :        ... unchanged thereafter (and potentially reused by other APIs
      48             :        ... needing similar randomization).  This eliminates all
      49             :        ... overheads associated with random number generation during
      50             :        ... operation.  But this also means that prio field is not
      51             :        ... available for use when a myele is not in the treap.
      52             : 
      53             :        ... In other situations, the user might choose to generate random
      54             :        ... priorities dynamically (as it done in textbook
      55             :        ... implementations) and/or adjust element priorities on the fly
      56             :        ... to splay-tree-like adaptively optimize treap queries.
      57             : 
      58             :        ... To support potential future bulk operations (e.g. fast treap
      59             :        ... splits / joins), it is recommended that these random values
      60             :        ... exclude the largest possible value but this is not strictly
      61             :        ... required currently.
      62             : 
      63             :        ... Note that other kinds of objects can use these fields for
      64             :        ... their metadata needs to keep element metadata / cache
      65             :        ... footprint overheads minimal.  The only restriction is that
      66             :        ... they cannot concurrently use the same field.  E.g. a pool
      67             :        ... could use the "parent" field for its next pointer while
      68             :        ... multiple other _disjoint_ treaps of myele_t from the same
      69             :        ... pool can all use the same treap fields.
      70             : 
      71             :        ... Note that fields could be made into narrow bit fields if
      72             :        ... useful for additional memory, bandwidth and cache efficiency.
      73             :        ... In particular, for priorities, unbiased pseudo random coin
      74             :        ... flipping is used to break ties (a little priority can go a
      75             :        ... very long way practically).
      76             : 
      77             :        ... Arbitrary application fields mixed in here.  Power-of-2
      78             :        ... element sizes have good cache and indexing Feng Shui.
      79             : 
      80             :        char key[ KEY_MAX ]; // For demonstration purposes
      81             : 
      82             :      };
      83             : 
      84             :      typedef struct myele myele_t;
      85             : 
      86             :      #define TREAP_NAME      mytreap
      87             :      #define TREAP_T         myele_t
      88             :      #define TREAP_QUERY_T   char const *
      89             :      #define TREAP_CMP(q,e)  strcmp( q, e->key )
      90             :      #define TREAP_LT(e0,e1) (strcmp( e0->key, e1->key )<0)
      91             :      #include "fd_treap.c"
      92             : 
      93             :    will declare the following APIs as a header-only style library in the
      94             :    compilation unit:
      95             : 
      96             :      int mytreap_cmp( char const *    q,  myele_t const * e  ); // Provides TREAP_CMP
      97             :      int mytreap_lt ( myele_t const * e0, myele_t const * e1 ); // Provides TREAP_LT
      98             : 
      99             :      // mytreap_idx_null returns the element index used to represent
     100             :      // NULL, infinite lifetime.  mytreap_ele_null returns NULL,
     101             :      // infinite lifetime, for completeness, mytreap_ele_null_const is a
     102             :      // const-correct version, also for completeness.
     103             : 
     104             :      ulong           mytreap_idx_null      ( void );
     105             :      myele_t *       mytreap_ele_null      ( void );
     106             :      myele_t const * mytreap_ele_null_const( void );
     107             : 
     108             :      // mytreap_{idx,ele}_is_null returns i==mytreap_idx_null() / !e
     109             : 
     110             :      int mytreap_idx_is_null( ulong           i );
     111             :      int mytreap_ele_is_null( myele_t const * e );
     112             : 
     113             :      // mytreap_idx returns e's index.  Assumes e is a pointer in the
     114             :      // caller's local address space to a pool element or is NULL.
     115             :      // Return will be in [0,ele_max) or mytreap_idx_null().  Lifetime
     116             :      // is the element storage lifetime.  mytreap_idx_fast is the same
     117             :      // assumes e is not NULL.  pool is a pointer in the caller's
     118             :      // address space to the ele_max linearly addressable storage region
     119             :      // backing the treap.
     120             : 
     121             :      ulong mytreap_idx     ( myele_t const * e, myele_t const * pool );
     122             :      ulong mytreap_idx_fast( myele_t const * e, myele_t const * pool );
     123             : 
     124             :      // mytreap_ele returns a pointer in the caller's address space to
     125             :      // element idx.  Assumes idx is in [0,ele_max) or is
     126             :      // mytreap_idx_null().  Return pointer lifetime is ele's local
     127             :      // lifetime.  mytreap_ele_fast is the same but assumes idx is not
     128             :      // mytreap_idx_null().  mytreap_ele[_fast]_const is a const correct
     129             :      // version.  pool is a pointer in the caller's address space to the
     130             :      // ele_max linearly addressable storage region backing the treap.
     131             : 
     132             :      myele_t * mytreap_ele     ( ulong i, myele_t * pool );
     133             :      myele_t * mytreap_ele_fast( ulong i, myele_t * pool );
     134             : 
     135             :      myele_t const * mytreap_ele_const     ( ulong i, myele_t const * pool );
     136             :      myele_t const * mytreap_ele_fast_const( ulong i, myele_t const * pool );
     137             : 
     138             :      // mytreap_seed is a helper that sets pool[i].prio for i in
     139             :      // [0,ele_max) to a random value in [0,PRIO_MAX) (yes half-open)
     140             :      // where PRIO_MAX is the largest possible value representable in
     141             :      // the prio field.  Uses seed (arbitrary) to select a simple hash
     142             :      // based random number of sequence for prio.
     143             :      //
     144             :      // If an application wants to set this as optimally and securely as
     145             :      // possible, it should seed pool[i].prio with a cryptographic
     146             :      // secure uniform random permutation of [0,ele_max) and/or
     147             :      // dynamically manage the prio field as described above.
     148             : 
     149             :      void mytreap_seed( myele_t * pool, ulong ele_max, ulong seed );
     150             : 
     151             :      // mytreap_{align,footprint} returns the alignment and footprint
     152             :      // needed for a memory region to hold the state of a mytreap of
     153             :      // elements from a linearly addressable ele_max element storage.
     154             :      // align will be an integer power-of-two and footprint will be a
     155             :      // multiple of align.  footprint will non-zero on a success and 0
     156             :      // on failure (silent) (e.g. ele_max too large for the specified
     157             :      // TREAP_IDX_T).  mytreap_t is stack declaration, data segment
     158             :      // declaration, heap allocation and stack allocation friendly.
     159             :      // Even though footprint is passed ele_max, the footprint is a
     160             :      // small O(1) spatial overhead.
     161             :      //
     162             :      // mytreap_new formats a memory region with the appropriate
     163             :      // alignment and footprint whose first byte in the caller's address
     164             :      // space is pointed to by shmem as a mytreap for elements from a
     165             :      // linearly addressable ele_max element storage.  Returns shmem on
     166             :      // success and NULL on failure (log details, e.g. ele_max is too
     167             :      // large for the width of the TREAP_IDX_T specified).  Caller is
     168             :      // not joined on return.  The treap will be empty.
     169             :      //
     170             :      // mytreap_join joins a mytreap.  Assumes shtreap points at a
     171             :      // memory region formatted as a mytreap in the caller's address
     172             :      // space.  Returns a handle to the caller's local join on success
     173             :      // and NULL on failure (logs details).
     174             :      //
     175             :      // mytreap_leave leaves a mytreap.  Assumes join points to a
     176             :      // current local join.  Returns shtreap used on join and NULL on
     177             :      // failure (logs details).
     178             :      //
     179             :      // mytreap_delete unformats a memory region used as a mytreap.
     180             :      // Assumes shtreap points to a memory region in the caller's local
     181             :      // address space formatted as a mytreap, that there are no joins to
     182             :      // the mytreap and that any application side cleanups have been
     183             :      // done.  Returns shtreap on success and NULL on failure (logs
     184             :      // details).
     185             : 
     186             :      ulong       mytreap_align    ( void                              );
     187             :      ulong       mytreap_footprint( ulong       ele_max               );
     188             :      void *      mytreap_new      ( void *      shmem,  ulong ele_max );
     189             :      mytreap_t * mytreap_join     ( void *      shtreap               );
     190             :      void *      mytreap_leave    ( mytreap_t * treap                 );
     191             :      void *      mytreap_delete   ( void *      shtreap               );
     192             : 
     193             :      // mytreap_ele_max gives the maximum number of elements the underlying
     194             :      // linearly addressable storage can support
     195             :      // mytreap_ele_cnt gives the current number of elements in the treap
     196             :      // mytreap_{ele_max,ele_cnt} assumes treap is a current local join.
     197             :      // These might be deprecated in the future.
     198             : 
     199             :      ulong mytreap_ele_max( mytreap_t const * treap );
     200             :      ulong mytreap_ele_cnt( mytreap_t const * treap );
     201             : 
     202             :      // mytreap_idx_query finds where q is stored in the treap.  Assumes
     203             :      // treap is a current local join and pool points in the caller's
     204             :      // address space to the ele_max element storage containing the
     205             :      // treap elements.  Returns [0,ele_max) on success and
     206             :      // mytreap_idx_null() on failure.  Lifetime of the returned idx is
     207             :      // the lesser of until it is removed or the underlying element
     208             :      // storage.  mytreap_ele_query is the same but returns the location
     209             :      // in the caller's address space of the found element on success
     210             :      // and NULL on failure (lifetime of the returned pointer is until
     211             :      // ele is removed or ele's local lifetime).  If there are multiple
     212             :      // elements matching q, this returns an arbitrary one of them.
     213             :      // mytreap_ele_query_const is a const correct version.
     214             :      //
     215             :      // These operations have HPC implementations and are O(lg N)
     216             :      // average with an ultra high probability of having a small
     217             :      // coefficient (i.e. close to algorithmically optimal trees).
     218             : 
     219             :      ulong           mytreap_idx_query      ( mytreap_t const * treap, char const * q, myele_t const * pool );
     220             :      myele_t *       mytreap_ele_query      ( mytreap_t *       treap, char const * q, myele_t *       pool );
     221             :      myele_t const * mytreap_ele_query_const( mytreap_t const * treap, char const * q, myele_t const * pool );
     222             : 
     223             :      // my_treap_idx_{ge,gt} return the index of the smallest element
     224             :      // in the treap that is {not less,strictly greater} than q.
     225             :      // my_treap_idx_{le,lt} return the index of the largest element
     226             :      // in the treap that is {not greater,strictly less} than q.
     227             :      // If no such element exists, they return idx_null
     228             :      // If the treap contains duplicate keys, any element with the
     229             :      // key satisfying the query is returned. E.g. if treap contains
     230             :      // {7,7,9}, lt(8) may return either of the 2 elements with key 7.
     231             : 
     232             :      ulong mytreap_idx_ge( mytreap_t const * treap, TREAP_QUERY_T * q, myele_t const * pool );
     233             :      ulong mytreap_idx_gt( mytreap_t const * treap, TREAP_QUERY_T * q, myele_t const * pool );
     234             :      ulong mytreap_idx_le( mytreap_t const * treap, TREAP_QUERY_T * q, myele_t const * pool );
     235             :      ulong mytreap_idx_lt( mytreap_t const * treap, TREAP_QUERY_T * q, myele_t const * pool );
     236             : 
     237             :      // mytreap_idx_{insert,remove} inserts / removes element n/d into
     238             :      // the treap and returns treap.  Assumes treap is a current local
     239             :      // join, pool points in the caller's address space to the ele_max
     240             :      // element storage used for treap elements, n/d are in [0,ele_max),
     241             :      // n/d are currently out of / in the treap.  Given these
     242             :      // assumptions, these cannot fail.
     243             :      //
     244             :      // For insert, n's query and prio fields should already be
     245             :      // populated (i.e. TREAP_LT( ele+n, ele+i ) should return valid
     246             :      // results before this is called and prio should be a suitable
     247             :      // value as described above.  On return, n and n's queries will be
     248             :      // in the treap.  n's left, right, parent, prio and/or queries
     249             :      // should not be modified while n is in the treap.  Further, the
     250             :      // caller should not assume n's left, right or parent values are
     251             :      // stable while n is in the treap.  The treap does not care about
     252             :      // any other fields and these can be modified by the user as
     253             :      // necessary.
     254             :      //
     255             :      // When inserting an element that compares equal (i.e.
     256             :      // TREAP_LT( x, y )==0 and TREAP_LT( y, x )==0), the newly inserted
     257             :      // element is treated as if being epsilon larger than all existing
     258             :      // equal elements.  This means that iterating in forward order will
     259             :      // iterate over equal elements in "time" order, with the one
     260             :      // inserted first returned first.
     261             :      //
     262             :      // For remove, on return d and d's queries are no longer in the
     263             :      // treap.  The caller is free to modify all fields of d as
     264             :      // necessary.
     265             :      //
     266             :      // mytreap_ele_{insert,remove} are the same but n and d point in
     267             :      // the caller's local address space the element to insert / remove.
     268             :      //
     269             :      // These operations have HPC implementations and are O(lg N)
     270             :      // average with an ultra high probability of having a small
     271             :      // coefficient (i.e. close to algorithmically optimal trees).
     272             : 
     273             :      mytreap_t * mytreap_idx_insert( mytreap_t * treap, ulong     n, myele_t * pool );
     274             :      mytreap_t * mytreap_idx_remove( mytreap_t * treap, ulong     d, myele_t * pool );
     275             : 
     276             :      mytreap_t * mytreap_ele_insert( mytreap_t * treap, myele_t * n, myele_t * pool );
     277             :      mytreap_t * mytreap_ele_remove( mytreap_t * treap, myele_t * d, myele_t * pool );
     278             : 
     279             :      // mytreap_fwd_iter_{init,done,next,idx,ele,ele_const} provide an
     280             :      // in-order iterator from smallest to largest value.  Typical
     281             :      // usage:
     282             :      //
     283             :      //  for( mytreap_fwd_iter_t iter = mytreap_fwd_iter_init( treap, pool );
     284             :      //       !mytreap_fwd_iter_done( iter );
     285             :      //       iter = mytreap_fwd_iter_next( iter, pool ) ) {
     286             :      //     ulong i = mytreap_fwd_iter_idx( iter );
     287             :      //     ... or myele_t *       e = mytreap_fwd_iter_ele      ( iter, pool );
     288             :      //     ... or myele_t const * e = mytreap_fwd_iter_ele_const( iter, pool );
     289             :      //
     290             :      //     ... process i (or e) here
     291             :      //
     292             :      //     ... Do not remove the element the iterator is currently
     293             :      //     ... pointing to, and do not change the element's parent,
     294             :      //     ... left, right, prio or queries here.  It is fine to run
     295             :      //     ... queries and other iterations concurrently.  Other fields
     296             :      //     ... are free to modify (from the treap's POV, the
     297             :      //     ... application manages concurrency for other fields).
     298             :      //  }
     299             :      //
     300             :      // pool is a pointer in the caller's address space to the ele_max
     301             :      // linearly addressable storage region backing the treap.
     302             : 
     303             :      typedef ... mytreap_fwd_iter_t;
     304             : 
     305             :      mytreap_fwd_iter_t mytreap_fwd_iter_init     ( mytreap_t const * treap, myele_t const * pool );
     306             :      int                mytreap_fwd_iter_done     ( mytreap_fwd_iter_t iter                       );
     307             :      mytreap_fwd_iter_t mytreap_fwd_iter_next     ( mytreap_fwd_iter_t iter, myele_t const * pool );
     308             :      ulong              mytreap_fwd_iter_idx      ( mytreap_fwd_iter_t iter                       );
     309             :      myele_t *          mytreap_fwd_iter_ele      ( mytreap_fwd_iter_t iter, myele_t *       pool );
     310             :      myele_t const *    mytreap_fwd_iter_ele_const( mytreap_fwd_iter_t iter, myele_t const * pool );
     311             : 
     312             :      // mytreap_rev_iter_{init,done,next,idx,ele,ele_const} is the same
     313             :      // but used when iterating from largest to smallest.
     314             : 
     315             :      typedef ... mytreap_rev_iter_t;
     316             : 
     317             :      mytreap_rev_iter_t mytreap_rev_iter_init     ( mytreap_t const * treap, myele_t const * pool );
     318             :      int                mytreap_rev_iter_done     ( mytreap_rev_iter_t iter                       );
     319             :      mytreap_rev_iter_t mytreap_rev_iter_next     ( mytreap_rev_iter_t iter, myele_t const * pool );
     320             :      ulong              mytreap_rev_iter_idx      ( mytreap_rev_iter_t iter                       );
     321             :      myele_t *          mytreap_rev_iter_ele      ( mytreap_rev_iter_t iter, myele_t *       pool );
     322             :      myele_t const *    mytreap_rev_iter_ele_const( mytreap_rev_iter_t iter, myele_t const * pool );
     323             : 
     324             :      // mytreap_merge merges two treaps backed by the same pool into a
     325             :      // single treap.  If all keys in treap_a and treap_b are distinct,
     326             :      // merge is equivalent to removing each element from treap_b and
     327             :      // inserting it into treap_a, but merging the heaps is
     328             :      // asymptotically slightly better.  If there are some duplicate
     329             :      // elements, they may be interleaved arbitrarily.  Returns treap_a,
     330             :      // which now additionally contains the elements from treap_b.
     331             :      // Requires that the treap does not use the maximum priority
     332             :      // element (see the note above about PRIO_MAX).
     333             : 
     334             :      mytreap * mytreap_merge( mytreap * treap_a, mytreap * treap_b, myele_t * pool );
     335             : 
     336             :      // mytreap_verify returns 0 if the mytreap is not obviously corrupt
     337             :      // or a -1 (i.e. ERR_INVAL) if it is (logs details).  treap is
     338             :      // current local join to a mytreap.  pool is a pointer in the
     339             :      // caller's address space to the ele_max linearly addressable
     340             :      // storage region backing the treap.
     341             : 
     342             :      int mytreap_verify( mytreap_t const * treap, myele_t const * pool );
     343             : 
     344             :      // IMPORTANT SAFETY TIP!  queries and iteration can be done
     345             :      // concurrently by multiple threads distributed arbitrarily over
     346             :      // multiple processes provided there are no concurrent insert /
     347             :      // remove operations on the treap and the application manages
     348             :      // concurrency for fields not managed by the treap.
     349             : 
     350             :    You can do this as often as you like within a compilation unit to get
     351             :    different types of treaps.  Variants exist for making separate headers
     352             :    and implementations for doing libraries and handling multiple
     353             :    compilation units.  Additional options exist as detailed below. */
     354             : 
     355             : /* TREAP_NAME gives the API prefix to use */
     356             : 
     357             : #ifndef TREAP_NAME
     358             : #error "Define TREAP_NAME"
     359             : #endif
     360             : 
     361             : /* TREAP_T is the treap element type */
     362             : 
     363             : #ifndef TREAP_T
     364             : #error "Define TREAP_T"
     365             : #endif
     366             : 
     367             : /* TREAP_QUERY_T is the type that is passed to the query function */
     368             : 
     369             : #ifndef TREAP_QUERY_T
     370             : #error "Define TREAP_QUERY_T"
     371             : #endif
     372             : 
     373             : /* TREAP_CMP compares a TREAP_QUERY_T q with an element e's query
     374             :    fields and returns a negative/zero/positive int if q is less
     375             :    than/equal/greater than element e's query fields.  Should be a pure
     376             :    function. */
     377             : 
     378             : #ifndef TREAP_CMP
     379             : #error "Define TREAP_CMP"
     380             : #endif
     381             : 
     382             : /* TREAP_LT returns 1 if the element e0's query fields are strictly less
     383             :    element e1's query fields and 0 otherwise.  Should be a pure
     384             :    function. */
     385             : 
     386             : #ifndef TREAP_LT
     387             : #error "Define TREAP_LT"
     388             : #endif
     389             : 
     390             : /* TREAP_IDX_T is the type used for the fields in the TREAP_T.  Should
     391             :    be a primitive unsigned integer type.  Defaults to ulong.  A treap
     392             :    can't use element memory regions that contain more than the maximum
     393             :    value that can be represented by a TREAP_IDX_T. */
     394             : 
     395             : #ifndef TREAP_IDX_T
     396   175689321 : #define TREAP_IDX_T ulong
     397             : #endif
     398             : 
     399             : /* TREAP_{PARENT,LEFT,RIGHT,PRIO} is the name the treap element parent /
     400             :    left / right / prio fields.  Defaults to parent / left / right /
     401             :    prio. */
     402             : 
     403             : #ifndef TREAP_PARENT
     404   136861020 : #define TREAP_PARENT parent
     405             : #endif
     406             : 
     407             : #ifndef TREAP_LEFT
     408   109430117 : #define TREAP_LEFT left
     409             : #endif
     410             : 
     411             : #ifndef TREAP_RIGHT
     412    82157433 : #define TREAP_RIGHT right
     413             : #endif
     414             : 
     415             : #ifndef TREAP_PRIO
     416    75797378 : #define TREAP_PRIO prio
     417             : #endif
     418             : 
     419             : /* TREAP_OPTIMIZE_ITERATION controls a space/time tradeoff: when
     420             :    TREAP_OPTIMIZE_ITERATION is set to 1, each element has two additional
     421             :    fields and insert and delete take slightly longer.  However, in
     422             :    return, iteration in either direction is substantially faster.  This
     423             :    works by essentially threading a doubly-linked list through elements
     424             :    in iteration order. The default is sets this to 0, meaning that the
     425             :    next and prev fields are not required. */
     426             : 
     427             : #ifndef TREAP_OPTIMIZE_ITERATION
     428             : #define TREAP_OPTIMIZE_ITERATION 0
     429             : #endif
     430             : 
     431             : #if TREAP_OPTIMIZE_ITERATION
     432             : # ifndef  TREAP_NEXT
     433    82079677 : #   define TREAP_NEXT next
     434             : # endif
     435             : # ifndef  TREAP_PREV
     436    78760730 : #   define TREAP_PREV prev
     437             : # endif
     438             : #endif
     439             : 
     440             : /* TREAP_IMPL_STYLE controls what this template should emit.
     441             :    0 - local use only
     442             :    1 - library header
     443             :    2 - library implementation */
     444             : 
     445             : #ifndef TREAP_IMPL_STYLE
     446             : #define TREAP_IMPL_STYLE 0
     447             : #endif
     448             : 
     449             : /* Implementation *****************************************************/
     450             : 
     451             : #if TREAP_IMPL_STYLE==0
     452             : #define TREAP_STATIC static FD_FN_UNUSED
     453             : #else
     454             : #define TREAP_STATIC
     455             : #endif
     456             : 
     457  3861927160 : #define TREAP_IDX_NULL           ((ulong)(TREAP_IDX_T)(~0UL))
     458  3638008201 : #define TREAP_IDX_IS_NULL( idx ) ((idx)==TREAP_IDX_NULL)
     459             : 
     460   677064527 : #define TREAP_(n) FD_EXPAND_THEN_CONCAT3(TREAP_NAME,_,n)
     461             : 
     462             : /* Verification logs details on failure.  The rest only needs fd_bits.h
     463             :    (consider making logging a compile time option). */
     464             : 
     465             : #include "../log/fd_log.h"
     466             : 
     467             : #if TREAP_IMPL_STYLE!=2 /* need structures, prototypes and inlines */
     468             : 
     469             : /* structures */
     470             : 
     471             : /* TODO: consider eliminating ele_cnt and maybe ele_max fields (less overhead,
     472             :    faster bulk ops, concurrency options, simpler constructors, etc) */
     473             : 
     474             : struct TREAP_(private) {
     475             :   ulong       ele_max; /* Maximum number of elements in underlying storage, in [0,TREAP_IDX_NULL] */
     476             :   ulong       ele_cnt; /* Current number of elements in treap, in [0,ele_max] */
     477             : # if TREAP_OPTIMIZE_ITERATION
     478             :   TREAP_IDX_T first;   /* Index of the left-most treap element, in [0,ele_max) or TREAP_IDX_NULL */
     479             :   TREAP_IDX_T last;    /* Index of the right-most treap element, in [0,ele_max) or TREAP_IDX_NULL */
     480             : # endif
     481             :   TREAP_IDX_T root;    /* Index of the root treap element, in [0,ele_max) or TREAP_IDX_NULL */
     482             : };
     483             : 
     484             : typedef struct TREAP_(private) TREAP_(t);
     485             : 
     486             : typedef ulong TREAP_(fwd_iter_t);
     487             : typedef ulong TREAP_(rev_iter_t);
     488             : 
     489             : FD_PROTOTYPES_BEGIN
     490             : 
     491             : /* prototypes */
     492             : 
     493             : TREAP_STATIC void TREAP_(seed)( TREAP_T * pool, ulong ele_max, ulong seed );
     494             : 
     495             : TREAP_STATIC FD_FN_CONST ulong       TREAP_(align)    ( void                              );
     496             : TREAP_STATIC FD_FN_CONST ulong       TREAP_(footprint)( ulong       ele_max               );
     497             : TREAP_STATIC /**/        void *      TREAP_(new)      ( void *      shmem,  ulong ele_max );
     498             : TREAP_STATIC /**/        TREAP_(t) * TREAP_(join)     ( void *      shtreap               );
     499             : TREAP_STATIC /**/        void *      TREAP_(leave)    ( TREAP_(t) * treap                 );
     500             : TREAP_STATIC /**/        void *      TREAP_(delete)   ( void *      shtreap               );
     501             : 
     502             : TREAP_STATIC FD_FN_PURE ulong TREAP_(idx_query)( TREAP_(t) const * treap, TREAP_QUERY_T q, TREAP_T const * pool );
     503             : TREAP_STATIC FD_FN_PURE ulong TREAP_(idx_ge)( TREAP_(t) const * treap, TREAP_QUERY_T q, TREAP_T const * pool );
     504             : TREAP_STATIC FD_FN_PURE ulong TREAP_(idx_gt)( TREAP_(t) const * treap, TREAP_QUERY_T q, TREAP_T const * pool );
     505             : TREAP_STATIC FD_FN_PURE ulong TREAP_(idx_le)( TREAP_(t) const * treap, TREAP_QUERY_T q, TREAP_T const * pool );
     506             : TREAP_STATIC FD_FN_PURE ulong TREAP_(idx_lt)( TREAP_(t) const * treap, TREAP_QUERY_T q, TREAP_T const * pool );
     507             : 
     508             : TREAP_STATIC TREAP_(t) * TREAP_(idx_insert)( TREAP_(t) * treap, ulong n, TREAP_T * pool );
     509             : TREAP_STATIC TREAP_(t) * TREAP_(idx_remove)( TREAP_(t) * treap, ulong d, TREAP_T * pool );
     510             : 
     511             : TREAP_STATIC FD_FN_PURE TREAP_(fwd_iter_t) TREAP_(fwd_iter_init)( TREAP_(t) const * treap, TREAP_T const * pool );
     512             : TREAP_STATIC FD_FN_PURE TREAP_(rev_iter_t) TREAP_(rev_iter_init)( TREAP_(t) const * treap, TREAP_T const * pool );
     513             : 
     514             : TREAP_STATIC FD_FN_PURE TREAP_(fwd_iter_t) TREAP_(fwd_iter_next)( TREAP_(fwd_iter_t) i, TREAP_T const * pool );
     515             : TREAP_STATIC FD_FN_PURE TREAP_(rev_iter_t) TREAP_(rev_iter_next)( TREAP_(rev_iter_t) i, TREAP_T const * pool );
     516             : 
     517             : TREAP_STATIC TREAP_(t) * TREAP_(merge)( TREAP_(t) * treap_a, TREAP_(t) * treap_b, TREAP_T * pool );
     518             : 
     519             : TREAP_STATIC int TREAP_(verify)( TREAP_(t) const * treap, TREAP_T const * pool );
     520             : 
     521             : /* inlines */
     522             : 
     523   168757365 : FD_FN_PURE static inline int TREAP_(cmp)( TREAP_QUERY_T   q,  TREAP_T const * e  ) { return TREAP_CMP( q, e );  }
     524  1409135223 : FD_FN_PURE static inline int TREAP_(lt) ( TREAP_T const * e0, TREAP_T const * e1 ) { return TREAP_LT( e0, e1 ); }
     525             : 
     526      692853 : FD_FN_CONST static inline ulong           TREAP_(idx_null)      ( void ) { return TREAP_IDX_NULL; }
     527           3 : FD_FN_CONST static inline TREAP_T *       TREAP_(ele_null)      ( void ) { return NULL;           }
     528           3 : FD_FN_CONST static inline TREAP_T const * TREAP_(ele_null_const)( void ) { return NULL;           }
     529             : 
     530     2956794 : FD_FN_CONST static inline int TREAP_(idx_is_null)( ulong           i ) { return TREAP_IDX_IS_NULL( i ); }
     531        1536 : FD_FN_CONST static inline int TREAP_(ele_is_null)( TREAP_T const * e ) { return !e;                     }
     532             : 
     533             : FD_FN_CONST static inline ulong
     534             : TREAP_(idx)( TREAP_T const * e,
     535     7507266 :              TREAP_T const * pool ) {
     536     7507266 :   return fd_ulong_if( !!e, (ulong)(e - pool), TREAP_IDX_NULL );
     537     7507266 : }
     538             : 
     539             : FD_FN_CONST static inline TREAP_T *
     540             : TREAP_(ele)( ulong     i,
     541         768 :              TREAP_T * pool ) {
     542         768 :   return fd_ptr_if( !TREAP_IDX_IS_NULL( i ), pool + i, NULL );
     543         768 : }
     544             : 
     545             : FD_FN_CONST static inline TREAP_T const *
     546             : TREAP_(ele_const)( ulong           i,
     547         768 :                    TREAP_T const * pool ) {
     548         768 :   return fd_ptr_if( !TREAP_IDX_IS_NULL( i ), pool + i, NULL );
     549         768 : }
     550             : 
     551             : FD_FN_CONST static inline ulong
     552             : TREAP_(idx_fast)( TREAP_T const * e,
     553        1776 :                   TREAP_T const * pool ) {
     554        1776 :   return (ulong)(e - pool);
     555        1776 : }
     556             : 
     557         765 : FD_FN_CONST static inline TREAP_T *       TREAP_(ele_fast)      ( ulong i, TREAP_T *       pool ) { return pool + i; }
     558         765 : FD_FN_CONST static inline TREAP_T const * TREAP_(ele_fast_const)( ulong i, TREAP_T const * pool ) { return pool + i; }
     559             : 
     560     3858669 : FD_FN_PURE static inline ulong TREAP_(ele_max)( TREAP_(t) const * treap ) { return treap->ele_max; }
     561    11298918 : FD_FN_PURE static inline ulong TREAP_(ele_cnt)( TREAP_(t) const * treap ) { return treap->ele_cnt; }
     562             : 
     563             : FD_FN_PURE static inline TREAP_T *
     564             : TREAP_(ele_query)( TREAP_(t) const * treap,
     565             :                    TREAP_QUERY_T     q,
     566     3752880 :                    TREAP_T *         pool ) {
     567     3752880 :   ulong i = TREAP_(idx_query)( treap, q, pool );
     568     3752880 :   return fd_ptr_if( !TREAP_IDX_IS_NULL( i ), pool + i, NULL );
     569     3752880 : }
     570             : 
     571             : FD_FN_PURE static inline TREAP_T const *
     572             : TREAP_(ele_query_const)( TREAP_(t) const * treap,
     573             :                          TREAP_QUERY_T     q,
     574     3752865 :                          TREAP_T const *   pool ) {
     575     3752865 :   ulong i = TREAP_(idx_query)( treap, q, pool );
     576     3752865 :   return fd_ptr_if( !TREAP_IDX_IS_NULL( i ), pool + i, NULL );
     577     3752865 : }
     578             : 
     579             : static inline TREAP_(t) *
     580             : TREAP_(ele_insert)( TREAP_(t) * treap,
     581             :                     TREAP_T *   e,
     582    27476729 :                     TREAP_T *   pool ) {
     583    27476729 :   return TREAP_(idx_insert)( treap, (ulong)(e - pool), pool );
     584    27476729 : }
     585             : 
     586             : static inline TREAP_(t) *
     587             : TREAP_(ele_remove)( TREAP_(t) * treap,
     588             :                     TREAP_T *   e,
     589    18049194 :                     TREAP_T *   pool ) {
     590    18049194 :   return TREAP_(idx_remove)( treap, (ulong)(e - pool), pool );
     591    18049194 : }
     592             : 
     593   215090542 : FD_FN_CONST static inline int             TREAP_(fwd_iter_done)     ( TREAP_(fwd_iter_t) i ) { return TREAP_IDX_IS_NULL( i ); }
     594   122905299 : FD_FN_CONST static inline ulong           TREAP_(fwd_iter_idx)      ( TREAP_(fwd_iter_t) i                       ) { return i;        }
     595   167266249 : FD_FN_CONST static inline TREAP_T *       TREAP_(fwd_iter_ele)      ( TREAP_(fwd_iter_t) i, TREAP_T *       pool ) { return pool + i; }
     596   122827101 : FD_FN_CONST static inline TREAP_T const * TREAP_(fwd_iter_ele_const)( TREAP_(fwd_iter_t) i, TREAP_T const * pool ) { return pool + i; }
     597             : 
     598    25379853 : FD_FN_CONST static inline int             TREAP_(rev_iter_done)     ( TREAP_(rev_iter_t) i ) { return TREAP_IDX_IS_NULL( i ); }
     599        2043 : FD_FN_CONST static inline ulong           TREAP_(rev_iter_idx)      ( TREAP_(rev_iter_t) i                       ) { return i;        }
     600    24597733 : FD_FN_CONST static inline TREAP_T *       TREAP_(rev_iter_ele)      ( TREAP_(rev_iter_t) i, TREAP_T *       pool ) { return pool + i; }
     601         423 : FD_FN_CONST static inline TREAP_T const * TREAP_(rev_iter_ele_const)( TREAP_(rev_iter_t) i, TREAP_T const * pool ) { return pool + i; }
     602             : 
     603             : FD_PROTOTYPES_END
     604             : 
     605             : #endif
     606             : 
     607             : #if TREAP_IMPL_STYLE!=1 /* need implementations */
     608             : 
     609             : TREAP_STATIC void
     610             : TREAP_(seed)( TREAP_T * pool,
     611             :               ulong     ele_max,
     612        6429 :               ulong     seed ) {
     613     7699644 :   for( ulong ele_idx=0UL; ele_idx<ele_max; ele_idx++ ) {
     614     7693215 :     ulong r = fd_ulong_hash( ele_idx ^ seed ) & TREAP_IDX_NULL;
     615     7693215 :     pool[ ele_idx ].TREAP_PRIO = (TREAP_IDX_T)(r - (ulong)(r==TREAP_IDX_NULL));
     616     7693215 :   }
     617        6429 : }
     618             : 
     619             : TREAP_STATIC FD_FN_CONST ulong
     620     5242086 : TREAP_(align)( void ) {
     621     5242086 :   return alignof(TREAP_(t));
     622     5242086 : }
     623             : 
     624             : TREAP_STATIC FD_FN_CONST ulong
     625         183 : TREAP_(footprint)( ulong ele_max ) {
     626         183 :   if( FD_UNLIKELY( ele_max>TREAP_IDX_NULL ) ) return 0UL;
     627         180 :   return sizeof(TREAP_(t));
     628         183 : }
     629             : 
     630             : TREAP_STATIC void *
     631             : TREAP_(new)( void * shmem,
     632     2661465 :              ulong  ele_max ) {
     633     2661465 :   if( !shmem ) {
     634           3 :     FD_LOG_WARNING(( "NULL shmem" ));
     635           3 :     return NULL;
     636           3 :   }
     637             : 
     638     2661462 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, TREAP_(align)() ) ) ) {
     639           3 :     FD_LOG_WARNING(( "misaligned shmem" ));
     640           3 :     return NULL;
     641           3 :   }
     642             : 
     643     2661459 :   if( FD_UNLIKELY( ele_max>TREAP_IDX_NULL ) ) {
     644           3 :     FD_LOG_WARNING(( "ele_max too large" ));
     645           3 :     return NULL;
     646           3 :   }
     647             : 
     648     2661456 :   TREAP_(t) * treap = (TREAP_(t) *)shmem;
     649             : 
     650     2661456 :   treap->ele_max = ele_max;
     651     2661456 :   treap->ele_cnt = 0UL;
     652     2661456 :   treap->root    = (TREAP_IDX_T)TREAP_IDX_NULL;
     653             : 
     654             : # if TREAP_OPTIMIZE_ITERATION
     655     2661336 :   treap->first   = (TREAP_IDX_T)TREAP_IDX_NULL;
     656     2661336 :   treap->last    = (TREAP_IDX_T)TREAP_IDX_NULL;
     657             : # endif
     658             : 
     659     2661456 :   return treap;
     660     2661459 : }
     661             : 
     662             : TREAP_STATIC TREAP_(t) *
     663     2551083 : TREAP_(join)( void * shtreap ) {
     664     2551083 :   if( FD_UNLIKELY( !shtreap ) ) {
     665           3 :     FD_LOG_WARNING(( "NULL shtreap" ));
     666           3 :     return NULL;
     667           3 :   }
     668             : 
     669     2551080 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shtreap, TREAP_(align)() ) ) ) {
     670           3 :     FD_LOG_WARNING(( "misaligned shtreap" ));
     671           3 :     return NULL;
     672           3 :   }
     673             : 
     674     2551077 :   return (TREAP_(t) *)shtreap;
     675     2551080 : }
     676             : 
     677             : TREAP_STATIC void *
     678       29208 : TREAP_(leave)( TREAP_(t) * treap ) {
     679       29208 :   if( FD_UNLIKELY( !treap ) ) {
     680           3 :     FD_LOG_WARNING(( "NULL treap" ));
     681           3 :     return NULL;
     682           3 :   }
     683             : 
     684       29205 :   return (void *)treap;
     685       29208 : }
     686             : 
     687             : TREAP_STATIC void *
     688       29211 : TREAP_(delete)( void * shtreap ) {
     689       29211 :   if( FD_UNLIKELY( !shtreap ) ) {
     690           3 :     FD_LOG_WARNING(( "NULL shtreap" ));
     691           3 :     return NULL;
     692           3 :   }
     693             : 
     694       29208 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shtreap, TREAP_(align)() ) ) ) {
     695           3 :     FD_LOG_WARNING(( "misaligned shtreap" ));
     696           3 :     return NULL;
     697           3 :   }
     698             : 
     699       29205 :   return shtreap;
     700       29208 : }
     701             : 
     702             : /* Template for binary search operations. Parameterized by:
     703             :    - name: function suffix (ge/gt/le/lt)
     704             :    - CMP: the corresponding comparator
     705             : 
     706             :   move_cmp is used to decide when to go left.
     707             :     - If le or lt, go left if c<=0.
     708             :     - Else, go left if c<0, which is equivalent to c<=-1 */
     709             : #define TREAP_CMP_QUERY_IMPL(name, CMP)               \
     710             : TREAP_STATIC ulong                                    \
     711             : TREAP_(idx_##name)( TREAP_(t) const * treap,          \
     712             :                     TREAP_QUERY_T     q,              \
     713    15440868 :                     TREAP_T const *   pool ) {        \
     714    15440868 :   int const allow_eq = 0 CMP 0;                       \
     715    15440868 :   int const move_cmp = 0 - (1 CMP 0);                 \
     716    15440868 :   ulong i         = (ulong)treap->root;               \
     717    15440868 :   ulong candidate = TREAP_IDX_NULL;                   \
     718    15440868 :                                                       \
     719   121235343 :   while( FD_LIKELY( !TREAP_IDX_IS_NULL(i) ) ) {       \
     720   109591257 :     ulong l = (ulong)pool[i].TREAP_LEFT;              \
     721   109591257 :     ulong r = (ulong)pool[i].TREAP_RIGHT;             \
     722   109591257 :     int   c = TREAP_(cmp)( q, pool + i );             \
     723   109591257 :     if( allow_eq && FD_UNLIKELY( !c ) ) {             \
     724     3796782 :       candidate = i;                                  \
     725     3796782 :       break;                                          \
     726     3796782 :     }                                                 \
     727   109591257 :                                                       \
     728   109591257 :     candidate = fd_ulong_if( 0 CMP c, i, candidate ); \
     729   105794475 :     i         = fd_ulong_if( c<=move_cmp, l, r );     \
     730   105794475 :   }                                                   \
     731    15440868 :   return candidate;                                   \
     732    15440868 : }
     733             : 
     734             : TREAP_CMP_QUERY_IMPL(ge, >=)
     735             : TREAP_CMP_QUERY_IMPL(gt, > )
     736             : TREAP_CMP_QUERY_IMPL(le, <=)
     737             : TREAP_CMP_QUERY_IMPL(lt, < )
     738             : 
     739             : TREAP_STATIC ulong
     740             : TREAP_(idx_query)( TREAP_(t) const * treap,
     741             :                    TREAP_QUERY_T     q,
     742    11258610 :                    TREAP_T const *   pool ) {
     743    11258610 :   ulong i = (ulong)treap->root;
     744    64847238 :   while( FD_LIKELY( !TREAP_IDX_IS_NULL( i ) ) ) { /* Optimize for found */
     745    59166108 :     ulong l = (ulong)pool[ i ].TREAP_LEFT;
     746    59166108 :     ulong r = (ulong)pool[ i ].TREAP_RIGHT;
     747    59166108 :     int   c = TREAP_(cmp)( q, pool + i );
     748    59166108 :     if( FD_UNLIKELY( !c ) ) break; /* Optimize for larger treaps */
     749    53588628 :     i = fd_ulong_if( c<0, l, r );
     750    53588628 :   }
     751    11258610 :   return i;
     752    11258610 : }
     753             : 
     754             : TREAP_STATIC TREAP_(t) *
     755             : TREAP_(idx_insert)( TREAP_(t) * treap,
     756             :                     ulong       n,
     757    39101816 :                     TREAP_T *   pool ) {
     758             : 
     759             : # if FD_TMPL_USE_HANDHOLDING
     760             :   if( FD_UNLIKELY( n>=treap->ele_max              ) ) FD_LOG_CRIT(( "index out of bounds" ));
     761             :   if( FD_UNLIKELY( treap->ele_cnt>=treap->ele_max ) ) FD_LOG_CRIT(( "treap full" ));
     762             : # endif
     763             : 
     764             :   /* Find leaf where to insert n */
     765             : 
     766    39101816 :   TREAP_IDX_T * _p_child = &treap->root;
     767             : # if TREAP_OPTIMIZE_ITERATION
     768    34685675 :   TREAP_IDX_T * _p_pnext = &treap->first; /* pointer to prev node's next idx */
     769    34685675 :   TREAP_IDX_T * _p_nprev = &treap->last;  /* pointer to next node's prev idx */
     770             : # endif
     771             : 
     772    39101816 :   ulong i = TREAP_IDX_NULL;
     773   482784110 :   for(;;) {
     774   482784110 :     ulong j = (ulong)*_p_child;
     775   482784110 :     if( FD_UNLIKELY( TREAP_IDX_IS_NULL( j ) ) ) break; /* Optimize for large treap */
     776   443682294 :     i = j;
     777   443682294 :     int lt = TREAP_(lt)( pool + n, pool + i );
     778   443682294 :     _p_child = fd_ptr_if( lt, &pool[ i ].TREAP_LEFT, &pool[ i ].TREAP_RIGHT );
     779             : #   if TREAP_OPTIMIZE_ITERATION
     780   385222617 :     _p_pnext = fd_ptr_if( lt, _p_pnext,              &pool[ i ].TREAP_NEXT  );
     781   385222617 :     _p_nprev = fd_ptr_if( lt, &pool[ i ].TREAP_PREV, _p_nprev               );
     782             : #   endif
     783   443682294 :   }
     784             : 
     785             :   /* Insert n.  This might momentarily break the heap property. */
     786             : 
     787    39101816 :   pool[ n ].TREAP_PARENT = (TREAP_IDX_T)i;
     788    39101816 :   pool[ n ].TREAP_LEFT   = (TREAP_IDX_T)TREAP_IDX_NULL;
     789    39101816 :   pool[ n ].TREAP_RIGHT  = (TREAP_IDX_T)TREAP_IDX_NULL;
     790    39101816 :   *_p_child = (TREAP_IDX_T)n;
     791             : 
     792             : # if TREAP_OPTIMIZE_ITERATION
     793    34685675 :   pool[ n ].TREAP_PREV = *_p_nprev;
     794    34685675 :   pool[ n ].TREAP_NEXT = *_p_pnext;
     795             :   *_p_nprev = (TREAP_IDX_T)n;
     796             :   *_p_pnext = (TREAP_IDX_T)n;
     797             : # endif
     798             : 
     799             :   /* Bubble n up until the heap property is restored. */
     800             : 
     801    39101816 :   ulong n_prio = (ulong)pool[ n ].TREAP_PRIO;
     802    80456923 :   while( !TREAP_IDX_IS_NULL( i ) ) {
     803    63358456 :     ulong i_prio = (ulong)pool[ i ].TREAP_PRIO;
     804             : 
     805    63358456 :     int heap_intact = (n_prio<i_prio) | ((n_prio==i_prio) & (!((n ^ i) & 1UL))); /* Flip coin on equal priority */
     806    63358456 :     if( heap_intact ) break;
     807             : 
     808             :     /* Get i's parent (if any) and parent's link to i (tree root link if no parent) */
     809             : 
     810    41355107 :     ulong p = (ulong)pool[ i ].TREAP_PARENT;
     811             : 
     812    41355107 :     TREAP_IDX_T * _t0      = fd_ptr_if( TREAP_IDX_IS_NULL( p ), &treap->root, &pool[ p ].TREAP_LEFT  );
     813    41355107 :     /**/          _p_child = fd_ptr_if( i==(ulong)*_t0,         _t0,          &pool[ p ].TREAP_RIGHT );
     814             : 
     815             :     /* Get n's child (if any) that will become i's child */
     816             : 
     817    41355107 :     int           n_is_left_child = (n==(ulong)pool[ i ].TREAP_LEFT);
     818    41355107 :     TREAP_IDX_T * _n_child        = fd_ptr_if( n_is_left_child, &pool[ n ].TREAP_RIGHT, &pool[ n ].TREAP_LEFT );
     819    41355107 :     ulong         j               = (ulong)*_n_child;
     820             : 
     821             :     /* Make n child of p (or the root if no parent) */
     822             : 
     823    41355107 :     *_p_child              = (TREAP_IDX_T)n;
     824    41355107 :     pool[ n ].TREAP_PARENT = (TREAP_IDX_T)p;
     825             : 
     826             :     /* Make i child of n */
     827             : 
     828    41355107 :     *_n_child              = (TREAP_IDX_T)i;
     829    41355107 :     pool[ i ].TREAP_PARENT = (TREAP_IDX_T)n;
     830             : 
     831             :     /* Make j (if present) child of i */
     832             : 
     833    41355107 :     TREAP_IDX_T dummy;
     834    41355107 :     *fd_ptr_if( n_is_left_child,        &pool[ i ].TREAP_LEFT, &pool[ i ].TREAP_RIGHT  ) = (TREAP_IDX_T)j;
     835    41355107 :     *fd_ptr_if( TREAP_IDX_IS_NULL( j ), &dummy,                &pool[ j ].TREAP_PARENT ) = (TREAP_IDX_T)i;
     836             : 
     837             :     /* Keep bubbling up */
     838             : 
     839    41355107 :     i = p;
     840    41355107 :   }
     841             : 
     842    39101816 :   treap->ele_cnt++;
     843    39101816 :   return treap;
     844    39101816 : }
     845             : 
     846             : TREAP_(t) *
     847             : TREAP_(idx_remove)( TREAP_(t) * treap,
     848             :                     ulong       d,
     849    39062004 :                     TREAP_T *   pool ) {
     850             : # if FD_TMPL_USE_HANDHOLDING
     851             :   if( FD_UNLIKELY( (d>=treap->ele_max) ) ) FD_LOG_CRIT(( "index out of bounds" ));
     852             :   if( FD_UNLIKELY( (treap->ele_cnt<1)  ) ) FD_LOG_CRIT(( "index out of bounds" ));
     853             : # endif
     854             : 
     855             :   /* Make a hole at d */
     856             : 
     857    39062004 :   ulong p = (ulong)pool[ d ].TREAP_PARENT;
     858    39062004 :   ulong l = (ulong)pool[ d ].TREAP_LEFT;
     859    39062004 :   ulong r = (ulong)pool[ d ].TREAP_RIGHT;
     860             : 
     861    39062004 :   TREAP_IDX_T * _t0      = fd_ptr_if( TREAP_IDX_IS_NULL( p ), &treap->root, &pool[ p ].TREAP_LEFT  );
     862    39062004 :   TREAP_IDX_T * _p_child = fd_ptr_if( d==(ulong)*_t0,         _t0,          &pool[ p ].TREAP_RIGHT );
     863             : 
     864             : # if TREAP_OPTIMIZE_ITERATION
     865    31331643 :   TREAP_IDX_T prev = pool[ d ].TREAP_PREV;
     866    31331643 :   TREAP_IDX_T next = pool[ d ].TREAP_NEXT;
     867    31331643 :   TREAP_IDX_T * _pnext = fd_ptr_if( TREAP_IDX_IS_NULL( prev ), &treap->first, &pool[ prev ].TREAP_NEXT );
     868    31331643 :   TREAP_IDX_T * _nprev = fd_ptr_if( TREAP_IDX_IS_NULL( next ), &treap->last,  &pool[ next ].TREAP_PREV );
     869             :   *_pnext = next;
     870             :   *_nprev = prev;
     871             : # endif
     872             : 
     873    42139246 :   for(;;) {
     874             : 
     875             :     /* At this point, we have a hole to fill at d:
     876             : 
     877             :        p is the hole's parent (if any)
     878             :        l is the hole's left subtree (if any)
     879             :        r is the hole's right subtree (if any)
     880             : 
     881             :        p_child points to the link from p to hole (if the hole has a
     882             :        parent) and to the treap root link otherwise.
     883             : 
     884             :        If there is neither a left subtree nor a right subtree, we are
     885             :        done.  If there is a left/right subtree, we fill the hole with
     886             :        the right/left subtree and we are done. */
     887             : 
     888    42139246 :     int is_null_left  = TREAP_IDX_IS_NULL( l );
     889    42139246 :     int is_null_right = TREAP_IDX_IS_NULL( r );
     890    42139246 :     if( FD_LIKELY( is_null_left | is_null_right ) ) { /* Most nodes near bottom */
     891    39062004 :       TREAP_IDX_T dummy;
     892    39062004 :       *_p_child = (TREAP_IDX_T)fd_ulong_if( !is_null_left, l, r );
     893    39062004 :       *( fd_ptr_if( !is_null_left,  &pool[ l ].TREAP_PARENT,
     894    39062004 :          fd_ptr_if( !is_null_right, &pool[ r ].TREAP_PARENT, &dummy ) ) ) = (TREAP_IDX_T)p;
     895    39062004 :       break;
     896    39062004 :     }
     897             : 
     898             :     /* The hole has two subtrees.  We bubble the hole down one, fill the
     899             :        hole with the root of the subtree that will preserve the heap
     900             :        priority up to the hole (flipping a coin on ties).  Note we don't
     901             :        need to update any links to/from d as we will be getting rid of
     902             :        all links / from d. */
     903             : 
     904     3077242 :     ulong l_prio = (ulong)pool[ l ].TREAP_PRIO;
     905     3077242 :     ulong r_prio = (ulong)pool[ r ].TREAP_PRIO;
     906             : 
     907     3077242 :     int promote_left = (l_prio>r_prio) | ((l_prio==r_prio) & (!((p ^ d) & 1UL)));
     908             : 
     909     3077242 :     ulong c = fd_ulong_if( promote_left, l, r );
     910             : 
     911     3077242 :     *_p_child = (TREAP_IDX_T)c;
     912     3077242 :     pool[ c ].TREAP_PARENT = (TREAP_IDX_T)p;
     913             : 
     914     3077242 :     _p_child = fd_ptr_if  ( promote_left, &pool[ l ].TREAP_RIGHT, &pool[ r ].TREAP_LEFT  );
     915     3077242 :     p        = c;
     916     3077242 :     l        = fd_ulong_if( promote_left,  pool[ l ].TREAP_RIGHT,        l               );
     917     3077242 :     r        = fd_ulong_if( promote_left,        r,                pool[ r ].TREAP_LEFT  );
     918             : 
     919     3077242 :   }
     920             : 
     921    39062004 :   treap->ele_cnt--;
     922    39062004 :   return treap;
     923    39062004 : }
     924             : 
     925             : static inline void
     926             : TREAP_(private_split)( TREAP_IDX_T   idx_node,         /* Tree to split */
     927             :                        TREAP_T *     key,              /* Element whose key is not in the treap rooted at idx_node */
     928             :                        TREAP_IDX_T * _idx_left,        /* Where to store the left tree root */
     929             :                        TREAP_IDX_T * _idx_right,       /* Where to store the right tree root */
     930             :                        TREAP_IDX_T * _idx_last_left,   /* Where to store the last (in BST order) element of the new left tree */
     931             :                        TREAP_IDX_T * _idx_first_right, /* Where to store the first(in BST order) element in the new right tree */
     932     3204168 :                        TREAP_T *     pool ) {          /* Underlying pool */
     933             : 
     934     3204168 :   TREAP_IDX_T idx_parent_left  = TREAP_IDX_NULL;
     935     3204168 :   TREAP_IDX_T idx_parent_right = TREAP_IDX_NULL;
     936     3204168 :   *_idx_last_left   = TREAP_IDX_NULL;
     937     3204168 :   *_idx_first_right = TREAP_IDX_NULL;
     938             : 
     939     6622920 :   while( !TREAP_IDX_IS_NULL( idx_node ) ) {
     940             : 
     941             :     /* At this point we have a non-empty subtree to split whose root is
     942             :        node and we should attach the left and right split trees at
     943             :        idx_parent_left / *_idx_left and idx_parent_right / *_idx_right.
     944             :        (On the first attach, idx_parent_left/right will be idx_null and
     945             :        *_idx_left / *_idx_right are locations where to store the output
     946             :        split treaps.) */
     947             : 
     948     3418752 :     if( TREAP_(lt)( &pool[ idx_node ], key ) ) {
     949             : 
     950             :       /* node is left of key which, by the BST property, means all
     951             :          elements in node's left subtree are also left of key.  We don't
     952             :          know if node's right subtree contains any elements left of key.
     953             :          If it does, these elements should be attached to node's right
     954             :          subtree to preserve the BST property of the left split.
     955             : 
     956             :          As such, we attach node and node's left subtree to the
     957             :          left split, update the attach point for the left split to
     958             :          node's right subtree and then recurse on the node's right
     959             :          subtree.
     960             : 
     961             :          Note that this operation does not do any reordering of
     962             :          priorities (e.g. if element B was a descendant of element A
     963             :          before the split and both B and A belong on the left split, B
     964             :          will still be a descendant of A). */
     965             : 
     966             :       /* Attach node and node's left subtree to the left split */
     967     3237015 :       pool[ idx_node ].TREAP_PARENT = idx_parent_left;
     968     3237015 :       *_idx_left = idx_node;
     969             : 
     970             :       /* The next left split attach is node's right child */
     971     3237015 :       idx_parent_left = idx_node;
     972     3237015 :       _idx_left = &pool[ idx_node ].TREAP_RIGHT;
     973             : 
     974             :       /* If everything in the right subtree is to the right of the key,
     975             :          this is the last node on the left. */
     976     3237015 :       *_idx_last_left = idx_node;
     977             : 
     978             :       /* Recurse on the right subtree */
     979     3237015 :       idx_node = pool[ idx_node ].TREAP_RIGHT;
     980             : 
     981     3237015 :     } else { /* Mirror image of the above */
     982             : 
     983      181737 :       pool[ idx_node ].TREAP_PARENT = idx_parent_right;
     984      181737 :       *_idx_right = idx_node;
     985             : 
     986      181737 :       idx_parent_right = idx_node;
     987      181737 :       _idx_right = &pool[ idx_node ].TREAP_LEFT;
     988             : 
     989      181737 :       *_idx_first_right = idx_node;
     990             : 
     991      181737 :       idx_node = pool[ idx_node ].TREAP_LEFT;
     992             : 
     993      181737 :     }
     994     3418752 :   }
     995             : 
     996             :   /* At this point, we have an empty tree to split */
     997             : 
     998     3204168 :   *_idx_left  = TREAP_IDX_NULL;
     999     3204168 :   *_idx_right = TREAP_IDX_NULL;
    1000     3204168 : }
    1001             : 
    1002             : #if !TREAP_OPTIMIZE_ITERATION
    1003             : static inline void
    1004             : TREAP_(private_join)( TREAP_IDX_T    idx_left,  /* Root of the left treap */
    1005             :                       TREAP_IDX_T    idx_right, /* Root of the right treap, keys in left treap < keys in right treap */
    1006             :                       TREAP_IDX_T *  _idx_join, /* Where to store root of joined treaps */
    1007           0 :                       TREAP_T     *  pool ) {   /* Underlying pool */
    1008           0 : 
    1009           0 :   TREAP_IDX_T idx_join_parent = TREAP_IDX_NULL;
    1010           0 : 
    1011           0 :   for(;;) {
    1012           0 : 
    1013           0 :     /* TODO: consolidate these cases into a single branch. */
    1014           0 : 
    1015           0 :     if( TREAP_IDX_IS_NULL( idx_left ) ) { /* Left treap empty */
    1016           0 :       /* join is the right treap (or empty if both left and right empty) */
    1017           0 :       if( !TREAP_IDX_IS_NULL( idx_right ) ) pool[ idx_right ].TREAP_PARENT = idx_join_parent;
    1018           0 :       *_idx_join = idx_right;
    1019           0 :       break;
    1020           0 :     }
    1021           0 : 
    1022           0 :     if( TREAP_IDX_IS_NULL( idx_right ) ) { /* Right treap empty */
    1023           0 :       /* join is the left treap */
    1024           0 :       pool[ idx_left ].TREAP_PARENT = idx_join_parent;
    1025           0 :       *_idx_join = idx_left;
    1026           0 :       break;
    1027           0 :     }
    1028           0 : 
    1029           0 :     /* At this point, we have two non empty treaps to join and elements
    1030           0 :        in the left treap have keys before elements in the right treap. */
    1031           0 : 
    1032           0 :     ulong prio_left  = (ulong)pool[ idx_left  ].TREAP_PRIO;
    1033           0 :     ulong prio_right = (ulong)pool[ idx_right ].TREAP_PRIO;
    1034           0 :     if( (prio_left>prio_right) | ((prio_left==prio_right) & (int)(idx_left^idx_right)) ) {
    1035           0 : 
    1036           0 :       /* At this point, the left treap root has higher priority than the
    1037           0 :          right treap root.  So we attach the left treap root and left
    1038           0 :          treap left subtree to the join to preserve the heap property.
    1039           0 :          We know that the left treap right subtree is to the right of
    1040           0 :          these and that the right treap is to the right of that.  So our
    1041           0 :          next join attachment point should be at the left treap right
    1042           0 :          subtree and we should recurse on the left treap right subtree
    1043           0 :          and the right treap. */
    1044           0 : 
    1045           0 :       /* Attach left's root and left's left subtree to the join */
    1046           0 :       pool[ idx_left ].TREAP_PARENT = idx_join_parent;
    1047           0 :       *_idx_join = idx_left;
    1048           0 : 
    1049           0 :       /* The next join attach should be left's right subtree */
    1050           0 :       idx_join_parent = idx_left;
    1051           0 :       _idx_join = &pool[ idx_left ].TREAP_LEFT;
    1052           0 : 
    1053           0 :       /* Recurse on left's right subtree and right treap */
    1054           0 :       idx_left = pool[ idx_left ].TREAP_RIGHT;
    1055           0 : 
    1056           0 :     } else { /* Mirror image of the above */
    1057           0 : 
    1058           0 :       pool[ idx_right ].TREAP_PARENT = idx_join_parent;
    1059           0 :       *_idx_join = idx_right;
    1060           0 : 
    1061           0 :       idx_join_parent = idx_right;
    1062           0 :       _idx_join = &pool[ idx_right ].TREAP_RIGHT;
    1063           0 : 
    1064           0 :       idx_right = pool[ idx_right ].TREAP_LEFT;
    1065           0 : 
    1066           0 :     }
    1067           0 :   }
    1068           0 : }
    1069             : #endif
    1070             : 
    1071             : TREAP_(t) *
    1072             : TREAP_(merge)( TREAP_(t) * treap_a,
    1073             :                TREAP_(t) * treap_b,
    1074       26430 :                TREAP_T *   pool ) {
    1075             : 
    1076       26430 :   TREAP_IDX_T   idx_a      = treap_a->root;
    1077       26430 :   TREAP_IDX_T   idx_b      = treap_b->root;
    1078       26430 :   TREAP_IDX_T   new_root   = TREAP_IDX_NULL;
    1079       26430 :   TREAP_IDX_T * _idx_merge = &new_root;
    1080             : 
    1081             : # if TREAP_OPTIMIZE_ITERATION
    1082             :   /* Invariant: idx_{a,b}_{first,last} is the index of the first/last
    1083             :      node in key order in the subtree rooted at idx_a/idx_b. */
    1084       13065 :   TREAP_IDX_T  idx_a_first = treap_a->first;
    1085       13065 :   TREAP_IDX_T  idx_a_last  = treap_a->last;
    1086       13065 :   TREAP_IDX_T  idx_b_first = treap_b->first;
    1087       13065 :   TREAP_IDX_T  idx_b_last  = treap_b->last;
    1088             : 
    1089             :   /* merged_{prev,next} are the nodes immediately before/after the
    1090             :      merged subtree.  If these are IDX_NULL, then treap_a->first/last
    1091             :      should be updated instead. */
    1092       13065 :   TREAP_IDX_T  merged_prev   = TREAP_IDX_NULL;
    1093       13065 :   TREAP_IDX_T  merged_next   = TREAP_IDX_NULL;
    1094             : # endif
    1095             : 
    1096       26430 : # define STACK_MAX (128UL)
    1097             : 
    1098       26430 :   struct { TREAP_IDX_T idx_merge_parent; TREAP_IDX_T * _idx_merge; TREAP_IDX_T idx_a; TREAP_IDX_T idx_b;
    1099             : #   if TREAP_OPTIMIZE_ITERATION
    1100             :     TREAP_IDX_T idx_a_first, idx_a_last, idx_b_first, idx_b_last;
    1101             :     TREAP_IDX_T merged_prev, merged_next;
    1102             : #   endif
    1103       26430 :   } stack[ STACK_MAX ];
    1104       26430 :   ulong stack_top = 0UL;
    1105             : 
    1106     3230598 : # define STACK_IS_EMPTY (!stack_top)
    1107       26430 : # define STACK_IS_FULL  (stack_top>=STACK_MAX)
    1108             : 
    1109             : # if TREAP_OPTIMIZE_ITERATION
    1110     1588032 : # define STACK_PUSH( imp, im, ia, ib, iaf, ial, ibf, ibl, mp, mn ) do { \
    1111     1588032 :     stack[ stack_top ].idx_merge_parent = (imp);                        \
    1112     1588032 :     stack[ stack_top ]._idx_merge       = (im);                         \
    1113     1588032 :     stack[ stack_top ].idx_a            = (ia);                         \
    1114     1588032 :     stack[ stack_top ].idx_b            = (ib);                         \
    1115     1588032 :     stack[ stack_top ].idx_a_first      = (iaf);                        \
    1116     1588032 :     stack[ stack_top ].idx_a_last       = (ial);                        \
    1117     1588032 :     stack[ stack_top ].idx_b_first      = (ibf);                        \
    1118     1588032 :     stack[ stack_top ].idx_b_last       = (ibl);                        \
    1119     1588032 :     stack[ stack_top ].merged_prev      = (mp);                         \
    1120     1588032 :     stack[ stack_top ].merged_next      = (mn);                         \
    1121     1588032 :     stack_top++;                                                        \
    1122     1588032 :   } while(0)
    1123     1588032 : # define STACK_POP( imp, im, ia, ib, iaf, ial, ibf, ibl, mp, mn ) do {  \
    1124     1588032 :     stack_top--;                                 \
    1125     1588032 :     (imp) = stack[ stack_top ].idx_merge_parent; \
    1126     1588032 :     (im)  = stack[ stack_top ]._idx_merge;       \
    1127     1588032 :     (ia)  = stack[ stack_top ].idx_a;            \
    1128     1588032 :     (ib)  = stack[ stack_top ].idx_b;            \
    1129     1588032 :     (iaf) = stack[ stack_top ].idx_a_first;      \
    1130     1588032 :     (ial) = stack[ stack_top ].idx_a_last;       \
    1131     1588032 :     (ibf) = stack[ stack_top ].idx_b_first;      \
    1132     1588032 :     (ibl) = stack[ stack_top ].idx_b_last;       \
    1133     1588032 :     (mp)  = stack[ stack_top ].merged_prev;      \
    1134     1588032 :     (mn)  = stack[ stack_top ].merged_next;      \
    1135     1588032 :   } while(0)
    1136             : # else
    1137     1616136 : # define STACK_PUSH( imp, im, ia, ib ) do {      \
    1138     1616136 :     stack[ stack_top ].idx_merge_parent = (imp); \
    1139     1616136 :     stack[ stack_top ]._idx_merge       = (im);  \
    1140     1616136 :     stack[ stack_top ].idx_a            = (ia);  \
    1141     1616136 :     stack[ stack_top ].idx_b            = (ib);  \
    1142     1616136 :     stack_top++;                                 \
    1143     1616136 :   } while(0)
    1144     1616136 : # define STACK_POP( imp, im, ia, ib ) do {       \
    1145     1616136 :     stack_top--;                                 \
    1146     1616136 :     (imp) = stack[ stack_top ].idx_merge_parent; \
    1147     1616136 :     (im)  = stack[ stack_top ]._idx_merge;       \
    1148     1616136 :     (ia)  = stack[ stack_top ].idx_a;            \
    1149     1616136 :     (ib)  = stack[ stack_top ].idx_b;            \
    1150     1616136 :   } while(0)
    1151             : # endif
    1152             : 
    1153       26430 :   TREAP_IDX_T idx_merge_parent = TREAP_IDX_NULL;
    1154             : 
    1155     6434766 :   for(;;) {
    1156             : 
    1157             :     /* At this point, we are to merge the treaps rooted at idx_a and
    1158             :        idx_b.  The result should be attached to the output treap at node
    1159             :        idx_merge_parent via the link *idx_merge.  (On the first
    1160             :        iteration, the idx_merge_parent will be idx_null and *_idx_merge
    1161             :        will be where to store the root of the output treap.) */
    1162             : 
    1163     6434766 :     int idx_a_is_null = TREAP_IDX_IS_NULL( idx_a );
    1164     6434766 :     int idx_b_is_null = TREAP_IDX_IS_NULL( idx_b );
    1165     6434766 :     if( idx_a_is_null | idx_b_is_null ) {
    1166             : 
    1167             :       /* At this point, at least one of the treaps to merge is empty.
    1168             :          Attach the non-empty treap (if any) accordingly.  If both are
    1169             :          empty, we attach NULL and there is no parent field to update. */
    1170             : 
    1171     3206598 :       TREAP_IDX_T idx_tmp;
    1172     3206598 :       *fd_ptr_if( idx_b_is_null, fd_ptr_if( idx_a_is_null, &idx_tmp,
    1173     3206598 :                                                            &pool[ idx_a ].TREAP_PARENT ),
    1174     3206598 :                                                            &pool[ idx_b ].TREAP_PARENT ) = idx_merge_parent;
    1175     3206598 :       *_idx_merge = (TREAP_IDX_T)fd_ulong_if( idx_b_is_null, (ulong)idx_a, (ulong)idx_b );
    1176             : 
    1177             : #     if TREAP_OPTIMIZE_ITERATION
    1178             :       /* Update the four pointers to insert the range
    1179             :          idx_a_first and idx_a_last (or b if a is the empty subtree)
    1180             :          between merged_prev and merged_next.  If both are the empty
    1181             :          subtree, then merged_prev connects directly to merged_next. */
    1182     1589097 :       *fd_ptr_if( TREAP_IDX_IS_NULL( merged_prev ), &treap_a->first, &pool[ merged_prev ].TREAP_NEXT ) =
    1183             :                                         (TREAP_IDX_T)fd_ulong_if( idx_b_is_null, fd_ulong_if( idx_a_is_null, (ulong)merged_next,
    1184             :                                                                                                              (ulong)idx_a_first ),
    1185             :                                                                                                              (ulong)idx_b_first );
    1186     1589097 :       *fd_ptr_if( TREAP_IDX_IS_NULL( merged_next ), &treap_a->last , &pool[ merged_next ].TREAP_PREV ) =
    1187             :                                         (TREAP_IDX_T)fd_ulong_if( idx_b_is_null, fd_ulong_if( idx_a_is_null, (ulong)merged_prev,
    1188             :                                                                                                              (ulong)idx_a_last  ),
    1189             :                                                                                                              (ulong)idx_b_last  );
    1190     1589097 :       *fd_ptr_if( idx_b_is_null, fd_ptr_if( idx_a_is_null, &idx_tmp,
    1191             :                                                            &pool[ idx_a_first ].TREAP_PREV ),
    1192             :                                                            &pool[ idx_b_first ].TREAP_PREV ) = merged_prev;
    1193     1589097 :       *fd_ptr_if( idx_b_is_null, fd_ptr_if( idx_a_is_null, &idx_tmp,
    1194             :                                                            &pool[ idx_a_last ].TREAP_NEXT ),
    1195             :                                                            &pool[ idx_b_last ].TREAP_NEXT ) = merged_next;
    1196             : 
    1197             : #     endif
    1198             :       /* Pop the stack to get the next merge to do.  If the stack is
    1199             :          empty, we are done. */
    1200             : 
    1201     3206598 :       if( STACK_IS_EMPTY ) break;
    1202             : #     if TREAP_OPTIMIZE_ITERATION
    1203     1576032 :       STACK_POP( idx_merge_parent, _idx_merge, idx_a, idx_b, idx_a_first, idx_a_last, idx_b_first, idx_b_last, merged_prev, merged_next );
    1204             : #     else
    1205     1604136 :       STACK_POP( idx_merge_parent, _idx_merge, idx_a, idx_b );
    1206     1604136 : #     endif
    1207     1604136 :       continue;
    1208     3206598 :     }
    1209             : 
    1210             :     /* If the stack is full, it appears we have exceedingly poorly
    1211             :        balanced treaps to merge.  To mitigate stack overflow risk from
    1212             :        the recursion, we fall back on a marginally less efficient brute
    1213             :        force non-recursive algorithm for the merge.  FIXME: consider
    1214             :        doing this post swap for statistical reasons (i.e. the treap with
    1215             :        the higher root priority is likely to be the larger treap and
    1216             :        such might have some performance implications for the below
    1217             :        loop). */
    1218             : 
    1219     3228168 :     if( FD_UNLIKELY( STACK_IS_FULL ) ) {
    1220             : 
    1221             :       /* Remove elements from B one-by-one and insert them into A.
    1222             :          O(B lg B) for the removes, O(B lg(A + B)) for the inserts.  The
    1223             :          value for ele_cnt in temp_treap_b is a dummy value to avoid
    1224             :          handholding checks from spuriously firing. */
    1225             : 
    1226             : #     if TREAP_OPTIMIZE_ITERATION
    1227       12000 :       TREAP_(t) temp_treap_a = { .ele_max = treap_a->ele_max, .ele_cnt = 0UL,              .root = idx_a, .first=idx_a_first, .last=idx_a_last };
    1228       12000 :       TREAP_(t) temp_treap_b = { .ele_max = treap_b->ele_max, .ele_cnt = treap_b->ele_max, .root = idx_b, .first=idx_b_first, .last=idx_b_last };
    1229             : #     else
    1230       12000 :       TREAP_(t) temp_treap_a = { .ele_max = treap_a->ele_max, .ele_cnt = 0UL,              .root = idx_a };
    1231       12000 :       TREAP_(t) temp_treap_b = { .ele_max = treap_b->ele_max, .ele_cnt = treap_b->ele_max, .root = idx_b };
    1232             : #     endif
    1233       24000 :       pool[ idx_a ].TREAP_PARENT = TREAP_IDX_NULL;
    1234       24000 :       pool[ idx_b ].TREAP_PARENT = TREAP_IDX_NULL;
    1235     1130412 :       do {
    1236     1130412 :         TREAP_IDX_T idx_tmp = temp_treap_b.root;
    1237     1130412 :         TREAP_(idx_remove)( &temp_treap_b, idx_tmp, pool );
    1238     1130412 :         TREAP_(idx_insert)( &temp_treap_a, idx_tmp, pool );
    1239     1130412 :       } while( !TREAP_IDX_IS_NULL( temp_treap_b.root ) );
    1240             : 
    1241       24000 :       idx_b = TREAP_IDX_NULL;
    1242       24000 :       idx_a = temp_treap_a.root;
    1243             : 
    1244             :       /* Attach the merged treap to the output */
    1245             : 
    1246       24000 :       pool[ idx_a ].TREAP_PARENT = idx_merge_parent;
    1247       24000 :       *_idx_merge = idx_a;
    1248             : 
    1249             : #     if TREAP_OPTIMIZE_ITERATION
    1250       12000 :       *fd_ptr_if( TREAP_IDX_IS_NULL( merged_prev ), &treap_a->first, &pool[ merged_prev ].TREAP_NEXT ) = temp_treap_a.first;
    1251       12000 :       *fd_ptr_if( TREAP_IDX_IS_NULL( merged_next ), &treap_a->last,  &pool[ merged_next ].TREAP_PREV ) = temp_treap_a.last;
    1252       12000 :       pool[ temp_treap_a.first ].TREAP_PREV = merged_prev;
    1253       12000 :       pool[ temp_treap_a.last  ].TREAP_NEXT = merged_next;
    1254             : #     endif
    1255             : 
    1256             :       /* Pop the stack to get the next merge to do.  If the stack is
    1257             :          empty, we are done. */
    1258             : 
    1259       24000 :       if( STACK_IS_EMPTY ) break;
    1260             : #     if TREAP_OPTIMIZE_ITERATION
    1261       12000 :       STACK_POP( idx_merge_parent, _idx_merge, idx_a, idx_b,
    1262       12000 :           idx_a_first, idx_a_last, idx_b_first, idx_b_last, merged_prev, merged_next );
    1263             : #     else
    1264       12000 :       STACK_POP( idx_merge_parent, _idx_merge, idx_a, idx_b );
    1265       12000 : #     endif
    1266       12000 :       continue;
    1267       24000 :     }
    1268             : 
    1269             :     /* At this point, we have two non-empty treaps A and B to merge and
    1270             :        we have stack space so we can use a fast recursive algorithm.  If
    1271             :        A's root priority is below B's root priority, swap A and B. */
    1272             : 
    1273     3204168 :     TREAP_IDX_T prio_a = pool[ idx_a ].TREAP_PRIO;
    1274     3204168 :     TREAP_IDX_T prio_b = pool[ idx_b ].TREAP_PRIO;
    1275     3204168 :     int swap = (prio_a<prio_b) | ((prio_a==prio_b) & (int)(idx_a ^ idx_b));
    1276     3204168 :     fd_swap_if( swap, idx_a,       idx_b       );
    1277             : #   if TREAP_OPTIMIZE_ITERATION
    1278     1588032 :     fd_swap_if( swap, idx_a_first, idx_b_first );
    1279     1588032 :     fd_swap_if( swap, idx_a_last,  idx_b_last  );
    1280             : #   endif
    1281             : 
    1282             :     /* At this point, we have two non-empty treaps to merge and A's root
    1283             :        priority is higher than B's root priority.  So, we know the root
    1284             :        of the merged treaps is A's root and can attach it to the output
    1285             :        treap accordingly. */
    1286             : 
    1287     3204168 :     pool[ idx_a ].TREAP_PARENT = idx_merge_parent;
    1288     3204168 :     *_idx_merge = idx_a;
    1289             : 
    1290             :     /* Get A's left and right subtrees */
    1291             : 
    1292     3204168 :     TREAP_IDX_T idx_a_left  = pool[ idx_a ].TREAP_LEFT;
    1293     3204168 :     TREAP_IDX_T idx_a_right = pool[ idx_a ].TREAP_RIGHT;
    1294             : 
    1295             :     /* Split B by A's root key */
    1296             : 
    1297     3204168 :     TREAP_IDX_T idx_b_left;
    1298     3204168 :     TREAP_IDX_T idx_b_right;
    1299     3204168 :     TREAP_IDX_T idx_b_left_last;
    1300     3204168 :     TREAP_IDX_T idx_b_right_first;
    1301     3204168 :     TREAP_(private_split)( idx_b, &pool[ idx_a ], &idx_b_left, &idx_b_right, &idx_b_left_last, &idx_b_right_first, pool );
    1302             : 
    1303             : #   if TREAP_OPTIMIZE_ITERATION
    1304             :     /* Split the iteration order links in B as well */
    1305     1588032 :     TREAP_IDX_T dummy;
    1306     1588032 :     *fd_ptr_if( TREAP_IDX_IS_NULL( idx_b_left_last   ), &dummy, &pool[ idx_b_left_last   ].TREAP_NEXT ) = TREAP_IDX_NULL;
    1307     1588032 :     *fd_ptr_if( TREAP_IDX_IS_NULL( idx_b_right_first ), &dummy, &pool[ idx_b_right_first ].TREAP_PREV ) = TREAP_IDX_NULL;
    1308             : 
    1309             :     /* The first node in B's left subtree is the first node in B unless
    1310             :        it is empty.  Similarly for B's right subtree. */
    1311     1588032 :     TREAP_IDX_T idx_b_left_first = (TREAP_IDX_T)fd_ulong_if( TREAP_IDX_IS_NULL( idx_b_left  ), TREAP_IDX_NULL, idx_b_first );
    1312     1588032 :     TREAP_IDX_T idx_b_right_last = (TREAP_IDX_T)fd_ulong_if( TREAP_IDX_IS_NULL( idx_b_right ), TREAP_IDX_NULL, idx_b_last  );
    1313             : #   endif
    1314             : 
    1315             :     /* At this point, A's left subtree and B's left split are all keys
    1316             :        to the left of A's root and A's right subtree.  Similarly, B's
    1317             :        right split are all keys to the right of A's root and A's left
    1318             :        subtree.  We can't do a fast join on A's left/right subtree and B's
    1319             :        left/right split though as theses are not guaranteed to already
    1320             :        have their keys distributed as required by join.  We instead
    1321             :        recursively merge the left side and right side.  We do the left
    1322             :        side first and the right side later (making this a cache oblivious
    1323             :        algorithm too). */
    1324             : 
    1325             : #   if TREAP_OPTIMIZE_ITERATION
    1326     1588032 :     STACK_PUSH( idx_a, &pool[ idx_a ].TREAP_RIGHT, idx_a_right, idx_b_right,
    1327             :                 pool[ idx_a ].TREAP_NEXT, idx_a_last, idx_b_right_first, idx_b_right_last, idx_a, merged_next );
    1328             : #   else
    1329     1616136 :     STACK_PUSH( idx_a, &pool[ idx_a ].TREAP_RIGHT, idx_a_right, idx_b_right );
    1330             : #   endif
    1331             : 
    1332     3204168 :     idx_merge_parent = idx_a;
    1333     3204168 :     _idx_merge       = &pool[ idx_a ].TREAP_LEFT;
    1334             : #   if TREAP_OPTIMIZE_ITERATION
    1335     1588032 :     idx_a_last       = pool[ idx_a ].TREAP_PREV;
    1336             :     idx_b_first      = idx_b_left_first;
    1337             :     idx_b_last       = idx_b_left_last;
    1338             :     merged_next      = idx_a;
    1339             : #   endif
    1340     3204168 :     idx_a            = idx_a_left;
    1341     3204168 :     idx_b            = idx_b_left;
    1342     3204168 :   }
    1343             : 
    1344       26430 :   treap_a->root     = new_root;
    1345       26430 :   treap_b->root     = TREAP_IDX_NULL;
    1346       26430 :   treap_a->ele_cnt += treap_b->ele_cnt;
    1347       26430 :   treap_b->ele_cnt  = 0UL;
    1348             : # if TREAP_OPTIMIZE_ITERATION
    1349       13065 :   treap_b->first    = TREAP_IDX_NULL;
    1350       13065 :   treap_b->last     = TREAP_IDX_NULL;
    1351             : # endif
    1352             : 
    1353       26430 :   return treap_a;
    1354             : 
    1355       26430 : # undef STACK_POP
    1356       26430 : # undef STACK_PUSH
    1357       26430 : # undef STACK_IS_FULL
    1358       26430 : # undef STACK_IS_EMPTY
    1359       26430 : # undef STACK_MAX
    1360       26430 : }
    1361             : 
    1362             : TREAP_STATIC TREAP_(fwd_iter_t)
    1363             : TREAP_(fwd_iter_init)( TREAP_(t) const * treap,
    1364    64569665 :                        TREAP_T const *   pool ) {
    1365             : # if TREAP_OPTIMIZE_ITERATION
    1366             :   (void)pool;
    1367             :   return treap->first;
    1368             : # else
    1369     3758886 :   ulong i = TREAP_IDX_NULL;
    1370             :   ulong j = (ulong)treap->root;
    1371    18049266 :   while( FD_LIKELY( !TREAP_IDX_IS_NULL( j ) ) ) { i = j; j = (ulong)pool[ j ].TREAP_LEFT; }
    1372             :   return i;
    1373             : # endif
    1374    64569665 : }
    1375             : 
    1376             : TREAP_STATIC TREAP_(rev_iter_t)
    1377             : TREAP_(rev_iter_init)( TREAP_(t) const * treap,
    1378     2204872 :                        TREAP_T const *   pool ) {
    1379             : # if TREAP_OPTIMIZE_ITERATION
    1380             :   (void)pool;
    1381             :   return treap->last;
    1382             : # else
    1383        1227 :   ulong i = TREAP_IDX_NULL;
    1384             :   ulong j = (ulong)treap->root;
    1385      956553 :   while( FD_LIKELY( !TREAP_IDX_IS_NULL( j ) ) ) { i = j; j = (ulong)pool[ j ].TREAP_RIGHT; }
    1386             :   return i;
    1387             : # endif
    1388     2204872 : }
    1389             : 
    1390             : TREAP_STATIC TREAP_(fwd_iter_t)
    1391             : TREAP_(fwd_iter_next)( TREAP_(fwd_iter_t) i,
    1392   150067451 :                        TREAP_T const *    pool ) {
    1393             : # if TREAP_OPTIMIZE_ITERATION
    1394    27161975 :   return pool[ i ].TREAP_NEXT;
    1395             : # else
    1396   122905476 :   ulong r = (ulong)pool[ i ].TREAP_RIGHT;
    1397             : 
    1398   122905476 :   if( TREAP_IDX_IS_NULL( r ) ) {
    1399    63315081 :     ulong p = (ulong)pool[ i ].TREAP_PARENT;
    1400   122905410 :     while( !TREAP_IDX_IS_NULL( p ) ) {
    1401   119202432 :       if( i==(ulong)pool[ p ].TREAP_LEFT ) break;
    1402    59590329 :       i = p;
    1403    59590329 :       p = (ulong)pool[ p ].TREAP_PARENT;
    1404    59590329 :     }
    1405    63315081 :     return p;
    1406    63315081 :   }
    1407             : 
    1408    59590395 :   i = r;
    1409   108615201 :   for(;;) {
    1410   108615201 :     ulong l = (ulong)pool[ i ].TREAP_LEFT;
    1411   108615201 :     if( TREAP_IDX_IS_NULL( l ) ) break;
    1412    49024806 :     i = l;
    1413    49024806 :   }
    1414             : 
    1415    59590395 :   return i;
    1416             : # endif
    1417   150067451 : }
    1418             : 
    1419             : TREAP_STATIC TREAP_(rev_iter_t)
    1420             : TREAP_(rev_iter_next)( TREAP_(rev_iter_t) i,
    1421    23845200 :                        TREAP_T const *    pool ) {
    1422             : # if TREAP_OPTIMIZE_ITERATION
    1423    23843028 :   return pool[ i ].TREAP_PREV;
    1424             : #else
    1425        2172 :   ulong l = (ulong)pool[ i ].TREAP_LEFT;
    1426             : 
    1427        2172 :   if( TREAP_IDX_IS_NULL( l ) ) {
    1428         360 :     ulong p = (ulong)pool[ i ].TREAP_PARENT;
    1429        1419 :     while( !TREAP_IDX_IS_NULL( p ) ) {
    1430        1383 :       if( i==(ulong)pool[ p ].TREAP_RIGHT ) break;
    1431        1059 :       i = p;
    1432        1059 :       p = (ulong)pool[ p ].TREAP_PARENT;
    1433        1059 :     }
    1434         360 :     return p;
    1435         360 :   }
    1436             : 
    1437        1812 :   i = l;
    1438        2028 :   for(;;) {
    1439        2028 :     ulong r = (ulong)pool[ i ].TREAP_RIGHT;
    1440        2028 :     if( TREAP_IDX_IS_NULL( r ) ) break;
    1441         216 :     i = r;
    1442         216 :   }
    1443             : 
    1444        1812 :   return i;
    1445             : #endif
    1446    23845200 : }
    1447             : 
    1448             : TREAP_STATIC int
    1449             : TREAP_(verify)( TREAP_(t) const * treap,
    1450    30061167 :                 TREAP_T const *   pool ) {
    1451             : 
    1452  7949150112 : # define TREAP_TEST( c ) do { if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: " #c )); return -1; } } while(0)
    1453             : 
    1454    30061167 :   TREAP_TEST( treap ); /* Validate local join */
    1455             : 
    1456    30061167 :   ulong ele_max = treap->ele_max; TREAP_TEST( ele_max<=TREAP_IDX_NULL ); /* Validate ele_max */
    1457    30061167 :   ulong ele_cnt = treap->ele_cnt; TREAP_TEST( ele_cnt<=ele_max        ); /* Validate ele_cnt */
    1458    30061167 :   if( ele_max ) TREAP_TEST( pool );                                      /* Validate ele storage */
    1459             : 
    1460             :   /* Find leftmost */
    1461             : 
    1462    30061167 :   ulong i = TREAP_IDX_NULL;
    1463    30061167 :   ulong l = (ulong)treap->root;
    1464             : 
    1465    30061167 :   ulong loop_cnt = 0UL;
    1466   153397833 :   while( FD_LIKELY( !TREAP_IDX_IS_NULL( l ) ) ) {
    1467   123336666 :     TREAP_TEST( loop_cnt<ele_cnt ); /* Make sure no cycles */
    1468   123336666 :     TREAP_TEST( l       <ele_max ); /* Make sure valid index */
    1469   123336666 :     i = l;
    1470   123336666 :     l = (ulong)pool[ l ].TREAP_LEFT;
    1471   123336666 :     loop_cnt++;
    1472   123336666 :   }
    1473             : # if TREAP_OPTIMIZE_ITERATION
    1474       43347 :   TREAP_TEST( treap->first==i );
    1475       43347 : # endif
    1476             : 
    1477             :   /* In-order traverse the treap starting from the leftmost */
    1478             : 
    1479    30061167 :   ulong cnt = 0UL; /* Number of elements we've visited so far */
    1480  1021711710 :   while( FD_LIKELY( !TREAP_IDX_IS_NULL( i ) ) ) {
    1481   991650543 :     TREAP_TEST( cnt<ele_cnt ); /* Make sure no cycles */
    1482             : 
    1483             :     /* At this point, we are visiting element i.  We've already visited
    1484             :        all elements less than i and l is the last element we visited (or
    1485             :        NULL if i is the first element we are visiting. */
    1486             : 
    1487   991650543 :     if( FD_LIKELY( !TREAP_IDX_IS_NULL( l ) ) ) TREAP_TEST( !TREAP_(lt)( pool + i, pool + l ) ); /* Make sure ordering valid */
    1488             : #   if TREAP_OPTIMIZE_ITERATION
    1489             :     /* Check the l <-> i link */
    1490     6839202 :     if( FD_LIKELY( !TREAP_IDX_IS_NULL( l ) ) ) TREAP_TEST( pool[ l ].TREAP_NEXT==i );
    1491     6839202 :     if( FD_LIKELY( !TREAP_IDX_IS_NULL( i ) ) ) TREAP_TEST( pool[ i ].TREAP_PREV==l );
    1492     6839202 : #   endif
    1493             : 
    1494             : 
    1495   991650543 :     ulong p = (ulong)pool[ i ].TREAP_PARENT;
    1496   991650543 :     if( FD_LIKELY( !TREAP_IDX_IS_NULL( p ) ) ) {
    1497   962034177 :       TREAP_TEST( p < ele_max );                                                /* Make sure valid index */
    1498   962034177 :       TREAP_TEST( (ulong)pool[ p ].TREAP_PRIO >= (ulong)pool[ i ].TREAP_PRIO ); /* Make sure heap property valid */
    1499   962034177 :     }
    1500             : 
    1501             :     /* Done visiting i, advance to i's successor */
    1502             : 
    1503   991650543 :     cnt++;
    1504             : 
    1505   991650543 :     l = i;
    1506             : 
    1507   991650543 :     ulong r = (ulong)pool[ i ].TREAP_RIGHT;
    1508   991650543 :     if( TREAP_IDX_IS_NULL( r ) ) {
    1509             : 
    1510             :       /* i has no right subtree.  Look for first ancestor of i that we
    1511             :          haven't visited (this will be the first ancestor for which i is
    1512             :          in the ancestor's left subtree).  If there is no such ancestor,
    1513             :          we are at the rightmost and we are done. */
    1514             : 
    1515   515402484 :       loop_cnt = 0UL;
    1516   991650543 :       while( !TREAP_IDX_IS_NULL( p ) ) {
    1517   962034177 :         TREAP_TEST( loop_cnt<ele_cnt ); /* Make sure no cycles */
    1518   962034177 :         TREAP_TEST( p       <ele_max ); /* Make sure valid index */
    1519   962034177 :         if( i==(ulong)pool[ p ].TREAP_LEFT ) break;
    1520   476248059 :         i = p;
    1521   476248059 :         p = (ulong)pool[ p ].TREAP_PARENT;
    1522   476248059 :         loop_cnt++;
    1523   476248059 :       }
    1524             : 
    1525   515402484 :       i = p;
    1526             : 
    1527   515402484 :     } else {
    1528             : 
    1529             :       /* i has a right subtree.  Find the leftmost in this subtree. */
    1530             : 
    1531   476248059 :       i = r;
    1532             : 
    1533   476248059 :       loop_cnt = 0UL;
    1534   868313877 :       for(;;) {
    1535   868313877 :         TREAP_TEST( loop_cnt<ele_cnt ); /* Make sure no cycles */
    1536   868313877 :         TREAP_TEST( i       <ele_max ); /* Make sure valid index */
    1537   868313877 :         ulong ll = (ulong)pool[ i ].TREAP_LEFT;
    1538   868313877 :         if( TREAP_IDX_IS_NULL( ll ) ) break;
    1539   392065818 :         i = ll;
    1540   392065818 :         loop_cnt++;
    1541   392065818 :       }
    1542             : 
    1543   476248059 :     }
    1544             : 
    1545   991650543 :   }
    1546             : 
    1547             : # if TREAP_OPTIMIZE_ITERATION
    1548       43347 :   TREAP_TEST( treap->last==l );
    1549       43347 : # endif
    1550             : 
    1551    30061167 :   TREAP_TEST( cnt==ele_cnt ); /* Make sure we visited correct number of elements */
    1552             : 
    1553    30061167 : # undef TREAP_TEST
    1554             : 
    1555    30061167 :   return 0;
    1556    30061167 : }
    1557             : 
    1558             : #endif
    1559             : 
    1560             : #undef TREAP_IDX_IS_NULL
    1561             : #undef TREAP_IDX_NULL
    1562             : #undef TREAP_STATIC
    1563             : 
    1564             : #undef TREAP_IMPL_STYLE
    1565             : #undef TREAP_NEXT
    1566             : #undef TREAP_PREV
    1567             : #undef TREAP_OPTIMIZE_ITERATION
    1568             : #undef TREAP_PRIO
    1569             : #undef TREAP_RIGHT
    1570             : #undef TREAP_LEFT
    1571             : #undef TREAP_PARENT
    1572             : #undef TREAP_IDX_T
    1573             : #undef TREAP_LT
    1574             : #undef TREAP_CMP
    1575             : #undef TREAP_QUERY_T
    1576             : #undef TREAP_T
    1577             : #undef TREAP_NAME

Generated by: LCOV version 1.14