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 chose 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,ele_cnt} gives the maximum number of elements
194 : // the treap can support / the current number of elements in the
195 : // treap. Assumes treap is a current local join. These might be
196 : // deprecated in the future.
197 :
198 : ulong mytreap_ele_max( mytreap_t const * treap );
199 : ulong mytreap_ele_cnt( mytreap_t const * treap );
200 :
201 : // mytreap_idx_query finds where q is stored in the treap. Assumes
202 : // treap is a current local join and pool points in the caller's
203 : // address space to the ele_max element storage containing the
204 : // treap elements. Returns [0,ele_max) on success and
205 : // mytreap_idx_null() on failure. Lifetime of the returned idx is
206 : // the lesser of until it is removed or the underlying element
207 : // storage. mytreap_ele_query is the same but returns the location
208 : // in the caller's address space of the found element on success
209 : // and NULL on failure (lifetime of the returned pointer is until
210 : // ele is removed or ele's local lifetime).
211 : // mytreap_ele_query_const is a const correct version.
212 : //
213 : // These operations have HPC implementations and are O(lg N)
214 : // average with an ultra high probability of having a small
215 : // coefficient (i.e. close to algorithmically optimal trees).
216 :
217 : ulong mytreap_idx_query ( mytreap_t const * treap, char const * q, myele_t const * pool );
218 : myele_t * mytreap_ele_query ( mytreap_t * treap, char const * q, myele_t * pool );
219 : myele_t const * mytreap_ele_query_const( mytreap_t const * treap, char const * q, myele_t const * pool );
220 :
221 : // mytreap_idx_{insert,remove} inserts / removes element n/d into
222 : // the treap and returns treap. Assumes treap is a current local
223 : // join, pool points in the caller's address space to the ele_max
224 : // element storage used for treap elements, n/d are in [0,ele_max),
225 : // n/d are currently out of / in the treap. Insert further assumes
226 : // that n's queries are not in the treap (n's queries are the set
227 : // of queries that are covered by n). Given these assumptions,
228 : // these cannot fail.
229 : //
230 : // For insert, n's query and prio fields should already be
231 : // populated (i.e. MYTREAP_LT( ele+n, ele+i ) should return valid
232 : // results before this is called and prio should be a suitable
233 : // value as described above. On return, n and n's queries will be
234 : // in the treap. n's left, right, parent, prio and/or queries
235 : // should not be modified while n is in the treap. Further, the
236 : // caller should not assume n's left, right or parent values are
237 : // stable while n is in the treap. The treap does not care about
238 : // any other fields and these can be modified by the user as
239 : // necessary.
240 : //
241 : // For remove, on return d and d's queries are no longer in the
242 : // treap. The caller is free to modify all fields of d as
243 : // necessary.
244 : //
245 : // mytreap_ele_{insert,remove} are the same but n and d point in
246 : // the caller's local address space the element to insert / remove.
247 : //
248 : // These operations have HPC implementations and are O(lg N)
249 : // average with an ultra high probability of having a small
250 : // coefficient (i.e. close to algorithmically optimal trees).
251 :
252 : mytreap_t * mytreap_idx_insert( mytreap_t * treap, ulong n, myele_t * pool );
253 : mytreap_t * mytreap_idx_remove( mytreap_t * treap, ulong d, myele_t * pool );
254 :
255 : mytreap_t * mytreap_ele_insert( mytreap_t * treap, myele_t * n, myele_t * pool );
256 : mytreap_t * mytreap_ele_remove( mytreap_t * treap, myele_t * d, myele_t * pool );
257 :
258 : // mytreap_fwd_iter_{init,done,next,idx,ele,ele_const} provide an
259 : // in-order iterator from smallest to largest value. Typical
260 : // usage:
261 : //
262 : // for( mytreap_fwd_iter_t iter = mytreap_fwd_iter_init( treap, pool );
263 : // !mytreap_fwd_iter_done( iter );
264 : // iter = mytreap_fwd_iter_next( iter, pool ) ) {
265 : // ulong i = mytreap_fwd_iter_idx( iter );
266 : // ... or myele_t * e = mytreap_fwd_iter_ele ( iter, pool );
267 : // ... or myele_t const * e = mytreap_fwd_iter_ele_const( iter, pool );
268 : //
269 : // ... process i (or e) here
270 : //
271 : // ... Do not remove the element the iterator is currently
272 : // ... pointing to, and do not change the element's parent,
273 : // ... left, right, prio or queries here. It is fine to run
274 : // ... queries and other iterations concurrently. Other fields
275 : // ... are free to modify (from the treap's POV, the
276 : // ... application manages concurrency for other fields).
277 : // }
278 : //
279 : // pool is a pointer in the caller's address space to the ele_max
280 : // linearly addressable storage region backing the treap.
281 :
282 : typedef ... mytreap_fwd_iter_t;
283 :
284 : mytreap_fwd_iter_t mytreap_fwd_iter_init ( mytreap_t const * treap, myele_t const * pool );
285 : int mytreap_fwd_iter_done ( mytreap_fwd_iter_t iter );
286 : mytreap_fwd_iter_t mytreap_fwd_iter_next ( mytreap_fwd_iter_t iter, myele_t const * pool );
287 : ulong mytreap_fwd_iter_idx ( mytreap_fwd_iter_t iter );
288 : myele_t * mytreap_fwd_iter_ele ( mytreap_fwd_iter_t iter, myele_t * pool );
289 : myele_t const * mytreap_fwd_iter_ele_const( mytreap_fwd_iter_t iter, myele_t const * pool );
290 :
291 : // mytreap_rev_iter_{init,done,next,idx,ele,ele_const} is the same
292 : // but used when iterating from largest to smallest.
293 :
294 : typedef ... mytreap_rev_iter_t;
295 :
296 : mytreap_rev_iter_t mytreap_rev_iter_init ( mytreap_t const * treap, myele_t const * pool );
297 : int mytreap_rev_iter_done ( mytreap_rev_iter_t iter );
298 : mytreap_rev_iter_t mytreap_rev_iter_next ( mytreap_rev_iter_t iter, myele_t const * pool );
299 : ulong mytreap_rev_iter_idx ( mytreap_rev_iter_t iter );
300 : myele_t * mytreap_rev_iter_ele ( mytreap_rev_iter_t iter, myele_t * pool );
301 : myele_t const * mytreap_rev_iter_ele_const( mytreap_rev_iter_t iter, myele_t const * pool );
302 :
303 : // mytreap_merge merges two treaps backed by the same pool into a
304 : // single treap. Merge is equivalent to removing each element from
305 : // treap_b and inserting it into treap_a, but merging the heaps is
306 : // asymptotically slightly better. Returns treap_a, which now
307 : // additionally contains the elements from treap_b. Requires that
308 : // the treap does not use the maximum priority element (see the
309 : // note above about PRIO_MAX). Assumes the A and B treaps contain
310 : // no common keys.
311 :
312 : mytreap * mytreap_merge( mytreap * treap_a, mytreap * treap_b, myele_t * pool );
313 :
314 : // mytreap_verify returns 0 if the mytreap is not obviously corrupt
315 : // or a -1 (i.e. ERR_INVAL) if it is (logs details). treap is
316 : // current local join to a mytreap. pool is a pointer in the
317 : // caller's address space to the ele_max linearly addressable
318 : // storage region backing the treap.
319 :
320 : int mytreap_verify( mytreap_t const * treap, myele_t const * pool );
321 :
322 : // IMPORTANT SAFETY TIP! queries and iteration can be done
323 : // concurrently by multiple threads distributed arbitrarily over
324 : // multiple processes provided there are no concurrent insert /
325 : // remove operations on the treap and the application manages
326 : // concurrency for fields not managed by the treap.
327 :
328 : You can do this as often as you like within a compilation unit to get
329 : different types of treaps. Variants exist for making separate headers
330 : and implementations for doing libraries and handling multiple
331 : compilation units. Additional options exist as detailed below. */
332 :
333 : /* TREAP_NAME gives the API prefix to use */
334 :
335 : #ifndef TREAP_NAME
336 : #error "Define TREAP_NAME"
337 : #endif
338 :
339 : /* TREAP_T is the treap element type */
340 :
341 : #ifndef TREAP_T
342 : #error "Define TREAP_T"
343 : #endif
344 :
345 : /* TREAP_QUERY_T is the type that is passed to the query function */
346 :
347 : #ifndef TREAP_QUERY_T
348 : #error "Define TREAP_QUERY_T"
349 : #endif
350 :
351 : /* TREAP_CMP compares a TREAP_QUERY_T q with an element e's query
352 : fields and returns a negative/zero/positive int if q is less
353 : than/equal/greater than element e's query fields. Should be a pure
354 : function. */
355 :
356 : #ifndef TREAP_CMP
357 : #error "Define TREAP_CMP"
358 : #endif
359 :
360 : /* TREAP_LT returns 1 if the element e0's query fields are strictly less
361 : element e1's query fields and 0 otherwise. Should be a pure
362 : function. */
363 :
364 : #ifndef TREAP_LT
365 : #error "Define TREAP_LT"
366 : #endif
367 :
368 : /* TREAP_IDX_T is the type used for the fields in the TREAP_T. Should
369 : be a primitive unsigned integer type. Defaults to ulong. A treap
370 : can't use element memory regions that contain more than the maximum
371 : value that can be represented by a TREAP_IDX_T. */
372 :
373 : #ifndef TREAP_IDX_T
374 9410049 : #define TREAP_IDX_T ulong
375 : #endif
376 :
377 : /* TREAP_{PARENT,LEFT,RIGHT,PRIO} is the name the treap element parent /
378 : left / right / prio fields. Defaults to parent / left / right /
379 : prio. */
380 :
381 : #ifndef TREAP_PARENT
382 77294467 : #define TREAP_PARENT parent
383 : #endif
384 :
385 : #ifndef TREAP_LEFT
386 49787709 : #define TREAP_LEFT left
387 : #endif
388 :
389 : #ifndef TREAP_RIGHT
390 32067478 : #define TREAP_RIGHT right
391 : #endif
392 :
393 : #ifndef TREAP_PRIO
394 46379740 : #define TREAP_PRIO prio
395 : #endif
396 :
397 : /* TREAP_OPTIMIZE_ITERATION controls a space/time tradeoff: when
398 : TREAP_OPTIMIZE_ITERATION is set to 1, each element has two additional
399 : fields and insert and delete take slightly longer. However, in
400 : return, iteration in either direction is substantially faster. This
401 : works by essentially threading a doubly-linked list through elements
402 : in iteration order. The default is sets this to 0, meaning that the
403 : next and prev fields are not required. */
404 : #ifndef TREAP_OPTIMIZE_ITERATION
405 : #define TREAP_OPTIMIZE_ITERATION 0
406 : #endif
407 :
408 : #if TREAP_OPTIMIZE_ITERATION
409 : # ifndef TREAP_NEXT
410 26161545 : # define TREAP_NEXT next
411 : # endif
412 :
413 : # ifndef TREAP_PREV
414 147096450 : # define TREAP_PREV prev
415 : # endif
416 : #endif
417 :
418 : /* TREAP_IMPL_STYLE controls what this template should emit.
419 : 0 - local use only
420 : 1 - library header
421 : 2 - library implementation */
422 :
423 : #ifndef TREAP_IMPL_STYLE
424 : #define TREAP_IMPL_STYLE 0
425 : #endif
426 :
427 : /* Implementation *****************************************************/
428 :
429 : #if TREAP_IMPL_STYLE==0
430 : #define TREAP_STATIC static FD_FN_UNUSED
431 : #else
432 : #define TREAP_STATIC
433 : #endif
434 :
435 4230749752 : #define TREAP_IDX_NULL ((ulong)(TREAP_IDX_T)(~0UL))
436 4055103907 : #define TREAP_IDX_IS_NULL( idx ) ((idx)==TREAP_IDX_NULL)
437 :
438 617644281 : #define TREAP_(n) FD_EXPAND_THEN_CONCAT3(TREAP_NAME,_,n)
439 :
440 : /* Verification logs details on failure. The rest only needs fd_bits.h
441 : (consider making logging a compile time option). */
442 :
443 : #include "../log/fd_log.h"
444 :
445 : #if TREAP_IMPL_STYLE!=2 /* need structures, prototypes and inlines */
446 :
447 : /* structures */
448 :
449 : /* TODO: consider eliminating ele_cnt and maybe ele_max fields (less overhead,
450 : faster bulk ops, concurrency options, simpler constructors, etc) */
451 :
452 : struct TREAP_(private) {
453 : ulong ele_max; /* Maximum number of elements in treap, in [0,TREAP_IDX_NULL] */
454 : ulong ele_cnt; /* Current number of elements in treap, in [0,ele_max] */
455 : #if TREAP_OPTIMIZE_ITERATION
456 : TREAP_IDX_T first; /* Index of the left-most treap element, in [0,ele_max) or TREAP_IDX_NULL */
457 : TREAP_IDX_T last; /* Index of the right-most treap element, in [0,ele_max) or TREAP_IDX_NULL */
458 : #endif
459 : TREAP_IDX_T root; /* Index of the root treap element, in [0,ele_max) or TREAP_IDX_NULL */
460 : };
461 :
462 : typedef struct TREAP_(private) TREAP_(t);
463 :
464 : typedef ulong TREAP_(fwd_iter_t);
465 : typedef ulong TREAP_(rev_iter_t);
466 :
467 : FD_PROTOTYPES_BEGIN
468 :
469 : /* prototypes */
470 :
471 : TREAP_STATIC void TREAP_(seed)( TREAP_T * pool, ulong ele_max, ulong seed );
472 :
473 : TREAP_STATIC FD_FN_CONST ulong TREAP_(align) ( void );
474 : TREAP_STATIC FD_FN_CONST ulong TREAP_(footprint)( ulong ele_max );
475 : TREAP_STATIC /**/ void * TREAP_(new) ( void * shmem, ulong ele_max );
476 : TREAP_STATIC /**/ TREAP_(t) * TREAP_(join) ( void * shtreap );
477 : TREAP_STATIC /**/ void * TREAP_(leave) ( TREAP_(t) * treap );
478 : TREAP_STATIC /**/ void * TREAP_(delete) ( void * shtreap );
479 :
480 : TREAP_STATIC FD_FN_PURE ulong TREAP_(idx_query)( TREAP_(t) const * treap, TREAP_QUERY_T q, TREAP_T const * pool );
481 :
482 : TREAP_STATIC TREAP_(t) * TREAP_(idx_insert)( TREAP_(t) * treap, ulong n, TREAP_T * pool );
483 : TREAP_STATIC TREAP_(t) * TREAP_(idx_remove)( TREAP_(t) * treap, ulong d, TREAP_T * pool );
484 :
485 : TREAP_STATIC FD_FN_PURE TREAP_(fwd_iter_t) TREAP_(fwd_iter_init)( TREAP_(t) const * treap, TREAP_T const * pool );
486 : TREAP_STATIC FD_FN_PURE TREAP_(rev_iter_t) TREAP_(rev_iter_init)( TREAP_(t) const * treap, TREAP_T const * pool );
487 :
488 : TREAP_STATIC FD_FN_PURE TREAP_(fwd_iter_t) TREAP_(fwd_iter_next)( TREAP_(fwd_iter_t) i, TREAP_T const * pool );
489 : TREAP_STATIC FD_FN_PURE TREAP_(rev_iter_t) TREAP_(rev_iter_next)( TREAP_(rev_iter_t) i, TREAP_T const * pool );
490 :
491 : TREAP_STATIC TREAP_(t) * TREAP_(merge)( TREAP_(t) * treap_a, TREAP_(t) * treap_b, TREAP_T * pool );
492 :
493 : TREAP_STATIC FD_FN_PURE int TREAP_(verify)( TREAP_(t) const * treap, TREAP_T const * pool );
494 :
495 : /* inlines */
496 :
497 119069568 : FD_FN_PURE static inline int TREAP_(cmp)( TREAP_QUERY_T q, TREAP_T const * e ) { return TREAP_CMP( q, e ); }
498 1404495186 : FD_FN_PURE static inline int TREAP_(lt) ( TREAP_T const * e0, TREAP_T const * e1 ) { return TREAP_LT( e0, e1 ); }
499 :
500 0 : FD_FN_CONST static inline ulong TREAP_(idx_null) ( void ) { return TREAP_IDX_NULL; }
501 0 : FD_FN_CONST static inline TREAP_T * TREAP_(ele_null) ( void ) { return NULL; }
502 0 : FD_FN_CONST static inline TREAP_T const * TREAP_(ele_null_const)( void ) { return NULL; }
503 :
504 3831663 : FD_FN_CONST static inline int TREAP_(idx_is_null)( ulong i ) { return TREAP_IDX_IS_NULL( i ); }
505 768 : FD_FN_CONST static inline int TREAP_(ele_is_null)( TREAP_T const * e ) { return !e; }
506 :
507 : FD_FN_CONST static inline ulong
508 : TREAP_(idx)( TREAP_T const * e,
509 15006036 : TREAP_T const * pool ) {
510 15006036 : return fd_ulong_if( !!e, (ulong)(e - pool), TREAP_IDX_NULL );
511 15006036 : }
512 :
513 : FD_FN_CONST static inline TREAP_T *
514 : TREAP_(ele)( ulong i,
515 768 : TREAP_T * pool ) {
516 768 : return fd_ptr_if( !TREAP_IDX_IS_NULL( i ), pool + i, NULL );
517 768 : }
518 :
519 : FD_FN_CONST static inline TREAP_T const *
520 : TREAP_(ele_const)( ulong i,
521 768 : TREAP_T const * pool ) {
522 768 : return fd_ptr_if( !TREAP_IDX_IS_NULL( i ), pool + i, NULL );
523 768 : }
524 :
525 : FD_FN_CONST static inline ulong
526 : TREAP_(idx_fast)( TREAP_T const * e,
527 765 : TREAP_T const * pool ) {
528 765 : return (ulong)(e - pool);
529 765 : }
530 :
531 765 : FD_FN_CONST static inline TREAP_T * TREAP_(ele_fast) ( ulong i, TREAP_T * pool ) { return pool + i; }
532 765 : FD_FN_CONST static inline TREAP_T const * TREAP_(ele_fast_const)( ulong i, TREAP_T const * pool ) { return pool + i; }
533 :
534 7513548 : FD_FN_PURE static inline ulong TREAP_(ele_max)( TREAP_(t) const * treap ) { return treap->ele_max; }
535 9326772 : FD_FN_PURE static inline ulong TREAP_(ele_cnt)( TREAP_(t) const * treap ) { return treap->ele_cnt; }
536 :
537 : FD_FN_PURE static inline TREAP_T *
538 : TREAP_(ele_query)( TREAP_(t) const * treap,
539 : TREAP_QUERY_T q,
540 7663467 : TREAP_T * pool ) {
541 7663467 : ulong i = TREAP_(idx_query)( treap, q, pool );
542 7663467 : return fd_ptr_if( !TREAP_IDX_IS_NULL( i ), pool + i, NULL );
543 7663467 : }
544 :
545 : FD_FN_PURE static inline TREAP_T const *
546 : TREAP_(ele_query_const)( TREAP_(t) const * treap,
547 : TREAP_QUERY_T q,
548 7508184 : TREAP_T const * pool ) {
549 7508184 : ulong i = TREAP_(idx_query)( treap, q, pool );
550 7508184 : return fd_ptr_if( !TREAP_IDX_IS_NULL( i ), pool + i, NULL );
551 7508184 : }
552 :
553 : static inline TREAP_(t) *
554 : TREAP_(ele_insert)( TREAP_(t) * treap,
555 : TREAP_T * e,
556 19085484 : TREAP_T * pool ) {
557 19085484 : return TREAP_(idx_insert)( treap, (ulong)(e - pool), pool );
558 19085484 : }
559 :
560 : static inline TREAP_(t) *
561 : TREAP_(ele_remove)( TREAP_(t) * treap,
562 : TREAP_T * e,
563 3746388 : TREAP_T * pool ) {
564 3746388 : return TREAP_(idx_remove)( treap, (ulong)(e - pool), pool );
565 3746388 : }
566 :
567 127094352 : FD_FN_CONST static inline int TREAP_(fwd_iter_done) ( TREAP_(fwd_iter_t) i ) { return TREAP_IDX_IS_NULL( i ); }
568 122331900 : FD_FN_CONST static inline ulong TREAP_(fwd_iter_idx) ( TREAP_(fwd_iter_t) i ) { return i; }
569 124294083 : FD_FN_CONST static inline TREAP_T * TREAP_(fwd_iter_ele) ( TREAP_(fwd_iter_t) i, TREAP_T * pool ) { return pool + i; }
570 120978141 : 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; }
571 :
572 246812079 : FD_FN_CONST static inline int TREAP_(rev_iter_done) ( TREAP_(rev_iter_t) i ) { return TREAP_IDX_IS_NULL( i ); }
573 121162683 : FD_FN_CONST static inline ulong TREAP_(rev_iter_idx) ( TREAP_(rev_iter_t) i ) { return i; }
574 121174026 : FD_FN_CONST static inline TREAP_T * TREAP_(rev_iter_ele) ( TREAP_(rev_iter_t) i, TREAP_T * pool ) { return pool + i; }
575 242095545 : 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; }
576 :
577 : FD_PROTOTYPES_END
578 :
579 : #endif
580 :
581 : #if TREAP_IMPL_STYLE!=1 /* need implementations */
582 :
583 : TREAP_STATIC void
584 : TREAP_(seed)( TREAP_T * pool,
585 : ulong ele_max,
586 2661 : ulong seed ) {
587 2720490 : for( ulong ele_idx=0UL; ele_idx<ele_max; ele_idx++ ) {
588 2717829 : ulong r = fd_ulong_hash( ele_idx ^ seed ) & TREAP_IDX_NULL;
589 2717829 : pool[ ele_idx ].TREAP_PRIO = (TREAP_IDX_T)(r - (ulong)(r==TREAP_IDX_NULL));
590 2717829 : }
591 2661 : }
592 :
593 : TREAP_STATIC FD_FN_CONST ulong
594 0 : TREAP_(align)( void ) {
595 0 : return alignof(TREAP_(t));
596 0 : }
597 :
598 : TREAP_STATIC FD_FN_CONST ulong
599 24 : TREAP_(footprint)( ulong ele_max ) {
600 24 : if( FD_UNLIKELY( ele_max>TREAP_IDX_NULL ) ) return 0UL;
601 21 : return sizeof(TREAP_(t));
602 24 : }
603 :
604 : TREAP_STATIC void *
605 : TREAP_(new)( void * shmem,
606 205377 : ulong ele_max ) {
607 205377 : if( !shmem ) {
608 3 : FD_LOG_WARNING(( "NULL shmem" ));
609 3 : return NULL;
610 3 : }
611 :
612 205374 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, TREAP_(align)() ) ) ) {
613 3 : FD_LOG_WARNING(( "misaligned shmem" ));
614 3 : return NULL;
615 3 : }
616 :
617 205371 : if( FD_UNLIKELY( ele_max>TREAP_IDX_NULL ) ) {
618 3 : FD_LOG_WARNING(( "ele_max too large" ));
619 3 : return NULL;
620 3 : }
621 :
622 205368 : TREAP_(t) * treap = (TREAP_(t) *)shmem;
623 :
624 205368 : treap->ele_max = ele_max;
625 205368 : treap->ele_cnt = 0UL;
626 205368 : treap->root = (TREAP_IDX_T)TREAP_IDX_NULL;
627 :
628 : #if TREAP_OPTIMIZE_ITERATION
629 27264 : treap->first = (TREAP_IDX_T)TREAP_IDX_NULL;
630 27264 : treap->last = (TREAP_IDX_T)TREAP_IDX_NULL;
631 : #endif
632 :
633 205368 : return treap;
634 205371 : }
635 :
636 : TREAP_STATIC TREAP_(t) *
637 204330 : TREAP_(join)( void * shtreap ) {
638 204330 : if( FD_UNLIKELY( !shtreap ) ) {
639 3 : FD_LOG_WARNING(( "NULL shtreap" ));
640 3 : return NULL;
641 3 : }
642 :
643 204327 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shtreap, TREAP_(align)() ) ) ) {
644 3 : FD_LOG_WARNING(( "misaligned shtreap" ));
645 3 : return NULL;
646 3 : }
647 :
648 204324 : return (TREAP_(t) *)shtreap;
649 204327 : }
650 :
651 : TREAP_STATIC void *
652 62796 : TREAP_(leave)( TREAP_(t) * treap ) {
653 62796 : if( FD_UNLIKELY( !treap ) ) {
654 3 : FD_LOG_WARNING(( "NULL treap" ));
655 3 : return NULL;
656 3 : }
657 :
658 62793 : return (void *)treap;
659 62796 : }
660 :
661 : TREAP_STATIC void *
662 62799 : TREAP_(delete)( void * shtreap ) {
663 62799 : if( FD_UNLIKELY( !shtreap ) ) {
664 3 : FD_LOG_WARNING(( "NULL shtreap" ));
665 3 : return NULL;
666 3 : }
667 :
668 62796 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shtreap, TREAP_(align)() ) ) ) {
669 3 : FD_LOG_WARNING(( "misaligned shtreap" ));
670 3 : return NULL;
671 3 : }
672 :
673 62793 : return shtreap;
674 62796 : }
675 :
676 : TREAP_STATIC ulong
677 : TREAP_(idx_query)( TREAP_(t) const * treap,
678 : TREAP_QUERY_T q,
679 22674285 : TREAP_T const * pool ) {
680 22674285 : ulong i = (ulong)treap->root;
681 130672515 : while( FD_LIKELY( !TREAP_IDX_IS_NULL( i ) ) ) { /* Optimize for found */
682 119069568 : ulong l = (ulong)pool[ i ].TREAP_LEFT;
683 119069568 : ulong r = (ulong)pool[ i ].TREAP_RIGHT;
684 119069568 : int c = TREAP_(cmp)( q, pool + i );
685 119069568 : if( FD_UNLIKELY( !c ) ) break; /* Optimize for larger treaps */
686 107998230 : i = fd_ulong_if( c<0, l, r );
687 107998230 : }
688 22674285 : return i;
689 22674285 : }
690 :
691 : TREAP_STATIC TREAP_(t) *
692 : TREAP_(idx_insert)( TREAP_(t) * treap,
693 : ulong n,
694 30568962 : TREAP_T * pool ) {
695 :
696 : /* Find leaf where to insert n */
697 :
698 30568962 : TREAP_IDX_T * _p_child = &treap->root;
699 : #if TREAP_OPTIMIZE_ITERATION
700 20288853 : TREAP_IDX_T * _p_pnext = &treap->first; /* pointer to prev node's next idx */
701 20288853 : TREAP_IDX_T * _p_nprev = &treap->last; /* pointer to next node's prev idx */
702 : #endif
703 :
704 30568962 : ulong i = TREAP_IDX_NULL;
705 485445204 : for(;;) {
706 485445204 : ulong j = (ulong)*_p_child;
707 485445204 : if( FD_UNLIKELY( TREAP_IDX_IS_NULL( j ) ) ) break; /* Optimize for large treap */
708 454876242 : i = j;
709 454876242 : int lt = TREAP_(lt)( pool + n, pool + i );
710 454876242 : _p_child = fd_ptr_if( lt, &pool[ i ].TREAP_LEFT, &pool[ i ].TREAP_RIGHT );
711 : #if TREAP_OPTIMIZE_ITERATION
712 373360263 : _p_pnext = fd_ptr_if( lt, _p_pnext, &pool[ i ].TREAP_NEXT );
713 373360263 : _p_nprev = fd_ptr_if( lt, &pool[ i ].TREAP_PREV, _p_nprev );
714 : #endif
715 454876242 : }
716 :
717 : /* Insert n. This might momentarily break the heap property. */
718 :
719 30568962 : pool[ n ].TREAP_PARENT = (TREAP_IDX_T)i;
720 30568962 : pool[ n ].TREAP_LEFT = (TREAP_IDX_T)TREAP_IDX_NULL;
721 30568962 : pool[ n ].TREAP_RIGHT = (TREAP_IDX_T)TREAP_IDX_NULL;
722 30568962 : *_p_child = (TREAP_IDX_T)n;
723 :
724 : #if TREAP_OPTIMIZE_ITERATION
725 20288853 : pool[ n ].TREAP_PREV = *_p_nprev;
726 20288853 : pool[ n ].TREAP_NEXT = *_p_pnext;
727 : *_p_nprev = (TREAP_IDX_T)n;
728 : *_p_pnext = (TREAP_IDX_T)n;
729 : #endif
730 :
731 : /* Bubble n up until the heap property is restored. */
732 :
733 30568962 : ulong n_prio = (ulong)pool[ n ].TREAP_PRIO;
734 65914526 : while( !TREAP_IDX_IS_NULL( i ) ) {
735 60007598 : ulong i_prio = (ulong)pool[ i ].TREAP_PRIO;
736 :
737 60007598 : int heap_intact = (n_prio<i_prio) | ((n_prio==i_prio) & (!((n ^ i) & 1UL))); /* Flip coin on equal priority */
738 60007598 : if( heap_intact ) break;
739 :
740 : /* Get i's parent (if any) and parent's link to i (tree root link if no parent) */
741 :
742 35345564 : ulong p = (ulong)pool[ i ].TREAP_PARENT;
743 :
744 35345564 : TREAP_IDX_T * _t0 = fd_ptr_if( TREAP_IDX_IS_NULL( p ), &treap->root, &pool[ p ].TREAP_LEFT );
745 35345564 : /**/ _p_child = fd_ptr_if( i==(ulong)*_t0, _t0, &pool[ p ].TREAP_RIGHT );
746 :
747 : /* Get n's child (if any) that will become i's child */
748 :
749 35345564 : int n_is_left_child = (n==(ulong)pool[ i ].TREAP_LEFT);
750 35345564 : TREAP_IDX_T * _n_child = fd_ptr_if( n_is_left_child, &pool[ n ].TREAP_RIGHT, &pool[ n ].TREAP_LEFT );
751 35345564 : ulong j = (ulong)*_n_child;
752 :
753 : /* Make n child of p (or the root if no parent) */
754 :
755 35345564 : *_p_child = (TREAP_IDX_T)n;
756 35345564 : pool[ n ].TREAP_PARENT = (TREAP_IDX_T)p;
757 :
758 : /* Make i child of n */
759 :
760 35345564 : *_n_child = (TREAP_IDX_T)i;
761 35345564 : pool[ i ].TREAP_PARENT = (TREAP_IDX_T)n;
762 :
763 : /* Make j (if present) child of i */
764 :
765 35345564 : TREAP_IDX_T dummy;
766 35345564 : *fd_ptr_if( n_is_left_child, &pool[ i ].TREAP_LEFT, &pool[ i ].TREAP_RIGHT ) = (TREAP_IDX_T)j;
767 35345564 : *fd_ptr_if( TREAP_IDX_IS_NULL( j ), &dummy, &pool[ j ].TREAP_PARENT ) = (TREAP_IDX_T)i;
768 :
769 : /* Keep bubbling up */
770 :
771 35345564 : i = p;
772 35345564 : }
773 :
774 30568962 : treap->ele_cnt++;
775 30568962 : return treap;
776 30568962 : }
777 :
778 : TREAP_(t) *
779 : TREAP_(idx_remove)( TREAP_(t) * treap,
780 : ulong d,
781 28294659 : TREAP_T * pool ) {
782 :
783 : /* Make a hole at d */
784 :
785 28294659 : ulong p = (ulong)pool[ d ].TREAP_PARENT;
786 28294659 : ulong l = (ulong)pool[ d ].TREAP_LEFT;
787 28294659 : ulong r = (ulong)pool[ d ].TREAP_RIGHT;
788 :
789 28294659 : TREAP_IDX_T * _t0 = fd_ptr_if( TREAP_IDX_IS_NULL( p ), &treap->root, &pool[ p ].TREAP_LEFT );
790 28294659 : TREAP_IDX_T * _p_child = fd_ptr_if( d==(ulong)*_t0, _t0, &pool[ p ].TREAP_RIGHT );
791 :
792 : #if TREAP_OPTIMIZE_ITERATION
793 16967448 : TREAP_IDX_T prev = pool[ d ].TREAP_PREV;
794 16967448 : TREAP_IDX_T next = pool[ d ].TREAP_NEXT;
795 16967448 : TREAP_IDX_T * _pnext = fd_ptr_if( TREAP_IDX_IS_NULL( prev ), &treap->first, &pool[ prev ].TREAP_NEXT );
796 16967448 : TREAP_IDX_T * _nprev = fd_ptr_if( TREAP_IDX_IS_NULL( next ), &treap->last, &pool[ next ].TREAP_PREV );
797 : *_pnext = next;
798 : *_nprev = prev;
799 : #endif
800 :
801 33864601 : for(;;) {
802 :
803 : /* At this point, we have a hole to fill at d:
804 :
805 : p is the hole's parent (if any)
806 : l is the hole's left subtree (if any)
807 : r is the hole's right subtree (if any)
808 :
809 : p_child points to the link from p to hole (if the hole has a
810 : parent) and to the treap root link otherwise.
811 :
812 : If there is neither a left subtree nor a right subtree, we are
813 : done. If there is a left/right subtree, we fill the hole with
814 : the right/left subtree and we are done. */
815 :
816 33864601 : int is_null_left = TREAP_IDX_IS_NULL( l );
817 33864601 : int is_null_right = TREAP_IDX_IS_NULL( r );
818 33864601 : if( FD_LIKELY( is_null_left | is_null_right ) ) { /* Most nodes near bottom */
819 28294659 : TREAP_IDX_T dummy;
820 28294659 : *_p_child = (TREAP_IDX_T)fd_ulong_if( !is_null_left, l, r );
821 28294659 : *( fd_ptr_if( !is_null_left, &pool[ l ].TREAP_PARENT,
822 28294659 : fd_ptr_if( !is_null_right, &pool[ r ].TREAP_PARENT, &dummy ) ) ) = (TREAP_IDX_T)p;
823 28294659 : break;
824 28294659 : }
825 :
826 : /* The hole has two subtrees. We bubble the hole down one, fill the
827 : hole with the root of the subtree that will preserve the heap
828 : priority up to the hole (flipping a coin on ties). Note we don't
829 : need to update any links to/from d as we will be getting rid of
830 : all links / from d. */
831 :
832 5569942 : ulong l_prio = (ulong)pool[ l ].TREAP_PRIO;
833 5569942 : ulong r_prio = (ulong)pool[ r ].TREAP_PRIO;
834 :
835 5569942 : int promote_left = (l_prio>r_prio) | ((l_prio==r_prio) & (!((p ^ d) & 1UL)));
836 :
837 5569942 : ulong c = fd_ulong_if( promote_left, l, r );
838 :
839 5569942 : *_p_child = (TREAP_IDX_T)c;
840 5569942 : pool[ c ].TREAP_PARENT = (TREAP_IDX_T)p;
841 :
842 5569942 : _p_child = fd_ptr_if ( promote_left, &pool[ l ].TREAP_RIGHT, &pool[ r ].TREAP_LEFT );
843 5569942 : p = c;
844 5569942 : l = fd_ulong_if( promote_left, pool[ l ].TREAP_RIGHT, l );
845 5569942 : r = fd_ulong_if( promote_left, r, pool[ r ].TREAP_LEFT );
846 :
847 5569942 : }
848 :
849 28294659 : treap->ele_cnt--;
850 28294659 : return treap;
851 28294659 : }
852 :
853 : static inline void
854 : TREAP_(private_split)( TREAP_IDX_T idx_node, /* Tree to split */
855 : TREAP_T * key, /* Element whose key is not in the treap rooted at idx_node */
856 : TREAP_IDX_T * _idx_left, /* Where to store the left tree root */
857 : TREAP_IDX_T * _idx_right, /* Where to store the right tree root */
858 : TREAP_IDX_T * _idx_last_left, /* Where to store the last (in BST order) element of the new left tree */
859 : TREAP_IDX_T * _idx_first_right, /* Where to store the first(in BST order) element in the new right tree */
860 3176244 : TREAP_T * pool ) { /* Underlying pool */
861 :
862 3176244 : TREAP_IDX_T idx_parent_left = TREAP_IDX_NULL;
863 3176244 : TREAP_IDX_T idx_parent_right = TREAP_IDX_NULL;
864 3176244 : *_idx_last_left = TREAP_IDX_NULL;
865 3176244 : *_idx_first_right = TREAP_IDX_NULL;
866 :
867 6521286 : while( !TREAP_IDX_IS_NULL( idx_node ) ) {
868 :
869 : /* At this point we have a non-empty subtree to split whose root is
870 : node and we should attach the left and right split trees at
871 : idx_parent_left / *_idx_left and idx_parent_right / *_idx_right.
872 : (On the first attach, idx_parent_left/right will be idx_null and
873 : *_idx_left / *_idx_right are locations where to store the output
874 : split treaps.) */
875 :
876 3345042 : if( TREAP_LT( &pool[ idx_node ], key ) ) {
877 :
878 : /* node is left of key which, by the BST property, means all
879 : elements in node's left subtree are also left of key. We don't
880 : know if node's right subtree contains any elements left of key.
881 : If it does, these elements should be attached to node's right
882 : subtree to preserve the BST property of the left split.
883 :
884 : As such, we attach node and node's left subtree to the
885 : left split, update the attach point for the left split to
886 : node's right subtree and then recurse on the node's right
887 : subtree.
888 :
889 : Note that this operation does not do any reordering of
890 : priorities (e.g. if element B was a descendant of element A
891 : before the split and both B and A belong on the left split, B
892 : will still be a descendant of A). */
893 :
894 : /* Attach node and node's left subtree to the left split */
895 3210357 : pool[ idx_node ].TREAP_PARENT = idx_parent_left;
896 3210357 : *_idx_left = idx_node;
897 :
898 : /* The next left split attach is node's right child */
899 3210357 : idx_parent_left = idx_node;
900 3210357 : _idx_left = &pool[ idx_node ].TREAP_RIGHT;
901 :
902 : /* If everything in the right subtree is to the right of the key,
903 : this is the last node on the left. */
904 3210357 : *_idx_last_left = idx_node;
905 :
906 : /* Recurse on the right subtree */
907 3210357 : idx_node = pool[ idx_node ].TREAP_RIGHT;
908 :
909 3210357 : } else { /* Mirror image of the above */
910 :
911 134685 : pool[ idx_node ].TREAP_PARENT = idx_parent_right;
912 134685 : *_idx_right = idx_node;
913 :
914 134685 : idx_parent_right = idx_node;
915 134685 : _idx_right = &pool[ idx_node ].TREAP_LEFT;
916 :
917 134685 : *_idx_first_right = idx_node;
918 :
919 134685 : idx_node = pool[ idx_node ].TREAP_LEFT;
920 :
921 134685 : }
922 3345042 : }
923 :
924 : /* At this point, we have an empty tree to split */
925 :
926 3176244 : *_idx_left = TREAP_IDX_NULL;
927 3176244 : *_idx_right = TREAP_IDX_NULL;
928 3176244 : }
929 :
930 : #if !TREAP_OPTIMIZE_ITERATION
931 : static inline void
932 : TREAP_(private_join)( TREAP_IDX_T idx_left, /* Root of the left treap */
933 : TREAP_IDX_T idx_right, /* Root of the right treap, keys in left treap < keys in right treap */
934 : TREAP_IDX_T * _idx_join, /* Where to store root of joined treaps */
935 0 : TREAP_T * pool ) { /* Underlying pool */
936 0 :
937 0 : TREAP_IDX_T idx_join_parent = TREAP_IDX_NULL;
938 0 :
939 0 : for(;;) {
940 0 :
941 0 : /* TODO: consolidate these cases into a single branch. */
942 0 :
943 0 : if( TREAP_IDX_IS_NULL( idx_left ) ) { /* Left treap empty */
944 0 : /* join is the right treap (or empty if both left and right empty) */
945 0 : if( !TREAP_IDX_IS_NULL( idx_right ) ) pool[ idx_right ].TREAP_PARENT = idx_join_parent;
946 0 : *_idx_join = idx_right;
947 0 : break;
948 0 : }
949 0 :
950 0 : if( TREAP_IDX_IS_NULL( idx_right ) ) { /* Right treap empty */
951 0 : /* join is the left treap */
952 0 : pool[ idx_left ].TREAP_PARENT = idx_join_parent;
953 0 : *_idx_join = idx_left;
954 0 : break;
955 0 : }
956 0 :
957 0 : /* At this point, we have two non empty treaps to join and elements
958 0 : in the left treap have keys before elements in the right treap. */
959 0 :
960 0 : ulong prio_left = (ulong)pool[ idx_left ].TREAP_PRIO;
961 0 : ulong prio_right = (ulong)pool[ idx_right ].TREAP_PRIO;
962 0 : if( (prio_left>prio_right) | ((prio_left==prio_right) & (int)(idx_left^idx_right)) ) {
963 0 :
964 0 : /* At this point, the left treap root has higher priority than the
965 0 : right treap root. So we attach the left treap root and left
966 0 : treap left subtree to the join to preserve the heap property.
967 0 : We know that the left treap right subtree is to the right of
968 0 : these and that the right treap is to the right of that. So our
969 0 : next join attachment point should be at the left treap right
970 0 : subtree and we should recurse on the left treap right subtree
971 0 : and the right treap. */
972 0 :
973 0 : /* Attach left's root and left's left subtree to the join */
974 0 : pool[ idx_left ].TREAP_PARENT = idx_join_parent;
975 0 : *_idx_join = idx_left;
976 0 :
977 0 : /* The next join attach should be left's right subtree */
978 0 : idx_join_parent = idx_left;
979 0 : _idx_join = &pool[ idx_left ].TREAP_LEFT;
980 0 :
981 0 : /* Recurse on left's right subtree and right treap */
982 0 : idx_left = pool[ idx_left ].TREAP_RIGHT;
983 0 :
984 0 : } else { /* Mirror image of the above */
985 0 :
986 0 : pool[ idx_right ].TREAP_PARENT = idx_join_parent;
987 0 : *_idx_join = idx_right;
988 0 :
989 0 : idx_join_parent = idx_right;
990 0 : _idx_join = &pool[ idx_right ].TREAP_RIGHT;
991 0 :
992 0 : idx_right = pool[ idx_right ].TREAP_LEFT;
993 0 :
994 0 : }
995 0 : }
996 0 : }
997 : #endif
998 :
999 : TREAP_(t) *
1000 : TREAP_(merge)( TREAP_(t) * treap_a,
1001 : TREAP_(t) * treap_b,
1002 26130 : TREAP_T * pool ) {
1003 :
1004 26130 : TREAP_IDX_T idx_a = treap_a->root;
1005 26130 : TREAP_IDX_T idx_b = treap_b->root;
1006 26130 : TREAP_IDX_T new_root = TREAP_IDX_NULL;
1007 26130 : TREAP_IDX_T * _idx_merge = &new_root;
1008 :
1009 : # if TREAP_OPTIMIZE_ITERATION
1010 : /* Invariant: idx_{a,b}_{first,last} is the index of the first/last
1011 : node in key order in the subtree rooted at idx_a/idx_b. */
1012 13065 : TREAP_IDX_T idx_a_first = treap_a->first;
1013 13065 : TREAP_IDX_T idx_a_last = treap_a->last;
1014 13065 : TREAP_IDX_T idx_b_first = treap_b->first;
1015 13065 : TREAP_IDX_T idx_b_last = treap_b->last;
1016 :
1017 : /* merged_{prev,next} are the nodes immediately before/after the
1018 : merged subtree. If these are IDX_NULL, then treap_a->first/last
1019 : should be updated instead. */
1020 13065 : TREAP_IDX_T merged_prev = TREAP_IDX_NULL;
1021 13065 : TREAP_IDX_T merged_next = TREAP_IDX_NULL;
1022 : # endif
1023 :
1024 26130 : # define STACK_MAX (128UL)
1025 :
1026 26130 : struct { TREAP_IDX_T idx_merge_parent; TREAP_IDX_T * _idx_merge; TREAP_IDX_T idx_a; TREAP_IDX_T idx_b;
1027 : # if TREAP_OPTIMIZE_ITERATION
1028 : TREAP_IDX_T idx_a_first, idx_a_last, idx_b_first, idx_b_last;
1029 : TREAP_IDX_T merged_prev, merged_next;
1030 : # endif
1031 26130 : } stack[ STACK_MAX ];
1032 26130 : ulong stack_top = 0UL;
1033 :
1034 3202374 : # define STACK_IS_EMPTY (!stack_top)
1035 26130 : # define STACK_IS_FULL (stack_top>=STACK_MAX)
1036 :
1037 : #if TREAP_OPTIMIZE_ITERATION
1038 1588221 : # define STACK_PUSH( imp, im, ia, ib, iaf, ial, ibf, ibl, mp, mn ) do { \
1039 1588221 : stack[ stack_top ].idx_merge_parent = (imp); \
1040 1588221 : stack[ stack_top ]._idx_merge = (im); \
1041 1588221 : stack[ stack_top ].idx_a = (ia); \
1042 1588221 : stack[ stack_top ].idx_b = (ib); \
1043 1588221 : stack[ stack_top ].idx_a_first = (iaf); \
1044 1588221 : stack[ stack_top ].idx_a_last = (ial); \
1045 1588221 : stack[ stack_top ].idx_b_first = (ibf); \
1046 1588221 : stack[ stack_top ].idx_b_last = (ibl); \
1047 1588221 : stack[ stack_top ].merged_prev = (mp); \
1048 1588221 : stack[ stack_top ].merged_next = (mn); \
1049 1588221 : stack_top++; \
1050 1588221 : } while(0)
1051 1588221 : # define STACK_POP( imp, im, ia, ib, iaf, ial, ibf, ibl, mp, mn ) do { \
1052 1588221 : stack_top--; \
1053 1588221 : (imp) = stack[ stack_top ].idx_merge_parent; \
1054 1588221 : (im) = stack[ stack_top ]._idx_merge; \
1055 1588221 : (ia) = stack[ stack_top ].idx_a; \
1056 1588221 : (ib) = stack[ stack_top ].idx_b; \
1057 1588221 : (iaf) = stack[ stack_top ].idx_a_first; \
1058 1588221 : (ial) = stack[ stack_top ].idx_a_last; \
1059 1588221 : (ibf) = stack[ stack_top ].idx_b_first; \
1060 1588221 : (ibl) = stack[ stack_top ].idx_b_last; \
1061 1588221 : (mp) = stack[ stack_top ].merged_prev; \
1062 1588221 : (mn) = stack[ stack_top ].merged_next; \
1063 1588221 : } while(0)
1064 : #else
1065 1588023 : # define STACK_PUSH( imp, im, ia, ib ) do { \
1066 1588023 : stack[ stack_top ].idx_merge_parent = (imp); \
1067 1588023 : stack[ stack_top ]._idx_merge = (im); \
1068 1588023 : stack[ stack_top ].idx_a = (ia); \
1069 1588023 : stack[ stack_top ].idx_b = (ib); \
1070 1588023 : stack_top++; \
1071 1588023 : } while(0)
1072 1588023 : # define STACK_POP( imp, im, ia, ib ) do { \
1073 1588023 : stack_top--; \
1074 1588023 : (imp) = stack[ stack_top ].idx_merge_parent; \
1075 1588023 : (im) = stack[ stack_top ]._idx_merge; \
1076 1588023 : (ia) = stack[ stack_top ].idx_a; \
1077 1588023 : (ib) = stack[ stack_top ].idx_b; \
1078 1588023 : } while(0)
1079 : #endif
1080 :
1081 26130 : TREAP_IDX_T idx_merge_parent = TREAP_IDX_NULL;
1082 :
1083 6378618 : for(;;) {
1084 :
1085 : /* At this point, we are to merge the treaps rooted at idx_a and
1086 : idx_b. The result should be attached to the output treap at node
1087 : idx_merge_parent via the link *idx_merge. (On the first
1088 : iteration, the idx_merge_parent will be idx_null and *_idx_merge
1089 : will be where to store the root of the output treap.) */
1090 :
1091 6378618 : int idx_a_is_null = TREAP_IDX_IS_NULL( idx_a );
1092 6378618 : int idx_b_is_null = TREAP_IDX_IS_NULL( idx_b );
1093 6378618 : if( idx_a_is_null | idx_b_is_null ) {
1094 :
1095 : /* At this point, at least one of the treaps to merge is empty.
1096 : Attach the non-empty treap (if any) accordingly. If both are
1097 : empty, we attach NULL and there is no parent field to update. */
1098 :
1099 3178374 : TREAP_IDX_T idx_tmp;
1100 3178374 : *fd_ptr_if( idx_b_is_null, fd_ptr_if( idx_a_is_null, &idx_tmp,
1101 3178374 : &pool[ idx_a ].TREAP_PARENT ),
1102 3178374 : &pool[ idx_b ].TREAP_PARENT ) = idx_merge_parent;
1103 3178374 : *_idx_merge = (TREAP_IDX_T)fd_ulong_if( idx_b_is_null, (ulong)idx_a, (ulong)idx_b );
1104 :
1105 : # if TREAP_OPTIMIZE_ITERATION
1106 : /* Update the four pointers to insert the range
1107 : idx_a_first and idx_a_last (or b if a is the empty subtree)
1108 : between merged_prev and merged_next. If both are the empty
1109 : subtree, then merged_prev connects directly to merged_next. */
1110 1589286 : *fd_ptr_if( TREAP_IDX_IS_NULL( merged_prev ), &treap_a->first, &pool[ merged_prev ].TREAP_NEXT ) =
1111 : (TREAP_IDX_T)fd_ulong_if( idx_b_is_null, fd_ulong_if( idx_a_is_null, (ulong)merged_next,
1112 : (ulong)idx_a_first ),
1113 : (ulong)idx_b_first );
1114 1589286 : *fd_ptr_if( TREAP_IDX_IS_NULL( merged_next ), &treap_a->last , &pool[ merged_next ].TREAP_PREV ) =
1115 : (TREAP_IDX_T)fd_ulong_if( idx_b_is_null, fd_ulong_if( idx_a_is_null, (ulong)merged_prev,
1116 : (ulong)idx_a_last ),
1117 : (ulong)idx_b_last );
1118 1589286 : *fd_ptr_if( idx_b_is_null, fd_ptr_if( idx_a_is_null, &idx_tmp,
1119 : &pool[ idx_a_first ].TREAP_PREV ),
1120 : &pool[ idx_b_first ].TREAP_PREV ) = merged_prev;
1121 1589286 : *fd_ptr_if( idx_b_is_null, fd_ptr_if( idx_a_is_null, &idx_tmp,
1122 : &pool[ idx_a_last ].TREAP_NEXT ),
1123 : &pool[ idx_b_last ].TREAP_NEXT ) = merged_next;
1124 :
1125 : # endif
1126 : /* Pop the stack to get the next merge to do. If the stack is
1127 : empty, we are done. */
1128 :
1129 3178374 : if( STACK_IS_EMPTY ) break;
1130 : # if TREAP_OPTIMIZE_ITERATION
1131 1576221 : 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 );
1132 : # else
1133 1576023 : STACK_POP( idx_merge_parent, _idx_merge, idx_a, idx_b );
1134 1576023 : # endif
1135 1576023 : continue;
1136 3178374 : }
1137 :
1138 : /* If the stack is full, it appears we have exceedingly poorly
1139 : balanced treaps to merge. To mitigate stack overflow risk from
1140 : the recursion, we fall back on a marginally less efficient brute
1141 : force non-recursive algorithm for the merge. FIXME: consider
1142 : doing this post swap for statistical reasons (i.e. the treap with
1143 : the higher root priority is likely to be the larger treap and
1144 : such might have some performance implications for the below
1145 : loop). */
1146 :
1147 3200244 : if( FD_UNLIKELY( STACK_IS_FULL ) ) {
1148 :
1149 : /* Remove elements from B one-by-one and insert them into A.
1150 : O(B lg B) for the removes, O(B lg(A + B)) for the inserts. */
1151 :
1152 : # if TREAP_OPTIMIZE_ITERATION
1153 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 };
1154 12000 : TREAP_(t) temp_treap_b = { .ele_max = treap_b->ele_max, .ele_cnt = 0UL, .root = idx_b, .first=idx_b_first, .last=idx_b_last };
1155 : # else
1156 12000 : TREAP_(t) temp_treap_a = { .ele_max = treap_a->ele_max, .ele_cnt = 0UL, .root = idx_a };
1157 12000 : TREAP_(t) temp_treap_b = { .ele_max = treap_b->ele_max, .ele_cnt = 0UL, .root = idx_b };
1158 : # endif
1159 24000 : pool[ idx_a ].TREAP_PARENT = TREAP_IDX_NULL;
1160 24000 : pool[ idx_b ].TREAP_PARENT = TREAP_IDX_NULL;
1161 1132668 : do {
1162 1132668 : TREAP_IDX_T idx_tmp = temp_treap_b.root;
1163 1132668 : TREAP_(idx_remove)( &temp_treap_b, idx_tmp, pool );
1164 1132668 : TREAP_(idx_insert)( &temp_treap_a, idx_tmp, pool );
1165 1132668 : } while( !TREAP_IDX_IS_NULL( temp_treap_b.root ) );
1166 :
1167 24000 : idx_b = TREAP_IDX_NULL;
1168 24000 : idx_a = temp_treap_a.root;
1169 :
1170 : /* Attach the merged treap to the output */
1171 :
1172 24000 : pool[ idx_a ].TREAP_PARENT = idx_merge_parent;
1173 24000 : *_idx_merge = idx_a;
1174 :
1175 : # if TREAP_OPTIMIZE_ITERATION
1176 12000 : *fd_ptr_if( TREAP_IDX_IS_NULL( merged_prev ), &treap_a->first, &pool[ merged_prev ].TREAP_NEXT ) = temp_treap_a.first;
1177 12000 : *fd_ptr_if( TREAP_IDX_IS_NULL( merged_next ), &treap_a->last, &pool[ merged_next ].TREAP_PREV ) = temp_treap_a.last;
1178 12000 : pool[ temp_treap_a.first ].TREAP_PREV = merged_prev;
1179 12000 : pool[ temp_treap_a.last ].TREAP_NEXT = merged_next;
1180 : # endif
1181 :
1182 : /* Pop the stack to get the next merge to do. If the stack is
1183 : empty, we are done. */
1184 :
1185 24000 : if( STACK_IS_EMPTY ) break;
1186 : # if TREAP_OPTIMIZE_ITERATION
1187 12000 : STACK_POP( idx_merge_parent, _idx_merge, idx_a, idx_b,
1188 12000 : idx_a_first, idx_a_last, idx_b_first, idx_b_last, merged_prev, merged_next );
1189 : # else
1190 12000 : STACK_POP( idx_merge_parent, _idx_merge, idx_a, idx_b );
1191 12000 : # endif
1192 12000 : continue;
1193 24000 : }
1194 :
1195 : /* At this point, we have two non-empty treaps A and B to merge and
1196 : we have stack space so we can use a fast recursive algorithm. If
1197 : A's root priority is below B's root priority, swap A and B. */
1198 :
1199 3176244 : TREAP_IDX_T prio_a = pool[ idx_a ].TREAP_PRIO;
1200 3176244 : TREAP_IDX_T prio_b = pool[ idx_b ].TREAP_PRIO;
1201 3176244 : int swap = (prio_a<prio_b) | ((prio_a==prio_b) & (int)(idx_a ^ idx_b));
1202 3176244 : fd_swap_if( swap, idx_a, idx_b );
1203 : # if TREAP_OPTIMIZE_ITERATION
1204 1588221 : fd_swap_if( swap, idx_a_first, idx_b_first );
1205 1588221 : fd_swap_if( swap, idx_a_last, idx_b_last );
1206 : # endif
1207 :
1208 : /* At this point, we have two non-empty treaps to merge and A's root
1209 : priority is higher than B's root priority. So, we know the root
1210 : of the merged treaps is A's root and can attach it to the output
1211 : treap accordingly. */
1212 :
1213 3176244 : pool[ idx_a ].TREAP_PARENT = idx_merge_parent;
1214 3176244 : *_idx_merge = idx_a;
1215 :
1216 : /* Get A's left and right subtrees */
1217 :
1218 3176244 : TREAP_IDX_T idx_a_left = pool[ idx_a ].TREAP_LEFT;
1219 3176244 : TREAP_IDX_T idx_a_right = pool[ idx_a ].TREAP_RIGHT;
1220 :
1221 : /* Split B by A's root key */
1222 :
1223 3176244 : TREAP_IDX_T idx_b_left;
1224 3176244 : TREAP_IDX_T idx_b_right;
1225 3176244 : TREAP_IDX_T idx_b_left_last;
1226 3176244 : TREAP_IDX_T idx_b_right_first;
1227 3176244 : TREAP_(private_split)( idx_b, &pool[ idx_a ], &idx_b_left, &idx_b_right, &idx_b_left_last, &idx_b_right_first, pool );
1228 :
1229 : # if TREAP_OPTIMIZE_ITERATION
1230 : /* Split the iteration order links in B as well */
1231 1588221 : TREAP_IDX_T dummy;
1232 1588221 : *fd_ptr_if( TREAP_IDX_IS_NULL( idx_b_left_last ), &dummy, &pool[ idx_b_left_last ].TREAP_NEXT ) = TREAP_IDX_NULL;
1233 1588221 : *fd_ptr_if( TREAP_IDX_IS_NULL( idx_b_right_first ), &dummy, &pool[ idx_b_right_first ].TREAP_PREV ) = TREAP_IDX_NULL;
1234 :
1235 : /* The first node in B's left subtree is the first node in B unless
1236 : it is empty. Similarly for B's right subtree. */
1237 1588221 : 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 );
1238 1588221 : 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 );
1239 : # endif
1240 :
1241 : /* At this point, A's left subtree and B's left split are all keys
1242 : to the left of A's root and A's right subtree. Similarly, B's
1243 : right split are all keys to the right of A's root and A's left
1244 : subtree. We can't do a fast join on A's left/right subtree and B's
1245 : left/right split though as theses are not guaranteed to already
1246 : have their keys distributed as required by join. We instead
1247 : recursively merge the left side and right side. We do the left
1248 : side first and the right side later (making this a cache oblivious
1249 : algorithm too). */
1250 :
1251 : # if TREAP_OPTIMIZE_ITERATION
1252 1588221 : STACK_PUSH( idx_a, &pool[ idx_a ].TREAP_RIGHT, idx_a_right, idx_b_right,
1253 : pool[ idx_a ].TREAP_NEXT, idx_a_last, idx_b_right_first, idx_b_right_last, idx_a, merged_next );
1254 : # else
1255 1588023 : STACK_PUSH( idx_a, &pool[ idx_a ].TREAP_RIGHT, idx_a_right, idx_b_right );
1256 : # endif
1257 :
1258 3176244 : idx_merge_parent = idx_a;
1259 3176244 : _idx_merge = &pool[ idx_a ].TREAP_LEFT;
1260 : # if TREAP_OPTIMIZE_ITERATION
1261 1588221 : idx_a_last = pool[ idx_a ].TREAP_PREV;
1262 : idx_b_first = idx_b_left_first;
1263 : idx_b_last = idx_b_left_last;
1264 : merged_next = idx_a;
1265 : # endif
1266 3176244 : idx_a = idx_a_left;
1267 3176244 : idx_b = idx_b_left;
1268 3176244 : }
1269 :
1270 26130 : treap_a->root = new_root;
1271 26130 : treap_b->root = TREAP_IDX_NULL;
1272 26130 : treap_a->ele_cnt += treap_b->ele_cnt;
1273 26130 : treap_b->ele_cnt = 0UL;
1274 : # if TREAP_OPTIMIZE_ITERATION
1275 13065 : treap_b->first = TREAP_IDX_NULL;
1276 13065 : treap_b->last = TREAP_IDX_NULL;
1277 : # endif
1278 :
1279 26130 : return treap_a;
1280 :
1281 26130 : # undef STACK_POP
1282 26130 : # undef STACK_PUSH
1283 26130 : # undef STACK_IS_FULL
1284 26130 : # undef STACK_IS_EMPTY
1285 26130 : # undef STACK_MAX
1286 26130 : }
1287 :
1288 : TREAP_STATIC TREAP_(fwd_iter_t)
1289 : TREAP_(fwd_iter_init)( TREAP_(t) const * treap,
1290 6128505 : TREAP_T const * pool ) {
1291 : #if TREAP_OPTIMIZE_ITERATION
1292 : (void)pool;
1293 : return treap->first;
1294 : #else
1295 3787455 : ulong i = TREAP_IDX_NULL;
1296 : ulong j = (ulong)treap->root;
1297 18311556 : while( FD_LIKELY( !TREAP_IDX_IS_NULL( j ) ) ) { i = j; j = (ulong)pool[ j ].TREAP_LEFT; }
1298 : return i;
1299 : #endif
1300 6128505 : }
1301 :
1302 : TREAP_STATIC TREAP_(rev_iter_t)
1303 : TREAP_(rev_iter_init)( TREAP_(t) const * treap,
1304 4536228 : TREAP_T const * pool ) {
1305 : #if TREAP_OPTIMIZE_ITERATION
1306 : (void)pool;
1307 : return treap->last;
1308 : #else
1309 3776349 : ulong i = TREAP_IDX_NULL;
1310 : ulong j = (ulong)treap->root;
1311 17945457 : while( FD_LIKELY( !TREAP_IDX_IS_NULL( j ) ) ) { i = j; j = (ulong)pool[ j ].TREAP_RIGHT; }
1312 : return i;
1313 : #endif
1314 4536228 : }
1315 :
1316 : TREAP_STATIC TREAP_(fwd_iter_t)
1317 : TREAP_(fwd_iter_next)( TREAP_(fwd_iter_t) i,
1318 123307053 : TREAP_T const * pool ) {
1319 : #if TREAP_OPTIMIZE_ITERATION
1320 2172 : return pool[ i ].TREAP_NEXT;
1321 : #else
1322 123304881 : ulong r = (ulong)pool[ i ].TREAP_RIGHT;
1323 :
1324 123304881 : if( TREAP_IDX_IS_NULL( r ) ) {
1325 62789109 : ulong p = (ulong)pool[ i ].TREAP_PARENT;
1326 123304821 : while( !TREAP_IDX_IS_NULL( p ) ) {
1327 119577366 : if( i==(ulong)pool[ p ].TREAP_LEFT ) break;
1328 60515712 : i = p;
1329 60515712 : p = (ulong)pool[ p ].TREAP_PARENT;
1330 60515712 : }
1331 62789109 : return p;
1332 62789109 : }
1333 :
1334 60515772 : i = r;
1335 108780810 : for(;;) {
1336 108780810 : ulong l = (ulong)pool[ i ].TREAP_LEFT;
1337 108780810 : if( TREAP_IDX_IS_NULL( l ) ) break;
1338 48265038 : i = l;
1339 48265038 : }
1340 :
1341 60515772 : return i;
1342 : #endif
1343 123307053 : }
1344 :
1345 : TREAP_STATIC TREAP_(rev_iter_t)
1346 : TREAP_(rev_iter_next)( TREAP_(rev_iter_t) i,
1347 242110803 : TREAP_T const * pool ) {
1348 : #if TREAP_OPTIMIZE_ITERATION
1349 120937077 : return pool[ i ].TREAP_PREV;
1350 : #else
1351 121173726 : ulong l = (ulong)pool[ i ].TREAP_LEFT;
1352 :
1353 121173726 : if( TREAP_IDX_IS_NULL( l ) ) {
1354 62467806 : ulong p = (ulong)pool[ i ].TREAP_PARENT;
1355 121172973 : while( !TREAP_IDX_IS_NULL( p ) ) {
1356 117462792 : if( i==(ulong)pool[ p ].TREAP_RIGHT ) break;
1357 58705167 : i = p;
1358 58705167 : p = (ulong)pool[ p ].TREAP_PARENT;
1359 58705167 : }
1360 62467806 : return p;
1361 62467806 : }
1362 :
1363 58705920 : i = l;
1364 107005542 : for(;;) {
1365 107005542 : ulong r = (ulong)pool[ i ].TREAP_RIGHT;
1366 107005542 : if( TREAP_IDX_IS_NULL( r ) ) break;
1367 48299622 : i = r;
1368 48299622 : }
1369 :
1370 58705920 : return i;
1371 : #endif
1372 242110803 : }
1373 :
1374 : TREAP_STATIC int
1375 : TREAP_(verify)( TREAP_(t) const * treap,
1376 30060567 : TREAP_T const * pool ) {
1377 :
1378 7849850331 : # define TREAP_TEST( c ) do { if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: " #c )); return -1; } } while(0)
1379 :
1380 30060567 : TREAP_TEST( treap ); /* Validate local join */
1381 :
1382 30060567 : ulong ele_max = treap->ele_max; TREAP_TEST( ele_max<=TREAP_IDX_NULL ); /* Validate ele_max */
1383 30060567 : ulong ele_cnt = treap->ele_cnt; TREAP_TEST( ele_cnt<=ele_max ); /* Validate ele_cnt */
1384 30060567 : if( ele_max ) TREAP_TEST( pool ); /* Validate ele storage */
1385 :
1386 : /* Find leftmost */
1387 :
1388 30060567 : ulong i = TREAP_IDX_NULL;
1389 30060567 : ulong l = (ulong)treap->root;
1390 :
1391 30060567 : ulong loop_cnt = 0UL;
1392 152399880 : while( FD_LIKELY( !TREAP_IDX_IS_NULL( l ) ) ) {
1393 122339313 : TREAP_TEST( loop_cnt<ele_cnt ); /* Make sure no cycles */
1394 122339313 : TREAP_TEST( l <ele_max ); /* Make sure valid index */
1395 122339313 : i = l;
1396 122339313 : l = (ulong)pool[ l ].TREAP_LEFT;
1397 122339313 : loop_cnt++;
1398 122339313 : }
1399 : #if TREAP_OPTIMIZE_ITERATION
1400 43347 : TREAP_TEST( treap->first==i );
1401 43347 : #endif
1402 :
1403 : /* In-order traverse the treap starting from the leftmost */
1404 :
1405 30060567 : ulong cnt = 0UL; /* Number of elements we've visited so far */
1406 1009304238 : while( FD_LIKELY( !TREAP_IDX_IS_NULL( i ) ) ) {
1407 979243671 : TREAP_TEST( cnt<ele_cnt ); /* Make sure no cycles */
1408 :
1409 : /* At this point, we are visiting element i. We've already visited
1410 : all elements less than i and l is the last element we visited (or
1411 : NULL if i is the first element we are visiting. */
1412 :
1413 979243671 : if( FD_LIKELY( !TREAP_IDX_IS_NULL( l ) ) ) TREAP_TEST( TREAP_(lt)( pool + l, pool + i ) ); /* Make sure ordering valid */
1414 : #if TREAP_OPTIMIZE_ITERATION
1415 : /* Check the l <-> i link */
1416 6839202 : if( FD_LIKELY( !TREAP_IDX_IS_NULL( l ) ) ) TREAP_TEST( pool[ l ].TREAP_NEXT==i );
1417 6839202 : if( FD_LIKELY( !TREAP_IDX_IS_NULL( i ) ) ) TREAP_TEST( pool[ i ].TREAP_PREV==l );
1418 6839202 : #endif
1419 :
1420 :
1421 979243671 : ulong p = (ulong)pool[ i ].TREAP_PARENT;
1422 979243671 : if( FD_LIKELY( !TREAP_IDX_IS_NULL( p ) ) ) {
1423 949618944 : TREAP_TEST( p < ele_max ); /* Make sure valid index */
1424 949618944 : TREAP_TEST( (ulong)pool[ p ].TREAP_PRIO >= (ulong)pool[ i ].TREAP_PRIO ); /* Make sure heap property valid */
1425 949618944 : }
1426 :
1427 : /* Done visiting i, advance to i's successor */
1428 :
1429 979243671 : cnt++;
1430 :
1431 979243671 : l = i;
1432 :
1433 979243671 : ulong r = (ulong)pool[ i ].TREAP_RIGHT;
1434 979243671 : if( TREAP_IDX_IS_NULL( r ) ) {
1435 :
1436 : /* i has no right subtree. Look for first ancestor of i that we
1437 : haven't visited (this will be the first ancestor for which i is
1438 : in the ancestor's left subtree). If there is no such ancestor,
1439 : we are at the rightmost and we are done. */
1440 :
1441 508904307 : loop_cnt = 0UL;
1442 979243671 : while( !TREAP_IDX_IS_NULL( p ) ) {
1443 949618944 : TREAP_TEST( loop_cnt<ele_cnt ); /* Make sure no cycles */
1444 949618944 : TREAP_TEST( p <ele_max ); /* Make sure valid index */
1445 949618944 : if( i==(ulong)pool[ p ].TREAP_LEFT ) break;
1446 470339364 : i = p;
1447 470339364 : p = (ulong)pool[ p ].TREAP_PARENT;
1448 470339364 : loop_cnt++;
1449 470339364 : }
1450 :
1451 508904307 : i = p;
1452 :
1453 508904307 : } else {
1454 :
1455 : /* i has a right subtree. Find the leftmost in this subtree. */
1456 :
1457 470339364 : i = r;
1458 :
1459 470339364 : loop_cnt = 0UL;
1460 856904358 : for(;;) {
1461 856904358 : TREAP_TEST( loop_cnt<ele_cnt ); /* Make sure no cycles */
1462 856904358 : TREAP_TEST( i <ele_max ); /* Make sure valid index */
1463 856904358 : ulong ll = (ulong)pool[ i ].TREAP_LEFT;
1464 856904358 : if( TREAP_IDX_IS_NULL( ll ) ) break;
1465 386564994 : i = ll;
1466 386564994 : loop_cnt++;
1467 386564994 : }
1468 :
1469 470339364 : }
1470 :
1471 979243671 : }
1472 :
1473 : #if TREAP_OPTIMIZE_ITERATION
1474 43347 : TREAP_TEST( treap->last==l );
1475 43347 : #endif
1476 :
1477 30060567 : TREAP_TEST( cnt==ele_cnt ); /* Make sure we visited correct number of elements */
1478 :
1479 30060567 : # undef TREAP_TEST
1480 :
1481 30060567 : return 0;
1482 30060567 : }
1483 :
1484 : #endif
1485 :
1486 : #undef TREAP_IDX_IS_NULL
1487 : #undef TREAP_IDX_NULL
1488 : #undef TREAP_STATIC
1489 :
1490 : #undef TREAP_IMPL_STYLE
1491 : #undef TREAP_NEXT
1492 : #undef TREAP_PREV
1493 : #undef TREAP_OPTIMIZE_ITERATION
1494 : #undef TREAP_PRIO
1495 : #undef TREAP_RIGHT
1496 : #undef TREAP_LEFT
1497 : #undef TREAP_PARENT
1498 : #undef TREAP_IDX_T
1499 : #undef TREAP_LT
1500 : #undef TREAP_CMP
1501 : #undef TREAP_QUERY_T
1502 : #undef TREAP_T
1503 : #undef TREAP_NAME
1504 :
|