The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
23 RCSID("$Id: 3ffddc515693dac2a7dd3a88c92de80c16f247cc $")
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 
65 typedef struct fr_minmax_heap_s minmax_heap_t;
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 
93 static 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 
111 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)
112 {
113  fr_minmax_heap_t *hp;
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 *) * (n_size + 1)));
175  if (unlikely(!h)) {
176  fr_strerror_printf("Failed expanding heap to %u elements (%u bytes)",
177  n_size, (n_size * (unsigned int)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 
188 static 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 
193 static 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 
198 static 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  */
302 static 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);
409  push_up_max(h, parent);
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);
417  push_up_min(h, parent);
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
584 void 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),
645  HEAP_LEFT(HEAP_LEFT(i)),
646  HEAP_RIGHT(HEAP_LEFT(i)),
647  HEAP_LEFT(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
#define RCSID(id)
Definition: build.h:444
#define unlikely(_x)
Definition: build.h:378
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#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:182
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
Definition: merged_model.c:30
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...
Definition: minmax_heap.c:332
int fr_minmax_heap_insert(fr_minmax_heap_t *hp, void *data)
Definition: minmax_heap.c:424
static bool has_grandchildren(minmax_heap_t *h, fr_minmax_heap_index_t i)
Definition: minmax_heap.c:203
#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)
Definition: minmax_heap.c:193
#define OFFSET_SET(_heap, _idx)
Definition: minmax_heap.c:208
static void push_up_min(minmax_heap_t *h, fr_minmax_heap_index_t idx)
Definition: minmax_heap.c:360
static int minmax_heap_expand(fr_minmax_heap_t *hp)
Definition: minmax_heap.c:154
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
Definition: minmax_heap.c:302
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.
Definition: minmax_heap.c:573
void * fr_minmax_heap_min_peek(fr_minmax_heap_t *hp)
Definition: minmax_heap.c:449
#define INITIAL_CAPACITY
Definition: minmax_heap.c:67
void * fr_minmax_heap_max_pop(fr_minmax_heap_t *hp)
Definition: minmax_heap.c:477
void * fr_minmax_heap_min_pop(fr_minmax_heap_t *hp)
Definition: minmax_heap.c:457
void * p[]
Array of nodes.
Definition: minmax_heap.c:62
static bool has_children(minmax_heap_t *h, fr_minmax_heap_index_t idx)
Definition: minmax_heap.c:198
#define OFFSET_RESET(_heap, _idx)
Definition: minmax_heap.c:209
#define is_max_level_index(_i)
Definition: minmax_heap.c:109
static void push_up(minmax_heap_t *h, fr_minmax_heap_index_t idx)
Definition: minmax_heap.c:384
#define HEAP_GRANDPARENT(_x)
Definition: minmax_heap.c:75
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
void * fr_minmax_heap_max_peek(fr_minmax_heap_t *hp)
Definition: minmax_heap.c:466
static void push_down(minmax_heap_t *h, fr_minmax_heap_index_t idx)
Definition: minmax_heap.c:351
fr_minmax_heap_cmp_t cmp
Comparator function.
Definition: minmax_heap.c:60
unsigned int fr_minmax_heap_num_elements(fr_minmax_heap_t *hp)
Return the number of elements in the minmax heap.
Definition: minmax_heap.c:533
static fr_minmax_heap_index_t max_child_or_grandchild(minmax_heap_t *h, fr_minmax_heap_index_t idx)
Definition: minmax_heap.c:268
#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)
Definition: minmax_heap.c:111
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
int fr_minmax_heap_extract(fr_minmax_heap_t *hp, void *data)
Definition: minmax_heap.c:486
static void push_up_max(minmax_heap_t *h, fr_minmax_heap_index_t idx)
Definition: minmax_heap.c:372
#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.
Definition: minmax_heap.c:237
unsigned int size
Number of nodes allocated.
Definition: minmax_heap.c:54
char const * type
Talloc type of elements.
Definition: minmax_heap.c:59
void * fr_minmax_heap_iter_init(fr_minmax_heap_t *hp, fr_minmax_heap_iter_t *iter)
Iterate over entries in a minmax heap.
Definition: minmax_heap.c:551
static fr_minmax_heap_index_t index_get(minmax_heap_t *h, void *data)
Definition: minmax_heap.c:188
void fr_minmax_heap_verify(char const *file, int line, fr_minmax_heap_t const *hp)
Definition: minmax_heap.c:584
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
static size_t min(size_t x, size_t y)
Definition: sbuff.c:135
init
Enter the EAP-IDENTITY state.
Definition: state_machine.c:90
fr_aka_sim_id_type_t type
static fr_slen_t parent
Definition: pair.h:844
#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:1259
int nonnull(2, 5))