splay.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1997 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #include "splay.h"
00026 
00027 /*
00028  * This macro compares two node keys i and j and returns:
00029  *
00030  *  negative value: when i is smaller than j
00031  *  zero          : when i is equal   to   j
00032  *  positive when : when i is larger  than j
00033  */
00034 #define compare(i,j) Curl_splaycomparekeys((i),(j))
00035 
00036 /*
00037  * Splay using the key i (which may or may not be in the tree.) The starting
00038  * root is t.
00039  */
00040 struct Curl_tree *Curl_splay(struct timeval i,
00041                              struct Curl_tree *t)
00042 {
00043   struct Curl_tree N, *l, *r, *y;
00044   long comp;
00045 
00046   if(t == NULL)
00047     return t;
00048   N.smaller = N.larger = NULL;
00049   l = r = &N;
00050 
00051   for(;;) {
00052     comp = compare(i, t->key);
00053     if(comp < 0) {
00054       if(t->smaller == NULL)
00055         break;
00056       if(compare(i, t->smaller->key) < 0) {
00057         y = t->smaller;                           /* rotate smaller */
00058         t->smaller = y->larger;
00059         y->larger = t;
00060         t = y;
00061         if(t->smaller == NULL)
00062           break;
00063       }
00064       r->smaller = t;                               /* link smaller */
00065       r = t;
00066       t = t->smaller;
00067     }
00068     else if(comp > 0) {
00069       if(t->larger == NULL)
00070         break;
00071       if(compare(i, t->larger->key) > 0) {
00072         y = t->larger;                          /* rotate larger */
00073         t->larger = y->smaller;
00074         y->smaller = t;
00075         t = y;
00076         if(t->larger == NULL)
00077           break;
00078       }
00079       l->larger = t;                              /* link larger */
00080       l = t;
00081       t = t->larger;
00082     }
00083     else
00084       break;
00085   }
00086 
00087   l->larger = t->smaller;                                /* assemble */
00088   r->smaller = t->larger;
00089   t->smaller = N.larger;
00090   t->larger = N.smaller;
00091 
00092   return t;
00093 }
00094 
00095 /* Insert key i into the tree t.  Return a pointer to the resulting tree or
00096  * NULL if something went wrong.
00097  *
00098  * @unittest: 1309
00099  */
00100 struct Curl_tree *Curl_splayinsert(struct timeval i,
00101                                    struct Curl_tree *t,
00102                                    struct Curl_tree *node)
00103 {
00104   static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */
00105 
00106   if(node == NULL)
00107     return t;
00108 
00109   if(t != NULL) {
00110     t = Curl_splay(i, t);
00111     if(compare(i, t->key)==0) {
00112       /* There already exists a node in the tree with the very same key. Build
00113          a linked list of nodes. We make the new 'node' struct the new master
00114          node and make the previous node the first one in the 'same' list. */
00115 
00116       node->same = t;
00117       node->key = i;
00118       node->smaller = t->smaller;
00119       node->larger = t->larger;
00120 
00121       t->smaller = node; /* in the sub node for this same key, we use the
00122                             smaller pointer to point back to the master
00123                             node */
00124 
00125       t->key = KEY_NOTUSED; /* and we set the key in the sub node to NOTUSED
00126                                to quickly identify this node as a subnode */
00127 
00128       return node; /* new root node */
00129     }
00130   }
00131 
00132   if(t == NULL) {
00133     node->smaller = node->larger = NULL;
00134   }
00135   else if(compare(i, t->key) < 0) {
00136     node->smaller = t->smaller;
00137     node->larger = t;
00138     t->smaller = NULL;
00139 
00140   }
00141   else {
00142     node->larger = t->larger;
00143     node->smaller = t;
00144     t->larger = NULL;
00145   }
00146   node->key = i;
00147 
00148   node->same = NULL; /* no identical node (yet) */
00149   return node;
00150 }
00151 
00152 /* Finds and deletes the best-fit node from the tree. Return a pointer to the
00153    resulting tree.  best-fit means the node with the given or lower key */
00154 struct Curl_tree *Curl_splaygetbest(struct timeval i,
00155                                     struct Curl_tree *t,
00156                                     struct Curl_tree **removed)
00157 {
00158   struct Curl_tree *x;
00159 
00160   if(!t) {
00161     *removed = NULL; /* none removed since there was no root */
00162     return NULL;
00163   }
00164 
00165   t = Curl_splay(i, t);
00166   if(compare(i, t->key) < 0) {
00167     /* too big node, try the smaller chain */
00168     if(t->smaller)
00169       t=Curl_splay(t->smaller->key, t);
00170     else {
00171       /* fail */
00172       *removed = NULL;
00173       return t;
00174     }
00175   }
00176 
00177   if(compare(i, t->key) >= 0) {               /* found it */
00178     /* FIRST! Check if there is a list with identical keys */
00179     x = t->same;
00180     if(x) {
00181       /* there is, pick one from the list */
00182 
00183       /* 'x' is the new root node */
00184 
00185       x->key = t->key;
00186       x->larger = t->larger;
00187       x->smaller = t->smaller;
00188 
00189       *removed = t;
00190       return x; /* new root */
00191     }
00192 
00193     if(t->smaller == NULL) {
00194       x = t->larger;
00195     }
00196     else {
00197       x = Curl_splay(i, t->smaller);
00198       x->larger = t->larger;
00199     }
00200     *removed = t;
00201 
00202     return x;
00203   }
00204   else {
00205     *removed = NULL; /* no match */
00206     return t;        /* It wasn't there */
00207   }
00208 }
00209 
00210 
00211 /* Deletes the very node we point out from the tree if it's there. Stores a
00212  * pointer to the new resulting tree in 'newroot'.
00213  *
00214  * Returns zero on success and non-zero on errors! TODO: document error codes.
00215  * When returning error, it does not touch the 'newroot' pointer.
00216  *
00217  * NOTE: when the last node of the tree is removed, there's no tree left so
00218  * 'newroot' will be made to point to NULL.
00219  *
00220  * @unittest: 1309
00221  */
00222 int Curl_splayremovebyaddr(struct Curl_tree *t,
00223                            struct Curl_tree *removenode,
00224                            struct Curl_tree **newroot)
00225 {
00226   static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */
00227   struct Curl_tree *x;
00228 
00229   if(!t || !removenode)
00230     return 1;
00231 
00232   if(compare(KEY_NOTUSED, removenode->key) == 0) {
00233     /* Key set to NOTUSED means it is a subnode within a 'same' linked list
00234        and thus we can unlink it easily. The 'smaller' link of a subnode
00235        links to the parent node. */
00236     if(removenode->smaller == NULL)
00237       return 3;
00238 
00239     removenode->smaller->same = removenode->same;
00240     if(removenode->same)
00241       removenode->same->smaller = removenode->smaller;
00242 
00243     /* Ensures that double-remove gets caught. */
00244     removenode->smaller = NULL;
00245 
00246     /* voila, we're done! */
00247     *newroot = t; /* return the same root */
00248     return 0;
00249   }
00250 
00251   t = Curl_splay(removenode->key, t);
00252 
00253   /* First make sure that we got the same root node as the one we want
00254      to remove, as otherwise we might be trying to remove a node that
00255      isn't actually in the tree.
00256 
00257      We cannot just compare the keys here as a double remove in quick
00258      succession of a node with key != KEY_NOTUSED && same != NULL
00259      could return the same key but a different node. */
00260   if(t != removenode)
00261     return 2;
00262 
00263   /* Check if there is a list with identical sizes, as then we're trying to
00264      remove the root node of a list of nodes with identical keys. */
00265   x = t->same;
00266   if(x) {
00267     /* 'x' is the new root node, we just make it use the root node's
00268        smaller/larger links */
00269 
00270     x->key = t->key;
00271     x->larger = t->larger;
00272     x->smaller = t->smaller;
00273   }
00274   else {
00275     /* Remove the root node */
00276     if(t->smaller == NULL)
00277       x = t->larger;
00278     else {
00279       x = Curl_splay(removenode->key, t->smaller);
00280       x->larger = t->larger;
00281     }
00282   }
00283 
00284   *newroot = x; /* store new root pointer */
00285 
00286   return 0;
00287 }
00288 


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:06