The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
minmax_heap_tests.c
Go to the documentation of this file.
1 #include <freeradius-devel/util/acutest.h>
2 #include <freeradius-devel/util/heap.h>
3 #include <freeradius-devel/util/rand.h>
4 #include <freeradius-devel/util/time.h>
5 
6 #include "minmax_heap.c"
7 
8 typedef struct {
9  unsigned int data;
10  fr_minmax_heap_index_t idx; /* for the heap */
11  bool visited;
13 
15 {
16  minmax_heap_t *h = *hp;
17 
18  for (unsigned int i = 1; i <= h->num_elements; i++) if (h->p[i] == data) return true;
19 
20  return false;
21 }
22 
23 static int8_t minmax_heap_cmp(void const *one, void const *two)
24 {
25  minmax_heap_thing const *a = one, *b = two;
26 
27  return CMP_PREFER_SMALLER(a->data, b->data);
28 }
29 
30 #if 0
31 #define is_power_of_2(_n) !((_n) & ((_n) - 1))
32 /*
33  * A simple minmax heap dump function, specific to minmax_heap_thing and
34  * intended for use only with small heaps. It only shows the data members
35  * in the order they appear in the array, ignoring the unused zeroeth
36  * entry and printing a vertical bar before the start of each successive level.
37  */
38 static void minmax_heap_dump(fr_minmax_heap_t *hp)
39 {
40  minmax_heap_t *h = *hp;
41  unsigned int num_elements = h->num_elements;
42 
43  fprintf(stderr, "%3u: ", num_elements);
44 
45  for (fr_minmax_heap_index_t i = 1; i <= num_elements; i++) {
46  if (is_power_of_2(i)) fprintf(stderr, "|");
47  fprintf(stderr, "%6u", ((minmax_heap_thing *)(h->p[i]))->data);
48  }
49  fprintf(stderr, "\n");
50 }
51 #endif
52 
53 static void populate_values(minmax_heap_thing values[], unsigned int len)
54 {
55  unsigned int i;
56  fr_fast_rand_t rand_ctx;
57 
58  for (i = 0; i < len; i++) {
59  values[i].data = i;
60  values[i].idx = 0;
61  values[i].visited = false;
62  }
63 
64  /* shuffle values before insertion, so the heap has to work to give them back in order */
65  rand_ctx.a = fr_rand();
66  rand_ctx.b = fr_rand();
67 
68  for (i = 0; i < len; i++) {
69  unsigned int j = fr_fast_rand(&rand_ctx) % len;
70  int temp = values[i].data;
71 
72  values[i].data = values[j].data;
73  values[j].data = temp;
74  }
75 }
76 
77 #define NVALUES 20
78 static void minmax_heap_test_basic(void)
79 {
80  fr_minmax_heap_t *hp;
81  minmax_heap_thing values[NVALUES];
82 
84  TEST_CHECK(hp != NULL);
85 
86  populate_values(values, NVALUES);
87 
88  /*
89  * minmax heaps can get the minimum value...
90  */
91  for (unsigned int i = 0; i < NVALUES; i++) {
92  TEST_CHECK(fr_minmax_heap_insert(hp, &values[i]) >= 0);
94  }
95 
96  for (unsigned int i = 0; i < NVALUES; i++) {
98 
99  TEST_CHECK(value != NULL);
101  TEST_CHECK(value->data == i);
102  TEST_MSG("iteration %u, popped %u", i, value->data);
103  }
104 
105  /*
106  * ...or the maximum value.
107  */
108  for (unsigned int i = 0; i < NVALUES; i++) {
109  TEST_CHECK(fr_minmax_heap_insert(hp, &values[i]) >= 0);
111  }
112 
113  for (unsigned int i = NVALUES; --i > 0; ) {
115 
116  TEST_CHECK(value != NULL);
118  TEST_CHECK(value->data == i);
119  TEST_MSG("iteration %u, popped %u", NVALUES - 1 - i, value->data);
120  }
121 
122  talloc_free(hp);
123 }
124 
125 #define MINMAX_HEAP_TEST_SIZE (4096)
126 
127 static void minmax_heap_test(int skip)
128 {
129  fr_minmax_heap_t *hp;
130  int i;
132  int left;
133  int ret;
134  fr_fast_rand_t rand_ctx;
135 
136  rand_ctx.a = fr_rand();
137  rand_ctx.b = fr_rand();
138 
140  TEST_CHECK(hp != NULL);
141 
142  array = talloc_zero_array(hp, minmax_heap_thing, MINMAX_HEAP_TEST_SIZE);
143 
144  /*
145  * Initialise random values
146  */
147  for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
148 
149  TEST_CASE("insertions");
150  for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) {
152  TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
153  TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
154 
156  TEST_MSG("element %i inserted but not in heap", i);
157  }
158 
159  TEST_CASE("deletions");
160  {
161  unsigned int entry;
162 
163  for (i = 0; i < MINMAX_HEAP_TEST_SIZE / skip; i++) {
164  entry = i * skip;
165 
167  TEST_CHECK(array[entry].idx != 0);
168  TEST_MSG("element %i removed out of order", entry);
169 
170  TEST_CHECK((ret = fr_minmax_heap_extract(hp, &array[entry])) >= 0);
171  TEST_MSG("element %i removal failed, returned %i - %s", entry, ret, fr_strerror());
172 
173  TEST_CHECK(!minmax_heap_contains(hp, &array[entry]));
174  TEST_MSG("element %i removed but still in heap", entry);
175 
176  TEST_CHECK(array[entry].idx == 0);
177  TEST_MSG("element %i removed out of order", entry);
178  }
179  }
180 
181  left = fr_minmax_heap_num_elements(hp);
182  for (i = 0; i < left; i++) {
184 
186  TEST_CHECK((t = fr_minmax_heap_min_peek(hp)) != NULL);
187  TEST_MSG("expected %i elements remaining in the heap", left - i);
188 
189  TEST_CHECK(fr_minmax_heap_extract(hp, t) >= 0);
190  TEST_MSG("failed extracting %i", i);
191  }
192 
193  TEST_CHECK((ret = fr_minmax_heap_num_elements(hp)) == 0);
194  TEST_MSG("%i elements remaining", ret);
195 
196  talloc_free(hp);
197 }
198 
199 /*
200  * minmax heaps can do anything heaps can do, so let's make sure we have
201  * a (proper!) superset of the heap tests.
202  */
203 
204 static void minmax_heap_test_skip_0(void)
205 {
206  minmax_heap_test(1);
207 }
208 
209 static void minmax_heap_test_skip_2(void)
210 {
211  minmax_heap_test(2);
212 }
213 
214 static void minmax_heap_test_skip_10(void)
215 {
216  minmax_heap_test(10);
217 }
218 
219 #define BURN_IN_OPS (10000000)
220 
221 static void minmax_heap_burn_in(void)
222 {
223  fr_minmax_heap_t *hp = NULL;
224  minmax_heap_thing *array = NULL;
225  fr_fast_rand_t rand_ctx;
226  int insert_count = 0;
227 
228  rand_ctx.a = fr_rand();
229  rand_ctx.b = fr_rand();
230 
231  array = calloc(BURN_IN_OPS, sizeof(minmax_heap_thing));
232  for (unsigned int i = 0; i < BURN_IN_OPS; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
233 
235  TEST_CHECK(hp != NULL);
236 
237  for (unsigned int i = 0; i < BURN_IN_OPS; i++) {
238  minmax_heap_thing *ret_thing = NULL;
239  int ret_insert = -1;
240 
241  if (fr_minmax_heap_num_elements(hp) == 0) {
242  insert:
243  TEST_CHECK((ret_insert = fr_minmax_heap_insert(hp, &array[insert_count])) >= 0);
244  insert_count++;
245  } else {
246  switch (fr_fast_rand(&rand_ctx) % 5) {
247  case 0: /* insert */
248  goto insert;
249 
250  case 1: /* min pop */
251  ret_thing = fr_minmax_heap_min_pop(hp);
252  TEST_CHECK(ret_thing != NULL);
253  break;
254  case 2: /* min peek */
255  ret_thing = fr_minmax_heap_min_peek(hp);
256  TEST_CHECK(ret_thing != NULL);
257  break;
258  case 3: /* max pop */
259  ret_thing = fr_minmax_heap_max_pop(hp);
260  TEST_CHECK(ret_thing != NULL);
261  break;
262  case 4: /* max peek */
263  ret_thing = fr_minmax_heap_max_peek(hp);
264  TEST_CHECK(ret_thing != NULL);
265  break;
266  }
267  }
268  }
269 
270  talloc_free(hp);
271  free(array);
272 }
273 
274 #define MINMAX_HEAP_CYCLE_SIZE (1600000)
275 
276 static void minmax_heap_test_order(void)
277 {
278  fr_minmax_heap_t *hp;
279  int i;
281  minmax_heap_thing *thing, *prev = NULL;
282  unsigned int data;
283  unsigned int count;
284  int ret;
285  fr_fast_rand_t rand_ctx;
286 
287  rand_ctx.a = fr_rand();
288  rand_ctx.b = fr_rand();
289 
291  TEST_CHECK(hp != NULL);
292 
293  array = talloc_zero_array(hp, minmax_heap_thing, MINMAX_HEAP_TEST_SIZE);
294 
295  /*
296  * Initialise random values
297  */
298  for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
299 
300  TEST_CASE("insertions for min");
301  for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) {
302  TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
303  TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
304 
306  TEST_MSG("element %i inserted but not in heap", i);
307  }
308 
309  TEST_CASE("min ordering");
310 
311  count = 0;
312  data = 0;
313  prev = NULL;
314  while ((thing = fr_minmax_heap_min_pop(hp))) {
315  TEST_CHECK(thing->data >= data);
316  TEST_MSG("Expected data >= %i, got %i", data, thing->data);
317  if (thing->data >= data) data = thing->data;
318  TEST_CHECK(thing != prev);
319  prev = thing;
320  count++;
321  }
322 
324 
325  TEST_CASE("insertions for max");
326  for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) {
327  TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
328  TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
329 
331  TEST_MSG("element %i inserted but not in heap", i);
332  }
333 
334  TEST_CASE("max ordering");
335 
336  count = 0;
337  data = UINT_MAX;
338  prev = NULL;
339  while ((thing = fr_minmax_heap_max_pop(hp))) {
340  TEST_CHECK(thing->data <= data);
341  TEST_MSG("Expected data >= %i, got %i", data, thing->data);
342  if (thing->data <= data) data = thing->data;
343  TEST_CHECK(thing != prev);
344  prev = thing;
345  count++;
346  }
347 
349 
350  talloc_free(hp);
351 }
352 
353 static CC_HINT(noinline) minmax_heap_thing *array_pop(minmax_heap_thing **array, unsigned int count)
354 {
355  minmax_heap_thing *low = NULL;
356  unsigned int idx = 0;
357 
358  for (unsigned int j = 0; j < count; j++) {
359  if (!array[j]) continue;
360 
361  if (!low || (minmax_heap_cmp(array[j], low) < 0)) {
362  idx = j;
363  low = array[j];
364  }
365  }
366  if (low) array[idx] = NULL;
367 
368  return low;
369 }
370 
371 /** Benchmarks for minmax heaps vs heaps when used as queues
372  *
373  */
374 static void queue_cmp(unsigned int count)
375 {
376  fr_minmax_heap_t *minmax;
377  fr_heap_t *hp;
378 
379  minmax_heap_thing *values;
380 
381  unsigned int i;
382 
383  values = talloc_array(NULL, minmax_heap_thing, count);
384 
385  /*
386  * Check times for minmax heap alloc, insert, pop
387  */
388  {
389  fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first = fr_time_wrap(0);
390 
391  populate_values(values, count);
392 
393  start_alloc = fr_time();
394  minmax = fr_minmax_heap_alloc(NULL, minmax_heap_cmp, minmax_heap_thing, idx, 0);
395  end_alloc = fr_time();
396  TEST_CHECK(minmax != NULL);
397 
398  start_insert = fr_time();
399  for (i = 0; i < count; i++) fr_minmax_heap_insert(minmax, &values[i]);
400  end_insert = fr_time();
401 
402  start_pop = fr_time();
403  for (i = 0; i < count; i++) {
404  TEST_CHECK(fr_minmax_heap_min_pop(minmax) != NULL);
405  if (i == 0) end_pop_first = fr_time();
406 
407  TEST_MSG("expected %u elements remaining in the minmax heap", count - i);
408  TEST_MSG("failed extracting %u", i);
409  }
410  end_pop = fr_time();
411 
412  TEST_MSG_ALWAYS("\nminmax heap size: %u\n", count);
413  TEST_MSG_ALWAYS("alloc: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_alloc, start_alloc)));
414  TEST_MSG_ALWAYS("insert: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_insert, start_insert)));
415  TEST_MSG_ALWAYS("pop-first: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop_first, start_pop)));
416  TEST_MSG_ALWAYS("pop: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop, start_pop)));
417  talloc_free(minmax);
418  }
419 
420  /*
421  * Check times for heap alloc, insert, pop
422  */
423  {
424  fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first = fr_time_min();
425 
426  populate_values(values, count);
427 
428  start_alloc = fr_time();
430  end_alloc = fr_time();
431  TEST_CHECK(hp != NULL);
432 
433  start_insert = fr_time();
434  for (i = 0; i < count; i++) fr_heap_insert(&hp, &values[i]);
435  end_insert = fr_time();
436 
437  start_pop = fr_time();
438  for (i = 0; i < count; i++) {
439  TEST_CHECK(fr_heap_pop(&hp) != NULL);
440  if (i == 0) end_pop_first = fr_time();
441 
442  TEST_MSG("expected %u elements remaining in the heap", count - i);
443  TEST_MSG("failed extracting %u", i);
444  }
445  end_pop = fr_time();
446 
447  TEST_MSG_ALWAYS("\nheap size: %u\n", count);
448  TEST_MSG_ALWAYS("alloc: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_alloc, start_alloc)));
449  TEST_MSG_ALWAYS("insert: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_insert, start_insert)));
450  TEST_MSG_ALWAYS("pop-first: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop_first, start_pop)));
451  TEST_MSG_ALWAYS("pop: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop, start_pop)));
452 
453  talloc_free(hp);
454  }
455 
456  /*
457  * Array
458  */
459  {
461  fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first;
462 
463  populate_values(values, count);
464  end_pop_first = fr_time_min();
465 
466  start_alloc = fr_time();
467  array = talloc_array(NULL, minmax_heap_thing *, count);
468  end_alloc = fr_time();
469 
470  start_insert = fr_time();
471  for (i = 0; i < count; i++) array[i] = &values[i];
472  end_insert = fr_time();
473 
474  start_pop = fr_time();
475  for (i = 0; i < count; i++) {
476  TEST_CHECK(array_pop(array, count) != NULL);
477  if (i == 0) end_pop_first = fr_time();
478  }
479  end_pop = fr_time();
480 
481  TEST_MSG_ALWAYS("\narray size: %u\n", count);
482  TEST_MSG_ALWAYS("alloc: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_alloc, start_alloc)));
483  TEST_MSG_ALWAYS("insert: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_insert, start_insert)));
484  TEST_MSG_ALWAYS("pop-first: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop_first, start_pop)));
485  TEST_MSG_ALWAYS("pop: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop, start_pop)));
486 
488  }
489 
490  talloc_free(values);
491 }
492 
493 static void queue_cmp_10(void)
494 {
495  queue_cmp(10);
496 }
497 
498 static void queue_cmp_50(void)
499 {
500  queue_cmp(50);
501 }
502 
503 static void queue_cmp_100(void)
504 {
505  queue_cmp(100);
506 }
507 
508 static void queue_cmp_1000(void)
509 {
510  queue_cmp(1000);
511 }
512 
513 static void minmax_heap_cycle(void)
514 {
515  fr_minmax_heap_t *hp;
516  int i;
518  int to_remove;
519  int inserted, removed;
520  int ret;
521  fr_time_t start_insert, start_remove, start_swap, end;
522  fr_fast_rand_t rand_ctx;
523 
524  rand_ctx.a = fr_rand();
525  rand_ctx.b = fr_rand();
526 
528  TEST_CHECK(hp != NULL);
529 
531 
532  /*
533  * Initialise random values
534  */
535  for (i = 0; i < MINMAX_HEAP_CYCLE_SIZE; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
536 
537  start_insert = fr_time();
538  TEST_CASE("insertions");
539  for (i = 0; i < MINMAX_HEAP_CYCLE_SIZE; i++) {
540  TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
541  TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
542  }
544 
545  TEST_CASE("pop");
546 
547  /*
548  * Remove a random number of elements from the heap
549  */
550  to_remove = fr_minmax_heap_num_elements(hp) / 2;
551  start_remove = fr_time();
552  for (i = 0; i < to_remove; i++) {
554 
555  TEST_CHECK((t = fr_minmax_heap_min_peek(hp)) != NULL);
556  TEST_MSG("expected %i elements remaining in the heap", to_remove - i);
557 
558  TEST_CHECK(fr_minmax_heap_extract(hp, t) >= 0);
559  TEST_MSG("failed extracting %i - %s", i, fr_strerror());
560  }
561 
562  /*
563  * Now swap the inserted and removed set creating churn
564  */
565  start_swap = fr_time();
566  inserted = 0;
567  removed = 0;
568 
569  for (i = 0; i < MINMAX_HEAP_CYCLE_SIZE; i++) {
570  if (!fr_minmax_heap_entry_inserted(array[i].idx)) {
571  TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
572  TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
573  inserted++;
574  } else {
575  TEST_CHECK((ret = fr_minmax_heap_extract(hp, &array[i])) >= 0);
576  TEST_MSG("element %i removal failed, returned %i - %s", i, ret, fr_strerror());
577  removed++;
578  }
579  }
580 
581  TEST_CHECK(removed == (MINMAX_HEAP_CYCLE_SIZE - to_remove));
582  TEST_MSG("expected %i", MINMAX_HEAP_CYCLE_SIZE - to_remove);
583  TEST_MSG("got %i", removed);
584 
585  TEST_CHECK(inserted == to_remove);
586  TEST_MSG("expected %i", to_remove);
587  TEST_MSG("got %i", inserted);
588 
589  end = fr_time();
590 
591  TEST_MSG_ALWAYS("\ncycle size: %d\n", MINMAX_HEAP_CYCLE_SIZE);
592  TEST_MSG_ALWAYS("insert: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(start_remove, start_insert)));
593  TEST_MSG_ALWAYS("extract: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(start_swap, start_remove)));
594  TEST_MSG_ALWAYS("swap: %"PRIu64" μs\n", fr_time_delta_to_usec(fr_time_sub(end, start_swap)));
595 
596  talloc_free(hp);
597  free(array);
598 }
599 
600 static void minmax_heap_iter(void)
601 {
602  fr_minmax_heap_t *hp;
604  minmax_heap_thing values[NVALUES], *data;
605  unsigned int total;
606 
608  TEST_CHECK(hp != NULL);
609 
610  populate_values(values, NUM_ELEMENTS(values));
611 
612  for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++) fr_minmax_heap_insert(hp, &values[i]);
613 
615 
616  for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++, data = fr_minmax_heap_iter_next(hp, &iter)) {
617  TEST_CHECK(data != NULL);
618  TEST_CHECK(!data->visited);
619  TEST_CHECK(data->idx > 0);
620  data->visited = true;
621  }
622 
623  TEST_CHECK(data == NULL);
624 
625  total = 0;
627  total += item->data;
628  }}
629  TEST_CHECK(total = 190);
630 
632 }
633 
635  /*
636  * Basic tests
637  */
638  { "minmax_heap_test_basic", minmax_heap_test_basic },
639  { "minmax_heap_test_skip_0", minmax_heap_test_skip_0 },
640  { "minmax_heap_test_skip_2", minmax_heap_test_skip_2 },
641  { "minmax_heap_test_skip_10", minmax_heap_test_skip_10 },
642  { "minmax_heap_test_order", minmax_heap_test_order },
643  { "minmax_heap_burn_in", minmax_heap_burn_in },
644  { "minmax_heap_cycle", minmax_heap_cycle },
645  { "minmax_heap_iter", minmax_heap_iter },
646  { "queue_cmp_10", queue_cmp_10 },
647  { "queue_cmp_50", queue_cmp_50 },
648  { "queue_cmp_100", queue_cmp_100 },
649  { "queue_cmp_1000", queue_cmp_1000 },
650  { NULL }
651 };
652 
#define TEST_MSG_ALWAYS(...)
Definition: acutest.h:222
#define TEST_CASE(name)
Definition: acutest.h:184
#define TEST_MSG(...)
Definition: acutest.h:215
#define CMP_PREFER_SMALLER(_a, _b)
Evaluates to +1 for a > b, and -1 for a < b.
Definition: build.h:102
#define NUM_ELEMENTS(_t)
Definition: build.h:335
fr_dcursor_iter_t iter
Definition: dcursor.h:147
return item
Definition: dcursor.h:553
Test enumeration values.
Definition: dict_test.h:92
void * fr_heap_pop(fr_heap_t **hp)
Remove a node from the heap.
Definition: heap.c:322
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition: heap.c:146
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
Definition: heap.h:100
The main heap structure.
Definition: heap.h:66
free(array)
#define is_power_of_2(_n)
Definition: lst.c:50
static size_t array[MY_ARRAY_SIZE]
Functions for a minmax heap.
int fr_minmax_heap_insert(fr_minmax_heap_t *hp, void *data)
Definition: minmax_heap.c:424
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
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
void * fr_minmax_heap_max_peek(fr_minmax_heap_t *hp)
Definition: minmax_heap.c:466
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
int fr_minmax_heap_extract(fr_minmax_heap_t *hp, void *data)
Definition: minmax_heap.c:486
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
unsigned int num_elements
Number of nodes used.
Definition: minmax_heap.c:57
#define FR_MINMAX_HEAP_VERIFY(_hp)
Definition: minmax_heap.h:131
#define fr_minmax_heap_foreach(_hp, _type, _data)
Iterate over the contents of a minmax_heap.
Definition: minmax_heap.h:124
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
#define fr_minmax_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a minmax heap that can be used with non-talloced elements.
Definition: minmax_heap.h:70
unsigned int fr_minmax_heap_index_t
Definition: minmax_heap.h:37
static void queue_cmp_100(void)
static void queue_cmp(unsigned int count)
Benchmarks for minmax heaps vs heaps when used as queues.
#define MINMAX_HEAP_TEST_SIZE
static bool minmax_heap_contains(fr_minmax_heap_t *hp, void *data)
TEST_CHECK(total=190)
#define NVALUES
#define MINMAX_HEAP_CYCLE_SIZE
#define BURN_IN_OPS
static void queue_cmp_50(void)
static void minmax_heap_test_order(void)
static void minmax_heap_test_skip_2(void)
fr_minmax_heap_index_t idx
static minmax_heap_thing * array_pop(minmax_heap_thing **array, unsigned int count)
static void minmax_heap_test_skip_0(void)
static void minmax_heap_cycle(void)
static void queue_cmp_1000(void)
static void queue_cmp_10(void)
static void minmax_heap_test_skip_10(void)
static void minmax_heap_test(int skip)
static void minmax_heap_test_basic(void)
static void minmax_heap_burn_in(void)
static void populate_values(minmax_heap_thing values[], unsigned int len)
talloc_free(hp)
static int8_t minmax_heap_cmp(void const *one, void const *two)
static void minmax_heap_iter(void)
uint32_t fr_fast_rand(fr_fast_rand_t *ctx)
Definition: rand.c:280
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
uint32_t b
Definition: rand.h:55
uint32_t a
Definition: rand.h:55
Smaller fast random number generator.
Definition: rand.h:54
return count
Definition: module.c:163
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
#define fr_time_min()
Definition: time.h:144
#define fr_time_wrap(_time)
Definition: time.h:145
static int64_t fr_time_delta_to_usec(fr_time_delta_t delta)
Definition: time.h:632
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition: time.h:229
"server local" time.
Definition: time.h:69
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
static fr_slen_t data
Definition: value.h:1265