blob: aa0f6652727c35472b8e59e4270602a074117ae3 [file] [log] [blame]
Craig Tillerfba79f22015-11-23 11:06:55 -08001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Craig Tillerfba79f22015-11-23 11:06:55 -08004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Craig Tillerfba79f22015-11-23 11:06:55 -08008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Craig Tillerfba79f22015-11-23 11:06:55 -080010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
Craig Tillerfba79f22015-11-23 11:06:55 -080016 *
17 */
18
19#include <grpc/support/avl.h>
20
21#include <assert.h>
22#include <stdlib.h>
23
24#include <grpc/support/alloc.h>
25#include <grpc/support/string_util.h>
26#include <grpc/support/useful.h>
27
28gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable) {
29 gpr_avl out;
30 out.vtable = vtable;
31 out.root = NULL;
32 return out;
33}
34
35static gpr_avl_node *ref_node(gpr_avl_node *node) {
36 if (node) {
37 gpr_ref(&node->refs);
38 }
39 return node;
40}
41
42static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node) {
43 if (node == NULL) {
44 return;
45 }
46 if (gpr_unref(&node->refs)) {
47 vtable->destroy_key(node->key);
48 vtable->destroy_value(node->value);
49 unref_node(vtable, node->left);
50 unref_node(vtable, node->right);
51 gpr_free(node);
52 }
53}
54
55static long node_height(gpr_avl_node *node) {
56 return node == NULL ? 0 : node->height;
57}
58
Craig Tiller05936222015-11-23 14:56:46 -080059#ifndef NDEBUG
Craig Tillerfba79f22015-11-23 11:06:55 -080060static long calculate_height(gpr_avl_node *node) {
61 return node == NULL ? 0 : 1 + GPR_MAX(calculate_height(node->left),
62 calculate_height(node->right));
63}
64
Craig Tiller05936222015-11-23 14:56:46 -080065static gpr_avl_node *assert_invariants(gpr_avl_node *n) {
66 if (n == NULL) return NULL;
Craig Tillerfba79f22015-11-23 11:06:55 -080067 assert_invariants(n->left);
68 assert_invariants(n->right);
69 assert(calculate_height(n) == n->height);
70 assert(labs(node_height(n->left) - node_height(n->right)) <= 1);
Craig Tiller05936222015-11-23 14:56:46 -080071 return n;
Craig Tillerfba79f22015-11-23 11:06:55 -080072}
Craig Tiller9c721ff2015-11-23 15:16:12 -080073#else
Craig Tiller22d11e12015-11-23 15:33:54 -080074static gpr_avl_node *assert_invariants(gpr_avl_node *n) { return n; }
Craig Tiller9c721ff2015-11-23 15:16:12 -080075#endif
Craig Tillerfba79f22015-11-23 11:06:55 -080076
77gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left,
78 gpr_avl_node *right) {
79 gpr_avl_node *node = gpr_malloc(sizeof(*node));
80 gpr_ref_init(&node->refs, 1);
81 node->key = key;
82 node->value = value;
Craig Tiller05936222015-11-23 14:56:46 -080083 node->left = assert_invariants(left);
84 node->right = assert_invariants(right);
Craig Tillerfba79f22015-11-23 11:06:55 -080085 node->height = 1 + GPR_MAX(node_height(left), node_height(right));
86 return node;
87}
88
89static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node,
90 void *key) {
91 long cmp;
92
93 if (node == NULL) {
94 return NULL;
95 }
96
97 cmp = vtable->compare_keys(node->key, key);
98 if (cmp == 0) {
99 return node;
100 } else if (cmp > 0) {
101 return get(vtable, node->left, key);
102 } else {
103 return get(vtable, node->right, key);
104 }
105}
106
107void *gpr_avl_get(gpr_avl avl, void *key) {
108 gpr_avl_node *node = get(avl.vtable, avl.root, key);
109 return node ? node->value : NULL;
110}
111
Craig Tiller965eab32016-05-07 22:11:37 -0700112int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value) {
113 gpr_avl_node *node = get(avl.vtable, avl.root, key);
114 if (node != NULL) {
115 *value = node->value;
116 return 1;
117 }
118 return 0;
119}
120
Craig Tillerfba79f22015-11-23 11:06:55 -0800121static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key,
122 void *value, gpr_avl_node *left,
123 gpr_avl_node *right) {
124 gpr_avl_node *n =
125 new_node(vtable->copy_key(right->key), vtable->copy_value(right->value),
126 new_node(key, value, left, ref_node(right->left)),
127 ref_node(right->right));
128 unref_node(vtable, right);
129 return n;
130}
131
132static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key,
133 void *value, gpr_avl_node *left,
134 gpr_avl_node *right) {
135 gpr_avl_node *n = new_node(
136 vtable->copy_key(left->key), vtable->copy_value(left->value),
137 ref_node(left->left), new_node(key, value, ref_node(left->right), right));
138 unref_node(vtable, left);
139 return n;
140}
141
142static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key,
143 void *value, gpr_avl_node *left,
144 gpr_avl_node *right) {
145 /* rotate_right(..., rotate_left(left), right) */
Craig Tiller05936222015-11-23 14:56:46 -0800146 gpr_avl_node *n = new_node(
Craig Tillerfba79f22015-11-23 11:06:55 -0800147 vtable->copy_key(left->right->key),
148 vtable->copy_value(left->right->value),
149 new_node(vtable->copy_key(left->key), vtable->copy_value(left->value),
150 ref_node(left->left), ref_node(left->right->left)),
Craig Tiller05936222015-11-23 14:56:46 -0800151 new_node(key, value, ref_node(left->right->right), right));
Craig Tillerfba79f22015-11-23 11:06:55 -0800152 unref_node(vtable, left);
Craig Tillerfba79f22015-11-23 11:06:55 -0800153 return n;
154}
155
156static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key,
157 void *value, gpr_avl_node *left,
158 gpr_avl_node *right) {
159 /* rotate_left(..., left, rotate_right(right)) */
Craig Tiller05936222015-11-23 14:56:46 -0800160 gpr_avl_node *n = new_node(
Craig Tillerfba79f22015-11-23 11:06:55 -0800161 vtable->copy_key(right->left->key),
Craig Tiller05936222015-11-23 14:56:46 -0800162 vtable->copy_value(right->left->value),
163 new_node(key, value, left, ref_node(right->left->left)),
Craig Tillerba7d4df2016-01-25 11:47:58 -0800164 new_node(vtable->copy_key(right->key), vtable->copy_value(right->value),
Craig Tillerfba79f22015-11-23 11:06:55 -0800165 ref_node(right->left->right), ref_node(right->right)));
Craig Tillerfba79f22015-11-23 11:06:55 -0800166 unref_node(vtable, right);
Craig Tillerfba79f22015-11-23 11:06:55 -0800167 return n;
168}
169
Craig Tiller05936222015-11-23 14:56:46 -0800170static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key,
171 void *value, gpr_avl_node *left,
172 gpr_avl_node *right) {
173 switch (node_height(left) - node_height(right)) {
174 case 2:
175 if (node_height(left->left) - node_height(left->right) == -1) {
176 return assert_invariants(
177 rotate_left_right(vtable, key, value, left, right));
178 } else {
179 return assert_invariants(rotate_right(vtable, key, value, left, right));
180 }
181 case -2:
182 if (node_height(right->left) - node_height(right->right) == 1) {
183 return assert_invariants(
184 rotate_right_left(vtable, key, value, left, right));
185 } else {
186 return assert_invariants(rotate_left(vtable, key, value, left, right));
187 }
188 default:
189 return assert_invariants(new_node(key, value, left, right));
190 }
191}
192
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200193static gpr_avl_node *add_key(const gpr_avl_vtable *vtable, gpr_avl_node *node,
194 void *key, void *value) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800195 long cmp;
Craig Tillerfba79f22015-11-23 11:06:55 -0800196 if (node == NULL) {
197 return new_node(key, value, NULL, NULL);
198 }
199 cmp = vtable->compare_keys(node->key, key);
200 if (cmp == 0) {
Craig Tiller22d11e12015-11-23 15:33:54 -0800201 return new_node(key, value, ref_node(node->left), ref_node(node->right));
202 } else if (cmp > 0) {
Craig Tiller3328a582015-11-23 15:39:32 -0800203 return rebalance(
204 vtable, vtable->copy_key(node->key), vtable->copy_value(node->value),
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200205 add_key(vtable, node->left, key, value), ref_node(node->right));
Craig Tillerfba79f22015-11-23 11:06:55 -0800206 } else {
Craig Tiller22d11e12015-11-23 15:33:54 -0800207 return rebalance(vtable, vtable->copy_key(node->key),
208 vtable->copy_value(node->value), ref_node(node->left),
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200209 add_key(vtable, node->right, key, value));
Craig Tillerfba79f22015-11-23 11:06:55 -0800210 }
Craig Tillerfba79f22015-11-23 11:06:55 -0800211}
212
213gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) {
214 gpr_avl_node *old_root = avl.root;
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200215 avl.root = add_key(avl.vtable, avl.root, key, value);
Craig Tillerfba79f22015-11-23 11:06:55 -0800216 assert_invariants(avl.root);
217 unref_node(avl.vtable, old_root);
218 return avl;
219}
220
Craig Tiller05936222015-11-23 14:56:46 -0800221static gpr_avl_node *in_order_head(gpr_avl_node *node) {
222 while (node->left != NULL) {
223 node = node->left;
224 }
225 return node;
226}
227
228static gpr_avl_node *in_order_tail(gpr_avl_node *node) {
229 while (node->right != NULL) {
230 node = node->right;
231 }
232 return node;
233}
234
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200235static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable,
236 gpr_avl_node *node, void *key) {
Craig Tiller05936222015-11-23 14:56:46 -0800237 long cmp;
Craig Tiller05936222015-11-23 14:56:46 -0800238 if (node == NULL) {
239 return NULL;
240 }
241 cmp = vtable->compare_keys(node->key, key);
242 if (cmp == 0) {
243 if (node->left == NULL) {
244 return ref_node(node->right);
245 } else if (node->right == NULL) {
246 return ref_node(node->left);
247 } else if (node->left->height < node->right->height) {
248 gpr_avl_node *h = in_order_head(node->right);
Craig Tiller22d11e12015-11-23 15:33:54 -0800249 return rebalance(vtable, vtable->copy_key(h->key),
Craig Tiller3328a582015-11-23 15:39:32 -0800250 vtable->copy_value(h->value), ref_node(node->left),
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200251 remove_key(vtable, node->right, h->key));
Craig Tiller05936222015-11-23 14:56:46 -0800252 } else {
253 gpr_avl_node *h = in_order_tail(node->left);
Craig Tiller3328a582015-11-23 15:39:32 -0800254 return rebalance(
255 vtable, vtable->copy_key(h->key), vtable->copy_value(h->value),
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200256 remove_key(vtable, node->left, h->key), ref_node(node->right));
Craig Tiller05936222015-11-23 14:56:46 -0800257 }
Craig Tiller22d11e12015-11-23 15:33:54 -0800258 } else if (cmp > 0) {
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200259 return rebalance(
260 vtable, vtable->copy_key(node->key), vtable->copy_value(node->value),
261 remove_key(vtable, node->left, key), ref_node(node->right));
Craig Tiller05936222015-11-23 14:56:46 -0800262 } else {
Craig Tiller22d11e12015-11-23 15:33:54 -0800263 return rebalance(vtable, vtable->copy_key(node->key),
264 vtable->copy_value(node->value), ref_node(node->left),
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200265 remove_key(vtable, node->right, key));
Craig Tiller05936222015-11-23 14:56:46 -0800266 }
Craig Tiller05936222015-11-23 14:56:46 -0800267}
268
269gpr_avl gpr_avl_remove(gpr_avl avl, void *key) {
270 gpr_avl_node *old_root = avl.root;
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200271 avl.root = remove_key(avl.vtable, avl.root, key);
Craig Tiller05936222015-11-23 14:56:46 -0800272 assert_invariants(avl.root);
273 unref_node(avl.vtable, old_root);
274 return avl;
275}
276
277gpr_avl gpr_avl_ref(gpr_avl avl) {
278 ref_node(avl.root);
279 return avl;
280}
281
282void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); }
Craig Tiller1c51edc2016-05-07 16:18:43 -0700283
284int gpr_avl_is_empty(gpr_avl avl) { return avl.root == NULL; }