1a0698ed9Schristos #include "test/jemalloc_test.h" 2a0698ed9Schristos 3*7bdf38e5Schristos #include <stdlib.h> 4*7bdf38e5Schristos 5a0698ed9Schristos #include "jemalloc/internal/rb.h" 6a0698ed9Schristos 7a0698ed9Schristos #define rbtn_black_height(a_type, a_field, a_rbt, r_height) do { \ 8a0698ed9Schristos a_type *rbp_bh_t; \ 9a0698ed9Schristos for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; rbp_bh_t != \ 10a0698ed9Schristos NULL; rbp_bh_t = rbtn_left_get(a_type, a_field, \ 11a0698ed9Schristos rbp_bh_t)) { \ 12a0698ed9Schristos if (!rbtn_red_get(a_type, a_field, rbp_bh_t)) { \ 13a0698ed9Schristos (r_height)++; \ 14a0698ed9Schristos } \ 15a0698ed9Schristos } \ 16a0698ed9Schristos } while (0) 17a0698ed9Schristos 18*7bdf38e5Schristos static bool summarize_always_returns_true = false; 19a0698ed9Schristos 20*7bdf38e5Schristos typedef struct node_s node_t; 21a0698ed9Schristos struct node_s { 22a0698ed9Schristos #define NODE_MAGIC 0x9823af7e 23a0698ed9Schristos uint32_t magic; 24a0698ed9Schristos rb_node(node_t) link; 25*7bdf38e5Schristos /* Order used by nodes. */ 26a0698ed9Schristos uint64_t key; 27*7bdf38e5Schristos /* 28*7bdf38e5Schristos * Our made-up summary property is "specialness", with summarization 29*7bdf38e5Schristos * taking the max. 30*7bdf38e5Schristos */ 31*7bdf38e5Schristos uint64_t specialness; 32*7bdf38e5Schristos 33*7bdf38e5Schristos /* 34*7bdf38e5Schristos * Used by some of the test randomization to avoid double-removing 35*7bdf38e5Schristos * nodes. 36*7bdf38e5Schristos */ 37*7bdf38e5Schristos bool mid_remove; 38*7bdf38e5Schristos 39*7bdf38e5Schristos /* 40*7bdf38e5Schristos * To test searching functionality, we want to temporarily weaken the 41*7bdf38e5Schristos * ordering to allow non-equal nodes that nevertheless compare equal. 42*7bdf38e5Schristos */ 43*7bdf38e5Schristos bool allow_duplicates; 44*7bdf38e5Schristos 45*7bdf38e5Schristos /* 46*7bdf38e5Schristos * In check_consistency, it's handy to know a node's rank in the tree; 47*7bdf38e5Schristos * this tracks it (but only there; not all tests use this). 48*7bdf38e5Schristos */ 49*7bdf38e5Schristos int rank; 50*7bdf38e5Schristos int filtered_rank; 51*7bdf38e5Schristos 52*7bdf38e5Schristos /* 53*7bdf38e5Schristos * Replicate the internal structure of the tree, to make sure the 54*7bdf38e5Schristos * implementation doesn't miss any updates. 55*7bdf38e5Schristos */ 56*7bdf38e5Schristos const node_t *summary_lchild; 57*7bdf38e5Schristos const node_t *summary_rchild; 58*7bdf38e5Schristos uint64_t summary_max_specialness; 59a0698ed9Schristos }; 60a0698ed9Schristos 61a0698ed9Schristos static int 62a0698ed9Schristos node_cmp(const node_t *a, const node_t *b) { 63a0698ed9Schristos int ret; 64a0698ed9Schristos 65*7bdf38e5Schristos expect_u32_eq(a->magic, NODE_MAGIC, "Bad magic"); 66*7bdf38e5Schristos expect_u32_eq(b->magic, NODE_MAGIC, "Bad magic"); 67a0698ed9Schristos 68a0698ed9Schristos ret = (a->key > b->key) - (a->key < b->key); 69*7bdf38e5Schristos if (ret == 0 && !a->allow_duplicates) { 70a0698ed9Schristos /* 71a0698ed9Schristos * Duplicates are not allowed in the tree, so force an 72*7bdf38e5Schristos * arbitrary ordering for non-identical items with equal keys, 73*7bdf38e5Schristos * unless the user is searching and wants to allow the 74*7bdf38e5Schristos * duplicate. 75a0698ed9Schristos */ 76a0698ed9Schristos ret = (((uintptr_t)a) > ((uintptr_t)b)) 77a0698ed9Schristos - (((uintptr_t)a) < ((uintptr_t)b)); 78a0698ed9Schristos } 79a0698ed9Schristos return ret; 80a0698ed9Schristos } 81a0698ed9Schristos 82*7bdf38e5Schristos static uint64_t 83*7bdf38e5Schristos node_subtree_specialness(node_t *n, const node_t *lchild, 84*7bdf38e5Schristos const node_t *rchild) { 85*7bdf38e5Schristos uint64_t subtree_specialness = n->specialness; 86*7bdf38e5Schristos if (lchild != NULL 87*7bdf38e5Schristos && lchild->summary_max_specialness > subtree_specialness) { 88*7bdf38e5Schristos subtree_specialness = lchild->summary_max_specialness; 89*7bdf38e5Schristos } 90*7bdf38e5Schristos if (rchild != NULL 91*7bdf38e5Schristos && rchild->summary_max_specialness > subtree_specialness) { 92*7bdf38e5Schristos subtree_specialness = rchild->summary_max_specialness; 93*7bdf38e5Schristos } 94*7bdf38e5Schristos return subtree_specialness; 95*7bdf38e5Schristos } 96*7bdf38e5Schristos 97*7bdf38e5Schristos static bool 98*7bdf38e5Schristos node_summarize(node_t *a, const node_t *lchild, const node_t *rchild) { 99*7bdf38e5Schristos uint64_t new_summary_max_specialness = node_subtree_specialness( 100*7bdf38e5Schristos a, lchild, rchild); 101*7bdf38e5Schristos bool changed = (a->summary_lchild != lchild) 102*7bdf38e5Schristos || (a->summary_rchild != rchild) 103*7bdf38e5Schristos || (new_summary_max_specialness != a->summary_max_specialness); 104*7bdf38e5Schristos a->summary_max_specialness = new_summary_max_specialness; 105*7bdf38e5Schristos a->summary_lchild = lchild; 106*7bdf38e5Schristos a->summary_rchild = rchild; 107*7bdf38e5Schristos return changed || summarize_always_returns_true; 108*7bdf38e5Schristos } 109*7bdf38e5Schristos 110a0698ed9Schristos typedef rb_tree(node_t) tree_t; 111*7bdf38e5Schristos rb_summarized_proto(static, tree_, tree_t, node_t); 112*7bdf38e5Schristos rb_summarized_gen(static, tree_, tree_t, node_t, link, node_cmp, 113*7bdf38e5Schristos node_summarize); 114*7bdf38e5Schristos 115*7bdf38e5Schristos static bool 116*7bdf38e5Schristos specialness_filter_node(void *ctx, node_t *node) { 117*7bdf38e5Schristos uint64_t specialness = *(uint64_t *)ctx; 118*7bdf38e5Schristos return node->specialness >= specialness; 119*7bdf38e5Schristos } 120*7bdf38e5Schristos 121*7bdf38e5Schristos static bool 122*7bdf38e5Schristos specialness_filter_subtree(void *ctx, node_t *node) { 123*7bdf38e5Schristos uint64_t specialness = *(uint64_t *)ctx; 124*7bdf38e5Schristos return node->summary_max_specialness >= specialness; 125*7bdf38e5Schristos } 126*7bdf38e5Schristos 127*7bdf38e5Schristos static node_t * 128*7bdf38e5Schristos tree_iterate_cb(tree_t *tree, node_t *node, void *data) { 129*7bdf38e5Schristos unsigned *i = (unsigned *)data; 130*7bdf38e5Schristos node_t *search_node; 131*7bdf38e5Schristos 132*7bdf38e5Schristos expect_u32_eq(node->magic, NODE_MAGIC, "Bad magic"); 133*7bdf38e5Schristos 134*7bdf38e5Schristos /* Test rb_search(). */ 135*7bdf38e5Schristos search_node = tree_search(tree, node); 136*7bdf38e5Schristos expect_ptr_eq(search_node, node, 137*7bdf38e5Schristos "tree_search() returned unexpected node"); 138*7bdf38e5Schristos 139*7bdf38e5Schristos /* Test rb_nsearch(). */ 140*7bdf38e5Schristos search_node = tree_nsearch(tree, node); 141*7bdf38e5Schristos expect_ptr_eq(search_node, node, 142*7bdf38e5Schristos "tree_nsearch() returned unexpected node"); 143*7bdf38e5Schristos 144*7bdf38e5Schristos /* Test rb_psearch(). */ 145*7bdf38e5Schristos search_node = tree_psearch(tree, node); 146*7bdf38e5Schristos expect_ptr_eq(search_node, node, 147*7bdf38e5Schristos "tree_psearch() returned unexpected node"); 148*7bdf38e5Schristos 149*7bdf38e5Schristos (*i)++; 150*7bdf38e5Schristos 151*7bdf38e5Schristos return NULL; 152*7bdf38e5Schristos } 153a0698ed9Schristos 154a0698ed9Schristos TEST_BEGIN(test_rb_empty) { 155a0698ed9Schristos tree_t tree; 156a0698ed9Schristos node_t key; 157a0698ed9Schristos 158a0698ed9Schristos tree_new(&tree); 159a0698ed9Schristos 160*7bdf38e5Schristos expect_true(tree_empty(&tree), "Tree should be empty"); 161*7bdf38e5Schristos expect_ptr_null(tree_first(&tree), "Unexpected node"); 162*7bdf38e5Schristos expect_ptr_null(tree_last(&tree), "Unexpected node"); 163a0698ed9Schristos 164a0698ed9Schristos key.key = 0; 165a0698ed9Schristos key.magic = NODE_MAGIC; 166*7bdf38e5Schristos expect_ptr_null(tree_search(&tree, &key), "Unexpected node"); 167a0698ed9Schristos 168a0698ed9Schristos key.key = 0; 169a0698ed9Schristos key.magic = NODE_MAGIC; 170*7bdf38e5Schristos expect_ptr_null(tree_nsearch(&tree, &key), "Unexpected node"); 171a0698ed9Schristos 172a0698ed9Schristos key.key = 0; 173a0698ed9Schristos key.magic = NODE_MAGIC; 174*7bdf38e5Schristos expect_ptr_null(tree_psearch(&tree, &key), "Unexpected node"); 175*7bdf38e5Schristos 176*7bdf38e5Schristos unsigned nodes = 0; 177*7bdf38e5Schristos tree_iter_filtered(&tree, NULL, &tree_iterate_cb, 178*7bdf38e5Schristos &nodes, &specialness_filter_node, &specialness_filter_subtree, 179*7bdf38e5Schristos NULL); 180*7bdf38e5Schristos expect_u_eq(0, nodes, ""); 181*7bdf38e5Schristos 182*7bdf38e5Schristos nodes = 0; 183*7bdf38e5Schristos tree_reverse_iter_filtered(&tree, NULL, &tree_iterate_cb, 184*7bdf38e5Schristos &nodes, &specialness_filter_node, &specialness_filter_subtree, 185*7bdf38e5Schristos NULL); 186*7bdf38e5Schristos expect_u_eq(0, nodes, ""); 187*7bdf38e5Schristos 188*7bdf38e5Schristos expect_ptr_null(tree_first_filtered(&tree, &specialness_filter_node, 189*7bdf38e5Schristos &specialness_filter_subtree, NULL), ""); 190*7bdf38e5Schristos expect_ptr_null(tree_last_filtered(&tree, &specialness_filter_node, 191*7bdf38e5Schristos &specialness_filter_subtree, NULL), ""); 192*7bdf38e5Schristos 193*7bdf38e5Schristos key.key = 0; 194*7bdf38e5Schristos key.magic = NODE_MAGIC; 195*7bdf38e5Schristos expect_ptr_null(tree_search_filtered(&tree, &key, 196*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, NULL), ""); 197*7bdf38e5Schristos expect_ptr_null(tree_nsearch_filtered(&tree, &key, 198*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, NULL), ""); 199*7bdf38e5Schristos expect_ptr_null(tree_psearch_filtered(&tree, &key, 200*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, NULL), ""); 201a0698ed9Schristos } 202a0698ed9Schristos TEST_END 203a0698ed9Schristos 204a0698ed9Schristos static unsigned 205a0698ed9Schristos tree_recurse(node_t *node, unsigned black_height, unsigned black_depth) { 206a0698ed9Schristos unsigned ret = 0; 207a0698ed9Schristos node_t *left_node; 208a0698ed9Schristos node_t *right_node; 209a0698ed9Schristos 210a0698ed9Schristos if (node == NULL) { 211a0698ed9Schristos return ret; 212a0698ed9Schristos } 213a0698ed9Schristos 214a0698ed9Schristos left_node = rbtn_left_get(node_t, link, node); 215a0698ed9Schristos right_node = rbtn_right_get(node_t, link, node); 216a0698ed9Schristos 217*7bdf38e5Schristos expect_ptr_eq(left_node, node->summary_lchild, 218*7bdf38e5Schristos "summary missed a tree update"); 219*7bdf38e5Schristos expect_ptr_eq(right_node, node->summary_rchild, 220*7bdf38e5Schristos "summary missed a tree update"); 221*7bdf38e5Schristos 222*7bdf38e5Schristos uint64_t expected_subtree_specialness = node_subtree_specialness(node, 223*7bdf38e5Schristos left_node, right_node); 224*7bdf38e5Schristos expect_u64_eq(expected_subtree_specialness, 225*7bdf38e5Schristos node->summary_max_specialness, "Incorrect summary"); 226*7bdf38e5Schristos 227a0698ed9Schristos if (!rbtn_red_get(node_t, link, node)) { 228a0698ed9Schristos black_depth++; 229a0698ed9Schristos } 230a0698ed9Schristos 231a0698ed9Schristos /* Red nodes must be interleaved with black nodes. */ 232a0698ed9Schristos if (rbtn_red_get(node_t, link, node)) { 233a0698ed9Schristos if (left_node != NULL) { 234*7bdf38e5Schristos expect_false(rbtn_red_get(node_t, link, left_node), 235a0698ed9Schristos "Node should be black"); 236a0698ed9Schristos } 237a0698ed9Schristos if (right_node != NULL) { 238*7bdf38e5Schristos expect_false(rbtn_red_get(node_t, link, right_node), 239a0698ed9Schristos "Node should be black"); 240a0698ed9Schristos } 241a0698ed9Schristos } 242a0698ed9Schristos 243a0698ed9Schristos /* Self. */ 244*7bdf38e5Schristos expect_u32_eq(node->magic, NODE_MAGIC, "Bad magic"); 245a0698ed9Schristos 246a0698ed9Schristos /* Left subtree. */ 247a0698ed9Schristos if (left_node != NULL) { 248a0698ed9Schristos ret += tree_recurse(left_node, black_height, black_depth); 249a0698ed9Schristos } else { 250a0698ed9Schristos ret += (black_depth != black_height); 251a0698ed9Schristos } 252a0698ed9Schristos 253a0698ed9Schristos /* Right subtree. */ 254a0698ed9Schristos if (right_node != NULL) { 255a0698ed9Schristos ret += tree_recurse(right_node, black_height, black_depth); 256a0698ed9Schristos } else { 257a0698ed9Schristos ret += (black_depth != black_height); 258a0698ed9Schristos } 259a0698ed9Schristos 260a0698ed9Schristos return ret; 261a0698ed9Schristos } 262a0698ed9Schristos 263a0698ed9Schristos static unsigned 264a0698ed9Schristos tree_iterate(tree_t *tree) { 265a0698ed9Schristos unsigned i; 266a0698ed9Schristos 267a0698ed9Schristos i = 0; 268a0698ed9Schristos tree_iter(tree, NULL, tree_iterate_cb, (void *)&i); 269a0698ed9Schristos 270a0698ed9Schristos return i; 271a0698ed9Schristos } 272a0698ed9Schristos 273a0698ed9Schristos static unsigned 274a0698ed9Schristos tree_iterate_reverse(tree_t *tree) { 275a0698ed9Schristos unsigned i; 276a0698ed9Schristos 277a0698ed9Schristos i = 0; 278a0698ed9Schristos tree_reverse_iter(tree, NULL, tree_iterate_cb, (void *)&i); 279a0698ed9Schristos 280a0698ed9Schristos return i; 281a0698ed9Schristos } 282a0698ed9Schristos 283a0698ed9Schristos static void 284a0698ed9Schristos node_remove(tree_t *tree, node_t *node, unsigned nnodes) { 285a0698ed9Schristos node_t *search_node; 286a0698ed9Schristos unsigned black_height, imbalances; 287a0698ed9Schristos 288a0698ed9Schristos tree_remove(tree, node); 289a0698ed9Schristos 290a0698ed9Schristos /* Test rb_nsearch(). */ 291a0698ed9Schristos search_node = tree_nsearch(tree, node); 292a0698ed9Schristos if (search_node != NULL) { 293*7bdf38e5Schristos expect_u64_ge(search_node->key, node->key, 294a0698ed9Schristos "Key ordering error"); 295a0698ed9Schristos } 296a0698ed9Schristos 297a0698ed9Schristos /* Test rb_psearch(). */ 298a0698ed9Schristos search_node = tree_psearch(tree, node); 299a0698ed9Schristos if (search_node != NULL) { 300*7bdf38e5Schristos expect_u64_le(search_node->key, node->key, 301a0698ed9Schristos "Key ordering error"); 302a0698ed9Schristos } 303a0698ed9Schristos 304a0698ed9Schristos node->magic = 0; 305a0698ed9Schristos 306a0698ed9Schristos rbtn_black_height(node_t, link, tree, black_height); 307a0698ed9Schristos imbalances = tree_recurse(tree->rbt_root, black_height, 0); 308*7bdf38e5Schristos expect_u_eq(imbalances, 0, "Tree is unbalanced"); 309*7bdf38e5Schristos expect_u_eq(tree_iterate(tree), nnodes-1, 310a0698ed9Schristos "Unexpected node iteration count"); 311*7bdf38e5Schristos expect_u_eq(tree_iterate_reverse(tree), nnodes-1, 312a0698ed9Schristos "Unexpected node iteration count"); 313a0698ed9Schristos } 314a0698ed9Schristos 315a0698ed9Schristos static node_t * 316a0698ed9Schristos remove_iterate_cb(tree_t *tree, node_t *node, void *data) { 317a0698ed9Schristos unsigned *nnodes = (unsigned *)data; 318a0698ed9Schristos node_t *ret = tree_next(tree, node); 319a0698ed9Schristos 320a0698ed9Schristos node_remove(tree, node, *nnodes); 321a0698ed9Schristos 322a0698ed9Schristos return ret; 323a0698ed9Schristos } 324a0698ed9Schristos 325a0698ed9Schristos static node_t * 326a0698ed9Schristos remove_reverse_iterate_cb(tree_t *tree, node_t *node, void *data) { 327a0698ed9Schristos unsigned *nnodes = (unsigned *)data; 328a0698ed9Schristos node_t *ret = tree_prev(tree, node); 329a0698ed9Schristos 330a0698ed9Schristos node_remove(tree, node, *nnodes); 331a0698ed9Schristos 332a0698ed9Schristos return ret; 333a0698ed9Schristos } 334a0698ed9Schristos 335a0698ed9Schristos static void 336a0698ed9Schristos destroy_cb(node_t *node, void *data) { 337a0698ed9Schristos unsigned *nnodes = (unsigned *)data; 338a0698ed9Schristos 339*7bdf38e5Schristos expect_u_gt(*nnodes, 0, "Destruction removed too many nodes"); 340a0698ed9Schristos (*nnodes)--; 341a0698ed9Schristos } 342a0698ed9Schristos 343a0698ed9Schristos TEST_BEGIN(test_rb_random) { 344*7bdf38e5Schristos enum { 345*7bdf38e5Schristos NNODES = 25, 346*7bdf38e5Schristos NBAGS = 500, 347*7bdf38e5Schristos SEED = 42 348*7bdf38e5Schristos }; 349a0698ed9Schristos sfmt_t *sfmt; 350a0698ed9Schristos uint64_t bag[NNODES]; 351a0698ed9Schristos tree_t tree; 352a0698ed9Schristos node_t nodes[NNODES]; 353a0698ed9Schristos unsigned i, j, k, black_height, imbalances; 354a0698ed9Schristos 355a0698ed9Schristos sfmt = init_gen_rand(SEED); 356a0698ed9Schristos for (i = 0; i < NBAGS; i++) { 357a0698ed9Schristos switch (i) { 358a0698ed9Schristos case 0: 359a0698ed9Schristos /* Insert in order. */ 360a0698ed9Schristos for (j = 0; j < NNODES; j++) { 361a0698ed9Schristos bag[j] = j; 362a0698ed9Schristos } 363a0698ed9Schristos break; 364a0698ed9Schristos case 1: 365a0698ed9Schristos /* Insert in reverse order. */ 366a0698ed9Schristos for (j = 0; j < NNODES; j++) { 367a0698ed9Schristos bag[j] = NNODES - j - 1; 368a0698ed9Schristos } 369a0698ed9Schristos break; 370a0698ed9Schristos default: 371a0698ed9Schristos for (j = 0; j < NNODES; j++) { 372a0698ed9Schristos bag[j] = gen_rand64_range(sfmt, NNODES); 373a0698ed9Schristos } 374a0698ed9Schristos } 375a0698ed9Schristos 376*7bdf38e5Schristos /* 377*7bdf38e5Schristos * We alternate test behavior with a period of 2 here, and a 378*7bdf38e5Schristos * period of 5 down below, so there's no cycle in which certain 379*7bdf38e5Schristos * combinations get omitted. 380*7bdf38e5Schristos */ 381*7bdf38e5Schristos summarize_always_returns_true = (i % 2 == 0); 382*7bdf38e5Schristos 383a0698ed9Schristos for (j = 1; j <= NNODES; j++) { 384a0698ed9Schristos /* Initialize tree and nodes. */ 385a0698ed9Schristos tree_new(&tree); 386a0698ed9Schristos for (k = 0; k < j; k++) { 387a0698ed9Schristos nodes[k].magic = NODE_MAGIC; 388a0698ed9Schristos nodes[k].key = bag[k]; 389*7bdf38e5Schristos nodes[k].specialness = gen_rand64_range(sfmt, 390*7bdf38e5Schristos NNODES); 391*7bdf38e5Schristos nodes[k].mid_remove = false; 392*7bdf38e5Schristos nodes[k].allow_duplicates = false; 393*7bdf38e5Schristos nodes[k].summary_lchild = NULL; 394*7bdf38e5Schristos nodes[k].summary_rchild = NULL; 395*7bdf38e5Schristos nodes[k].summary_max_specialness = 0; 396a0698ed9Schristos } 397a0698ed9Schristos 398a0698ed9Schristos /* Insert nodes. */ 399a0698ed9Schristos for (k = 0; k < j; k++) { 400a0698ed9Schristos tree_insert(&tree, &nodes[k]); 401a0698ed9Schristos 402a0698ed9Schristos rbtn_black_height(node_t, link, &tree, 403a0698ed9Schristos black_height); 404a0698ed9Schristos imbalances = tree_recurse(tree.rbt_root, 405a0698ed9Schristos black_height, 0); 406*7bdf38e5Schristos expect_u_eq(imbalances, 0, 407a0698ed9Schristos "Tree is unbalanced"); 408a0698ed9Schristos 409*7bdf38e5Schristos expect_u_eq(tree_iterate(&tree), k+1, 410a0698ed9Schristos "Unexpected node iteration count"); 411*7bdf38e5Schristos expect_u_eq(tree_iterate_reverse(&tree), k+1, 412a0698ed9Schristos "Unexpected node iteration count"); 413a0698ed9Schristos 414*7bdf38e5Schristos expect_false(tree_empty(&tree), 415a0698ed9Schristos "Tree should not be empty"); 416*7bdf38e5Schristos expect_ptr_not_null(tree_first(&tree), 417a0698ed9Schristos "Tree should not be empty"); 418*7bdf38e5Schristos expect_ptr_not_null(tree_last(&tree), 419a0698ed9Schristos "Tree should not be empty"); 420a0698ed9Schristos 421a0698ed9Schristos tree_next(&tree, &nodes[k]); 422a0698ed9Schristos tree_prev(&tree, &nodes[k]); 423a0698ed9Schristos } 424a0698ed9Schristos 425a0698ed9Schristos /* Remove nodes. */ 426a0698ed9Schristos switch (i % 5) { 427a0698ed9Schristos case 0: 428a0698ed9Schristos for (k = 0; k < j; k++) { 429a0698ed9Schristos node_remove(&tree, &nodes[k], j - k); 430a0698ed9Schristos } 431a0698ed9Schristos break; 432a0698ed9Schristos case 1: 433a0698ed9Schristos for (k = j; k > 0; k--) { 434a0698ed9Schristos node_remove(&tree, &nodes[k-1], k); 435a0698ed9Schristos } 436a0698ed9Schristos break; 437a0698ed9Schristos case 2: { 438a0698ed9Schristos node_t *start; 439a0698ed9Schristos unsigned nnodes = j; 440a0698ed9Schristos 441a0698ed9Schristos start = NULL; 442a0698ed9Schristos do { 443a0698ed9Schristos start = tree_iter(&tree, start, 444a0698ed9Schristos remove_iterate_cb, (void *)&nnodes); 445a0698ed9Schristos nnodes--; 446a0698ed9Schristos } while (start != NULL); 447*7bdf38e5Schristos expect_u_eq(nnodes, 0, 448a0698ed9Schristos "Removal terminated early"); 449a0698ed9Schristos break; 450a0698ed9Schristos } case 3: { 451a0698ed9Schristos node_t *start; 452a0698ed9Schristos unsigned nnodes = j; 453a0698ed9Schristos 454a0698ed9Schristos start = NULL; 455a0698ed9Schristos do { 456a0698ed9Schristos start = tree_reverse_iter(&tree, start, 457a0698ed9Schristos remove_reverse_iterate_cb, 458a0698ed9Schristos (void *)&nnodes); 459a0698ed9Schristos nnodes--; 460a0698ed9Schristos } while (start != NULL); 461*7bdf38e5Schristos expect_u_eq(nnodes, 0, 462a0698ed9Schristos "Removal terminated early"); 463a0698ed9Schristos break; 464a0698ed9Schristos } case 4: { 465a0698ed9Schristos unsigned nnodes = j; 466a0698ed9Schristos tree_destroy(&tree, destroy_cb, &nnodes); 467*7bdf38e5Schristos expect_u_eq(nnodes, 0, 468a0698ed9Schristos "Destruction terminated early"); 469a0698ed9Schristos break; 470a0698ed9Schristos } default: 471a0698ed9Schristos not_reached(); 472a0698ed9Schristos } 473a0698ed9Schristos } 474a0698ed9Schristos } 475a0698ed9Schristos fini_gen_rand(sfmt); 476*7bdf38e5Schristos } 477*7bdf38e5Schristos TEST_END 478*7bdf38e5Schristos 479*7bdf38e5Schristos static void 480*7bdf38e5Schristos expect_simple_consistency(tree_t *tree, uint64_t specialness, 481*7bdf38e5Schristos bool expected_empty, node_t *expected_first, node_t *expected_last) { 482*7bdf38e5Schristos bool empty; 483*7bdf38e5Schristos node_t *first; 484*7bdf38e5Schristos node_t *last; 485*7bdf38e5Schristos 486*7bdf38e5Schristos empty = tree_empty_filtered(tree, &specialness_filter_node, 487*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 488*7bdf38e5Schristos expect_b_eq(expected_empty, empty, ""); 489*7bdf38e5Schristos 490*7bdf38e5Schristos first = tree_first_filtered(tree, 491*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 492*7bdf38e5Schristos (void *)&specialness); 493*7bdf38e5Schristos expect_ptr_eq(expected_first, first, ""); 494*7bdf38e5Schristos 495*7bdf38e5Schristos last = tree_last_filtered(tree, 496*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 497*7bdf38e5Schristos (void *)&specialness); 498*7bdf38e5Schristos expect_ptr_eq(expected_last, last, ""); 499*7bdf38e5Schristos } 500*7bdf38e5Schristos 501*7bdf38e5Schristos TEST_BEGIN(test_rb_filter_simple) { 502*7bdf38e5Schristos enum {FILTER_NODES = 10}; 503*7bdf38e5Schristos node_t nodes[FILTER_NODES]; 504*7bdf38e5Schristos for (unsigned i = 0; i < FILTER_NODES; i++) { 505*7bdf38e5Schristos nodes[i].magic = NODE_MAGIC; 506*7bdf38e5Schristos nodes[i].key = i; 507*7bdf38e5Schristos if (i == 0) { 508*7bdf38e5Schristos nodes[i].specialness = 0; 509*7bdf38e5Schristos } else { 510*7bdf38e5Schristos nodes[i].specialness = ffs_u(i); 511*7bdf38e5Schristos } 512*7bdf38e5Schristos nodes[i].mid_remove = false; 513*7bdf38e5Schristos nodes[i].allow_duplicates = false; 514*7bdf38e5Schristos nodes[i].summary_lchild = NULL; 515*7bdf38e5Schristos nodes[i].summary_rchild = NULL; 516*7bdf38e5Schristos nodes[i].summary_max_specialness = 0; 517*7bdf38e5Schristos } 518*7bdf38e5Schristos 519*7bdf38e5Schristos summarize_always_returns_true = false; 520*7bdf38e5Schristos 521*7bdf38e5Schristos tree_t tree; 522*7bdf38e5Schristos tree_new(&tree); 523*7bdf38e5Schristos 524*7bdf38e5Schristos /* Should be empty */ 525*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 0, /* empty */ true, 526*7bdf38e5Schristos /* first */ NULL, /* last */ NULL); 527*7bdf38e5Schristos 528*7bdf38e5Schristos /* Fill in just the odd nodes. */ 529*7bdf38e5Schristos for (int i = 1; i < FILTER_NODES; i += 2) { 530*7bdf38e5Schristos tree_insert(&tree, &nodes[i]); 531*7bdf38e5Schristos } 532*7bdf38e5Schristos 533*7bdf38e5Schristos /* A search for an odd node should succeed. */ 534*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 0, /* empty */ false, 535*7bdf38e5Schristos /* first */ &nodes[1], /* last */ &nodes[9]); 536*7bdf38e5Schristos 537*7bdf38e5Schristos /* But a search for an even one should fail. */ 538*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 1, /* empty */ true, 539*7bdf38e5Schristos /* first */ NULL, /* last */ NULL); 540*7bdf38e5Schristos 541*7bdf38e5Schristos /* Now we add an even. */ 542*7bdf38e5Schristos tree_insert(&tree, &nodes[4]); 543*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 1, /* empty */ false, 544*7bdf38e5Schristos /* first */ &nodes[4], /* last */ &nodes[4]); 545*7bdf38e5Schristos 546*7bdf38e5Schristos /* A smaller even, and a larger even. */ 547*7bdf38e5Schristos tree_insert(&tree, &nodes[2]); 548*7bdf38e5Schristos tree_insert(&tree, &nodes[8]); 549*7bdf38e5Schristos 550*7bdf38e5Schristos /* 551*7bdf38e5Schristos * A first-search (resp. last-search) for an even should switch to the 552*7bdf38e5Schristos * lower (higher) one, now that it's been added. 553*7bdf38e5Schristos */ 554*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 1, /* empty */ false, 555*7bdf38e5Schristos /* first */ &nodes[2], /* last */ &nodes[8]); 556*7bdf38e5Schristos 557*7bdf38e5Schristos /* 558*7bdf38e5Schristos * If we remove 2, a first-search we should go back to 4, while a 559*7bdf38e5Schristos * last-search should remain unchanged. 560*7bdf38e5Schristos */ 561*7bdf38e5Schristos tree_remove(&tree, &nodes[2]); 562*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 1, /* empty */ false, 563*7bdf38e5Schristos /* first */ &nodes[4], /* last */ &nodes[8]); 564*7bdf38e5Schristos 565*7bdf38e5Schristos /* Reinsert 2, then find it again. */ 566*7bdf38e5Schristos tree_insert(&tree, &nodes[2]); 567*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 1, /* empty */ false, 568*7bdf38e5Schristos /* first */ &nodes[2], /* last */ &nodes[8]); 569*7bdf38e5Schristos 570*7bdf38e5Schristos /* Searching for a multiple of 4 should not have changed. */ 571*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 2, /* empty */ false, 572*7bdf38e5Schristos /* first */ &nodes[4], /* last */ &nodes[8]); 573*7bdf38e5Schristos 574*7bdf38e5Schristos /* And a multiple of 8 */ 575*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 3, /* empty */ false, 576*7bdf38e5Schristos /* first */ &nodes[8], /* last */ &nodes[8]); 577*7bdf38e5Schristos 578*7bdf38e5Schristos /* But not a multiple of 16 */ 579*7bdf38e5Schristos expect_simple_consistency(&tree, /* specialness */ 4, /* empty */ true, 580*7bdf38e5Schristos /* first */ NULL, /* last */ NULL); 581*7bdf38e5Schristos } 582*7bdf38e5Schristos TEST_END 583*7bdf38e5Schristos 584*7bdf38e5Schristos typedef struct iter_ctx_s iter_ctx_t; 585*7bdf38e5Schristos struct iter_ctx_s { 586*7bdf38e5Schristos int ncalls; 587*7bdf38e5Schristos node_t *last_node; 588*7bdf38e5Schristos 589*7bdf38e5Schristos int ncalls_max; 590*7bdf38e5Schristos bool forward; 591*7bdf38e5Schristos }; 592*7bdf38e5Schristos 593*7bdf38e5Schristos static node_t * 594*7bdf38e5Schristos tree_iterate_filtered_cb(tree_t *tree, node_t *node, void *arg) { 595*7bdf38e5Schristos iter_ctx_t *ctx = (iter_ctx_t *)arg; 596*7bdf38e5Schristos ctx->ncalls++; 597*7bdf38e5Schristos expect_u64_ge(node->specialness, 1, 598*7bdf38e5Schristos "Should only invoke cb on nodes that pass the filter"); 599*7bdf38e5Schristos if (ctx->last_node != NULL) { 600*7bdf38e5Schristos if (ctx->forward) { 601*7bdf38e5Schristos expect_d_lt(node_cmp(ctx->last_node, node), 0, 602*7bdf38e5Schristos "Incorrect iteration order"); 603*7bdf38e5Schristos } else { 604*7bdf38e5Schristos expect_d_gt(node_cmp(ctx->last_node, node), 0, 605*7bdf38e5Schristos "Incorrect iteration order"); 606*7bdf38e5Schristos } 607*7bdf38e5Schristos } 608*7bdf38e5Schristos ctx->last_node = node; 609*7bdf38e5Schristos if (ctx->ncalls == ctx->ncalls_max) { 610*7bdf38e5Schristos return node; 611*7bdf38e5Schristos } 612*7bdf38e5Schristos return NULL; 613*7bdf38e5Schristos } 614*7bdf38e5Schristos 615*7bdf38e5Schristos static int 616*7bdf38e5Schristos qsort_node_cmp(const void *ap, const void *bp) { 617*7bdf38e5Schristos node_t *a = *(node_t **)ap; 618*7bdf38e5Schristos node_t *b = *(node_t **)bp; 619*7bdf38e5Schristos return node_cmp(a, b); 620*7bdf38e5Schristos } 621*7bdf38e5Schristos 622*7bdf38e5Schristos #define UPDATE_TEST_MAX 100 623*7bdf38e5Schristos static void 624*7bdf38e5Schristos check_consistency(tree_t *tree, node_t nodes[UPDATE_TEST_MAX], int nnodes) { 625*7bdf38e5Schristos uint64_t specialness = 1; 626*7bdf38e5Schristos 627*7bdf38e5Schristos bool empty; 628*7bdf38e5Schristos bool real_empty = true; 629*7bdf38e5Schristos node_t *first; 630*7bdf38e5Schristos node_t *real_first = NULL; 631*7bdf38e5Schristos node_t *last; 632*7bdf38e5Schristos node_t *real_last = NULL; 633*7bdf38e5Schristos for (int i = 0; i < nnodes; i++) { 634*7bdf38e5Schristos if (nodes[i].specialness >= specialness) { 635*7bdf38e5Schristos real_empty = false; 636*7bdf38e5Schristos if (real_first == NULL 637*7bdf38e5Schristos || node_cmp(&nodes[i], real_first) < 0) { 638*7bdf38e5Schristos real_first = &nodes[i]; 639*7bdf38e5Schristos } 640*7bdf38e5Schristos if (real_last == NULL 641*7bdf38e5Schristos || node_cmp(&nodes[i], real_last) > 0) { 642*7bdf38e5Schristos real_last = &nodes[i]; 643*7bdf38e5Schristos } 644*7bdf38e5Schristos } 645*7bdf38e5Schristos } 646*7bdf38e5Schristos 647*7bdf38e5Schristos empty = tree_empty_filtered(tree, &specialness_filter_node, 648*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 649*7bdf38e5Schristos expect_b_eq(real_empty, empty, ""); 650*7bdf38e5Schristos 651*7bdf38e5Schristos first = tree_first_filtered(tree, &specialness_filter_node, 652*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 653*7bdf38e5Schristos expect_ptr_eq(real_first, first, ""); 654*7bdf38e5Schristos 655*7bdf38e5Schristos last = tree_last_filtered(tree, &specialness_filter_node, 656*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 657*7bdf38e5Schristos expect_ptr_eq(real_last, last, ""); 658*7bdf38e5Schristos 659*7bdf38e5Schristos for (int i = 0; i < nnodes; i++) { 660*7bdf38e5Schristos node_t *next_filtered; 661*7bdf38e5Schristos node_t *real_next_filtered = NULL; 662*7bdf38e5Schristos node_t *prev_filtered; 663*7bdf38e5Schristos node_t *real_prev_filtered = NULL; 664*7bdf38e5Schristos for (int j = 0; j < nnodes; j++) { 665*7bdf38e5Schristos if (nodes[j].specialness < specialness) { 666*7bdf38e5Schristos continue; 667*7bdf38e5Schristos } 668*7bdf38e5Schristos if (node_cmp(&nodes[j], &nodes[i]) < 0 669*7bdf38e5Schristos && (real_prev_filtered == NULL 670*7bdf38e5Schristos || node_cmp(&nodes[j], real_prev_filtered) > 0)) { 671*7bdf38e5Schristos real_prev_filtered = &nodes[j]; 672*7bdf38e5Schristos } 673*7bdf38e5Schristos if (node_cmp(&nodes[j], &nodes[i]) > 0 674*7bdf38e5Schristos && (real_next_filtered == NULL 675*7bdf38e5Schristos || node_cmp(&nodes[j], real_next_filtered) < 0)) { 676*7bdf38e5Schristos real_next_filtered = &nodes[j]; 677*7bdf38e5Schristos } 678*7bdf38e5Schristos } 679*7bdf38e5Schristos next_filtered = tree_next_filtered(tree, &nodes[i], 680*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 681*7bdf38e5Schristos &specialness); 682*7bdf38e5Schristos expect_ptr_eq(real_next_filtered, next_filtered, ""); 683*7bdf38e5Schristos 684*7bdf38e5Schristos prev_filtered = tree_prev_filtered(tree, &nodes[i], 685*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 686*7bdf38e5Schristos &specialness); 687*7bdf38e5Schristos expect_ptr_eq(real_prev_filtered, prev_filtered, ""); 688*7bdf38e5Schristos 689*7bdf38e5Schristos node_t *search_filtered; 690*7bdf38e5Schristos node_t *real_search_filtered; 691*7bdf38e5Schristos node_t *nsearch_filtered; 692*7bdf38e5Schristos node_t *real_nsearch_filtered; 693*7bdf38e5Schristos node_t *psearch_filtered; 694*7bdf38e5Schristos node_t *real_psearch_filtered; 695*7bdf38e5Schristos 696*7bdf38e5Schristos /* 697*7bdf38e5Schristos * search, nsearch, psearch from a node before nodes[i] in the 698*7bdf38e5Schristos * ordering. 699*7bdf38e5Schristos */ 700*7bdf38e5Schristos node_t before; 701*7bdf38e5Schristos before.magic = NODE_MAGIC; 702*7bdf38e5Schristos before.key = nodes[i].key - 1; 703*7bdf38e5Schristos before.allow_duplicates = false; 704*7bdf38e5Schristos real_search_filtered = NULL; 705*7bdf38e5Schristos search_filtered = tree_search_filtered(tree, &before, 706*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 707*7bdf38e5Schristos &specialness); 708*7bdf38e5Schristos expect_ptr_eq(real_search_filtered, search_filtered, ""); 709*7bdf38e5Schristos 710*7bdf38e5Schristos real_nsearch_filtered = (nodes[i].specialness >= specialness ? 711*7bdf38e5Schristos &nodes[i] : real_next_filtered); 712*7bdf38e5Schristos nsearch_filtered = tree_nsearch_filtered(tree, &before, 713*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 714*7bdf38e5Schristos &specialness); 715*7bdf38e5Schristos expect_ptr_eq(real_nsearch_filtered, nsearch_filtered, ""); 716*7bdf38e5Schristos 717*7bdf38e5Schristos real_psearch_filtered = real_prev_filtered; 718*7bdf38e5Schristos psearch_filtered = tree_psearch_filtered(tree, &before, 719*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 720*7bdf38e5Schristos &specialness); 721*7bdf38e5Schristos expect_ptr_eq(real_psearch_filtered, psearch_filtered, ""); 722*7bdf38e5Schristos 723*7bdf38e5Schristos /* search, nsearch, psearch from nodes[i] */ 724*7bdf38e5Schristos real_search_filtered = (nodes[i].specialness >= specialness ? 725*7bdf38e5Schristos &nodes[i] : NULL); 726*7bdf38e5Schristos search_filtered = tree_search_filtered(tree, &nodes[i], 727*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 728*7bdf38e5Schristos &specialness); 729*7bdf38e5Schristos expect_ptr_eq(real_search_filtered, search_filtered, ""); 730*7bdf38e5Schristos 731*7bdf38e5Schristos real_nsearch_filtered = (nodes[i].specialness >= specialness ? 732*7bdf38e5Schristos &nodes[i] : real_next_filtered); 733*7bdf38e5Schristos nsearch_filtered = tree_nsearch_filtered(tree, &nodes[i], 734*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 735*7bdf38e5Schristos &specialness); 736*7bdf38e5Schristos expect_ptr_eq(real_nsearch_filtered, nsearch_filtered, ""); 737*7bdf38e5Schristos 738*7bdf38e5Schristos real_psearch_filtered = (nodes[i].specialness >= specialness ? 739*7bdf38e5Schristos &nodes[i] : real_prev_filtered); 740*7bdf38e5Schristos psearch_filtered = tree_psearch_filtered(tree, &nodes[i], 741*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 742*7bdf38e5Schristos &specialness); 743*7bdf38e5Schristos expect_ptr_eq(real_psearch_filtered, psearch_filtered, ""); 744*7bdf38e5Schristos 745*7bdf38e5Schristos /* 746*7bdf38e5Schristos * search, nsearch, psearch from a node equivalent to but 747*7bdf38e5Schristos * distinct from nodes[i]. 748*7bdf38e5Schristos */ 749*7bdf38e5Schristos node_t equiv; 750*7bdf38e5Schristos equiv.magic = NODE_MAGIC; 751*7bdf38e5Schristos equiv.key = nodes[i].key; 752*7bdf38e5Schristos equiv.allow_duplicates = true; 753*7bdf38e5Schristos real_search_filtered = (nodes[i].specialness >= specialness ? 754*7bdf38e5Schristos &nodes[i] : NULL); 755*7bdf38e5Schristos search_filtered = tree_search_filtered(tree, &equiv, 756*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 757*7bdf38e5Schristos &specialness); 758*7bdf38e5Schristos expect_ptr_eq(real_search_filtered, search_filtered, ""); 759*7bdf38e5Schristos 760*7bdf38e5Schristos real_nsearch_filtered = (nodes[i].specialness >= specialness ? 761*7bdf38e5Schristos &nodes[i] : real_next_filtered); 762*7bdf38e5Schristos nsearch_filtered = tree_nsearch_filtered(tree, &equiv, 763*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 764*7bdf38e5Schristos &specialness); 765*7bdf38e5Schristos expect_ptr_eq(real_nsearch_filtered, nsearch_filtered, ""); 766*7bdf38e5Schristos 767*7bdf38e5Schristos real_psearch_filtered = (nodes[i].specialness >= specialness ? 768*7bdf38e5Schristos &nodes[i] : real_prev_filtered); 769*7bdf38e5Schristos psearch_filtered = tree_psearch_filtered(tree, &equiv, 770*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 771*7bdf38e5Schristos &specialness); 772*7bdf38e5Schristos expect_ptr_eq(real_psearch_filtered, psearch_filtered, ""); 773*7bdf38e5Schristos 774*7bdf38e5Schristos /* 775*7bdf38e5Schristos * search, nsearch, psearch from a node after nodes[i] in the 776*7bdf38e5Schristos * ordering. 777*7bdf38e5Schristos */ 778*7bdf38e5Schristos node_t after; 779*7bdf38e5Schristos after.magic = NODE_MAGIC; 780*7bdf38e5Schristos after.key = nodes[i].key + 1; 781*7bdf38e5Schristos after.allow_duplicates = false; 782*7bdf38e5Schristos real_search_filtered = NULL; 783*7bdf38e5Schristos search_filtered = tree_search_filtered(tree, &after, 784*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 785*7bdf38e5Schristos &specialness); 786*7bdf38e5Schristos expect_ptr_eq(real_search_filtered, search_filtered, ""); 787*7bdf38e5Schristos 788*7bdf38e5Schristos real_nsearch_filtered = real_next_filtered; 789*7bdf38e5Schristos nsearch_filtered = tree_nsearch_filtered(tree, &after, 790*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 791*7bdf38e5Schristos &specialness); 792*7bdf38e5Schristos expect_ptr_eq(real_nsearch_filtered, nsearch_filtered, ""); 793*7bdf38e5Schristos 794*7bdf38e5Schristos real_psearch_filtered = (nodes[i].specialness >= specialness ? 795*7bdf38e5Schristos &nodes[i] : real_prev_filtered); 796*7bdf38e5Schristos psearch_filtered = tree_psearch_filtered(tree, &after, 797*7bdf38e5Schristos &specialness_filter_node, &specialness_filter_subtree, 798*7bdf38e5Schristos &specialness); 799*7bdf38e5Schristos expect_ptr_eq(real_psearch_filtered, psearch_filtered, ""); 800*7bdf38e5Schristos } 801*7bdf38e5Schristos 802*7bdf38e5Schristos /* Filtered iteration test setup. */ 803*7bdf38e5Schristos int nspecial = 0; 804*7bdf38e5Schristos node_t *sorted_nodes[UPDATE_TEST_MAX]; 805*7bdf38e5Schristos node_t *sorted_filtered_nodes[UPDATE_TEST_MAX]; 806*7bdf38e5Schristos for (int i = 0; i < nnodes; i++) { 807*7bdf38e5Schristos sorted_nodes[i] = &nodes[i]; 808*7bdf38e5Schristos } 809*7bdf38e5Schristos qsort(sorted_nodes, nnodes, sizeof(node_t *), &qsort_node_cmp); 810*7bdf38e5Schristos for (int i = 0; i < nnodes; i++) { 811*7bdf38e5Schristos sorted_nodes[i]->rank = i; 812*7bdf38e5Schristos sorted_nodes[i]->filtered_rank = nspecial; 813*7bdf38e5Schristos if (sorted_nodes[i]->specialness >= 1) { 814*7bdf38e5Schristos sorted_filtered_nodes[nspecial] = sorted_nodes[i]; 815*7bdf38e5Schristos nspecial++; 816*7bdf38e5Schristos } 817*7bdf38e5Schristos } 818*7bdf38e5Schristos 819*7bdf38e5Schristos node_t *iter_result; 820*7bdf38e5Schristos 821*7bdf38e5Schristos iter_ctx_t ctx; 822*7bdf38e5Schristos ctx.ncalls = 0; 823*7bdf38e5Schristos ctx.last_node = NULL; 824*7bdf38e5Schristos ctx.ncalls_max = INT_MAX; 825*7bdf38e5Schristos ctx.forward = true; 826*7bdf38e5Schristos 827*7bdf38e5Schristos /* Filtered forward iteration from the beginning. */ 828*7bdf38e5Schristos iter_result = tree_iter_filtered(tree, NULL, &tree_iterate_filtered_cb, 829*7bdf38e5Schristos &ctx, &specialness_filter_node, &specialness_filter_subtree, 830*7bdf38e5Schristos &specialness); 831*7bdf38e5Schristos expect_ptr_null(iter_result, ""); 832*7bdf38e5Schristos expect_d_eq(nspecial, ctx.ncalls, ""); 833*7bdf38e5Schristos /* Filtered forward iteration from a starting point. */ 834*7bdf38e5Schristos for (int i = 0; i < nnodes; i++) { 835*7bdf38e5Schristos ctx.ncalls = 0; 836*7bdf38e5Schristos ctx.last_node = NULL; 837*7bdf38e5Schristos iter_result = tree_iter_filtered(tree, &nodes[i], 838*7bdf38e5Schristos &tree_iterate_filtered_cb, &ctx, &specialness_filter_node, 839*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 840*7bdf38e5Schristos expect_ptr_null(iter_result, ""); 841*7bdf38e5Schristos expect_d_eq(nspecial - nodes[i].filtered_rank, ctx.ncalls, ""); 842*7bdf38e5Schristos } 843*7bdf38e5Schristos /* Filtered forward iteration from the beginning, with stopping */ 844*7bdf38e5Schristos for (int i = 0; i < nspecial; i++) { 845*7bdf38e5Schristos ctx.ncalls = 0; 846*7bdf38e5Schristos ctx.last_node = NULL; 847*7bdf38e5Schristos ctx.ncalls_max = i + 1; 848*7bdf38e5Schristos iter_result = tree_iter_filtered(tree, NULL, 849*7bdf38e5Schristos &tree_iterate_filtered_cb, &ctx, &specialness_filter_node, 850*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 851*7bdf38e5Schristos expect_ptr_eq(sorted_filtered_nodes[i], iter_result, ""); 852*7bdf38e5Schristos expect_d_eq(ctx.ncalls, i + 1, ""); 853*7bdf38e5Schristos } 854*7bdf38e5Schristos /* Filtered forward iteration from a starting point, with stopping. */ 855*7bdf38e5Schristos for (int i = 0; i < nnodes; i++) { 856*7bdf38e5Schristos for (int j = 0; j < nspecial - nodes[i].filtered_rank; j++) { 857*7bdf38e5Schristos ctx.ncalls = 0; 858*7bdf38e5Schristos ctx.last_node = NULL; 859*7bdf38e5Schristos ctx.ncalls_max = j + 1; 860*7bdf38e5Schristos iter_result = tree_iter_filtered(tree, &nodes[i], 861*7bdf38e5Schristos &tree_iterate_filtered_cb, &ctx, 862*7bdf38e5Schristos &specialness_filter_node, 863*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 864*7bdf38e5Schristos expect_d_eq(j + 1, ctx.ncalls, ""); 865*7bdf38e5Schristos expect_ptr_eq(sorted_filtered_nodes[ 866*7bdf38e5Schristos nodes[i].filtered_rank + j], iter_result, ""); 867*7bdf38e5Schristos } 868*7bdf38e5Schristos } 869*7bdf38e5Schristos 870*7bdf38e5Schristos /* Backwards iteration. */ 871*7bdf38e5Schristos ctx.ncalls = 0; 872*7bdf38e5Schristos ctx.last_node = NULL; 873*7bdf38e5Schristos ctx.ncalls_max = INT_MAX; 874*7bdf38e5Schristos ctx.forward = false; 875*7bdf38e5Schristos 876*7bdf38e5Schristos /* Filtered backward iteration from the end. */ 877*7bdf38e5Schristos iter_result = tree_reverse_iter_filtered(tree, NULL, 878*7bdf38e5Schristos &tree_iterate_filtered_cb, &ctx, &specialness_filter_node, 879*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 880*7bdf38e5Schristos expect_ptr_null(iter_result, ""); 881*7bdf38e5Schristos expect_d_eq(nspecial, ctx.ncalls, ""); 882*7bdf38e5Schristos /* Filtered backward iteration from a starting point. */ 883*7bdf38e5Schristos for (int i = 0; i < nnodes; i++) { 884*7bdf38e5Schristos ctx.ncalls = 0; 885*7bdf38e5Schristos ctx.last_node = NULL; 886*7bdf38e5Schristos iter_result = tree_reverse_iter_filtered(tree, &nodes[i], 887*7bdf38e5Schristos &tree_iterate_filtered_cb, &ctx, &specialness_filter_node, 888*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 889*7bdf38e5Schristos expect_ptr_null(iter_result, ""); 890*7bdf38e5Schristos int surplus_rank = (nodes[i].specialness >= 1 ? 1 : 0); 891*7bdf38e5Schristos expect_d_eq(nodes[i].filtered_rank + surplus_rank, ctx.ncalls, 892*7bdf38e5Schristos ""); 893*7bdf38e5Schristos } 894*7bdf38e5Schristos /* Filtered backward iteration from the end, with stopping */ 895*7bdf38e5Schristos for (int i = 0; i < nspecial; i++) { 896*7bdf38e5Schristos ctx.ncalls = 0; 897*7bdf38e5Schristos ctx.last_node = NULL; 898*7bdf38e5Schristos ctx.ncalls_max = i + 1; 899*7bdf38e5Schristos iter_result = tree_reverse_iter_filtered(tree, NULL, 900*7bdf38e5Schristos &tree_iterate_filtered_cb, &ctx, &specialness_filter_node, 901*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 902*7bdf38e5Schristos expect_ptr_eq(sorted_filtered_nodes[nspecial - i - 1], 903*7bdf38e5Schristos iter_result, ""); 904*7bdf38e5Schristos expect_d_eq(ctx.ncalls, i + 1, ""); 905*7bdf38e5Schristos } 906*7bdf38e5Schristos /* Filtered backward iteration from a starting point, with stopping. */ 907*7bdf38e5Schristos for (int i = 0; i < nnodes; i++) { 908*7bdf38e5Schristos int surplus_rank = (nodes[i].specialness >= 1 ? 1 : 0); 909*7bdf38e5Schristos for (int j = 0; j < nodes[i].filtered_rank + surplus_rank; 910*7bdf38e5Schristos j++) { 911*7bdf38e5Schristos ctx.ncalls = 0; 912*7bdf38e5Schristos ctx.last_node = NULL; 913*7bdf38e5Schristos ctx.ncalls_max = j + 1; 914*7bdf38e5Schristos iter_result = tree_reverse_iter_filtered(tree, 915*7bdf38e5Schristos &nodes[i], &tree_iterate_filtered_cb, &ctx, 916*7bdf38e5Schristos &specialness_filter_node, 917*7bdf38e5Schristos &specialness_filter_subtree, &specialness); 918*7bdf38e5Schristos expect_d_eq(j + 1, ctx.ncalls, ""); 919*7bdf38e5Schristos expect_ptr_eq(sorted_filtered_nodes[ 920*7bdf38e5Schristos nodes[i].filtered_rank - j - 1 + surplus_rank], 921*7bdf38e5Schristos iter_result, ""); 922*7bdf38e5Schristos } 923*7bdf38e5Schristos } 924*7bdf38e5Schristos } 925*7bdf38e5Schristos 926*7bdf38e5Schristos static void 927*7bdf38e5Schristos do_update_search_test(int nnodes, int ntrees, int nremovals, 928*7bdf38e5Schristos int nupdates) { 929*7bdf38e5Schristos node_t nodes[UPDATE_TEST_MAX]; 930*7bdf38e5Schristos assert(nnodes <= UPDATE_TEST_MAX); 931*7bdf38e5Schristos 932*7bdf38e5Schristos sfmt_t *sfmt = init_gen_rand(12345); 933*7bdf38e5Schristos for (int i = 0; i < ntrees; i++) { 934*7bdf38e5Schristos tree_t tree; 935*7bdf38e5Schristos tree_new(&tree); 936*7bdf38e5Schristos for (int j = 0; j < nnodes; j++) { 937*7bdf38e5Schristos nodes[j].magic = NODE_MAGIC; 938*7bdf38e5Schristos /* 939*7bdf38e5Schristos * In consistency checking, we increment or decrement a 940*7bdf38e5Schristos * key and assume that the result is not a key in the 941*7bdf38e5Schristos * tree. This isn't a *real* concern with 64-bit keys 942*7bdf38e5Schristos * and a good PRNG, but why not be correct anyways? 943*7bdf38e5Schristos */ 944*7bdf38e5Schristos nodes[j].key = 2 * gen_rand64(sfmt); 945*7bdf38e5Schristos nodes[j].specialness = 0; 946*7bdf38e5Schristos nodes[j].mid_remove = false; 947*7bdf38e5Schristos nodes[j].allow_duplicates = false; 948*7bdf38e5Schristos nodes[j].summary_lchild = NULL; 949*7bdf38e5Schristos nodes[j].summary_rchild = NULL; 950*7bdf38e5Schristos nodes[j].summary_max_specialness = 0; 951*7bdf38e5Schristos tree_insert(&tree, &nodes[j]); 952*7bdf38e5Schristos } 953*7bdf38e5Schristos for (int j = 0; j < nremovals; j++) { 954*7bdf38e5Schristos int victim = (int)gen_rand64_range(sfmt, nnodes); 955*7bdf38e5Schristos if (!nodes[victim].mid_remove) { 956*7bdf38e5Schristos tree_remove(&tree, &nodes[victim]); 957*7bdf38e5Schristos nodes[victim].mid_remove = true; 958*7bdf38e5Schristos } 959*7bdf38e5Schristos } 960*7bdf38e5Schristos for (int j = 0; j < nnodes; j++) { 961*7bdf38e5Schristos if (nodes[j].mid_remove) { 962*7bdf38e5Schristos nodes[j].mid_remove = false; 963*7bdf38e5Schristos nodes[j].key = 2 * gen_rand64(sfmt); 964*7bdf38e5Schristos tree_insert(&tree, &nodes[j]); 965*7bdf38e5Schristos } 966*7bdf38e5Schristos } 967*7bdf38e5Schristos for (int j = 0; j < nupdates; j++) { 968*7bdf38e5Schristos uint32_t ind = gen_rand32_range(sfmt, nnodes); 969*7bdf38e5Schristos nodes[ind].specialness = 1 - nodes[ind].specialness; 970*7bdf38e5Schristos tree_update_summaries(&tree, &nodes[ind]); 971*7bdf38e5Schristos check_consistency(&tree, nodes, nnodes); 972*7bdf38e5Schristos } 973*7bdf38e5Schristos } 974*7bdf38e5Schristos } 975*7bdf38e5Schristos 976*7bdf38e5Schristos TEST_BEGIN(test_rb_update_search) { 977*7bdf38e5Schristos summarize_always_returns_true = false; 978*7bdf38e5Schristos do_update_search_test(2, 100, 3, 50); 979*7bdf38e5Schristos do_update_search_test(5, 100, 3, 50); 980*7bdf38e5Schristos do_update_search_test(12, 100, 5, 1000); 981*7bdf38e5Schristos do_update_search_test(100, 1, 50, 500); 982*7bdf38e5Schristos } 983*7bdf38e5Schristos TEST_END 984*7bdf38e5Schristos 985*7bdf38e5Schristos typedef rb_tree(node_t) unsummarized_tree_t; 986*7bdf38e5Schristos rb_gen(static UNUSED, unsummarized_tree_, unsummarized_tree_t, node_t, link, 987*7bdf38e5Schristos node_cmp); 988*7bdf38e5Schristos 989*7bdf38e5Schristos static node_t * 990*7bdf38e5Schristos unsummarized_tree_iterate_cb(unsummarized_tree_t *tree, node_t *node, 991*7bdf38e5Schristos void *data) { 992*7bdf38e5Schristos unsigned *i = (unsigned *)data; 993*7bdf38e5Schristos (*i)++; 994*7bdf38e5Schristos return NULL; 995*7bdf38e5Schristos } 996*7bdf38e5Schristos /* 997*7bdf38e5Schristos * The unsummarized and summarized funtionality is implemented via the same 998*7bdf38e5Schristos * functions; we don't really need to do much more than test that we can exclude 999*7bdf38e5Schristos * the filtered functionality without anything breaking. 1000*7bdf38e5Schristos */ 1001*7bdf38e5Schristos TEST_BEGIN(test_rb_unsummarized) { 1002*7bdf38e5Schristos unsummarized_tree_t tree; 1003*7bdf38e5Schristos unsummarized_tree_new(&tree); 1004*7bdf38e5Schristos unsigned nnodes = 0; 1005*7bdf38e5Schristos unsummarized_tree_iter(&tree, NULL, &unsummarized_tree_iterate_cb, 1006*7bdf38e5Schristos &nnodes); 1007*7bdf38e5Schristos expect_u_eq(0, nnodes, ""); 1008a0698ed9Schristos } 1009a0698ed9Schristos TEST_END 1010a0698ed9Schristos 1011a0698ed9Schristos int 1012a0698ed9Schristos main(void) { 1013*7bdf38e5Schristos return test_no_reentrancy( 1014a0698ed9Schristos test_rb_empty, 1015*7bdf38e5Schristos test_rb_random, 1016*7bdf38e5Schristos test_rb_filter_simple, 1017*7bdf38e5Schristos test_rb_update_search, 1018*7bdf38e5Schristos test_rb_unsummarized); 1019a0698ed9Schristos } 1020