1*459d04a5SEd Schouten /*- 2*459d04a5SEd Schouten * Copyright (c) 2015 Nuxi, https://nuxi.nl/ 364566a3eSAlfred Perlstein * 4*459d04a5SEd Schouten * Redistribution and use in source and binary forms, with or without 5*459d04a5SEd Schouten * modification, are permitted provided that the following conditions 6*459d04a5SEd Schouten * are met: 7*459d04a5SEd Schouten * 1. Redistributions of source code must retain the above copyright 8*459d04a5SEd Schouten * notice, this list of conditions and the following disclaimer. 9*459d04a5SEd Schouten * 2. Redistributions in binary form must reproduce the above copyright 10*459d04a5SEd Schouten * notice, this list of conditions and the following disclaimer in the 11*459d04a5SEd Schouten * documentation and/or other materials provided with the distribution. 1264566a3eSAlfred Perlstein * 13*459d04a5SEd Schouten * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*459d04a5SEd Schouten * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*459d04a5SEd Schouten * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*459d04a5SEd Schouten * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17*459d04a5SEd Schouten * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*459d04a5SEd Schouten * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*459d04a5SEd Schouten * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*459d04a5SEd Schouten * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*459d04a5SEd Schouten * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*459d04a5SEd Schouten * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*459d04a5SEd Schouten * SUCH DAMAGE. 2464566a3eSAlfred Perlstein */ 2564566a3eSAlfred Perlstein 2664566a3eSAlfred Perlstein #include <sys/cdefs.h> 27333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 2864566a3eSAlfred Perlstein 2964566a3eSAlfred Perlstein #define _SEARCH_PRIVATE 3064566a3eSAlfred Perlstein #include <search.h> 3164566a3eSAlfred Perlstein #include <stdlib.h> 3264566a3eSAlfred Perlstein 33*459d04a5SEd Schouten #include "tsearch_path.h" 34*459d04a5SEd Schouten 3564566a3eSAlfred Perlstein void * 36*459d04a5SEd Schouten tsearch(const void *key, void **rootp, 378a29851fSPedro F. Giffuni int (*compar)(const void *, const void *)) 3864566a3eSAlfred Perlstein { 39*459d04a5SEd Schouten struct path path; 40*459d04a5SEd Schouten node_t *root, **base, **leaf, *result, *n, *x, *y, *z; 41*459d04a5SEd Schouten int cmp; 4264566a3eSAlfred Perlstein 43*459d04a5SEd Schouten /* POSIX requires that tsearch() returns NULL if rootp is NULL. */ 4464566a3eSAlfred Perlstein if (rootp == NULL) 45*459d04a5SEd Schouten return (NULL); 46*459d04a5SEd Schouten root = *rootp; 4764566a3eSAlfred Perlstein 48*459d04a5SEd Schouten /* 49*459d04a5SEd Schouten * Find the leaf where the new key needs to be inserted. Return 50*459d04a5SEd Schouten * if we've found an existing entry. Keep track of the path that 51*459d04a5SEd Schouten * is taken to get to the node, as we will need it to adjust the 52*459d04a5SEd Schouten * balances. 53*459d04a5SEd Schouten */ 54*459d04a5SEd Schouten path_init(&path); 55*459d04a5SEd Schouten base = &root; 56*459d04a5SEd Schouten leaf = &root; 57*459d04a5SEd Schouten while (*leaf != NULL) { 58*459d04a5SEd Schouten if ((*leaf)->balance != 0) { 59*459d04a5SEd Schouten /* 60*459d04a5SEd Schouten * If we reach a node that has a non-zero 61*459d04a5SEd Schouten * balance on the way, we know that we won't 62*459d04a5SEd Schouten * need to perform any rotations above this 63*459d04a5SEd Schouten * point. In this case rotations are always 64*459d04a5SEd Schouten * capable of keeping the subtree in balance. 65*459d04a5SEd Schouten * Make this the base node and reset the path. 66*459d04a5SEd Schouten */ 67*459d04a5SEd Schouten base = leaf; 68*459d04a5SEd Schouten path_init(&path); 69*459d04a5SEd Schouten } 70*459d04a5SEd Schouten cmp = compar(key, (*leaf)->key); 71*459d04a5SEd Schouten if (cmp < 0) { 72*459d04a5SEd Schouten path_taking_left(&path); 73*459d04a5SEd Schouten leaf = &(*leaf)->llink; 74*459d04a5SEd Schouten } else if (cmp > 0) { 75*459d04a5SEd Schouten path_taking_right(&path); 76*459d04a5SEd Schouten leaf = &(*leaf)->rlink; 77*459d04a5SEd Schouten } else { 78*459d04a5SEd Schouten return (&(*leaf)->key); 79*459d04a5SEd Schouten } 8064566a3eSAlfred Perlstein } 8164566a3eSAlfred Perlstein 82*459d04a5SEd Schouten /* Did not find a matching key in the tree. Insert a new node. */ 83*459d04a5SEd Schouten result = *leaf = malloc(sizeof(**leaf)); 84*459d04a5SEd Schouten if (result == NULL) 85*459d04a5SEd Schouten return (NULL); 86*459d04a5SEd Schouten result->key = (void *)key; 87*459d04a5SEd Schouten result->llink = NULL; 88*459d04a5SEd Schouten result->rlink = NULL; 89*459d04a5SEd Schouten result->balance = 0; 90*459d04a5SEd Schouten 91*459d04a5SEd Schouten /* 92*459d04a5SEd Schouten * Walk along the same path a second time and adjust the 93*459d04a5SEd Schouten * balances. Except for the first node, all of these nodes must 94*459d04a5SEd Schouten * have a balance of zero, meaning that these nodes will not get 95*459d04a5SEd Schouten * out of balance. 96*459d04a5SEd Schouten */ 97*459d04a5SEd Schouten for (n = *base; n != *leaf;) { 98*459d04a5SEd Schouten if (path_took_left(&path)) { 99*459d04a5SEd Schouten n->balance += 1; 100*459d04a5SEd Schouten n = n->llink; 101*459d04a5SEd Schouten } else { 102*459d04a5SEd Schouten n->balance -= 1; 103*459d04a5SEd Schouten n = n->rlink; 10464566a3eSAlfred Perlstein } 105*459d04a5SEd Schouten } 106*459d04a5SEd Schouten 107*459d04a5SEd Schouten /* 108*459d04a5SEd Schouten * Adjusting the balances may have pushed the balance of the 109*459d04a5SEd Schouten * base node out of range. Perform a rotation to bring the 110*459d04a5SEd Schouten * balance back in range. 111*459d04a5SEd Schouten */ 112*459d04a5SEd Schouten x = *base; 113*459d04a5SEd Schouten if (x->balance > 1) { 114*459d04a5SEd Schouten y = x->llink; 115*459d04a5SEd Schouten if (y->balance < 0) { 116*459d04a5SEd Schouten /* 117*459d04a5SEd Schouten * Left-right case. 118*459d04a5SEd Schouten * 119*459d04a5SEd Schouten * x 120*459d04a5SEd Schouten * / \ z 121*459d04a5SEd Schouten * y D / \ 122*459d04a5SEd Schouten * / \ --> y x 123*459d04a5SEd Schouten * A z /| |\ 124*459d04a5SEd Schouten * / \ A B C D 125*459d04a5SEd Schouten * B C 126*459d04a5SEd Schouten */ 127*459d04a5SEd Schouten z = y->rlink; 128*459d04a5SEd Schouten y->rlink = z->llink; 129*459d04a5SEd Schouten z->llink = y; 130*459d04a5SEd Schouten x->llink = z->rlink; 131*459d04a5SEd Schouten z->rlink = x; 132*459d04a5SEd Schouten *base = z; 133*459d04a5SEd Schouten 134*459d04a5SEd Schouten x->balance = z->balance > 0 ? -1 : 0; 135*459d04a5SEd Schouten y->balance = z->balance < 0 ? 1 : 0; 136*459d04a5SEd Schouten z->balance = 0; 137*459d04a5SEd Schouten } else { 138*459d04a5SEd Schouten /* 139*459d04a5SEd Schouten * Left-left case. 140*459d04a5SEd Schouten * 141*459d04a5SEd Schouten * x y 142*459d04a5SEd Schouten * / \ / \ 143*459d04a5SEd Schouten * y C --> A x 144*459d04a5SEd Schouten * / \ / \ 145*459d04a5SEd Schouten * A B B C 146*459d04a5SEd Schouten */ 147*459d04a5SEd Schouten x->llink = y->rlink; 148*459d04a5SEd Schouten y->rlink = x; 149*459d04a5SEd Schouten *base = y; 150*459d04a5SEd Schouten 151*459d04a5SEd Schouten x->balance = 0; 152*459d04a5SEd Schouten y->balance = 0; 153*459d04a5SEd Schouten } 154*459d04a5SEd Schouten } else if (x->balance < -1) { 155*459d04a5SEd Schouten y = x->rlink; 156*459d04a5SEd Schouten if (y->balance > 0) { 157*459d04a5SEd Schouten /* 158*459d04a5SEd Schouten * Right-left case. 159*459d04a5SEd Schouten * 160*459d04a5SEd Schouten * x 161*459d04a5SEd Schouten * / \ z 162*459d04a5SEd Schouten * A y / \ 163*459d04a5SEd Schouten * / \ --> x y 164*459d04a5SEd Schouten * z D /| |\ 165*459d04a5SEd Schouten * / \ A B C D 166*459d04a5SEd Schouten * B C 167*459d04a5SEd Schouten */ 168*459d04a5SEd Schouten node_t *z = y->llink; 169*459d04a5SEd Schouten x->rlink = z->llink; 170*459d04a5SEd Schouten z->llink = x; 171*459d04a5SEd Schouten y->llink = z->rlink; 172*459d04a5SEd Schouten z->rlink = y; 173*459d04a5SEd Schouten *base = z; 174*459d04a5SEd Schouten 175*459d04a5SEd Schouten x->balance = z->balance < 0 ? 1 : 0; 176*459d04a5SEd Schouten y->balance = z->balance > 0 ? -1 : 0; 177*459d04a5SEd Schouten z->balance = 0; 178*459d04a5SEd Schouten } else { 179*459d04a5SEd Schouten /* 180*459d04a5SEd Schouten * Right-right case. 181*459d04a5SEd Schouten * 182*459d04a5SEd Schouten * x y 183*459d04a5SEd Schouten * / \ / \ 184*459d04a5SEd Schouten * A y --> x C 185*459d04a5SEd Schouten * / \ / \ 186*459d04a5SEd Schouten * B C A B 187*459d04a5SEd Schouten */ 188*459d04a5SEd Schouten x->rlink = y->llink; 189*459d04a5SEd Schouten y->llink = x; 190*459d04a5SEd Schouten *base = y; 191*459d04a5SEd Schouten 192*459d04a5SEd Schouten x->balance = 0; 193*459d04a5SEd Schouten y->balance = 0; 194*459d04a5SEd Schouten } 195*459d04a5SEd Schouten } 196*459d04a5SEd Schouten 197*459d04a5SEd Schouten /* Return the new entry. */ 198*459d04a5SEd Schouten *rootp = root; 199*459d04a5SEd Schouten return (&result->key); 20064566a3eSAlfred Perlstein } 201