17db96d56Sopenharmony_ci#include "rotatingtree.h"
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci#define KEY_LOWER_THAN(key1, key2)  ((char*)(key1) < (char*)(key2))
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci/* The randombits() function below is a fast-and-dirty generator that
67db96d56Sopenharmony_ci * is probably irregular enough for our purposes.  Note that it's biased:
77db96d56Sopenharmony_ci * I think that ones are slightly more probable than zeroes.  It's not
87db96d56Sopenharmony_ci * important here, though.
97db96d56Sopenharmony_ci */
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_cistatic unsigned int random_value = 1;
127db96d56Sopenharmony_cistatic unsigned int random_stream = 0;
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_cistatic int
157db96d56Sopenharmony_cirandombits(int bits)
167db96d56Sopenharmony_ci{
177db96d56Sopenharmony_ci    int result;
187db96d56Sopenharmony_ci    if (random_stream < (1U << bits)) {
197db96d56Sopenharmony_ci        random_value *= 1082527;
207db96d56Sopenharmony_ci        random_stream = random_value;
217db96d56Sopenharmony_ci    }
227db96d56Sopenharmony_ci    result = random_stream & ((1<<bits)-1);
237db96d56Sopenharmony_ci    random_stream >>= bits;
247db96d56Sopenharmony_ci    return result;
257db96d56Sopenharmony_ci}
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ci/* Insert a new node into the tree.
297db96d56Sopenharmony_ci   (*root) is modified to point to the new root. */
307db96d56Sopenharmony_civoid
317db96d56Sopenharmony_ciRotatingTree_Add(rotating_node_t **root, rotating_node_t *node)
327db96d56Sopenharmony_ci{
337db96d56Sopenharmony_ci    while (*root != NULL) {
347db96d56Sopenharmony_ci        if (KEY_LOWER_THAN(node->key, (*root)->key))
357db96d56Sopenharmony_ci            root = &((*root)->left);
367db96d56Sopenharmony_ci        else
377db96d56Sopenharmony_ci            root = &((*root)->right);
387db96d56Sopenharmony_ci    }
397db96d56Sopenharmony_ci    node->left = NULL;
407db96d56Sopenharmony_ci    node->right = NULL;
417db96d56Sopenharmony_ci    *root = node;
427db96d56Sopenharmony_ci}
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci/* Locate the node with the given key.  This is the most complicated
457db96d56Sopenharmony_ci   function because it occasionally rebalances the tree to move the
467db96d56Sopenharmony_ci   resulting node closer to the root. */
477db96d56Sopenharmony_cirotating_node_t *
487db96d56Sopenharmony_ciRotatingTree_Get(rotating_node_t **root, void *key)
497db96d56Sopenharmony_ci{
507db96d56Sopenharmony_ci    if (randombits(3) != 4) {
517db96d56Sopenharmony_ci        /* Fast path, no rebalancing */
527db96d56Sopenharmony_ci        rotating_node_t *node = *root;
537db96d56Sopenharmony_ci        while (node != NULL) {
547db96d56Sopenharmony_ci            if (node->key == key)
557db96d56Sopenharmony_ci                return node;
567db96d56Sopenharmony_ci            if (KEY_LOWER_THAN(key, node->key))
577db96d56Sopenharmony_ci                node = node->left;
587db96d56Sopenharmony_ci            else
597db96d56Sopenharmony_ci                node = node->right;
607db96d56Sopenharmony_ci        }
617db96d56Sopenharmony_ci        return NULL;
627db96d56Sopenharmony_ci    }
637db96d56Sopenharmony_ci    else {
647db96d56Sopenharmony_ci        rotating_node_t **pnode = root;
657db96d56Sopenharmony_ci        rotating_node_t *node = *pnode;
667db96d56Sopenharmony_ci        rotating_node_t *next;
677db96d56Sopenharmony_ci        int rotate;
687db96d56Sopenharmony_ci        if (node == NULL)
697db96d56Sopenharmony_ci            return NULL;
707db96d56Sopenharmony_ci        while (1) {
717db96d56Sopenharmony_ci            if (node->key == key)
727db96d56Sopenharmony_ci                return node;
737db96d56Sopenharmony_ci            rotate = !randombits(1);
747db96d56Sopenharmony_ci            if (KEY_LOWER_THAN(key, node->key)) {
757db96d56Sopenharmony_ci                next = node->left;
767db96d56Sopenharmony_ci                if (next == NULL)
777db96d56Sopenharmony_ci                    return NULL;
787db96d56Sopenharmony_ci                if (rotate) {
797db96d56Sopenharmony_ci                    node->left = next->right;
807db96d56Sopenharmony_ci                    next->right = node;
817db96d56Sopenharmony_ci                    *pnode = next;
827db96d56Sopenharmony_ci                }
837db96d56Sopenharmony_ci                else
847db96d56Sopenharmony_ci                    pnode = &(node->left);
857db96d56Sopenharmony_ci            }
867db96d56Sopenharmony_ci            else {
877db96d56Sopenharmony_ci                next = node->right;
887db96d56Sopenharmony_ci                if (next == NULL)
897db96d56Sopenharmony_ci                    return NULL;
907db96d56Sopenharmony_ci                if (rotate) {
917db96d56Sopenharmony_ci                    node->right = next->left;
927db96d56Sopenharmony_ci                    next->left = node;
937db96d56Sopenharmony_ci                    *pnode = next;
947db96d56Sopenharmony_ci                }
957db96d56Sopenharmony_ci                else
967db96d56Sopenharmony_ci                    pnode = &(node->right);
977db96d56Sopenharmony_ci            }
987db96d56Sopenharmony_ci            node = next;
997db96d56Sopenharmony_ci        }
1007db96d56Sopenharmony_ci    }
1017db96d56Sopenharmony_ci}
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci/* Enumerate all nodes in the tree.  The callback enumfn() should return
1047db96d56Sopenharmony_ci   zero to continue the enumeration, or non-zero to interrupt it.
1057db96d56Sopenharmony_ci   A non-zero value is directly returned by RotatingTree_Enum(). */
1067db96d56Sopenharmony_ciint
1077db96d56Sopenharmony_ciRotatingTree_Enum(rotating_node_t *root, rotating_tree_enum_fn enumfn,
1087db96d56Sopenharmony_ci                  void *arg)
1097db96d56Sopenharmony_ci{
1107db96d56Sopenharmony_ci    int result;
1117db96d56Sopenharmony_ci    rotating_node_t *node;
1127db96d56Sopenharmony_ci    while (root != NULL) {
1137db96d56Sopenharmony_ci        result = RotatingTree_Enum(root->left, enumfn, arg);
1147db96d56Sopenharmony_ci        if (result != 0) return result;
1157db96d56Sopenharmony_ci        node = root->right;
1167db96d56Sopenharmony_ci        result = enumfn(root, arg);
1177db96d56Sopenharmony_ci        if (result != 0) return result;
1187db96d56Sopenharmony_ci        root = node;
1197db96d56Sopenharmony_ci    }
1207db96d56Sopenharmony_ci    return 0;
1217db96d56Sopenharmony_ci}
122