xref: /third_party/curl/lib/splay.c (revision 13498266)
113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci#include "curl_setup.h"
2613498266Sopenharmony_ci
2713498266Sopenharmony_ci#include "splay.h"
2813498266Sopenharmony_ci
2913498266Sopenharmony_ci/*
3013498266Sopenharmony_ci * This macro compares two node keys i and j and returns:
3113498266Sopenharmony_ci *
3213498266Sopenharmony_ci *  negative value: when i is smaller than j
3313498266Sopenharmony_ci *  zero          : when i is equal   to   j
3413498266Sopenharmony_ci *  positive when : when i is larger  than j
3513498266Sopenharmony_ci */
3613498266Sopenharmony_ci#define compare(i,j) Curl_splaycomparekeys((i),(j))
3713498266Sopenharmony_ci
3813498266Sopenharmony_ci/*
3913498266Sopenharmony_ci * Splay using the key i (which may or may not be in the tree.) The starting
4013498266Sopenharmony_ci * root is t.
4113498266Sopenharmony_ci */
4213498266Sopenharmony_cistruct Curl_tree *Curl_splay(struct curltime i,
4313498266Sopenharmony_ci                             struct Curl_tree *t)
4413498266Sopenharmony_ci{
4513498266Sopenharmony_ci  struct Curl_tree N, *l, *r, *y;
4613498266Sopenharmony_ci
4713498266Sopenharmony_ci  if(!t)
4813498266Sopenharmony_ci    return t;
4913498266Sopenharmony_ci  N.smaller = N.larger = NULL;
5013498266Sopenharmony_ci  l = r = &N;
5113498266Sopenharmony_ci
5213498266Sopenharmony_ci  for(;;) {
5313498266Sopenharmony_ci    long comp = compare(i, t->key);
5413498266Sopenharmony_ci    if(comp < 0) {
5513498266Sopenharmony_ci      if(!t->smaller)
5613498266Sopenharmony_ci        break;
5713498266Sopenharmony_ci      if(compare(i, t->smaller->key) < 0) {
5813498266Sopenharmony_ci        y = t->smaller;                           /* rotate smaller */
5913498266Sopenharmony_ci        t->smaller = y->larger;
6013498266Sopenharmony_ci        y->larger = t;
6113498266Sopenharmony_ci        t = y;
6213498266Sopenharmony_ci        if(!t->smaller)
6313498266Sopenharmony_ci          break;
6413498266Sopenharmony_ci      }
6513498266Sopenharmony_ci      r->smaller = t;                               /* link smaller */
6613498266Sopenharmony_ci      r = t;
6713498266Sopenharmony_ci      t = t->smaller;
6813498266Sopenharmony_ci    }
6913498266Sopenharmony_ci    else if(comp > 0) {
7013498266Sopenharmony_ci      if(!t->larger)
7113498266Sopenharmony_ci        break;
7213498266Sopenharmony_ci      if(compare(i, t->larger->key) > 0) {
7313498266Sopenharmony_ci        y = t->larger;                          /* rotate larger */
7413498266Sopenharmony_ci        t->larger = y->smaller;
7513498266Sopenharmony_ci        y->smaller = t;
7613498266Sopenharmony_ci        t = y;
7713498266Sopenharmony_ci        if(!t->larger)
7813498266Sopenharmony_ci          break;
7913498266Sopenharmony_ci      }
8013498266Sopenharmony_ci      l->larger = t;                              /* link larger */
8113498266Sopenharmony_ci      l = t;
8213498266Sopenharmony_ci      t = t->larger;
8313498266Sopenharmony_ci    }
8413498266Sopenharmony_ci    else
8513498266Sopenharmony_ci      break;
8613498266Sopenharmony_ci  }
8713498266Sopenharmony_ci
8813498266Sopenharmony_ci  l->larger = t->smaller;                                /* assemble */
8913498266Sopenharmony_ci  r->smaller = t->larger;
9013498266Sopenharmony_ci  t->smaller = N.larger;
9113498266Sopenharmony_ci  t->larger = N.smaller;
9213498266Sopenharmony_ci
9313498266Sopenharmony_ci  return t;
9413498266Sopenharmony_ci}
9513498266Sopenharmony_ci
9613498266Sopenharmony_ci/* Insert key i into the tree t.  Return a pointer to the resulting tree or
9713498266Sopenharmony_ci * NULL if something went wrong.
9813498266Sopenharmony_ci *
9913498266Sopenharmony_ci * @unittest: 1309
10013498266Sopenharmony_ci */
10113498266Sopenharmony_cistruct Curl_tree *Curl_splayinsert(struct curltime i,
10213498266Sopenharmony_ci                                   struct Curl_tree *t,
10313498266Sopenharmony_ci                                   struct Curl_tree *node)
10413498266Sopenharmony_ci{
10513498266Sopenharmony_ci  static const struct curltime KEY_NOTUSED = {
10613498266Sopenharmony_ci    ~0, -1
10713498266Sopenharmony_ci  }; /* will *NEVER* appear */
10813498266Sopenharmony_ci
10913498266Sopenharmony_ci  if(!node)
11013498266Sopenharmony_ci    return t;
11113498266Sopenharmony_ci
11213498266Sopenharmony_ci  if(t) {
11313498266Sopenharmony_ci    t = Curl_splay(i, t);
11413498266Sopenharmony_ci    if(compare(i, t->key) == 0) {
11513498266Sopenharmony_ci      /* There already exists a node in the tree with the very same key. Build
11613498266Sopenharmony_ci         a doubly-linked circular list of nodes. We add the new 'node' struct
11713498266Sopenharmony_ci         to the end of this list. */
11813498266Sopenharmony_ci
11913498266Sopenharmony_ci      node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED
12013498266Sopenharmony_ci                                  to quickly identify this node as a subnode */
12113498266Sopenharmony_ci      node->samen = t;
12213498266Sopenharmony_ci      node->samep = t->samep;
12313498266Sopenharmony_ci      t->samep->samen = node;
12413498266Sopenharmony_ci      t->samep = node;
12513498266Sopenharmony_ci
12613498266Sopenharmony_ci      return t; /* the root node always stays the same */
12713498266Sopenharmony_ci    }
12813498266Sopenharmony_ci  }
12913498266Sopenharmony_ci
13013498266Sopenharmony_ci  if(!t) {
13113498266Sopenharmony_ci    node->smaller = node->larger = NULL;
13213498266Sopenharmony_ci  }
13313498266Sopenharmony_ci  else if(compare(i, t->key) < 0) {
13413498266Sopenharmony_ci    node->smaller = t->smaller;
13513498266Sopenharmony_ci    node->larger = t;
13613498266Sopenharmony_ci    t->smaller = NULL;
13713498266Sopenharmony_ci
13813498266Sopenharmony_ci  }
13913498266Sopenharmony_ci  else {
14013498266Sopenharmony_ci    node->larger = t->larger;
14113498266Sopenharmony_ci    node->smaller = t;
14213498266Sopenharmony_ci    t->larger = NULL;
14313498266Sopenharmony_ci  }
14413498266Sopenharmony_ci  node->key = i;
14513498266Sopenharmony_ci
14613498266Sopenharmony_ci  /* no identical nodes (yet), we are the only one in the list of nodes */
14713498266Sopenharmony_ci  node->samen = node;
14813498266Sopenharmony_ci  node->samep = node;
14913498266Sopenharmony_ci  return node;
15013498266Sopenharmony_ci}
15113498266Sopenharmony_ci
15213498266Sopenharmony_ci/* Finds and deletes the best-fit node from the tree. Return a pointer to the
15313498266Sopenharmony_ci   resulting tree.  best-fit means the smallest node if it is not larger than
15413498266Sopenharmony_ci   the key */
15513498266Sopenharmony_cistruct Curl_tree *Curl_splaygetbest(struct curltime i,
15613498266Sopenharmony_ci                                    struct Curl_tree *t,
15713498266Sopenharmony_ci                                    struct Curl_tree **removed)
15813498266Sopenharmony_ci{
15913498266Sopenharmony_ci  static const struct curltime tv_zero = {0, 0};
16013498266Sopenharmony_ci  struct Curl_tree *x;
16113498266Sopenharmony_ci
16213498266Sopenharmony_ci  if(!t) {
16313498266Sopenharmony_ci    *removed = NULL; /* none removed since there was no root */
16413498266Sopenharmony_ci    return NULL;
16513498266Sopenharmony_ci  }
16613498266Sopenharmony_ci
16713498266Sopenharmony_ci  /* find smallest */
16813498266Sopenharmony_ci  t = Curl_splay(tv_zero, t);
16913498266Sopenharmony_ci  if(compare(i, t->key) < 0) {
17013498266Sopenharmony_ci    /* even the smallest is too big */
17113498266Sopenharmony_ci    *removed = NULL;
17213498266Sopenharmony_ci    return t;
17313498266Sopenharmony_ci  }
17413498266Sopenharmony_ci
17513498266Sopenharmony_ci  /* FIRST! Check if there is a list with identical keys */
17613498266Sopenharmony_ci  x = t->samen;
17713498266Sopenharmony_ci  if(x != t) {
17813498266Sopenharmony_ci    /* there is, pick one from the list */
17913498266Sopenharmony_ci
18013498266Sopenharmony_ci    /* 'x' is the new root node */
18113498266Sopenharmony_ci
18213498266Sopenharmony_ci    x->key = t->key;
18313498266Sopenharmony_ci    x->larger = t->larger;
18413498266Sopenharmony_ci    x->smaller = t->smaller;
18513498266Sopenharmony_ci    x->samep = t->samep;
18613498266Sopenharmony_ci    t->samep->samen = x;
18713498266Sopenharmony_ci
18813498266Sopenharmony_ci    *removed = t;
18913498266Sopenharmony_ci    return x; /* new root */
19013498266Sopenharmony_ci  }
19113498266Sopenharmony_ci
19213498266Sopenharmony_ci  /* we splayed the tree to the smallest element, there is no smaller */
19313498266Sopenharmony_ci  x = t->larger;
19413498266Sopenharmony_ci  *removed = t;
19513498266Sopenharmony_ci
19613498266Sopenharmony_ci  return x;
19713498266Sopenharmony_ci}
19813498266Sopenharmony_ci
19913498266Sopenharmony_ci
20013498266Sopenharmony_ci/* Deletes the very node we point out from the tree if it's there. Stores a
20113498266Sopenharmony_ci * pointer to the new resulting tree in 'newroot'.
20213498266Sopenharmony_ci *
20313498266Sopenharmony_ci * Returns zero on success and non-zero on errors!
20413498266Sopenharmony_ci * When returning error, it does not touch the 'newroot' pointer.
20513498266Sopenharmony_ci *
20613498266Sopenharmony_ci * NOTE: when the last node of the tree is removed, there's no tree left so
20713498266Sopenharmony_ci * 'newroot' will be made to point to NULL.
20813498266Sopenharmony_ci *
20913498266Sopenharmony_ci * @unittest: 1309
21013498266Sopenharmony_ci */
21113498266Sopenharmony_ciint Curl_splayremove(struct Curl_tree *t,
21213498266Sopenharmony_ci                     struct Curl_tree *removenode,
21313498266Sopenharmony_ci                     struct Curl_tree **newroot)
21413498266Sopenharmony_ci{
21513498266Sopenharmony_ci  static const struct curltime KEY_NOTUSED = {
21613498266Sopenharmony_ci    ~0, -1
21713498266Sopenharmony_ci  }; /* will *NEVER* appear */
21813498266Sopenharmony_ci  struct Curl_tree *x;
21913498266Sopenharmony_ci
22013498266Sopenharmony_ci  if(!t || !removenode)
22113498266Sopenharmony_ci    return 1;
22213498266Sopenharmony_ci
22313498266Sopenharmony_ci  if(compare(KEY_NOTUSED, removenode->key) == 0) {
22413498266Sopenharmony_ci    /* Key set to NOTUSED means it is a subnode within a 'same' linked list
22513498266Sopenharmony_ci       and thus we can unlink it easily. */
22613498266Sopenharmony_ci    if(removenode->samen == removenode)
22713498266Sopenharmony_ci      /* A non-subnode should never be set to KEY_NOTUSED */
22813498266Sopenharmony_ci      return 3;
22913498266Sopenharmony_ci
23013498266Sopenharmony_ci    removenode->samep->samen = removenode->samen;
23113498266Sopenharmony_ci    removenode->samen->samep = removenode->samep;
23213498266Sopenharmony_ci
23313498266Sopenharmony_ci    /* Ensures that double-remove gets caught. */
23413498266Sopenharmony_ci    removenode->samen = removenode;
23513498266Sopenharmony_ci
23613498266Sopenharmony_ci    *newroot = t; /* return the same root */
23713498266Sopenharmony_ci    return 0;
23813498266Sopenharmony_ci  }
23913498266Sopenharmony_ci
24013498266Sopenharmony_ci  t = Curl_splay(removenode->key, t);
24113498266Sopenharmony_ci
24213498266Sopenharmony_ci  /* First make sure that we got the same root node as the one we want
24313498266Sopenharmony_ci     to remove, as otherwise we might be trying to remove a node that
24413498266Sopenharmony_ci     isn't actually in the tree.
24513498266Sopenharmony_ci
24613498266Sopenharmony_ci     We cannot just compare the keys here as a double remove in quick
24713498266Sopenharmony_ci     succession of a node with key != KEY_NOTUSED && same != NULL
24813498266Sopenharmony_ci     could return the same key but a different node. */
24913498266Sopenharmony_ci  if(t != removenode)
25013498266Sopenharmony_ci    return 2;
25113498266Sopenharmony_ci
25213498266Sopenharmony_ci  /* Check if there is a list with identical sizes, as then we're trying to
25313498266Sopenharmony_ci     remove the root node of a list of nodes with identical keys. */
25413498266Sopenharmony_ci  x = t->samen;
25513498266Sopenharmony_ci  if(x != t) {
25613498266Sopenharmony_ci    /* 'x' is the new root node, we just make it use the root node's
25713498266Sopenharmony_ci       smaller/larger links */
25813498266Sopenharmony_ci
25913498266Sopenharmony_ci    x->key = t->key;
26013498266Sopenharmony_ci    x->larger = t->larger;
26113498266Sopenharmony_ci    x->smaller = t->smaller;
26213498266Sopenharmony_ci    x->samep = t->samep;
26313498266Sopenharmony_ci    t->samep->samen = x;
26413498266Sopenharmony_ci  }
26513498266Sopenharmony_ci  else {
26613498266Sopenharmony_ci    /* Remove the root node */
26713498266Sopenharmony_ci    if(!t->smaller)
26813498266Sopenharmony_ci      x = t->larger;
26913498266Sopenharmony_ci    else {
27013498266Sopenharmony_ci      x = Curl_splay(removenode->key, t->smaller);
27113498266Sopenharmony_ci      x->larger = t->larger;
27213498266Sopenharmony_ci    }
27313498266Sopenharmony_ci  }
27413498266Sopenharmony_ci
27513498266Sopenharmony_ci  *newroot = x; /* store new root pointer */
27613498266Sopenharmony_ci
27713498266Sopenharmony_ci  return 0;
27813498266Sopenharmony_ci}
279