The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
minmax_heap_tests.c
Go to the documentation of this file.
1#include "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
8typedef 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
23static fr_cmp_ret_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 */
38static 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
53static 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
78static void minmax_heap_test_basic(void)
79{
80 unsigned int i;
83
85 TEST_CHECK(hp != NULL);
86
87 populate_values(values, NVALUES);
88
89 /*
90 * minmax heaps can get the minimum value...
91 */
92 for (i = 0; i < NVALUES; i++) {
93 TEST_CHECK(fr_minmax_heap_insert(hp, &values[i]) >= 0);
95 }
96
97 for (i = 0; i < NVALUES; i++) {
99
100 fr_minmax_heap_min_pop((void **)&value, hp);
101 TEST_CHECK(value != NULL);
103 TEST_CHECK(value->data == i);
104 TEST_MSG("iteration %u, popped %u", i, value->data);
105 }
106
107 /*
108 * ...or the maximum value.
109 */
110 for (i = 0; i < NVALUES; i++) {
111 TEST_CHECK(fr_minmax_heap_insert(hp, &values[i]) >= 0);
113 }
114
115 for (i = NVALUES; i-- > 0; ) {
117
118 fr_minmax_heap_max_pop((void **)&value, hp);
119 TEST_CHECK(value != NULL);
121 TEST_CHECK(value->data == i);
122 TEST_MSG("iteration %u, popped %u", NVALUES - 1 - i, value->data);
123 }
124
125 talloc_free(hp);
126}
127
128#define MINMAX_HEAP_TEST_SIZE (4096)
129
130static void minmax_heap_test(int skip)
131{
133 int i;
134 minmax_heap_thing *array;
135 int left;
136 int ret;
137 fr_fast_rand_t rand_ctx;
138
139 rand_ctx.a = fr_rand();
140 rand_ctx.b = fr_rand();
141
143 TEST_CHECK(hp != NULL);
144
145 array = talloc_zero_array(hp, minmax_heap_thing, MINMAX_HEAP_TEST_SIZE);
146
147 /*
148 * Initialise random values
149 */
150 for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
151
152 TEST_CASE("insertions");
153 for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) {
155 TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
156 TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
157
158 TEST_CHECK(minmax_heap_contains(hp, &array[i]));
159 TEST_MSG("element %i inserted but not in heap", i);
160 }
161
162 TEST_CASE("deletions");
163 {
164 int entry;
165
166 for (i = 0; i < MINMAX_HEAP_TEST_SIZE / skip; i++) {
167 entry = i * skip;
168
170 TEST_CHECK(array[entry].idx != 0);
171 TEST_MSG("element %i removed out of order", entry);
172
173 TEST_CHECK((ret = fr_minmax_heap_extract(hp, &array[entry])) >= 0);
174 TEST_MSG("element %i removal failed, returned %i - %s", entry, ret, fr_strerror());
175
176 TEST_CHECK(!minmax_heap_contains(hp, &array[entry]));
177 TEST_MSG("element %i removed but still in heap", entry);
178
179 TEST_CHECK(array[entry].idx == 0);
180 TEST_MSG("element %i removed out of order", entry);
181 }
182 }
183
185 for (i = 0; i < left; i++) {
187
189 TEST_CHECK((t = fr_minmax_heap_min_peek(hp)) != NULL);
190 TEST_MSG("expected %i elements remaining in the heap", left - i);
191
193 TEST_MSG("failed extracting %i", i);
194 }
195
196 TEST_CHECK((ret = fr_minmax_heap_num_elements(hp)) == 0);
197 TEST_MSG("%i elements remaining", ret);
198
199 talloc_free(hp);
200}
201
202/*
203 * minmax heaps can do anything heaps can do, so let's make sure we have
204 * a (proper!) superset of the heap tests.
205 */
206
207static void minmax_heap_test_skip_0(void)
208{
210}
211
212static void minmax_heap_test_skip_2(void)
213{
215}
216
218{
220}
221
222#define BURN_IN_OPS (10000000)
223
224static void minmax_heap_burn_in(void)
225{
226 fr_minmax_heap_t *hp = NULL;
227 minmax_heap_thing *array = NULL;
228 fr_fast_rand_t rand_ctx;
229 int insert_count = 0;
230
231 rand_ctx.a = fr_rand();
232 rand_ctx.b = fr_rand();
233
234 array = calloc(BURN_IN_OPS, sizeof(minmax_heap_thing));
235 for (unsigned int i = 0; i < BURN_IN_OPS; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
236
238 TEST_CHECK(hp != NULL);
239
240 for (unsigned int i = 0; i < BURN_IN_OPS; i++) {
241 minmax_heap_thing *ret_thing = NULL;
242 int ret_insert = -1;
243
244 if (fr_minmax_heap_num_elements(hp) == 0) {
245 insert:
246 TEST_CHECK((ret_insert = fr_minmax_heap_insert(hp, &array[insert_count])) >= 0);
247 insert_count++;
248 } else {
249 switch (fr_fast_rand(&rand_ctx) % 5) {
250 case 0: /* insert */
251 goto insert;
252
253 case 1: /* min pop */
254 fr_minmax_heap_min_pop((void **)&ret_thing, hp);
255 TEST_CHECK(ret_thing != NULL);
256 break;
257 case 2: /* min peek */
258 ret_thing = fr_minmax_heap_min_peek(hp);
259 TEST_CHECK(ret_thing != NULL);
260 break;
261 case 3: /* max pop */
262 fr_minmax_heap_max_pop((void **)&ret_thing, hp);
263 TEST_CHECK(ret_thing != NULL);
264 break;
265 case 4: /* max peek */
266 fr_minmax_heap_max_peek((void **)&ret_thing, hp);
267 TEST_CHECK(ret_thing != NULL);
268 break;
269 }
270 }
271 }
272
273 talloc_free(hp);
274 free(array);
275}
276
277#define MINMAX_HEAP_CYCLE_SIZE (1600000)
278
279static void minmax_heap_test_order(void)
280{
282 int i;
283 minmax_heap_thing *array;
284 minmax_heap_thing *thing, *prev = NULL;
285 unsigned int data;
286 unsigned int count;
287 int ret;
288 fr_fast_rand_t rand_ctx;
289
290 rand_ctx.a = fr_rand();
291 rand_ctx.b = fr_rand();
292
294 TEST_CHECK(hp != NULL);
295
296 array = talloc_zero_array(hp, minmax_heap_thing, MINMAX_HEAP_TEST_SIZE);
297
298 /*
299 * Initialise random values
300 */
301 for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
302
303 TEST_CASE("insertions for min");
304 for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) {
305 TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
306 TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
307
308 TEST_CHECK(minmax_heap_contains(hp, &array[i]));
309 TEST_MSG("element %i inserted but not in heap", i);
310 }
311
312 TEST_CASE("min ordering");
313
314 count = 0;
315 data = 0;
316 prev = NULL;
317 while ((fr_minmax_heap_min_pop((void **)&thing, hp) == 0) && thing) {
318 TEST_CHECK(thing->data >= data);
319 TEST_MSG("Expected data >= %u, got %u", data, thing->data);
320 if (thing->data >= data) data = thing->data;
321 TEST_CHECK(thing != prev);
322 prev = thing;
323 count++;
324 }
325
327
328 TEST_CASE("insertions for max");
329 for (i = 0; i < MINMAX_HEAP_TEST_SIZE; i++) {
330 TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
331 TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
332
333 TEST_CHECK(minmax_heap_contains(hp, &array[i]));
334 TEST_MSG("element %i inserted but not in heap", i);
335 }
336
337 TEST_CASE("max ordering");
338
339 count = 0;
340 data = UINT_MAX;
341 prev = NULL;
342 while ((fr_minmax_heap_max_pop((void **)&thing, hp) == 0) && thing) {
343 TEST_CHECK(thing->data <= data);
344 TEST_MSG("Expected data >= %u, got %u", data, thing->data);
345 if (thing->data <= data) data = thing->data;
346 TEST_CHECK(thing != prev);
347 prev = thing;
348 count++;
349 }
350
352
353 talloc_free(hp);
354}
355
356static CC_HINT(noinline) minmax_heap_thing *array_pop(minmax_heap_thing **array, unsigned int count)
357{
358 minmax_heap_thing *low = NULL;
359 unsigned int idx = 0;
360
361 for (unsigned int j = 0; j < count; j++) {
362 if (!array[j]) continue;
363
364 if (!low || (minmax_heap_cmp(array[j], low) < 0)) {
365 idx = j;
366 low = array[j];
367 }
368 }
369 if (low) array[idx] = NULL;
370
371 return low;
372}
373
374/** Benchmarks for minmax heaps vs heaps when used as queues
375 *
376 */
377static void queue_cmp(unsigned int count)
378{
379 fr_minmax_heap_t *minmax;
380 fr_heap_t *hp;
381
382 minmax_heap_thing *values;
383
384 unsigned int i;
385
386 values = talloc_array(NULL, minmax_heap_thing, count);
387
388 /*
389 * Check times for minmax heap alloc, insert, pop
390 */
391 {
392 fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first = fr_time_wrap(0);
393
394 populate_values(values, count);
395
396 start_alloc = fr_time();
398 end_alloc = fr_time();
399 TEST_CHECK(minmax != NULL);
400
401 start_insert = fr_time();
402 for (i = 0; i < count; i++) (void) fr_minmax_heap_insert(minmax, &values[i]);
403 end_insert = fr_time();
404
405 start_pop = fr_time();
406 for (i = 0; i < count; i++) {
407 void *popped;
408
409 fr_minmax_heap_min_pop(&popped, minmax);
410 TEST_CHECK(popped != NULL);
411 if (i == 0) end_pop_first = fr_time();
412
413 TEST_MSG("expected %u elements remaining in the minmax heap", count - i);
414 TEST_MSG("failed extracting %u", i);
415 }
416 end_pop = fr_time();
417
418 TEST_MSG_ALWAYS("\nminmax heap size: %u\n", count);
419 TEST_MSG_ALWAYS("alloc: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_alloc, start_alloc)));
420 TEST_MSG_ALWAYS("insert: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_insert, start_insert)));
421 TEST_MSG_ALWAYS("pop-first: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop_first, start_pop)));
422 TEST_MSG_ALWAYS("pop: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop, start_pop)));
423 talloc_free(minmax);
424 }
425
426 /*
427 * Check times for heap alloc, insert, pop
428 */
429 {
430 fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first = fr_time_min();
431
432 populate_values(values, count);
433
434 start_alloc = fr_time();
436 end_alloc = fr_time();
437 TEST_CHECK(hp != NULL);
438
439 start_insert = fr_time();
440 for (i = 0; i < count; i++) fr_heap_insert(&hp, &values[i]);
441 end_insert = fr_time();
442
443 start_pop = fr_time();
444 for (i = 0; i < count; i++) {
445 void *popped;
446
447 fr_heap_pop(&popped, &hp);
448 TEST_CHECK(popped != NULL);
449 if (i == 0) end_pop_first = fr_time();
450
451 TEST_MSG("expected %u elements remaining in the heap", count - i);
452 TEST_MSG("failed extracting %u", i);
453 }
454 end_pop = fr_time();
455
456 TEST_MSG_ALWAYS("\nheap size: %u\n", count);
457 TEST_MSG_ALWAYS("alloc: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_alloc, start_alloc)));
458 TEST_MSG_ALWAYS("insert: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_insert, start_insert)));
459 TEST_MSG_ALWAYS("pop-first: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop_first, start_pop)));
460 TEST_MSG_ALWAYS("pop: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop, start_pop)));
461
462 talloc_free(hp);
463 }
464
465 /*
466 * Array
467 */
468 {
469 minmax_heap_thing **array;
470 fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first;
471
472 populate_values(values, count);
473 end_pop_first = fr_time_min();
474
475 start_alloc = fr_time();
476 array = talloc_array(NULL, minmax_heap_thing *, count);
477 end_alloc = fr_time();
478
479 start_insert = fr_time();
480 for (i = 0; i < count; i++) array[i] = &values[i];
481 end_insert = fr_time();
482
483 start_pop = fr_time();
484 for (i = 0; i < count; i++) {
485 TEST_CHECK(array_pop(array, count) != NULL);
486 if (i == 0) end_pop_first = fr_time();
487 }
488 end_pop = fr_time();
489
490 TEST_MSG_ALWAYS("\narray size: %u\n", count);
491 TEST_MSG_ALWAYS("alloc: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_alloc, start_alloc)));
492 TEST_MSG_ALWAYS("insert: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_insert, start_insert)));
493 TEST_MSG_ALWAYS("pop-first: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop_first, start_pop)));
494 TEST_MSG_ALWAYS("pop: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end_pop, start_pop)));
495
496 talloc_free(array);
497 }
498
499 talloc_free(values);
500}
501
502static void queue_cmp_10(void)
503{
504 queue_cmp(10);
505}
506
507static void queue_cmp_50(void)
508{
509 queue_cmp(50);
510}
511
512static void queue_cmp_100(void)
513{
514 queue_cmp(100);
515}
516
517static void queue_cmp_1000(void)
518{
519 queue_cmp(1000);
520}
521
522static void minmax_heap_cycle(void)
523{
525 int i;
526 minmax_heap_thing *array;
527 int to_remove;
528 int inserted, removed;
529 int ret;
530 fr_time_t start_insert, start_remove, start_swap, end;
531 fr_fast_rand_t rand_ctx;
532
533 rand_ctx.a = fr_rand();
534 rand_ctx.b = fr_rand();
535
537 TEST_CHECK(hp != NULL);
538
539 array = calloc(MINMAX_HEAP_CYCLE_SIZE, sizeof(minmax_heap_thing));
540
541 /*
542 * Initialise random values
543 */
544 for (i = 0; i < MINMAX_HEAP_CYCLE_SIZE; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
545
546 start_insert = fr_time();
547 TEST_CASE("insertions");
548 for (i = 0; i < MINMAX_HEAP_CYCLE_SIZE; i++) {
549 TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
550 TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
551 }
553
554 TEST_CASE("pop");
555
556 /*
557 * Remove a random number of elements from the heap
558 */
559 to_remove = fr_minmax_heap_num_elements(hp) / 2;
560 start_remove = fr_time();
561 for (i = 0; i < to_remove; i++) {
563
564 TEST_CHECK((t = fr_minmax_heap_min_peek(hp)) != NULL);
565 TEST_MSG("expected %i elements remaining in the heap", to_remove - i);
566
568 TEST_MSG("failed extracting %i - %s", i, fr_strerror());
569 }
570
571 /*
572 * Now swap the inserted and removed set creating churn
573 */
574 start_swap = fr_time();
575 inserted = 0;
576 removed = 0;
577
578 for (i = 0; i < MINMAX_HEAP_CYCLE_SIZE; i++) {
579 if (!fr_minmax_heap_entry_inserted(array[i].idx)) {
580 TEST_CHECK((ret = fr_minmax_heap_insert(hp, &array[i])) >= 0);
581 TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
582 inserted++;
583 } else {
584 TEST_CHECK((ret = fr_minmax_heap_extract(hp, &array[i])) >= 0);
585 TEST_MSG("element %i removal failed, returned %i - %s", i, ret, fr_strerror());
586 removed++;
587 }
588 }
589
590 TEST_CHECK(removed == (MINMAX_HEAP_CYCLE_SIZE - to_remove));
591 TEST_MSG("expected %i", MINMAX_HEAP_CYCLE_SIZE - to_remove);
592 TEST_MSG("got %i", removed);
593
594 TEST_CHECK(inserted == to_remove);
595 TEST_MSG("expected %i", to_remove);
596 TEST_MSG("got %i", inserted);
597
598 end = fr_time();
599
600 TEST_MSG_ALWAYS("\ncycle size: %d\n", MINMAX_HEAP_CYCLE_SIZE);
601 TEST_MSG_ALWAYS("insert: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(start_remove, start_insert)));
602 TEST_MSG_ALWAYS("extract: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(start_swap, start_remove)));
603 TEST_MSG_ALWAYS("swap: %"PRId64" μs\n", fr_time_delta_to_usec(fr_time_sub(end, start_swap)));
604
605 talloc_free(hp);
606 free(array);
607}
608
609static void minmax_heap_iter(void)
610{
614 unsigned int total;
615
617 TEST_CHECK(hp != NULL);
618
619 populate_values(values, NUM_ELEMENTS(values));
620
621 for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++) (void) fr_minmax_heap_insert(hp, &values[i]);
622
623 data = fr_minmax_heap_iter_init(hp, &iter);
624
625 for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++, data = fr_minmax_heap_iter_next(hp, &iter)) {
626 TEST_CHECK(data != NULL);
627 TEST_CHECK(!data->visited);
628 TEST_CHECK(data->idx > 0);
629 data->visited = true;
630 }
631
632 TEST_CHECK(data == NULL);
633
634 total = 0;
636 total += item->data;
637 }}
638 TEST_CHECK(total == 190);
639
641}
642
643static bool poisoned;
644
645static fr_cmp_ret_t minmax_heap_poison_cmp(void const *one, void const *two)
646{
647 if (poisoned) {
648 fr_strerror_const("Poisoned comparator");
649 return CMP_ERR;
650 }
651
652 return minmax_heap_cmp(one, two);
653}
654
655/*
656 * A comparator returning CMP_ERR must complete the operation
657 * structurally (no lost or duplicated elements), report the error
658 * through the int return, and leave the ordering undefined
659 * until the offending element is removed.
660 */
662{
664 minmax_heap_thing values[8] = {};
665 void *found;
666 size_t i;
667 unsigned int popped;
668
669 TEST_CASE("comparator error reported, heap structurally intact");
671 TEST_ASSERT(hp != NULL);
672
673 poisoned = false;
674 for (i = 0; i < NUM_ELEMENTS(values); i++) {
675 values[i].data = NUM_ELEMENTS(values) - i;
676 TEST_CHECK(fr_minmax_heap_insert(hp, &values[i]) == 0);
677 }
678
679 poisoned = true;
680
681 TEST_CHECK(fr_minmax_heap_min_pop(&found, hp) == -1);
682 TEST_CHECK(found == NULL);
684
685 TEST_CHECK(fr_minmax_heap_max_peek(&found, hp) == -1);
686 TEST_CHECK(found == NULL);
687
688 /*
689 * Once the comparator recovers, every remaining element pops
690 * back out exactly once.
691 */
692 poisoned = false;
693 popped = 0;
694 while ((fr_minmax_heap_min_pop(&found, hp) == 0) && found) {
695 popped++;
696 }
697 TEST_CHECK(popped == NUM_ELEMENTS(values) - 1);
699
700 talloc_free(hp);
701}
702
704 /*
705 * Basic tests
706 */
707 { "minmax_heap_test_basic", minmax_heap_test_basic },
708 { "minmax_heap_test_cmp_err", minmax_heap_test_cmp_err },
709 { "minmax_heap_test_skip_0", minmax_heap_test_skip_0 },
710 { "minmax_heap_test_skip_2", minmax_heap_test_skip_2 },
711 { "minmax_heap_test_skip_10", minmax_heap_test_skip_10 },
712 { "minmax_heap_test_order", minmax_heap_test_order },
713 { "minmax_heap_burn_in", minmax_heap_burn_in },
714 { "minmax_heap_cycle", minmax_heap_cycle },
715 { "minmax_heap_iter", minmax_heap_iter },
716 { "queue_cmp_10", queue_cmp_10 },
717 { "queue_cmp_50", queue_cmp_50 },
718 { "queue_cmp_100", queue_cmp_100 },
719 { "queue_cmp_1000", queue_cmp_1000 },
721};
722
#define TEST_MSG_ALWAYS(...)
Definition acutest.h:224
#define TEST_CHECK(cond)
Definition acutest.h:87
#define TEST_CASE(name)
Definition acutest.h:186
#define TEST_ASSERT(cond)
Definition acutest.h:110
#define TEST_TERMINATOR
Definition acutest.h:64
#define TEST_MSG(...)
Definition acutest.h:217
#define CMP_PREFER_SMALLER(_a, _b)
Evaluates to +1 for a > b, and -1 for a < b.
Definition build.h:105
#define NUM_ELEMENTS(_t)
Definition build.h:406
Test enumeration values.
Definition dict_test.h:92
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition heap.c:149
int fr_heap_pop(void **out, fr_heap_t **hp)
Remove a node from the heap.
Definition heap.c:359
#define fr_heap_alloc(_ctx, _cmp, _type, _field, _init)
Creates a heap that can be used with non-talloced elements.
Definition heap.h:102
The main heap structure.
Definition heap.h:68
free(array)
#define fr_time()
Definition event.c:60
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
Definition lst.c:121
#define is_power_of_2(_n)
Definition lst.c:49
int fr_minmax_heap_insert(fr_minmax_heap_t *hp, void *data)
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.
int fr_minmax_heap_min_pop(void **out, fr_minmax_heap_t *hp)
void * p[]
Array of nodes.
Definition minmax_heap.c:62
int fr_minmax_heap_max_pop(void **out, fr_minmax_heap_t *hp)
void * fr_minmax_heap_min_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.
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)
int fr_minmax_heap_max_peek(void **out, fr_minmax_heap_t *hp)
unsigned int num_elements
Number of nodes used.
Definition minmax_heap.c:57
#define FR_MINMAX_HEAP_VERIFY(_hp)
#define fr_minmax_heap_foreach(_hp, _type, _data)
Iterate over the contents of a minmax_heap.
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:95
unsigned int fr_minmax_heap_iter_t
Definition minmax_heap.h:39
#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:72
unsigned int fr_minmax_heap_index_t
Definition minmax_heap.h:38
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)
#define NVALUES
#define MINMAX_HEAP_CYCLE_SIZE
#define BURN_IN_OPS
static void minmax_heap_test_cmp_err(void)
static void queue_cmp_50(void)
static void minmax_heap_test_order(void)
static void minmax_heap_test_skip_2(void)
static fr_cmp_ret_t minmax_heap_cmp(void const *one, void const *two)
fr_minmax_heap_index_t idx
static void minmax_heap_test_skip_0(void)
static void minmax_heap_cycle(void)
static bool poisoned
static fr_cmp_ret_t minmax_heap_poison_cmp(void const *one, void const *two)
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)
static minmax_heap_thing * array_pop(minmax_heap_thing **array, unsigned int count)
talloc_free(hp)
static void minmax_heap_iter(void)
fr_cmp_ret_t
Result of an ordering comparison.
Definition misc.h:50
@ CMP_ERR
comparison failed
Definition misc.h:51
uint32_t fr_fast_rand(fr_fast_rand_t *ctx)
Definition rand.c:278
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:104
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:155
#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:558
#define fr_strerror_const(_msg)
Definition strerror.h:223
static fr_slen_t data
Definition value.h:1340