The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
lst_tests.c
Go to the documentation of this file.
1#include "acutest.h"
2#include"acutest_helpers.h"
3#include <freeradius-devel/util/rand.h>
4#include <freeradius-devel/util/time.h>
5#include <freeradius-devel/util/heap.h>
6
7/*
8 * This counterintuitive #include gives these separately-compiled tests
9 * access to fr_lst_t internals that lst.h doesn't reveal
10 * to those who #include it.
11 */
12#include "../lst.c"
13
14typedef struct {
15 unsigned int data;
17 bool visited; /* Only used by iterator test */
18} lst_thing;
19
20#if 0
21static void lst_validate(fr_lst_t *lst);
22#endif
23
24static bool fr_lst_contains(fr_lst_t *lst, void *data)
25{
26 unsigned int size = fr_lst_num_elements(lst);
27
28 for (unsigned int i = 0; i < size; i++) if (item(lst, i + lst->idx) == data) return true;
29
30 return false;
31}
32
33static fr_cmp_ret_t lst_cmp(void const *one, void const *two)
34{
35 lst_thing const *item1 = one, *item2 = two;
36
37 return CMP(item1->data, item2->data);
38}
39
40static void populate_values(lst_thing values[], unsigned int len)
41{
42 unsigned int i;
43 fr_fast_rand_t rand_ctx;
44
45 for (i = 0; i < len; i++) {
46 values[i].data = i;
47 values[i].idx = 0;
48 values[i].visited = false;
49 }
50
51 /* shuffle values before insertion, so the heap has to work to give them back in order */
52 rand_ctx.a = fr_rand();
53 rand_ctx.b = fr_rand();
54
55 for (i = 0; i < len; i++) {
56 unsigned int j = fr_fast_rand(&rand_ctx) % len;
57 int temp = values[i].data;
58
59 values[i].data = values[j].data;
60 values[j].data = temp;
61 }
62}
63
64#define NVALUES 20
65static void lst_test_basic(void)
66{
67 fr_lst_t *lst;
68 lst_thing values[NVALUES];
69
70 lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, NVALUES);
71 TEST_ASSERT(lst != NULL);
72
73 populate_values(values, NUM_ELEMENTS(values));
74
75 for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++) {
76 TEST_CHECK(fr_lst_insert(lst, &values[i]) >= 0);
77 TEST_CHECK(fr_lst_entry_inserted(values[i].idx));
78 }
79
80 for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++) {
82
83 fr_lst_pop((void **)&value, lst);
84 TEST_CHECK(value != NULL);
86 TEST_CHECK(value->data == i);
87 TEST_MSG("iteration %u, popped %u", i, value->data);
88 }
89 talloc_free(lst);
90}
91
92#define LST_TEST_SIZE (4096)
93
94static void lst_test(int skip)
95{
96 fr_lst_t *lst;
97 int i;
98 lst_thing *values;
99 int left;
100 int ret;
101
102 lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
103 TEST_ASSERT(lst != NULL);
104
105 values = calloc(LST_TEST_SIZE, sizeof(lst_thing));
106
107 /*
108 * Initialise random values
109 */
111
112 TEST_CASE("insertions");
113 for (i = 0; i < LST_TEST_SIZE; i++) {
114 FR_LST_VERIFY(lst);
115 TEST_CHECK((ret = fr_lst_insert(lst, &values[i])) >= 0);
116 TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
117
118 TEST_CHECK(fr_lst_contains(lst, &values[i]));
119 TEST_MSG("element %i inserted but not in LST", i);
120 }
121
122 TEST_CASE("deletions");
123 for (int entry = 0; entry < LST_TEST_SIZE; entry += skip) {
124 FR_LST_VERIFY(lst);
125 TEST_CHECK(values[entry].idx != 0);
126 TEST_MSG("element %i removed out of order", entry);
127
128 TEST_CHECK((ret = fr_lst_extract(lst, &values[entry])) >= 0);
129 TEST_MSG("element %i removal failed, returned %i", entry, ret);
130
131 TEST_CHECK(!fr_lst_contains(lst, &values[entry]));
132 TEST_MSG("element %i removed but still in LST", entry);
133
134 TEST_CHECK(values[entry].idx == 0);
135 TEST_MSG("element %i removed out of order", entry);
136 }
137
138 left = fr_lst_num_elements(lst);
139 for (i = 0; i < left; i++) {
140 void *popped;
141
142 FR_LST_VERIFY(lst);
143 fr_lst_pop(&popped, lst);
144 TEST_CHECK(popped != NULL);
145 TEST_MSG("expected %i elements remaining in the lst", left - i);
146 TEST_MSG("failed extracting %i", i);
147 }
148
149 TEST_CHECK((ret = fr_lst_num_elements(lst)) == 0);
150 TEST_MSG("%i elements remaining", ret);
151
152 talloc_free(lst);
153 free(values);
154}
155
156static void lst_test_skip_1(void)
157{
158 lst_test(1);
159}
160
161static void lst_test_skip_2(void)
162{
163 lst_test(2);
164}
165
166static void lst_test_skip_10(void)
167{
168 lst_test(10);
169}
170
171
172static void lst_stress_realloc(void)
173{
174 fr_lst_t *lst;
175 fr_heap_t *hp;
176 lst_thing *lst_array, *hp_array;
177 fr_fast_rand_t rand_ctx;
178 int ret;
179 lst_thing *from_lst, *from_hp;
180
181 rand_ctx.a = fr_rand();
182 rand_ctx.b = fr_rand();
183
184 lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
185 TEST_ASSERT(lst != NULL);
186 hp = fr_heap_alloc(NULL, lst_cmp, lst_thing, idx, 0);
187 TEST_ASSERT(hp != NULL);
188
189 lst_array = calloc(2 * INITIAL_CAPACITY, sizeof(lst_thing));
190 hp_array = calloc(2 * INITIAL_CAPACITY, sizeof(lst_thing));
191
192 /*
193 * Initialise random values
194 */
195 for (unsigned int i = 0; i < 2 * INITIAL_CAPACITY; i++) {
196 lst_array[i].data = hp_array[i].data = fr_fast_rand(&rand_ctx) % 65537;
197 }
198
199 /* Add the first INITIAL_CAPACITY values to lst and to hp */
200 TEST_CASE("partial fill");
201 for (int i = 0; i < INITIAL_CAPACITY; i++) {
202 TEST_CHECK((ret = fr_lst_insert(lst, &lst_array[i])) >= 0);
203 TEST_MSG("lst insert failed, iteration %d; returned %i - %s", i, ret, fr_strerror());
204 TEST_CHECK((ret = fr_heap_insert(&hp, &hp_array[i])) >= 0);
205 TEST_MSG("heap insert failed, iteration %d; returned %i - %s", i, ret, fr_strerror());
206 }
207
208 /* Pop INITIAL_CAPACITY / 2 values from each (they should all be equal) */
209 TEST_CASE("partial pop");
210 for (unsigned int i = 0; i < INITIAL_CAPACITY / 2; i++) {
211 fr_lst_pop((void **)&from_lst, lst);
212 TEST_CHECK(from_lst != NULL);
213 fr_heap_pop((void **)&from_hp, &hp);
214 TEST_CHECK(from_hp != NULL);
215 TEST_CHECK(lst_cmp(from_lst, from_hp) == 0);
216 }
217
218 /*
219 * Add the second INITIAL_CAPACITY values to lst and to hp.
220 * This should force lst to move entries to maintain adjacency,
221 * which is what we're testing here.
222 */
223 TEST_CASE("force move with expansion");
224 for (unsigned int i = INITIAL_CAPACITY; i < 2 * INITIAL_CAPACITY; i++) {
225 TEST_CHECK((ret = fr_lst_insert(lst, &lst_array[i])) >= 0);
226 TEST_MSG("lst insert failed, iteration %u; returned %i - %s", i, ret, fr_strerror());
227 TEST_CHECK((ret = fr_heap_insert(&hp, &hp_array[i])) >= 0);
228 TEST_MSG("heap insert failed, iteration %u; returned %i - %s", i, ret, fr_strerror());
229 }
230
231 /* pop the remaining 3 * INITIAL_CAPACITY / 2 values from each (they should all be equal) */
232 TEST_CASE("complete pop");
233 for (unsigned int i = 0; i < 3 * INITIAL_CAPACITY / 2; i++) {
234 fr_lst_pop((void **)&from_lst, lst);
235 TEST_CHECK(from_lst != NULL);
236 fr_heap_pop((void **)&from_hp, &hp);
237 TEST_CHECK(from_hp != NULL);
238 TEST_CHECK(lst_cmp(from_lst, from_hp) == 0);
239 }
240
243
244 talloc_free(lst);
245 talloc_free(hp);
246 free(lst_array);
247 free(hp_array);
248}
249
250#define BURN_IN_OPS (10000000)
251
252static void lst_burn_in(void)
253{
254 fr_lst_t *lst = NULL;
255 lst_thing *array = NULL;
256 fr_fast_rand_t rand_ctx;
257 int insert_count = 0;
258
259 rand_ctx.a = fr_rand();
260 rand_ctx.b = fr_rand();
261
262 array = calloc(BURN_IN_OPS, sizeof(lst_thing));
263 for (unsigned int i = 0; i < BURN_IN_OPS; i++) array[i].data = fr_fast_rand(&rand_ctx) % 65537;
264
265 /* Make init small to exercise growing the pivot stack. */
266 lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 32);
267
268 for (unsigned int i = 0; i < BURN_IN_OPS; i++) {
269 lst_thing *ret_thing = NULL;
270 int ret_insert = -1;
271
272 if (fr_lst_num_elements(lst) == 0) {
273 insert:
274 TEST_CHECK((ret_insert = fr_lst_insert(lst, &array[insert_count])) >= 0);
275 insert_count++;
276 } else {
277 switch (fr_fast_rand(&rand_ctx) % 3) {
278 case 0: /* insert */
279 goto insert;
280
281 case 1: /* pop */
282 fr_lst_pop((void **)&ret_thing, lst);
283 TEST_CHECK(ret_thing != NULL);
284 break;
285 case 2: /* peek */
286 fr_lst_peek((void **)&ret_thing, lst);
287 TEST_CHECK(ret_thing != NULL);
288 break;
289 }
290 }
291 }
292
293 talloc_free(lst);
294 free(array);
295}
296
297#define LST_CYCLE_SIZE (1600000)
298
299static void lst_cycle(void)
300{
301 fr_lst_t *lst;
302 int i;
303 lst_thing *values;
304 int to_remove;
305 int inserted, removed;
306 int ret;
307 fr_time_t start_insert, start_remove, start_swap, end;
308
309 lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
310 TEST_ASSERT(lst != NULL);
311
312 values = calloc(LST_CYCLE_SIZE, sizeof(lst_thing));
313
314 /*
315 * Initialise random values
316 */
318
319 start_insert = fr_time();
320 TEST_CASE("insertions");
321 for (i = 0; i < LST_CYCLE_SIZE; i++) {
322 TEST_CHECK((ret = fr_lst_insert(lst, &values[i])) >= 0);
323 TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
324 }
326
327 TEST_CASE("pop");
328
329 /*
330 * Remove a random number of elements from the LST
331 */
332 to_remove = fr_lst_num_elements(lst) / 2;
333 start_remove = fr_time();
334 for (i = 0; i < to_remove; i++) {
335 void *popped;
336
337 fr_lst_pop(&popped, lst);
338 TEST_CHECK(popped != NULL);
339 TEST_MSG("failed extracting %i", i);
340 TEST_MSG("expected %i elements remaining in the LST", to_remove - i);
341 }
342
343 /*
344 * Now swap the inserted and removed set creating churn
345 */
346 start_swap = fr_time();
347
348 inserted = 0;
349 removed = 0;
350
351 for (i = 0; i < LST_CYCLE_SIZE; i++) {
352 if (values[i].idx == 0) {
353 TEST_CHECK((ret = fr_lst_insert(lst, &values[i])) >= 0);
354 TEST_MSG("insert failed, returned %i - %s", ret, fr_strerror());
355 inserted++;
356 } else {
357 TEST_CHECK((ret = fr_lst_extract(lst, &values[i])) >= 0);
358 TEST_MSG("element %i removal failed, returned %i", i, ret);
359 removed++;
360 }
361 }
362
363 TEST_CHECK(removed == (LST_CYCLE_SIZE - to_remove));
364 TEST_MSG("expected %i", LST_CYCLE_SIZE - to_remove);
365 TEST_MSG("got %i", removed);
366
367 TEST_CHECK(inserted == to_remove);
368 TEST_MSG("expected %i", to_remove);
369 TEST_MSG("got %i", inserted);
370
371 end = fr_time();
372
373 TEST_MSG_ALWAYS("\ncycle size: %d\n", LST_CYCLE_SIZE);
374 TEST_MSG_ALWAYS("insert: %.2fs\n", fr_time_delta_unwrap(fr_time_sub(start_remove, start_insert)) / (double)NSEC);
375 TEST_MSG_ALWAYS("extract: %.2fs\n", fr_time_delta_unwrap(fr_time_sub(start_swap, start_remove)) / (double)NSEC);
376 TEST_MSG_ALWAYS("swap: %.2fs\n", fr_time_delta_unwrap(fr_time_sub(end, start_swap)) / (double)NSEC);
377
378 talloc_free(lst);
379 free(values);
380}
381
382static void lst_iter(void)
383{
384 fr_lst_t *lst;
385 fr_lst_iter_t iter;
386 lst_thing values[NVALUES], *data;
387 unsigned int total;
388
389 lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
390 TEST_ASSERT(lst != NULL);
391
392 populate_values(values, NUM_ELEMENTS(values));
393
394 for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++) TEST_CHECK(fr_lst_insert(lst, &values[i]) == 0);
395
396 data = fr_lst_iter_init(lst, &iter);
397
398 for (unsigned int i = 0; i < NUM_ELEMENTS(values); i++, data = fr_lst_iter_next(lst, &iter)) {
399 TEST_CHECK(data != NULL);
400 TEST_CHECK(!data->visited);
401 TEST_CHECK(data->idx > 0);
402 data->visited = true;
403 }
404
405 TEST_CHECK(data == NULL);
406
407 total = 0;
409 total += item->data;
410 }}
411 TEST_CHECK(total == 190);
412
414}
415
416static CC_HINT(noinline) lst_thing *array_pop(lst_thing **array, unsigned int count)
417{
418 lst_thing *low = NULL;
419 unsigned int idx = 0;
420
421 for (unsigned int j = 0; j < count; j++) {
422 if (!array[j]) continue;
423
424 if (!low || (lst_cmp(array[j], low) < 0)) {
425 idx = j;
426 low = array[j];
427 }
428 }
429 if (low) array[idx] = NULL;
430
431 return low;
432}
433
434/** Benchmarks for LSTs vs heaps when used as queues
435 *
436 */
437static void queue_cmp(unsigned int count)
438{
439 fr_lst_t *lst;
440 fr_heap_t *hp;
441
442 lst_thing *values;
443
444 unsigned int i;
445
446 values = talloc_array(NULL, lst_thing, count);
447
448 /*
449 * Check times for LST alloc, insert, pop
450 */
451 {
452 fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first = fr_time_wrap(0);
453
454 populate_values(values, count);
455
456 start_alloc = fr_time();
457 lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0);
458 end_alloc = fr_time();
459 TEST_ASSERT(lst != NULL);
460
461 start_insert = fr_time();
462 for (i = 0; i < count; i++) TEST_CHECK(fr_lst_insert(lst, &values[i]) == 0);
463 end_insert = fr_time();
464
465 start_pop = fr_time();
466 for (i = 0; i < count; i++) {
467 void *popped;
468
469 fr_lst_pop(&popped, lst);
470 TEST_CHECK(popped != NULL);
471 if (i == 0) end_pop_first = fr_time();
472
473 TEST_MSG("expected %u elements remaining in the lst", count - i);
474 TEST_MSG("failed extracting %u", i);
475 }
476 end_pop = fr_time();
477
478 TEST_MSG_ALWAYS("\nlst size: %u\n", count);
479 TEST_MSG_ALWAYS("alloc: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_alloc, start_alloc)) / 1000);
480 TEST_MSG_ALWAYS("insert: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_insert, start_insert)) / 1000);
481 TEST_MSG_ALWAYS("pop-first: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop_first, start_pop)) / 1000);
482 TEST_MSG_ALWAYS("pop: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop, start_pop)) / 1000);
483
484 talloc_free(lst);
485 }
486
487 /*
488 * Check times for heap alloc, insert, pop
489 */
490 {
491 fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first = fr_time_wrap(0);
492
493 populate_values(values, count);
494
495 start_alloc = fr_time();
496 hp = fr_heap_alloc(NULL, lst_cmp, lst_thing, idx, count);
497 end_alloc = fr_time();
498 TEST_ASSERT(hp != NULL);
499
500 start_insert = fr_time();
501 for (i = 0; i < count; i++) fr_heap_insert(&hp, &values[i]);
502 end_insert = fr_time();
503
504 start_pop = fr_time();
505 for (i = 0; i < count; i++) {
506 void *popped;
507
508 fr_heap_pop(&popped, &hp);
509 TEST_CHECK(popped != NULL);
510 if (i == 0) end_pop_first = fr_time();
511
512 TEST_MSG("expected %u elements remaining in the heap", count - i);
513 TEST_MSG("failed extracting %u", i);
514 }
515 end_pop = fr_time();
516
517 TEST_MSG_ALWAYS("\nheap size: %u\n", count);
518 TEST_MSG_ALWAYS("alloc: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_alloc, start_alloc)) / 1000);
519 TEST_MSG_ALWAYS("insert: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_insert, start_insert)) / 1000);
520 TEST_MSG_ALWAYS("pop-first: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop_first, start_pop)) / 1000);
521 TEST_MSG_ALWAYS("pop: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop, start_pop)) / 1000);
522
523 talloc_free(hp);
524 }
525
526 /*
527 * Array
528 */
529 {
530 lst_thing **array;
531 fr_time_t start_alloc, end_alloc, start_insert, end_insert, start_pop, end_pop, end_pop_first;
532
533 populate_values(values, count);
534 end_pop_first = fr_time_wrap(0);
535
536 start_alloc = fr_time();
537 array = talloc_array(NULL, lst_thing *, count);
538 end_alloc = fr_time();
539
540 start_insert = fr_time();
541 for (i = 0; i < count; i++) array[i] = &values[i];
542 end_insert = fr_time();
543
544 start_pop = fr_time();
545 for (i = 0; i < count; i++) {
546 TEST_CHECK(array_pop(array, count) != NULL);
547 if (i == 0) end_pop_first = fr_time();
548 }
549 end_pop = fr_time();
550
551 TEST_MSG_ALWAYS("\narray size: %u\n", count);
552 TEST_MSG_ALWAYS("alloc: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_alloc, start_alloc)) / 1000);
553 TEST_MSG_ALWAYS("insert: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_insert, start_insert)) / 1000);
554 TEST_MSG_ALWAYS("pop-first: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop_first, start_pop)) / 1000);
555 TEST_MSG_ALWAYS("pop: %"PRId64" μs\n", fr_time_delta_unwrap(fr_time_sub(end_pop, start_pop)) / 1000);
556
557 talloc_free(array);
558 }
559
560 talloc_free(values);
561}
562
563static void queue_cmp_10(void)
564{
565 queue_cmp(10);
566}
567
568static void queue_cmp_50(void)
569{
570 queue_cmp(50);
571}
572
573static void queue_cmp_100(void)
574{
575 queue_cmp(100);
576}
577
578static void queue_cmp_1000(void)
579{
580 queue_cmp(1000);
581}
582
583static bool poisoned;
584
585static fr_cmp_ret_t _lst_poison_cmp(void const *one, void const *two)
586{
587 if (poisoned) {
588 fr_strerror_const("Poisoned comparator");
589 return CMP_ERR;
590 }
591
592 return lst_cmp(one, two);
593}
594
595/*
596 * A comparator returning CMP_ERR must fail the operation closed,
597 * report the error through the int return, and leave the
598 * LST structurally intact.
599 */
600static void lst_test_cmp_err(void)
601{
602 fr_lst_t *lst;
603 lst_thing values[NVALUES];
604 void *found;
605 unsigned int i, remaining;
606
607 TEST_CASE("comparator error fails closed");
608 lst = fr_lst_alloc(NULL, _lst_poison_cmp, lst_thing, idx, NVALUES);
609 TEST_ASSERT(lst != NULL);
610
611 populate_values(values, NUM_ELEMENTS(values));
612
613 /*
614 * Insertion into a single bucket never compares,
615 * the first peek partitions and does.
616 */
617 poisoned = false;
618 for (i = 0; i < NUM_ELEMENTS(values); i++) {
619 TEST_CHECK(fr_lst_insert(lst, &values[i]) >= 0);
620 }
621
622 poisoned = true;
623
624 TEST_CHECK(fr_lst_peek(&found, lst) == -1);
625 TEST_CHECK(found == NULL);
626
627 TEST_CHECK(fr_lst_pop(&found, lst) == -1);
628 TEST_CHECK(found == NULL);
630
631 /*
632 * Once the comparator recovers, every element pops back
633 * out in order.
634 */
635 poisoned = false;
636 remaining = NUM_ELEMENTS(values);
637 for (i = 0; i < NUM_ELEMENTS(values); i++) {
639
640 fr_lst_pop((void **)&value, lst);
641 TEST_CHECK(value != NULL);
642 TEST_CHECK(value->data == i);
643 remaining--;
644 }
645 TEST_CHECK(remaining == 0);
647
648 talloc_free(lst);
649}
650
652 /*
653 * Basic tests
654 */
655 { "lst_test_basic", lst_test_basic },
656 { "lst_test_cmp_err", lst_test_cmp_err },
657 { "lst_test_skip_1", lst_test_skip_1 },
658 { "lst_test_skip_2", lst_test_skip_2 },
659 { "lst_test_skip_10", lst_test_skip_10 },
660 { "lst_stress_realloc", lst_stress_realloc },
661 { "lst_burn_in", lst_burn_in },
662 { "lst_cycle", lst_cycle },
663 { "lst_iter", lst_iter },
664 { "queue_cmp_10", queue_cmp_10 },
665 { "queue_cmp_50", queue_cmp_50 },
666 { "queue_cmp_100", queue_cmp_100 },
667 { "queue_cmp_1000", queue_cmp_1000 },
669};
#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(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:113
#define NUM_ELEMENTS(_t)
Definition build.h:406
Test enumeration values.
Definition dict_test.h:92
#define INITIAL_CAPACITY
Definition heap.c:31
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
static unsigned int fr_heap_num_elements(fr_heap_t *h)
Return the number of elements in the heap.
Definition heap.h:181
The main heap structure.
Definition heap.h:68
free(array)
#define fr_time()
Definition event.c:60
void * fr_lst_iter_next(fr_lst_t *lst, fr_lst_iter_t *iter)
Get the next entry in an LST.
Definition lst.c:802
int fr_lst_extract(fr_lst_t *lst, void *data)
Remove an element from an LST.
Definition lst.c:734
int fr_lst_pop(void **out, fr_lst_t *lst)
Definition lst.c:712
void * fr_lst_iter_init(fr_lst_t *lst, fr_lst_iter_t *iter)
Iterate over entries in LST.
Definition lst.c:783
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
Definition lst.c:121
fr_lst_index_t idx
Starting index, initially zero.
Definition lst.c:61
int fr_lst_insert(fr_lst_t *lst, void *data)
Definition lst.c:749
unsigned int fr_lst_num_elements(fr_lst_t *lst)
Definition lst.c:767
int fr_lst_peek(void **out, fr_lst_t *lst)
Definition lst.c:719
Definition lst.c:59
#define FR_LST_VERIFY(_lst)
Definition lst.h:114
#define fr_lst_alloc(_ctx, _cmp, _type, _field, _init)
Creates an LST that can be used with non-talloced elements.
Definition lst.h:60
static bool fr_lst_entry_inserted(fr_lst_index_t lst_id)
Check if an entry is inserted into an LST.
Definition lst.h:92
fr_lst_index_t fr_lst_iter_t
Definition lst.h:46
unsigned int fr_lst_index_t
Definition lst.h:44
#define fr_lst_foreach(_lst, _type, _data)
Iterate over the contents of an LST.
Definition lst.h:135
static void queue_cmp_100(void)
Definition lst_tests.c:573
static void queue_cmp(unsigned int count)
Benchmarks for LSTs vs heaps when used as queues.
Definition lst_tests.c:437
TEST_LIST
Definition lst_tests.c:651
static lst_thing * array_pop(lst_thing **array, unsigned int count)
Definition lst_tests.c:416
static void lst_test_skip_10(void)
Definition lst_tests.c:166
#define NVALUES
Definition lst_tests.c:64
static fr_cmp_ret_t _lst_poison_cmp(void const *one, void const *two)
Definition lst_tests.c:585
static void lst_test(int skip)
Definition lst_tests.c:94
static fr_cmp_ret_t lst_cmp(void const *one, void const *two)
Definition lst_tests.c:33
unsigned int data
Definition lst_tests.c:15
static void lst_test_cmp_err(void)
Definition lst_tests.c:600
#define LST_TEST_SIZE
Definition lst_tests.c:92
#define BURN_IN_OPS
Definition lst_tests.c:250
fr_lst_index_t idx
Definition lst_tests.c:16
static void queue_cmp_50(void)
Definition lst_tests.c:568
static void lst_cycle(void)
Definition lst_tests.c:299
static void lst_burn_in(void)
Definition lst_tests.c:252
static void lst_test_basic(void)
Definition lst_tests.c:65
static void lst_iter(void)
Definition lst_tests.c:382
#define LST_CYCLE_SIZE
Definition lst_tests.c:297
static bool poisoned
Definition lst_tests.c:583
static void queue_cmp_1000(void)
Definition lst_tests.c:578
static void lst_test_skip_2(void)
Definition lst_tests.c:161
static void queue_cmp_10(void)
Definition lst_tests.c:563
static bool fr_lst_contains(fr_lst_t *lst, void *data)
Definition lst_tests.c:24
static void lst_test_skip_1(void)
Definition lst_tests.c:156
static void lst_stress_realloc(void)
Definition lst_tests.c:172
static void populate_values(lst_thing values[], unsigned int len)
Definition lst_tests.c:40
bool visited
Definition lst_tests.c:17
talloc_free(lst)
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
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
#define fr_time_wrap(_time)
Definition time.h:145
#define NSEC
Definition time.h:379
#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