Home | History | Annotate | Download | only in Modules
      1 #include "rotatingtree.h"
      2 
      3 #define KEY_LOWER_THAN(key1, key2)  ((char*)(key1) < (char*)(key2))
      4 
      5 /* The randombits() function below is a fast-and-dirty generator that
      6  * is probably irregular enough for our purposes.  Note that it's biased:
      7  * I think that ones are slightly more probable than zeroes.  It's not
      8  * important here, though.
      9  */
     10 
     11 static unsigned int random_value = 1;
     12 static unsigned int random_stream = 0;
     13 
     14 static int
     15 randombits(int bits)
     16 {
     17     int result;
     18     if (random_stream < (1U << bits)) {
     19         random_value *= 1082527;
     20         random_stream = random_value;
     21     }
     22     result = random_stream & ((1<<bits)-1);
     23     random_stream >>= bits;
     24     return result;
     25 }
     26 
     27 
     28 /* Insert a new node into the tree.
     29    (*root) is modified to point to the new root. */
     30 void
     31 RotatingTree_Add(rotating_node_t **root, rotating_node_t *node)
     32 {
     33     while (*root != NULL) {
     34         if (KEY_LOWER_THAN(node->key, (*root)->key))
     35             root = &((*root)->left);
     36         else
     37             root = &((*root)->right);
     38     }
     39     node->left = NULL;
     40     node->right = NULL;
     41     *root = node;
     42 }
     43 
     44 /* Locate the node with the given key.  This is the most complicated
     45    function because it occasionally rebalances the tree to move the
     46    resulting node closer to the root. */
     47 rotating_node_t *
     48 RotatingTree_Get(rotating_node_t **root, void *key)
     49 {
     50     if (randombits(3) != 4) {
     51         /* Fast path, no rebalancing */
     52         rotating_node_t *node = *root;
     53         while (node != NULL) {
     54             if (node->key == key)
     55                 return node;
     56             if (KEY_LOWER_THAN(key, node->key))
     57                 node = node->left;
     58             else
     59                 node = node->right;
     60         }
     61         return NULL;
     62     }
     63     else {
     64         rotating_node_t **pnode = root;
     65         rotating_node_t *node = *pnode;
     66         rotating_node_t *next;
     67         int rotate;
     68         if (node == NULL)
     69             return NULL;
     70         while (1) {
     71             if (node->key == key)
     72                 return node;
     73             rotate = !randombits(1);
     74             if (KEY_LOWER_THAN(key, node->key)) {
     75                 next = node->left;
     76                 if (next == NULL)
     77                     return NULL;
     78                 if (rotate) {
     79                     node->left = next->right;
     80                     next->right = node;
     81                     *pnode = next;
     82                 }
     83                 else
     84                     pnode = &(node->left);
     85             }
     86             else {
     87                 next = node->right;
     88                 if (next == NULL)
     89                     return NULL;
     90                 if (rotate) {
     91                     node->right = next->left;
     92                     next->left = node;
     93                     *pnode = next;
     94                 }
     95                 else
     96                     pnode = &(node->right);
     97             }
     98             node = next;
     99         }
    100     }
    101 }
    102 
    103 /* Enumerate all nodes in the tree.  The callback enumfn() should return
    104    zero to continue the enumeration, or non-zero to interrupt it.
    105    A non-zero value is directly returned by RotatingTree_Enum(). */
    106 int
    107 RotatingTree_Enum(rotating_node_t *root, rotating_tree_enum_fn enumfn,
    108                   void *arg)
    109 {
    110     int result;
    111     rotating_node_t *node;
    112     while (root != NULL) {
    113         result = RotatingTree_Enum(root->left, enumfn, arg);
    114         if (result != 0) return result;
    115         node = root->right;
    116         result = enumfn(root, arg);
    117         if (result != 0) return result;
    118         root = node;
    119     }
    120     return 0;
    121 }
    122