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