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 | }
|
---|