The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
minmax_heap.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Functions for a minmax heap
18 *
19 * @file src/lib/util/minmax_heap.c
20 *
21 * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
22 */
23RCSID("$Id: f7256c103ab736d4e2dac7441a1f4503b466b0b2 $")
24
25#include <freeradius-devel/util/minmax_heap.h>
26#include <freeradius-devel/util/strerror.h>
27#include <freeradius-devel/util/debug.h>
28#include <freeradius-devel/util/misc.h>
29
30/*
31 * The internal representation of minmax heaps is that of plain
32 * binary heaps. They differ in where entries are placed, and how
33 * the operations are done. Also, minmax heaps allow peeking or
34 * popping the maximum value as well as the minimum.
35 *
36 * The heap itself is an array of pointers to objects, each of which
37 * contains a key and an fr_minmax_heap_index_t value indicating the
38 * location in the array holding the pointer to it. To allow 0 to
39 * represent objects not in a heap, the pointers start at element
40 * one of the array rather than element zero. The offset of that
41 * fr_minmax_heap_index_t value is held inside the heap structure.
42 *
43 * Minmax heaps are trees, like binary heaps, but the levels (all
44 * values at the same depth) alternate between "min" (starting at
45 * depth 0, i.e. the root) and "max" levels. The operations preserve
46 * these properties:
47 * - A node on a min level will compare as less than or equal to any
48 * of its descendants.
49 * - A node on a max level will compare as greater than or equal to
50 * any of its descendants.
51 */
52
54 unsigned int size; //!< Number of nodes allocated.
55 size_t offset; //!< Offset of heap index in element structure.
56
57 unsigned int num_elements; //!< Number of nodes used.
58
59 char const *type; //!< Talloc type of elements.
60 fr_minmax_heap_cmp_t cmp; //!< Comparator function.
61
62 void *p[]; //!< Array of nodes.
63};
64
66
67#define INITIAL_CAPACITY 2048
68
69/*
70 * First node in a heap is element 1. Children of i are 2i and
71 * 2i+1. These macros wrap the logic, so the code is more
72 * descriptive.
73 */
74#define HEAP_PARENT(_x) ((_x) >> 1)
75#define HEAP_GRANDPARENT(_x) HEAP_PARENT(HEAP_PARENT(_x))
76#define HEAP_LEFT(_x) (2 * (_x))
77#define HEAP_RIGHT(_x) (2 * (_x) + 1 )
78#define HEAP_SWAP(_a, _b) do { void *_tmp = _a; _a = _b; _b = _tmp; } while (0)
79
80/**
81 * @hidecallergraph
82 */
84{
85 return fr_high_bit_pos(i) - 1;
86}
87
89{
90 return (depth(i) & 1) == 0;
91}
92
93static inline bool is_descendant(fr_minmax_heap_index_t candidate, fr_minmax_heap_index_t ancestor)
94{
95 fr_minmax_heap_index_t level_min;
96 uint8_t candidate_depth = depth(candidate);
97 uint8_t ancestor_depth = depth(ancestor);
98
99 /*
100 * This will never happen given the its use by fr_minmax_heap_extract(),
101 * but it's here for safety and to make static analysis happy.
102 */
103 if (unlikely(candidate_depth < ancestor_depth)) return false;
104
105 level_min = ((fr_minmax_heap_index_t) 1) << (candidate_depth - ancestor_depth);
106 return (candidate - level_min) < level_min;
107}
108
109#define is_max_level_index(_i) (!(is_min_level_index(_i)))
110
111fr_minmax_heap_t *_fr_minmax_heap_alloc(TALLOC_CTX *ctx, fr_minmax_heap_cmp_t cmp, char const *type, size_t offset, unsigned int init)
112{
114 minmax_heap_t *h;
115
116 if (!init) init = INITIAL_CAPACITY;
117
118 hp = talloc(ctx, fr_minmax_heap_t);
119 if (unlikely(!hp)) return NULL;
120
121 /*
122 * For small heaps (< 40 elements) the
123 * increase in memory locality gives us
124 * a 100% performance increase
125 * (talloc headers are big);
126 */
127 h = (minmax_heap_t *)talloc_array(hp, uint8_t, sizeof(minmax_heap_t) + (sizeof(void *) * (init + 1)));
128 if (unlikely(!h)) {
129 talloc_free(hp);
130 return NULL;
131 }
132 talloc_set_type(h, minmax_heap_t);
133
134 *h = (minmax_heap_t){
135 .size = init,
136 .type = type,
137 .cmp = cmp,
138 .offset = offset
139 };
140
141 /*
142 * As we're using unsigned index values
143 * index 0 is a special value meaning
144 * that the data isn't currently inserted
145 * into the heap.
146 */
147 h->p[0] = (void *)UINTPTR_MAX;
148
149 *hp = h;
150
151 return hp;
152}
153
155{
156 minmax_heap_t *h = *hp;
157 unsigned int n_size;
158
159 /*
160 * One will almost certainly run out of RAM first,
161 * but the size must be representable. This form
162 * of the check avoids overflow.
163 */
164 if (unlikely(h->size > UINT_MAX - h->size)) {
165 if (h->size == UINT_MAX) {
166 fr_strerror_const("Heap is full");
167 return -1;
168 }
169 n_size = UINT_MAX;
170 } else {
171 n_size = 2 * h->size;
172 }
173
174 h = (minmax_heap_t *)talloc_realloc(hp, h, uint8_t, sizeof(minmax_heap_t) + (sizeof(void *) * ((size_t)n_size + 1)));
175 if (unlikely(!h)) {
176 fr_strerror_printf("Failed expanding heap to %u elements (%zu bytes)",
177 n_size, (n_size * sizeof(void *)));
178 return -1;
179 }
180
181 talloc_set_type(h, minmax_heap_t);
182 h->size = n_size;
183 *hp = h;
184 return 0;
185}
186
187
188static inline CC_HINT(always_inline, nonnull) fr_minmax_heap_index_t index_get(minmax_heap_t *h, void *data)
189{
190 return *((fr_minmax_heap_index_t const *)(((uint8_t const *)data) + h->offset));
191}
192
193static inline CC_HINT(always_inline, nonnull) void index_set(minmax_heap_t *h, void *data, fr_minmax_heap_index_t idx)
194{
195 *((fr_minmax_heap_index_t *)(((uint8_t *)data) + h->offset)) = idx;
196}
197
198static inline CC_HINT(always_inline, nonnull) bool has_children(minmax_heap_t *h, fr_minmax_heap_index_t idx)
199{
200 return HEAP_LEFT(idx) <= h->num_elements;
201}
202
204{
205 return HEAP_LEFT(HEAP_LEFT(i)) <= h->num_elements;
206}
207
208#define OFFSET_SET(_heap, _idx) index_set(_heap, _heap->p[_idx], _idx)
209#define OFFSET_RESET(_heap, _idx) index_set(_heap, _heap->p[_idx], 0)
210
211/*
212 * The minmax heap has the same basic idea as binary heaps:
213 * 1. To insert a value, put it at the bottom and push it up to where it should be.
214 * 2. To remove a value, take it out; if it's not at the bottom, move what is at the
215 * bottom up to fill the hole, and push it down to where it should be.
216 * The difference is how you push, and the invariants to preserve.
217 *
218 * Since we store the index in the item (or zero if it's not in the heap), when we
219 * move an item around, we have to set its index. The general principle is that we
220 * set it when we put the item in the place it will ultimately be when the push_down()
221 * or push_up() is finished.
222 */
223
224/** Find the index of the minimum child or grandchild of the entry at a given index.
225 * precondition: has_children(h, idx), i.e. there is stuff in the heap below
226 * idx.
227 *
228 * These functions are called by push_down_{min, max}() with idx the index of
229 * an element moved into that position but which may or may not be where it
230 * should ultimately go. The minmax heap property still holds for its (positional,
231 * at least) descendants, though. That lets us cut down on the number of
232 * comparisons over brute force iteration over every child and grandchild.
233 *
234 * In the case where the desired item must be a child, there are at most two,
235 * so we just do it inlne; no loop needed.
236 */
238{
239 fr_minmax_heap_index_t lwb, upb, min;
240
241 if (is_max_level_index(idx) || !has_grandchildren(h, idx)) {
242 /* minimum must be a chld */
243 min = HEAP_LEFT(idx);
244 upb = HEAP_RIGHT(idx);
245 if (upb <= h->num_elements && h->cmp(h->p[upb], h->p[min]) < 0) min = upb;
246 return min;
247 }
248
249 /* minimum must be a grandchild, unless the right child is childless */
250 if (!has_children(h, HEAP_RIGHT(idx))) {
251 min = HEAP_RIGHT(idx);
252 lwb = HEAP_LEFT(HEAP_LEFT(idx));
253 } else {
254 min = HEAP_LEFT(HEAP_LEFT(idx));
255 lwb = min + 1;
256 }
257 upb = HEAP_RIGHT(HEAP_RIGHT(idx));
258
259 /* Some grandchildren may not exist. */
260 if (upb > h->num_elements) upb = h->num_elements;
261
262 for (fr_minmax_heap_index_t i = lwb; i <= upb; i++) {
263 if (h->cmp(h->p[i], h->p[min]) < 0) min = i;
264 }
265 return min;
266}
267
269{
270 fr_minmax_heap_index_t lwb, upb, max;
271
272 if (is_min_level_index(idx) || !has_grandchildren(h, idx)) {
273 /* maximum must be a chld */
274 max = HEAP_LEFT(idx);
275 upb = HEAP_RIGHT(idx);
276 if (upb <= h->num_elements && h->cmp(h->p[upb], h->p[max]) > 0) max = upb;
277 return max;
278 }
279
280 /* minimum must be a grandchild, unless the right child is childless */
281 if (!has_children(h, HEAP_RIGHT(idx))) {
282 max = HEAP_RIGHT(idx);
283 lwb = HEAP_LEFT(HEAP_LEFT(idx));
284 } else {
285 max = HEAP_LEFT(HEAP_LEFT(idx));
286 lwb = max + 1;
287 }
288 upb = HEAP_RIGHT(HEAP_RIGHT(idx));
289
290 /* Some grandchildren may not exist. */
291 if (upb > h->num_elements) upb = h->num_elements;
292
293 for (fr_minmax_heap_index_t i = lwb; i <= upb; i++) {
294 if (h->cmp(h->p[i], h->p[max]) > 0) max = i;
295 }
296 return max;
297}
298
299/**
300 * precondition: idx is the index of an existing entry on a min level
301 */
302static inline CC_HINT(always_inline, nonnull) void push_down_min(minmax_heap_t *h, fr_minmax_heap_index_t idx)
303{
304 while (has_children(h, idx)) {
306
307 /*
308 * If p[m] doesn't precede p[idx], we're done.
309 */
310 if (h->cmp(h->p[m], h->p[idx]) >= 0) break;
311
312 HEAP_SWAP(h->p[idx], h->p[m]);
313 OFFSET_SET(h, idx);
314
315 /*
316 * The entry now at m may belong where the parent is.
317 */
318 if (HEAP_GRANDPARENT(m) == idx && h->cmp(h->p[m], h->p[HEAP_PARENT(m)]) > 0) {
319 HEAP_SWAP(h->p[HEAP_PARENT(m)], h->p[m]);
320 OFFSET_SET(h, HEAP_PARENT(m));
321 }
322 idx = m;
323 }
324 OFFSET_SET(h, idx);
325}
326
327/**
328 * precondition: idx is the index of an existing entry on a max level
329 * (Just like push_down_min() save for reversal of ordering, so comments there apply,
330 * mutatis mutandis.)
331 */
333{
334 while (has_children(h, idx)) {
336
337 if (h->cmp(h->p[m], h->p[idx]) <= 0) break;
338
339 HEAP_SWAP(h->p[idx], h->p[m]);
340 OFFSET_SET(h, idx);
341
342 if (HEAP_GRANDPARENT(m) == idx && h->cmp(h->p[m], h->p[HEAP_PARENT(m)]) < 0) {
343 HEAP_SWAP(h->p[HEAP_PARENT(m)], h->p[m]);
344 OFFSET_SET(h, HEAP_PARENT(m));
345 }
346 idx = m;
347 }
348 OFFSET_SET(h, idx);
349}
350
352{
353 if (is_min_level_index(idx)) {
354 push_down_min(h, idx);
355 } else {
356 push_down_max(h, idx);
357 }
358}
359
361{
362 fr_minmax_heap_index_t grandparent;
363
364 while ((grandparent = HEAP_GRANDPARENT(idx)) > 0 && h->cmp(h->p[idx], h->p[grandparent]) < 0) {
365 HEAP_SWAP(h->p[idx], h->p[grandparent]);
366 OFFSET_SET(h, idx);
367 idx = grandparent;
368 }
369 OFFSET_SET(h, idx);
370}
371
373{
374 fr_minmax_heap_index_t grandparent;
375
376 while ((grandparent = HEAP_GRANDPARENT(idx)) > 0 && h->cmp(h->p[idx], h->p[grandparent]) > 0) {
377 HEAP_SWAP(h->p[idx], h->p[grandparent]);
378 OFFSET_SET(h, idx);
379 idx = grandparent;
380 }
381 OFFSET_SET(h, idx);
382}
383
385{
387 int8_t order;
388
389 /*
390 * First entry? No need to move; set its index and be done with it.
391 */
392 if (idx == 1) {
393 OFFSET_SET(h, idx);
394 return;
395 }
396
397 /*
398 * Otherwise, move to the next level up if need be.
399 * Once it's positioned appropriately on an even or odd layer,
400 * it can percolate up two at a time.
401 */
402 parent = HEAP_PARENT(idx);
403 order = h->cmp(h->p[idx], h->p[parent]);
404
405 if (is_min_level_index(idx)) {
406 if (order > 0) {
407 HEAP_SWAP(h->p[idx], h->p[parent]);
408 OFFSET_SET(h, idx);
410 } else {
411 push_up_min(h, idx);
412 }
413 } else {
414 if (order < 0) {
415 HEAP_SWAP(h->p[idx], h->p[parent]);
416 OFFSET_SET(h, idx);
418 } else {
419 push_up_max(h, idx);
420 }
421 }
422}
423
425{
426 minmax_heap_t *h = *hp;
428
430 fr_strerror_const("Node is already in a heap");
431 return -1;
432 }
433
434 child = h->num_elements + 1;
435 if (unlikely(child > h->size)) {
436 if (unlikely(minmax_heap_expand(hp) < 0)) return -1;
437 h = *hp;
438 }
439
440 /*
441 * Add it to the end, and move it up as needed.
442 */
443 h->p[child] = data;
444 h->num_elements++;
445 push_up(h, child);
446 return 0;
447}
448
450{
451 minmax_heap_t *h = *hp;
452
453 if (unlikely(h->num_elements == 0)) return NULL;
454 return h->p[1];
455}
456
458{
459 void *data = fr_minmax_heap_min_peek(hp);
460
461 if (unlikely(!data)) return NULL;
462 if (unlikely(fr_minmax_heap_extract(hp, data) < 0)) return NULL;
463 return data;
464}
465
467{
468 minmax_heap_t *h = *hp;
469
470 if (unlikely(h->num_elements == 0)) return NULL;
471
472 if (h->num_elements < 3) return h->p[h->num_elements];
473
474 return h->p[2 + (h->cmp(h->p[2], h->p[3]) < 0)];
475}
476
478{
479 void *data = fr_minmax_heap_max_peek(hp);
480
481 if (unlikely(!data)) return NULL;
482 if (unlikely(fr_minmax_heap_extract(hp, data) < 0)) return NULL;
483 return data;
484}
485
487{
488 minmax_heap_t *h = *hp;
490
491 if (unlikely(h->num_elements < idx)) {
492 fr_strerror_printf("data (index %u) exceeds heap size %u", idx, h->num_elements);
493 return -1;
494 }
495 if (unlikely(!fr_minmax_heap_entry_inserted(index_get(h, data)) || h->p[idx] != data)) {
496 fr_strerror_printf("data (index %u) not in heap", idx);
497 return -1;
498 }
499
500 OFFSET_RESET(h, idx);
501
502 /*
503 * Removing the last element can't break the minmax heap property, so
504 * decrement the number of elements and be done with it.
505 */
506 if (h->num_elements == idx) {
507 h->num_elements--;
508 return 0;
509 }
510
511 /*
512 * Move the last element into the now-available position,
513 * and then move it as needed.
514 */
515 h->p[idx] = h->p[h->num_elements];
516 h->num_elements--;
517 /*
518 * If the new position is the root, that's as far up as it gets.
519 * If the old position is a descendant of the new position,
520 * the entry itself remains a descendant of the new position's
521 * parent, and hence by minmax heap property is in the proper
522 * relation to the parent and doesn't need to move up.
523 */
524 if (idx > 1 && !is_descendant(h->num_elements, idx)) push_up(h, idx);
525 push_down(h, idx);
526 return 0;
527}
528
529/** Return the number of elements in the minmax heap
530 *
531 * @param[in] hp to return the number of elements from.
532 */
534{
535 minmax_heap_t *h = *hp;
536
537 return h->num_elements;
538}
539
540/** Iterate over entries in a minmax heap
541 *
542 * @note If the heap is modified the iterator should be considered invalidated.
543 *
544 * @param[in] hp to iterate over.
545 * @param[in] iter Pointer to an iterator struct, used to maintain
546 * state between calls.
547 * @return
548 * - User data.
549 * - NULL if at the end of the list.
550 */
552{
553 minmax_heap_t *h = *hp;
554
555 *iter = 1;
556
557 if (h->num_elements == 0) return NULL;
558
559 return h->p[1];
560}
561
562/** Get the next entry in a minmax heap
563 *
564 * @note If the heap is modified the iterator should be considered invalidated.
565 *
566 * @param[in] hp to iterate over.
567 * @param[in] iter Pointer to an iterator struct, used to maintain
568 * state between calls.
569 * @return
570 * - User data.
571 * - NULL if at the end of the list.
572 */
574{
575 minmax_heap_t *h = *hp;
576
577 if ((*iter + 1) > h->num_elements) return NULL;
578 *iter += 1;
579
580 return h->p[*iter];
581}
582
583#ifndef TALLOC_GET_TYPE_ABORT_NOOP
584void fr_minmax_heap_verify(char const *file, int line, fr_minmax_heap_t const *hp)
585{
586 minmax_heap_t *h;
587
588 /*
589 * The usual start...
590 */
591 fr_fatal_assert_msg(hp, "CONSISTENCY CHECK FAILED %s[%i]: fr_minmax_heap_t pointer was NULL", file, line);
592 (void) talloc_get_type_abort(hp, fr_minmax_heap_t);
593
594 /*
595 * Allocating the heap structure and the array holding the heap as described in data structure
596 * texts together is a respectable savings, but it means adding a level of indirection so the
597 * fr_heap_t * isn't realloc()ed out from under the user, hence the following (and the use of h
598 * rather than hp to access anything in the heap structure).
599 */
600 h = *hp;
601 fr_fatal_assert_msg(h, "CONSISTENCY CHECK FAILED %s[%i]: minmax_heap_t pointer was NULL", file, line);
602 (void) talloc_get_type_abort(h, minmax_heap_t);
603
605 "CONSISTENCY CHECK FAILED %s[%i]: num_elements exceeds size", file, line);
606
607 fr_fatal_assert_msg(h->p[0] == (void *)UINTPTR_MAX,
608 "CONSISTENCY CHECK FAILED %s[%i]: zeroeth element special value overwritten", file, line);
609
610 for (fr_minmax_heap_index_t i = 1; i <= h->num_elements; i++) {
611 void *data = h->p[i];
612
613 fr_fatal_assert_msg(data, "CONSISTENCY CHECK FAILED %s[%i]: node %u was NULL", file, line, i);
614 if (h->type) (void)_talloc_get_type_abort(data, h->type, __location__);
616 "CONSISTENCY CHECK FAILED %s[%i]: node %u index != %u", file, line, i, i);
617 }
618
619 /*
620 * Verify minmax heap property, which is:
621 * A node in a min level precedes all its descendants;
622 * a node in a max level follows all its descencdants.
623 * (if equal keys are allowed, that should be "doesn't follow" and
624 * "doesn't precede" respectively)
625 *
626 * We claim looking at one's children and grandchildren (if any)
627 * suffices. Why? Induction on floor(depth / 2):
628 *
629 * Base case:
630 * If the depth of the tree is <= 2, that *is* all the
631 * descendants, so we're done.
632 * Induction step:
633 * Suppose you're on a min level and the check passes.
634 * If the test works on the next min level down, transitivity
635 * of <= means the level you're on satisfies the property
636 * two levels further down.
637 * For max level, >= is transitive, too, so you're good.
638 */
639
640 for (fr_minmax_heap_index_t i = 1; HEAP_LEFT(i) <= h->num_elements; i++) {
641 bool on_min_level = is_min_level_index(i);
642 fr_minmax_heap_index_t others[] = {
643 HEAP_LEFT(i),
644 HEAP_RIGHT(i),
649 };
650
651 for (size_t j = 0; j < NUM_ELEMENTS(others) && others[j] <= h->num_elements; j++) {
652 int8_t cmp_result = h->cmp(h->p[i], h->p[others[j]]);
653
654 fr_fatal_assert_msg(on_min_level ? (cmp_result <= 0) : (cmp_result >= 0),
655 "CONSISTENCY CHECK FAILED %s[%i]: node %u violates %s level condition",
656 file, line, i, on_min_level ? "min" : "max");
657 }
658 }
659}
660#endif
int const char * file
Definition acutest.h:702
int const char int line
Definition acutest.h:702
static bool init
Definition fuzzer.c:41
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
#define NUM_ELEMENTS(_t)
Definition build.h:337
static size_t min(size_t x, size_t y)
Definition dbuff.c:66
#define fr_fatal_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:184
talloc_free(reap)
static uint8_t fr_high_bit_pos(uint64_t num)
Find the highest order high bit in an unsigned 64 bit integer.
Definition math.h:36
unsigned char uint8_t
static void push_down_max(minmax_heap_t *h, fr_minmax_heap_index_t idx)
precondition: idx is the index of an existing entry on a max level (Just like push_down_min() save fo...
void * fr_minmax_heap_max_pop(fr_minmax_heap_t *hp)
int fr_minmax_heap_insert(fr_minmax_heap_t *hp, void *data)
static bool has_grandchildren(minmax_heap_t *h, fr_minmax_heap_index_t i)
#define HEAP_PARENT(_x)
Definition minmax_heap.c:74
static void index_set(minmax_heap_t *h, void *data, fr_minmax_heap_index_t idx)
#define OFFSET_SET(_heap, _idx)
static void push_up_min(minmax_heap_t *h, fr_minmax_heap_index_t idx)
static int minmax_heap_expand(fr_minmax_heap_t *hp)
void * fr_minmax_heap_iter_next(fr_minmax_heap_t *hp, fr_minmax_heap_iter_t *iter)
Get the next entry in a minmax heap.
static void push_down_min(minmax_heap_t *h, fr_minmax_heap_index_t idx)
precondition: idx is the index of an existing entry on a min level
#define INITIAL_CAPACITY
Definition minmax_heap.c:67
void * p[]
Array of nodes.
Definition minmax_heap.c:62
static bool has_children(minmax_heap_t *h, fr_minmax_heap_index_t idx)
void * fr_minmax_heap_min_peek(fr_minmax_heap_t *hp)
#define OFFSET_RESET(_heap, _idx)
#define is_max_level_index(_i)
static void push_up(minmax_heap_t *h, fr_minmax_heap_index_t idx)
#define HEAP_GRANDPARENT(_x)
Definition minmax_heap.c:75
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
static void push_down(minmax_heap_t *h, fr_minmax_heap_index_t idx)
void * fr_minmax_heap_min_pop(fr_minmax_heap_t *hp)
fr_minmax_heap_cmp_t cmp
Comparator function.
Definition minmax_heap.c:60
void * fr_minmax_heap_max_peek(fr_minmax_heap_t *hp)
unsigned int fr_minmax_heap_num_elements(fr_minmax_heap_t *hp)
Return the number of elements in the minmax heap.
static fr_minmax_heap_index_t max_child_or_grandchild(minmax_heap_t *h, fr_minmax_heap_index_t idx)
#define HEAP_SWAP(_a, _b)
Definition minmax_heap.c:78
#define HEAP_LEFT(_x)
Definition minmax_heap.c:76
struct fr_minmax_heap_s minmax_heap_t
Definition minmax_heap.c:65
fr_minmax_heap_t * _fr_minmax_heap_alloc(TALLOC_CTX *ctx, fr_minmax_heap_cmp_t cmp, char const *type, size_t offset, unsigned int init)
static bool is_min_level_index(fr_minmax_heap_index_t i)
Definition minmax_heap.c:88
static bool is_descendant(fr_minmax_heap_index_t candidate, fr_minmax_heap_index_t ancestor)
Definition minmax_heap.c:93
size_t offset
Offset of heap index in element structure.
Definition minmax_heap.c:55
void * fr_minmax_heap_iter_init(fr_minmax_heap_t *hp, fr_minmax_heap_iter_t *iter)
Iterate over entries in a minmax heap.
int fr_minmax_heap_extract(fr_minmax_heap_t *hp, void *data)
static void push_up_max(minmax_heap_t *h, fr_minmax_heap_index_t idx)
#define HEAP_RIGHT(_x)
Definition minmax_heap.c:77
static fr_minmax_heap_index_t min_child_or_grandchild(minmax_heap_t *h, fr_minmax_heap_index_t idx)
Find the index of the minimum child or grandchild of the entry at a given index.
unsigned int size
Number of nodes allocated.
Definition minmax_heap.c:54
char const * type
Talloc type of elements.
Definition minmax_heap.c:59
static fr_minmax_heap_index_t index_get(minmax_heap_t *h, void *data)
void fr_minmax_heap_verify(char const *file, int line, fr_minmax_heap_t const *hp)
unsigned int num_elements
Number of nodes used.
Definition minmax_heap.c:57
int8_t(* fr_minmax_heap_cmp_t)(void const *a, void const *b)
Comparator to order elements.
Definition minmax_heap.h:50
static bool fr_minmax_heap_entry_inserted(fr_minmax_heap_index_t heap_idx)
Check if an entry is inserted into a heap.
Definition minmax_heap.h:93
unsigned int fr_minmax_heap_iter_t
Definition minmax_heap.h:38
unsigned int fr_minmax_heap_index_t
Definition minmax_heap.h:37
fr_aka_sim_id_type_t type
static fr_slen_t parent
Definition pair.h:851
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static fr_slen_t data
Definition value.h:1265
int nonnull(2, 5))