/* Find or insert datum into search tree. KEY is the key to be located, ROOTP is the address of tree root, COMPAR the ordering function. */ void * __tsearch (const void *key, void **vrootp, __compar_fn_t compar) { node q; node *parentp = NULL, *gparentp = NULL; node *rootp = (node *) vrootp; node *nextp; int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler. */ if (rootp == NULL) return NULL; /* This saves some additional tests below. */ if (*rootp != NULL) (*rootp)->red = 0; CHECK_TREE (*rootp); nextp = rootp; while (*nextp != NULL) { node root = *rootp; r = (*compar) (key, root->key); if (r == 0) return root; maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0); /* If that did any rotations, parentp and gparentp are now garbage. That doesn't matter, because the values they contain are never used again in that case. */ nextp = r < 0 ? &root->left : &root->right; if (*nextp == NULL) break; gparentp = parentp; parentp = rootp; rootp = nextp; gp_r = p_r; p_r = r; } q = (struct node_t *) malloc (sizeof (struct node_t)); if (q != NULL) { *nextp = q; /* link new node to old */ q->key = key; /* initialize new node */ q->red = 1; q->left = q->right = NULL; if (nextp != rootp) /* There may be two red edges in a row now, which we must avoid by rotating the tree. */ maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1); } return q; }
/** * Find or insert datum with given key into search tree. rootp * is the address of tree root, cmpfun the ordering function. */ GtKeytype gt_rbt_search(const GtKeytype key, bool *nodecreated, GtRBTnode **rootp, GtDictcomparefunction cmpfun, void *cmpinfo) { GtRBTnode *newnode, **parentp = NULL, **gparentp = NULL, **nextp; int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler. */ if (rootp == NULL) { *nodecreated = false; return GtKeytypeerror; } /* This saves some additional tests below. */ if (*rootp != NULL) { (*rootp)->red = false; } CHECK_TREE (*rootp); nextp = rootp; while (*nextp != NULL) { GtRBTnode *root = *rootp; r = cmpfun (key, root->key, cmpinfo); if (r == 0) { *nodecreated = false; return root->key; } maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0); /* * If that did any rotations, parentp and gparentp are now garbage. That * doesn't matter, because the values they contain are never used again in * that case. */ nextp = r < 0 ? &root->left : &root->right; if (*nextp == NULL) { break; } gparentp = parentp; parentp = rootp; rootp = nextp; gp_r = p_r; p_r = r; } newnode = (GtRBTnode *) gt_malloc (sizeof (GtRBTnode)); *nextp = newnode; /* link new node to old */ newnode->key = key; /* initialize new node */ newnode->red = true; newnode->left = NULL; newnode->right = NULL; if (nextp != rootp) { /* There may be two red edges in a row now, which we must avoid by rotating the tree. */ maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1UL); } *nodecreated = true; return newnode->key; }
/* Find or insert datum into search tree. KEY is the key to be located, ROOTP is the address of tree root, COMPAR the ordering function. */ void * __tsearch (const void *key, void **vrootp, __compar_fn_t compar) { node q, root; node *parentp = NULL, *gparentp = NULL; node *rootp = (node *) vrootp; node *nextp; int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler. */ #ifdef USE_MALLOC_LOW_BIT static_assert (alignof (max_align_t) > 1, "malloc must return aligned ptrs"); #endif if (rootp == NULL) return NULL; /* This saves some additional tests below. */ root = DEREFNODEPTR(rootp); if (root != NULL) SETBLACK(root); CHECK_TREE (root); nextp = rootp; while (DEREFNODEPTR(nextp) != NULL) { root = DEREFNODEPTR(rootp); r = (*compar) (key, root->key); if (r == 0) return root; maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0); /* If that did any rotations, parentp and gparentp are now garbage. That doesn't matter, because the values they contain are never used again in that case. */ nextp = r < 0 ? LEFTPTR(root) : RIGHTPTR(root); if (DEREFNODEPTR(nextp) == NULL) break; gparentp = parentp; parentp = rootp; rootp = nextp; gp_r = p_r; p_r = r; } q = (struct node_t *) malloc (sizeof (struct node_t)); if (q != NULL) { /* Make sure the malloc implementation returns naturally aligned memory blocks when expected. Or at least even pointers, so we can use the low bit as red/black flag. Even though we have a static_assert to make sure alignof (max_align_t) > 1 there could be an interposed malloc implementation that might cause havoc by not obeying the malloc contract. */ #ifdef USE_MALLOC_LOW_BIT assert (((uintptr_t) q & (uintptr_t) 0x1) == 0); #endif SETNODEPTR(nextp,q); /* link new node to old */ q->key = key; /* initialize new node */ SETRED(q); SETLEFT(q,NULL); SETRIGHT(q,NULL); if (nextp != rootp) /* There may be two red edges in a row now, which we must avoid by rotating the tree. */ maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1); } return q; }