1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1997 - 2009, 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.
21 ***************************************************************************/
28 * This macro compares two node keys i and j and returns:
30 * negative value: when i is smaller than j
31 * zero : when i is equal to j
32 * positive when : when i is larger than j
34 #define compare(i,j) Curl_splaycomparekeys((i),(j))
37 * Splay using the key i (which may or may not be in the tree.) The starting
40 struct Curl_tree *Curl_splay(struct timeval i,
43 struct Curl_tree N, *l, *r, *y;
48 N.smaller = N.larger = NULL;
52 comp = compare(i, t->key);
54 if(t->smaller == NULL)
56 if(compare(i, t->smaller->key) < 0) {
57 y = t->smaller; /* rotate smaller */
58 t->smaller = y->larger;
61 if(t->smaller == NULL)
64 r->smaller = t; /* link smaller */
71 if(compare(i, t->larger->key) > 0) {
72 y = t->larger; /* rotate larger */
73 t->larger = y->smaller;
79 l->larger = t; /* link larger */
87 l->larger = t->smaller; /* assemble */
88 r->smaller = t->larger;
89 t->smaller = N.larger;
90 t->larger = N.smaller;
95 /* Insert key i into the tree t. Return a pointer to the resulting tree or
96 NULL if something went wrong. */
97 struct Curl_tree *Curl_splayinsert(struct timeval i,
99 struct Curl_tree *node)
101 static struct timeval KEY_NOTUSED = {-1,-1}; /* key that will *NEVER* appear */
108 if(compare(i, t->key)==0) {
109 /* There already exists a node in the tree with the very same key. Build
110 a linked list of nodes. We make the new 'node' struct the new master
111 node and make the previous node the first one in the 'same' list. */
115 node->smaller = t->smaller;
116 node->larger = t->larger;
118 t->smaller = node; /* in the sub node for this same key, we use the
119 smaller pointer to point back to the master
122 t->key = KEY_NOTUSED; /* and we set the key in the sub node to NOTUSED
123 to quickly identify this node as a subnode */
125 return node; /* new root node */
130 node->smaller = node->larger = NULL;
132 else if(compare(i, t->key) < 0) {
133 node->smaller = t->smaller;
139 node->larger = t->larger;
145 node->same = NULL; /* no identical node (yet) */
150 /* Deletes 'i' from the tree if it's there (with an exact match). Returns a
151 pointer to the resulting tree.
153 Function not used in libcurl.
155 struct Curl_tree *Curl_splayremove(struct timeval i,
157 struct Curl_tree **removed)
161 *removed = NULL; /* default to no removed */
167 if(compare(i, t->key) == 0) { /* found it */
169 /* FIRST! Check if there is a list with identical sizes */
170 if((x = t->same) != NULL) {
171 /* there is, pick one from the list */
173 /* 'x' is the new root node */
176 x->larger = t->larger;
177 x->smaller = t->smaller;
180 return x; /* new root */
183 if(t->smaller == NULL) {
187 x = Curl_splay(i, t->smaller);
188 x->larger = t->larger;
195 return t; /* It wasn't there */
199 /* Finds and deletes the best-fit node from the tree. Return a pointer to the
200 resulting tree. best-fit means the node with the given or lower key */
201 struct Curl_tree *Curl_splaygetbest(struct timeval i,
203 struct Curl_tree **removed)
208 *removed = NULL; /* none removed since there was no root */
213 if(compare(i, t->key) < 0) {
214 /* too big node, try the smaller chain */
216 t=Curl_splay(t->smaller->key, t);
224 if(compare(i, t->key) >= 0) { /* found it */
225 /* FIRST! Check if there is a list with identical keys */
228 /* there is, pick one from the list */
230 /* 'x' is the new root node */
233 x->larger = t->larger;
234 x->smaller = t->smaller;
237 return x; /* new root */
240 if(t->smaller == NULL) {
244 x = Curl_splay(i, t->smaller);
245 x->larger = t->larger;
252 *removed = NULL; /* no match */
253 return t; /* It wasn't there */
258 /* Deletes the very node we point out from the tree if it's there. Stores a
259 pointer to the new resulting tree in 'newroot'.
261 Returns zero on success and non-zero on errors! TODO: document error codes.
262 When returning error, it does not touch the 'newroot' pointer.
264 NOTE: when the last node of the tree is removed, there's no tree left so
265 'newroot' will be made to point to NULL.
267 int Curl_splayremovebyaddr(struct Curl_tree *t,
268 struct Curl_tree *removenode,
269 struct Curl_tree **newroot)
271 static struct timeval KEY_NOTUSED = {-1,-1}; /* key that will *NEVER* appear */
274 if(!t || !removenode)
277 if(compare(KEY_NOTUSED, removenode->key) == 0) {
278 /* Key set to NOTUSED means it is a subnode within a 'same' linked list
279 and thus we can unlink it easily. The 'smaller' link of a subnode
280 links to the parent node. */
281 if(removenode->smaller == NULL)
284 removenode->smaller->same = removenode->same;
286 removenode->same->smaller = removenode->smaller;
288 /* Ensures that double-remove gets caught. */
289 removenode->smaller = NULL;
291 /* voila, we're done! */
292 *newroot = t; /* return the same root */
296 t = Curl_splay(removenode->key, t);
298 /* First make sure that we got the same root node as the one we want
299 to remove, as otherwise we might be trying to remove a node that
300 isn't actually in the tree.
302 We cannot just compare the keys here as a double remove in quick
303 succession of a node with key != KEY_NOTUSED && same != NULL
304 could return the same key but a different node. */
308 /* Check if there is a list with identical sizes, as then we're trying to
309 remove the root node of a list of nodes with identical keys. */
312 /* 'x' is the new root node, we just make it use the root node's
313 smaller/larger links */
316 x->larger = t->larger;
317 x->smaller = t->smaller;
320 /* Remove the root node */
321 if(t->smaller == NULL)
324 x = Curl_splay(removenode->key, t->smaller);
325 x->larger = t->larger;
329 *newroot = x; /* store new root pointer */
336 void Curl_splayprint(struct Curl_tree * t, int d, char output)
338 struct Curl_tree *node;
344 Curl_splayprint(t->larger, d+1, output);
347 fprintf(stderr, " ");
351 fprintf(stderr, "%ld[%d]", (long)t->key.tv_usec, i);
353 fprintf(stderr, "%ld.%ld[%d]", (long)t->key.tv_sec, (long)t->key.tv_usec, i);
357 for(count=0, node = t->same; node; node = node->same, count++)
362 fprintf(stderr, " [%d more]\n", count);
364 fprintf(stderr, "\n");
367 Curl_splayprint(t->smaller, d+1, output);
377 /* A sample use of these functions. Start with the empty tree, insert some
378 stuff into it, and then delete it */
379 int main(int argc, argv_item_t argv[])
381 struct Curl_tree *root, *t;
386 static const long sizes[]={
387 50, 60, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, 300,
388 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200,
389 300, 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120,
390 200, 300, 220, 80, 90};
392 root = NULL; /* the empty tree */
394 for (i = 0; i < MAX; i++) {
396 ptrs[i] = t = malloc(sizeof(struct Curl_tree));
398 puts("out of memory!");
404 key.tv_usec = sizes[i];
406 key.tv_usec = (541*i)%1023;
411 t->payload = (void *)key.tv_usec; /* for simplicity */
412 root = Curl_splayinsert(key, root, t);
417 Curl_splayprint(root, 0, 1);
421 for (i = 0; i < MAX; i++) {
424 printf("Tree look:\n");
425 Curl_splayprint(root, 0, 1);
426 printf("remove pointer %d, payload %ld\n", rem,
427 (long)((struct Curl_tree *)ptrs[rem])->payload);
428 rc = Curl_splayremovebyaddr(root, (struct Curl_tree *)ptrs[rem], &root);
431 printf("remove %d failed!\n", rem);
438 #endif /* TEST_SPLAY */