xref: /aosp_15_r20/external/curl/lib/splay.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker 
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker #include "timeval.h"
28*6236dae4SAndroid Build Coastguard Worker #include "splay.h"
29*6236dae4SAndroid Build Coastguard Worker 
30*6236dae4SAndroid Build Coastguard Worker /*
31*6236dae4SAndroid Build Coastguard Worker  * This macro compares two node keys i and j and returns:
32*6236dae4SAndroid Build Coastguard Worker  *
33*6236dae4SAndroid Build Coastguard Worker  *  negative value: when i is smaller than j
34*6236dae4SAndroid Build Coastguard Worker  *  zero          : when i is equal   to   j
35*6236dae4SAndroid Build Coastguard Worker  *  positive when : when i is larger  than j
36*6236dae4SAndroid Build Coastguard Worker  */
37*6236dae4SAndroid Build Coastguard Worker #define compare(i,j) Curl_timediff_us(i,j)
38*6236dae4SAndroid Build Coastguard Worker 
39*6236dae4SAndroid Build Coastguard Worker /*
40*6236dae4SAndroid Build Coastguard Worker  * Splay using the key i (which may or may not be in the tree.) The starting
41*6236dae4SAndroid Build Coastguard Worker  * root is t.
42*6236dae4SAndroid Build Coastguard Worker  */
Curl_splay(struct curltime i,struct Curl_tree * t)43*6236dae4SAndroid Build Coastguard Worker struct Curl_tree *Curl_splay(struct curltime i,
44*6236dae4SAndroid Build Coastguard Worker                              struct Curl_tree *t)
45*6236dae4SAndroid Build Coastguard Worker {
46*6236dae4SAndroid Build Coastguard Worker   struct Curl_tree N, *l, *r, *y;
47*6236dae4SAndroid Build Coastguard Worker 
48*6236dae4SAndroid Build Coastguard Worker   if(!t)
49*6236dae4SAndroid Build Coastguard Worker     return NULL;
50*6236dae4SAndroid Build Coastguard Worker   N.smaller = N.larger = NULL;
51*6236dae4SAndroid Build Coastguard Worker   l = r = &N;
52*6236dae4SAndroid Build Coastguard Worker 
53*6236dae4SAndroid Build Coastguard Worker   for(;;) {
54*6236dae4SAndroid Build Coastguard Worker     timediff_t comp = compare(i, t->key);
55*6236dae4SAndroid Build Coastguard Worker     if(comp < 0) {
56*6236dae4SAndroid Build Coastguard Worker       if(!t->smaller)
57*6236dae4SAndroid Build Coastguard Worker         break;
58*6236dae4SAndroid Build Coastguard Worker       if(compare(i, t->smaller->key) < 0) {
59*6236dae4SAndroid Build Coastguard Worker         y = t->smaller;                           /* rotate smaller */
60*6236dae4SAndroid Build Coastguard Worker         t->smaller = y->larger;
61*6236dae4SAndroid Build Coastguard Worker         y->larger = t;
62*6236dae4SAndroid Build Coastguard Worker         t = y;
63*6236dae4SAndroid Build Coastguard Worker         if(!t->smaller)
64*6236dae4SAndroid Build Coastguard Worker           break;
65*6236dae4SAndroid Build Coastguard Worker       }
66*6236dae4SAndroid Build Coastguard Worker       r->smaller = t;                               /* link smaller */
67*6236dae4SAndroid Build Coastguard Worker       r = t;
68*6236dae4SAndroid Build Coastguard Worker       t = t->smaller;
69*6236dae4SAndroid Build Coastguard Worker     }
70*6236dae4SAndroid Build Coastguard Worker     else if(comp > 0) {
71*6236dae4SAndroid Build Coastguard Worker       if(!t->larger)
72*6236dae4SAndroid Build Coastguard Worker         break;
73*6236dae4SAndroid Build Coastguard Worker       if(compare(i, t->larger->key) > 0) {
74*6236dae4SAndroid Build Coastguard Worker         y = t->larger;                          /* rotate larger */
75*6236dae4SAndroid Build Coastguard Worker         t->larger = y->smaller;
76*6236dae4SAndroid Build Coastguard Worker         y->smaller = t;
77*6236dae4SAndroid Build Coastguard Worker         t = y;
78*6236dae4SAndroid Build Coastguard Worker         if(!t->larger)
79*6236dae4SAndroid Build Coastguard Worker           break;
80*6236dae4SAndroid Build Coastguard Worker       }
81*6236dae4SAndroid Build Coastguard Worker       l->larger = t;                              /* link larger */
82*6236dae4SAndroid Build Coastguard Worker       l = t;
83*6236dae4SAndroid Build Coastguard Worker       t = t->larger;
84*6236dae4SAndroid Build Coastguard Worker     }
85*6236dae4SAndroid Build Coastguard Worker     else
86*6236dae4SAndroid Build Coastguard Worker       break;
87*6236dae4SAndroid Build Coastguard Worker   }
88*6236dae4SAndroid Build Coastguard Worker 
89*6236dae4SAndroid Build Coastguard Worker   l->larger = t->smaller;                                /* assemble */
90*6236dae4SAndroid Build Coastguard Worker   r->smaller = t->larger;
91*6236dae4SAndroid Build Coastguard Worker   t->smaller = N.larger;
92*6236dae4SAndroid Build Coastguard Worker   t->larger = N.smaller;
93*6236dae4SAndroid Build Coastguard Worker 
94*6236dae4SAndroid Build Coastguard Worker   return t;
95*6236dae4SAndroid Build Coastguard Worker }
96*6236dae4SAndroid Build Coastguard Worker 
97*6236dae4SAndroid Build Coastguard Worker /* Insert key i into the tree t. Return a pointer to the resulting tree or
98*6236dae4SAndroid Build Coastguard Worker  * NULL if something went wrong.
99*6236dae4SAndroid Build Coastguard Worker  *
100*6236dae4SAndroid Build Coastguard Worker  * @unittest: 1309
101*6236dae4SAndroid Build Coastguard Worker  */
Curl_splayinsert(struct curltime i,struct Curl_tree * t,struct Curl_tree * node)102*6236dae4SAndroid Build Coastguard Worker struct Curl_tree *Curl_splayinsert(struct curltime i,
103*6236dae4SAndroid Build Coastguard Worker                                    struct Curl_tree *t,
104*6236dae4SAndroid Build Coastguard Worker                                    struct Curl_tree *node)
105*6236dae4SAndroid Build Coastguard Worker {
106*6236dae4SAndroid Build Coastguard Worker   static const struct curltime KEY_NOTUSED = {
107*6236dae4SAndroid Build Coastguard Worker     ~0, -1
108*6236dae4SAndroid Build Coastguard Worker   }; /* will *NEVER* appear */
109*6236dae4SAndroid Build Coastguard Worker 
110*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(node);
111*6236dae4SAndroid Build Coastguard Worker 
112*6236dae4SAndroid Build Coastguard Worker   if(t) {
113*6236dae4SAndroid Build Coastguard Worker     t = Curl_splay(i, t);
114*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(t);
115*6236dae4SAndroid Build Coastguard Worker     if(compare(i, t->key) == 0) {
116*6236dae4SAndroid Build Coastguard Worker       /* There already exists a node in the tree with the same key. Build a
117*6236dae4SAndroid Build Coastguard Worker          doubly-linked circular list of nodes. We add the new 'node' struct to
118*6236dae4SAndroid Build Coastguard Worker          the end of this list. */
119*6236dae4SAndroid Build Coastguard Worker 
120*6236dae4SAndroid Build Coastguard Worker       node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED
121*6236dae4SAndroid Build Coastguard Worker                                   to quickly identify this node as a subnode */
122*6236dae4SAndroid Build Coastguard Worker       node->samen = t;
123*6236dae4SAndroid Build Coastguard Worker       node->samep = t->samep;
124*6236dae4SAndroid Build Coastguard Worker       t->samep->samen = node;
125*6236dae4SAndroid Build Coastguard Worker       t->samep = node;
126*6236dae4SAndroid Build Coastguard Worker 
127*6236dae4SAndroid Build Coastguard Worker       return t; /* the root node always stays the same */
128*6236dae4SAndroid Build Coastguard Worker     }
129*6236dae4SAndroid Build Coastguard Worker   }
130*6236dae4SAndroid Build Coastguard Worker 
131*6236dae4SAndroid Build Coastguard Worker   if(!t) {
132*6236dae4SAndroid Build Coastguard Worker     node->smaller = node->larger = NULL;
133*6236dae4SAndroid Build Coastguard Worker   }
134*6236dae4SAndroid Build Coastguard Worker   else if(compare(i, t->key) < 0) {
135*6236dae4SAndroid Build Coastguard Worker     node->smaller = t->smaller;
136*6236dae4SAndroid Build Coastguard Worker     node->larger = t;
137*6236dae4SAndroid Build Coastguard Worker     t->smaller = NULL;
138*6236dae4SAndroid Build Coastguard Worker 
139*6236dae4SAndroid Build Coastguard Worker   }
140*6236dae4SAndroid Build Coastguard Worker   else {
141*6236dae4SAndroid Build Coastguard Worker     node->larger = t->larger;
142*6236dae4SAndroid Build Coastguard Worker     node->smaller = t;
143*6236dae4SAndroid Build Coastguard Worker     t->larger = NULL;
144*6236dae4SAndroid Build Coastguard Worker   }
145*6236dae4SAndroid Build Coastguard Worker   node->key = i;
146*6236dae4SAndroid Build Coastguard Worker 
147*6236dae4SAndroid Build Coastguard Worker   /* no identical nodes (yet), we are the only one in the list of nodes */
148*6236dae4SAndroid Build Coastguard Worker   node->samen = node;
149*6236dae4SAndroid Build Coastguard Worker   node->samep = node;
150*6236dae4SAndroid Build Coastguard Worker   return node;
151*6236dae4SAndroid Build Coastguard Worker }
152*6236dae4SAndroid Build Coastguard Worker 
153*6236dae4SAndroid Build Coastguard Worker /* Finds and deletes the best-fit node from the tree. Return a pointer to the
154*6236dae4SAndroid Build Coastguard Worker    resulting tree. best-fit means the smallest node if it is not larger than
155*6236dae4SAndroid Build Coastguard Worker    the key */
Curl_splaygetbest(struct curltime i,struct Curl_tree * t,struct Curl_tree ** removed)156*6236dae4SAndroid Build Coastguard Worker struct Curl_tree *Curl_splaygetbest(struct curltime i,
157*6236dae4SAndroid Build Coastguard Worker                                     struct Curl_tree *t,
158*6236dae4SAndroid Build Coastguard Worker                                     struct Curl_tree **removed)
159*6236dae4SAndroid Build Coastguard Worker {
160*6236dae4SAndroid Build Coastguard Worker   static const struct curltime tv_zero = {0, 0};
161*6236dae4SAndroid Build Coastguard Worker   struct Curl_tree *x;
162*6236dae4SAndroid Build Coastguard Worker 
163*6236dae4SAndroid Build Coastguard Worker   if(!t) {
164*6236dae4SAndroid Build Coastguard Worker     *removed = NULL; /* none removed since there was no root */
165*6236dae4SAndroid Build Coastguard Worker     return NULL;
166*6236dae4SAndroid Build Coastguard Worker   }
167*6236dae4SAndroid Build Coastguard Worker 
168*6236dae4SAndroid Build Coastguard Worker   /* find smallest */
169*6236dae4SAndroid Build Coastguard Worker   t = Curl_splay(tv_zero, t);
170*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(t);
171*6236dae4SAndroid Build Coastguard Worker   if(compare(i, t->key) < 0) {
172*6236dae4SAndroid Build Coastguard Worker     /* even the smallest is too big */
173*6236dae4SAndroid Build Coastguard Worker     *removed = NULL;
174*6236dae4SAndroid Build Coastguard Worker     return t;
175*6236dae4SAndroid Build Coastguard Worker   }
176*6236dae4SAndroid Build Coastguard Worker 
177*6236dae4SAndroid Build Coastguard Worker   /* FIRST! Check if there is a list with identical keys */
178*6236dae4SAndroid Build Coastguard Worker   x = t->samen;
179*6236dae4SAndroid Build Coastguard Worker   if(x != t) {
180*6236dae4SAndroid Build Coastguard Worker     /* there is, pick one from the list */
181*6236dae4SAndroid Build Coastguard Worker 
182*6236dae4SAndroid Build Coastguard Worker     /* 'x' is the new root node */
183*6236dae4SAndroid Build Coastguard Worker 
184*6236dae4SAndroid Build Coastguard Worker     x->key = t->key;
185*6236dae4SAndroid Build Coastguard Worker     x->larger = t->larger;
186*6236dae4SAndroid Build Coastguard Worker     x->smaller = t->smaller;
187*6236dae4SAndroid Build Coastguard Worker     x->samep = t->samep;
188*6236dae4SAndroid Build Coastguard Worker     t->samep->samen = x;
189*6236dae4SAndroid Build Coastguard Worker 
190*6236dae4SAndroid Build Coastguard Worker     *removed = t;
191*6236dae4SAndroid Build Coastguard Worker     return x; /* new root */
192*6236dae4SAndroid Build Coastguard Worker   }
193*6236dae4SAndroid Build Coastguard Worker 
194*6236dae4SAndroid Build Coastguard Worker   /* we splayed the tree to the smallest element, there is no smaller */
195*6236dae4SAndroid Build Coastguard Worker   x = t->larger;
196*6236dae4SAndroid Build Coastguard Worker   *removed = t;
197*6236dae4SAndroid Build Coastguard Worker 
198*6236dae4SAndroid Build Coastguard Worker   return x;
199*6236dae4SAndroid Build Coastguard Worker }
200*6236dae4SAndroid Build Coastguard Worker 
201*6236dae4SAndroid Build Coastguard Worker 
202*6236dae4SAndroid Build Coastguard Worker /* Deletes the node we point out from the tree if it is there. Stores a
203*6236dae4SAndroid Build Coastguard Worker  * pointer to the new resulting tree in 'newroot'.
204*6236dae4SAndroid Build Coastguard Worker  *
205*6236dae4SAndroid Build Coastguard Worker  * Returns zero on success and non-zero on errors!
206*6236dae4SAndroid Build Coastguard Worker  * When returning error, it does not touch the 'newroot' pointer.
207*6236dae4SAndroid Build Coastguard Worker  *
208*6236dae4SAndroid Build Coastguard Worker  * NOTE: when the last node of the tree is removed, there is no tree left so
209*6236dae4SAndroid Build Coastguard Worker  * 'newroot' will be made to point to NULL.
210*6236dae4SAndroid Build Coastguard Worker  *
211*6236dae4SAndroid Build Coastguard Worker  * @unittest: 1309
212*6236dae4SAndroid Build Coastguard Worker  */
Curl_splayremove(struct Curl_tree * t,struct Curl_tree * removenode,struct Curl_tree ** newroot)213*6236dae4SAndroid Build Coastguard Worker int Curl_splayremove(struct Curl_tree *t,
214*6236dae4SAndroid Build Coastguard Worker                      struct Curl_tree *removenode,
215*6236dae4SAndroid Build Coastguard Worker                      struct Curl_tree **newroot)
216*6236dae4SAndroid Build Coastguard Worker {
217*6236dae4SAndroid Build Coastguard Worker   static const struct curltime KEY_NOTUSED = {
218*6236dae4SAndroid Build Coastguard Worker     ~0, -1
219*6236dae4SAndroid Build Coastguard Worker   }; /* will *NEVER* appear */
220*6236dae4SAndroid Build Coastguard Worker   struct Curl_tree *x;
221*6236dae4SAndroid Build Coastguard Worker 
222*6236dae4SAndroid Build Coastguard Worker   if(!t)
223*6236dae4SAndroid Build Coastguard Worker     return 1;
224*6236dae4SAndroid Build Coastguard Worker 
225*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(removenode);
226*6236dae4SAndroid Build Coastguard Worker 
227*6236dae4SAndroid Build Coastguard Worker   if(compare(KEY_NOTUSED, removenode->key) == 0) {
228*6236dae4SAndroid Build Coastguard Worker     /* Key set to NOTUSED means it is a subnode within a 'same' linked list
229*6236dae4SAndroid Build Coastguard Worker        and thus we can unlink it easily. */
230*6236dae4SAndroid Build Coastguard Worker     if(removenode->samen == removenode)
231*6236dae4SAndroid Build Coastguard Worker       /* A non-subnode should never be set to KEY_NOTUSED */
232*6236dae4SAndroid Build Coastguard Worker       return 3;
233*6236dae4SAndroid Build Coastguard Worker 
234*6236dae4SAndroid Build Coastguard Worker     removenode->samep->samen = removenode->samen;
235*6236dae4SAndroid Build Coastguard Worker     removenode->samen->samep = removenode->samep;
236*6236dae4SAndroid Build Coastguard Worker 
237*6236dae4SAndroid Build Coastguard Worker     /* Ensures that double-remove gets caught. */
238*6236dae4SAndroid Build Coastguard Worker     removenode->samen = removenode;
239*6236dae4SAndroid Build Coastguard Worker 
240*6236dae4SAndroid Build Coastguard Worker     *newroot = t; /* return the same root */
241*6236dae4SAndroid Build Coastguard Worker     return 0;
242*6236dae4SAndroid Build Coastguard Worker   }
243*6236dae4SAndroid Build Coastguard Worker 
244*6236dae4SAndroid Build Coastguard Worker   t = Curl_splay(removenode->key, t);
245*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(t);
246*6236dae4SAndroid Build Coastguard Worker 
247*6236dae4SAndroid Build Coastguard Worker   /* First make sure that we got the same root node as the one we want
248*6236dae4SAndroid Build Coastguard Worker      to remove, as otherwise we might be trying to remove a node that
249*6236dae4SAndroid Build Coastguard Worker      is not actually in the tree.
250*6236dae4SAndroid Build Coastguard Worker 
251*6236dae4SAndroid Build Coastguard Worker      We cannot just compare the keys here as a double remove in quick
252*6236dae4SAndroid Build Coastguard Worker      succession of a node with key != KEY_NOTUSED && same != NULL
253*6236dae4SAndroid Build Coastguard Worker      could return the same key but a different node. */
254*6236dae4SAndroid Build Coastguard Worker   if(t != removenode)
255*6236dae4SAndroid Build Coastguard Worker     return 2;
256*6236dae4SAndroid Build Coastguard Worker 
257*6236dae4SAndroid Build Coastguard Worker   /* Check if there is a list with identical sizes, as then we are trying to
258*6236dae4SAndroid Build Coastguard Worker      remove the root node of a list of nodes with identical keys. */
259*6236dae4SAndroid Build Coastguard Worker   x = t->samen;
260*6236dae4SAndroid Build Coastguard Worker   if(x != t) {
261*6236dae4SAndroid Build Coastguard Worker     /* 'x' is the new root node, we just make it use the root node's
262*6236dae4SAndroid Build Coastguard Worker        smaller/larger links */
263*6236dae4SAndroid Build Coastguard Worker 
264*6236dae4SAndroid Build Coastguard Worker     x->key = t->key;
265*6236dae4SAndroid Build Coastguard Worker     x->larger = t->larger;
266*6236dae4SAndroid Build Coastguard Worker     x->smaller = t->smaller;
267*6236dae4SAndroid Build Coastguard Worker     x->samep = t->samep;
268*6236dae4SAndroid Build Coastguard Worker     t->samep->samen = x;
269*6236dae4SAndroid Build Coastguard Worker   }
270*6236dae4SAndroid Build Coastguard Worker   else {
271*6236dae4SAndroid Build Coastguard Worker     /* Remove the root node */
272*6236dae4SAndroid Build Coastguard Worker     if(!t->smaller)
273*6236dae4SAndroid Build Coastguard Worker       x = t->larger;
274*6236dae4SAndroid Build Coastguard Worker     else {
275*6236dae4SAndroid Build Coastguard Worker       x = Curl_splay(removenode->key, t->smaller);
276*6236dae4SAndroid Build Coastguard Worker       DEBUGASSERT(x);
277*6236dae4SAndroid Build Coastguard Worker       x->larger = t->larger;
278*6236dae4SAndroid Build Coastguard Worker     }
279*6236dae4SAndroid Build Coastguard Worker   }
280*6236dae4SAndroid Build Coastguard Worker 
281*6236dae4SAndroid Build Coastguard Worker   *newroot = x; /* store new root pointer */
282*6236dae4SAndroid Build Coastguard Worker 
283*6236dae4SAndroid Build Coastguard Worker   return 0;
284*6236dae4SAndroid Build Coastguard Worker }
285*6236dae4SAndroid Build Coastguard Worker 
286*6236dae4SAndroid Build Coastguard Worker /* set and get the custom payload for this tree node */
Curl_splayset(struct Curl_tree * node,void * payload)287*6236dae4SAndroid Build Coastguard Worker void Curl_splayset(struct Curl_tree *node, void *payload)
288*6236dae4SAndroid Build Coastguard Worker {
289*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(node);
290*6236dae4SAndroid Build Coastguard Worker   node->ptr = payload;
291*6236dae4SAndroid Build Coastguard Worker }
292*6236dae4SAndroid Build Coastguard Worker 
Curl_splayget(struct Curl_tree * node)293*6236dae4SAndroid Build Coastguard Worker void *Curl_splayget(struct Curl_tree *node)
294*6236dae4SAndroid Build Coastguard Worker {
295*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(node);
296*6236dae4SAndroid Build Coastguard Worker   return node->ptr;
297*6236dae4SAndroid Build Coastguard Worker }
298