| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 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; | 
| Tim Peters | 219c164 | 2006-02-15 03:01:30 +0000 | [diff] [blame] | 18 | 	if (random_stream < (1U << bits)) { | 
| Armin Rigo | a871ef2 | 2006-02-08 12:53:56 +0000 | [diff] [blame] | 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 | } |