static int
node_cmp(const node_t *a, const node_t *b) {
int ret;
ret = (a->key > b->key) - (a->key < b->key);
if (ret == 0) {
/*
* Duplicates are not allowed in the heap, so force an
* arbitrary ordering for non-identical items with equal keys.
*/
ret = (((uintptr_t)a) > ((uintptr_t)b))
- (((uintptr_t)a) < ((uintptr_t)b));
}
return ret;
}
static int
node_cmp_magic(const node_t *a, const node_t *b) {
if (parent != NULL) {
expect_d_ge(node_cmp_magic(node, parent), 0,
"Child is less than parent");
}
leftmost_child = node_lchild_get(node);
if (leftmost_child == NULL) {
return nnodes;
}
expect_ptr_eq(node_prev_get(leftmost_child),
(void *)node, "Leftmost child does not link to node");
nnodes += node_validate(leftmost_child, node);
for (sibling = node_next_get(leftmost_child); sibling !=
NULL; sibling = node_next_get(sibling)) {
expect_ptr_eq(node_next_get(node_prev_get(sibling)), sibling,
"sibling's prev doesn't link to sibling");
nnodes += node_validate(sibling, node);
}
return nnodes;
}
sfmt = init_gen_rand(SEED);
for (i = 0; i < NBAGS; i++) {
switch (i) {
case 0:
/* Insert in order. */
for (j = 0; j < NNODES; j++) {
bag[j] = j;
}
break;
case 1:
/* Insert in reverse order. */
for (j = 0; j < NNODES; j++) {
bag[j] = NNODES - j - 1;
}
break;
default:
for (j = 0; j < NNODES; j++) {
bag[j] = gen_rand64_range(sfmt, NNODES);
}
}
for (j = 1; j <= NNODES; j++) {
/* Initialize heap and nodes. */
heap_new(&heap);
expect_u_eq(heap_validate(&heap), 0,
"Incorrect node count");
for (k = 0; k < j; k++) {
nodes[k].magic = NODE_MAGIC;
nodes[k].key = bag[k];
}
/* Insert nodes. */
for (k = 0; k < j; k++) {
heap_insert(&heap, &nodes[k]);
if (i % 13 == 12) {
expect_ptr_not_null(heap_any(&heap),
"Heap should not be empty");
/* Trigger merging. */
expect_ptr_not_null(heap_first(&heap),
"Heap should not be empty");
}
expect_u_eq(heap_validate(&heap), k + 1,
"Incorrect node count");
}
expect_false(heap_empty(&heap),
"Heap should not be empty");
/* Remove nodes. */
switch (i % 6) {
case 0:
for (k = 0; k < j; k++) {
expect_u_eq(heap_validate(&heap), j - k,
"Incorrect node count");
node_remove(&heap, &nodes[k]);
expect_u_eq(heap_validate(&heap), j - k
- 1, "Incorrect node count");
}
break;
case 1:
for (k = j; k > 0; k--) {
node_remove(&heap, &nodes[k-1]);
expect_u_eq(heap_validate(&heap), k - 1,
"Incorrect node count");
}
break;
case 2: {
node_t *prev = NULL;
for (k = 0; k < j; k++) {
node_t *node = node_remove_first(&heap);
expect_u_eq(heap_validate(&heap), j - k
- 1, "Incorrect node count");
if (prev != NULL) {
expect_d_ge(node_cmp(node,
prev), 0,
"Bad removal order");
}
prev = node;
}
break;
} case 3: {
node_t *prev = NULL;
for (k = 0; k < j; k++) {
node_t *node = heap_first(&heap);
expect_u_eq(heap_validate(&heap), j - k,
"Incorrect node count");
if (prev != NULL) {
expect_d_ge(node_cmp(node,
prev), 0,
"Bad removal order");
}
node_remove(&heap, node);
expect_u_eq(heap_validate(&heap), j - k
- 1, "Incorrect node count");
prev = node;
}
break;
} case 4: {
for (k = 0; k < j; k++) {
node_remove_any(&heap);
expect_u_eq(heap_validate(&heap), j - k
- 1, "Incorrect node count");
}
break;
} case 5: {
for (k = 0; k < j; k++) {
node_t *node = heap_any(&heap);
expect_u_eq(heap_validate(&heap), j - k,
"Incorrect node count");
node_remove(&heap, node);
expect_u_eq(heap_validate(&heap), j - k
- 1, "Incorrect node count");
}
break;
} default:
not_reached();
}
expect_ptr_null(heap_first(&heap),
"Heap should be empty");
expect_ptr_null(heap_any(&heap),
"Heap should be empty");
expect_true(heap_empty(&heap), "Heap should be empty");
}
}
fini_gen_rand(sfmt);
#undef NNODES
#undef SEED
}
TEST_END
int
main(void) {
return test(
test_ph_empty,
test_ph_random);
}