1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1997 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
22 ***************************************************************************/
29 #define compare(i,j) ((i)-(j))
31 /* Set this to a key value that will *NEVER* appear otherwise */
32 #define KEY_NOTUSED -1
35 * Splay using the key i (which may or may not be in the tree.) The starting
38 struct Curl_tree *Curl_splay(int i, struct Curl_tree *t)
40 struct Curl_tree N, *l, *r, *y;
45 N.smaller = N.larger = NULL;
49 comp = compare(i, t->key);
51 if (t->smaller == NULL)
53 if (compare(i, t->smaller->key) < 0) {
54 y = t->smaller; /* rotate smaller */
55 t->smaller = y->larger;
58 if (t->smaller == NULL)
61 r->smaller = t; /* link smaller */
66 if (t->larger == NULL)
68 if (compare(i, t->larger->key) > 0) {
69 y = t->larger; /* rotate larger */
70 t->larger = y->smaller;
73 if (t->larger == NULL)
76 l->larger = t; /* link larger */
83 l->larger = r->smaller = NULL;
85 l->larger = t->smaller; /* assemble */
86 r->smaller = t->larger;
87 t->smaller = N.larger;
88 t->larger = N.smaller;
93 /* Insert key i into the tree t. Return a pointer to the resulting tree or
94 NULL if something went wrong. */
95 struct Curl_tree *Curl_splayinsert(int i,
97 struct Curl_tree *node)
104 if (compare(i, t->key)==0) {
105 /* There already exists a node in the tree with the very same key. Build
106 a linked list of nodes. We make the new 'node' struct the new master
107 node and make the previous node the first one in the 'same' list. */
111 node->smaller = t->smaller;
112 node->larger = t->larger;
114 t->smaller = node; /* in the sub node for this same key, we use the
115 smaller pointer to point back to the master
117 t->key = KEY_NOTUSED; /* and we set the key in the sub node to NOTUSED
118 to quickly identify this node as a subnode */
120 return node; /* new root node */
125 node->smaller = node->larger = NULL;
127 else if (compare(i, t->key) < 0) {
128 node->smaller = t->smaller;
134 node->larger = t->larger;
140 node->same = NULL; /* no identical node (yet) */
145 /* Deletes 'i' from the tree if it's there (with an exact match). Returns a
146 pointer to the resulting tree.
148 Function not used in libcurl.
150 struct Curl_tree *Curl_splayremove(int i, struct Curl_tree *t,
151 struct Curl_tree **removed)
155 *removed = NULL; /* default to no removed */
161 if (compare(i, t->key) == 0) { /* found it */
163 /* FIRST! Check if there is a list with identical sizes */
165 /* there is, pick one from the list */
167 /* 'x' is the new root node */
170 x->larger = t->larger;
171 x->smaller = t->smaller;
174 return x; /* new root */
177 if (t->smaller == NULL) {
181 x = Curl_splay(i, t->smaller);
182 x->larger = t->larger;
189 return t; /* It wasn't there */
193 /* Finds and deletes the best-fit node from the tree. Return a pointer to the
194 resulting tree. best-fit means the node with the given or lower number */
195 struct Curl_tree *Curl_splaygetbest(int i, struct Curl_tree *t,
196 struct Curl_tree **removed)
201 *removed = NULL; /* none removed since there was no root */
206 if(compare(i, t->key) < 0) {
207 /* too big node, try the smaller chain */
209 t=Curl_splay(t->smaller->key, t);
217 if (compare(i, t->key) >= 0) { /* found it */
218 /* FIRST! Check if there is a list with identical sizes */
221 /* there is, pick one from the list */
223 /* 'x' is the new root node */
226 x->larger = t->larger;
227 x->smaller = t->smaller;
230 return x; /* new root */
233 if (t->smaller == NULL) {
237 x = Curl_splay(i, t->smaller);
238 x->larger = t->larger;
245 *removed = NULL; /* no match */
246 return t; /* It wasn't there */
251 /* Deletes the very node we point out from the tree if it's there. Stores a
252 pointer to the new resulting tree in 'newroot'.
254 Returns zero on success and non-zero on errors! TODO: document error codes.
255 When returning error, it does not touch the 'newroot' pointer.
257 NOTE: when the last node of the tree is removed, there's no tree left so
258 'newroot' will be made to point to NULL.
260 int Curl_splayremovebyaddr(struct Curl_tree *t,
261 struct Curl_tree *remove,
262 struct Curl_tree **newroot)
269 if(KEY_NOTUSED == remove->key) {
270 /* Key set to NOTUSED means it is a subnode within a 'same' linked list
271 and thus we can unlink it easily. The 'smaller' link of a subnode
272 links to the parent node. */
273 remove->smaller->same = remove->same;
275 remove->same->smaller = remove->smaller;
276 /* voila, we're done! */
277 *newroot = t; /* return the same root */
281 t = Curl_splay(remove->key, t);
283 /* First make sure that we got a root node witht he same key as the one we
284 want to remove, as otherwise we might be trying to remove a node that
285 isn't actually in the tree. */
286 if(t->key != remove->key)
289 /* Check if there is a list with identical sizes, as then we're trying to
290 remove the root node of a list of nodes with identical keys. */
293 /* 'x' is the new root node, we just make it use the root node's
294 smaller/larger links */
297 x->larger = t->larger;
298 x->smaller = t->smaller;
301 /* Remove the root node */
302 if (t->smaller == NULL)
305 x = Curl_splay(remove->key, t->smaller);
306 x->larger = t->larger;
310 *newroot = x; /* store new root pointer */
317 void Curl_splayprint(struct Curl_tree * t, int d, char output)
319 struct Curl_tree *node;
325 Curl_splayprint(t->larger, d+1, output);
331 printf("%d[%d]", t->key, i);
334 for(count=0, node = t->same; node; node = node->same, count++)
339 printf(" [%d more]\n", count);
344 Curl_splayprint(t->smaller, d+1, output);
354 /* A sample use of these functions. Start with the empty tree, insert some
355 stuff into it, and then delete it */
356 int main(int argc, char **argv)
358 struct Curl_tree *root, *t;
364 50, 60, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, 300,
365 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200,
366 300, 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120,
367 200, 300, 220, 80, 90};
369 root = NULL; /* the empty tree */
371 for (i = 0; i < MAX; i++) {
373 ptrs[i] = t = (struct Curl_tree *)malloc(sizeof(struct Curl_tree));
383 t->payload = (void *)key; /* for simplicity */
385 puts("out of memory!");
388 root = Curl_splayinsert(key, root, t);
393 Curl_splayprint(root, 0, 1);
397 for (i = 0; i < MAX; i++) {
400 printf("Tree look:\n");
401 Curl_splayprint(root, 0, 1);
402 printf("remove pointer %d, payload %d\n", rem,
403 (int)((struct Curl_tree *)ptrs[rem])->payload);
404 rc = Curl_splayremovebyaddr(root, (struct Curl_tree *)ptrs[rem], &root);
407 printf("remove %d failed!\n", rem);
414 #endif /* TEST_SPLAY */