blob: 0e28b24c98ef19b5d040dc7f9f981d21516292e1 [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
yang-gd66ee1a2017-07-18 08:11:10 -070035static gpr_avl_node *ref_node(gpr_avl_node *node) {
Craig Tillerfba79f22015-11-23 11:06:55 -080036 if (node) {
37 gpr_ref(&node->refs);
38 }
39 return node;
40}
41
yang-g59ef6482017-07-17 13:52:24 -070042static void unref_node(const gpr_avl_vtable *vtable, gpr_avl_node *node,
43 void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -080044 if (node == NULL) {
45 return;
46 }
47 if (gpr_unref(&node->refs)) {
yang-g59ef6482017-07-17 13:52:24 -070048 vtable->destroy_key(node->key, user_data);
49 vtable->destroy_value(node->value, user_data);
50 unref_node(vtable, node->left, user_data);
51 unref_node(vtable, node->right, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -080052 gpr_free(node);
53 }
54}
55
56static long node_height(gpr_avl_node *node) {
57 return node == NULL ? 0 : node->height;
58}
59
Craig Tiller05936222015-11-23 14:56:46 -080060#ifndef NDEBUG
Craig Tillerfba79f22015-11-23 11:06:55 -080061static long calculate_height(gpr_avl_node *node) {
62 return node == NULL ? 0 : 1 + GPR_MAX(calculate_height(node->left),
63 calculate_height(node->right));
64}
65
Craig Tiller05936222015-11-23 14:56:46 -080066static gpr_avl_node *assert_invariants(gpr_avl_node *n) {
67 if (n == NULL) return NULL;
Craig Tillerfba79f22015-11-23 11:06:55 -080068 assert_invariants(n->left);
69 assert_invariants(n->right);
70 assert(calculate_height(n) == n->height);
71 assert(labs(node_height(n->left) - node_height(n->right)) <= 1);
Craig Tiller05936222015-11-23 14:56:46 -080072 return n;
Craig Tillerfba79f22015-11-23 11:06:55 -080073}
Craig Tiller9c721ff2015-11-23 15:16:12 -080074#else
Craig Tiller22d11e12015-11-23 15:33:54 -080075static gpr_avl_node *assert_invariants(gpr_avl_node *n) { return n; }
Craig Tiller9c721ff2015-11-23 15:16:12 -080076#endif
Craig Tillerfba79f22015-11-23 11:06:55 -080077
78gpr_avl_node *new_node(void *key, void *value, gpr_avl_node *left,
79 gpr_avl_node *right) {
Craig Tillered380162017-07-11 08:34:26 -070080 gpr_avl_node *node = (gpr_avl_node *)gpr_malloc(sizeof(*node));
Craig Tillerfba79f22015-11-23 11:06:55 -080081 gpr_ref_init(&node->refs, 1);
82 node->key = key;
83 node->value = value;
Craig Tiller05936222015-11-23 14:56:46 -080084 node->left = assert_invariants(left);
85 node->right = assert_invariants(right);
Craig Tillerfba79f22015-11-23 11:06:55 -080086 node->height = 1 + GPR_MAX(node_height(left), node_height(right));
87 return node;
88}
89
90static gpr_avl_node *get(const gpr_avl_vtable *vtable, gpr_avl_node *node,
yang-g59ef6482017-07-17 13:52:24 -070091 void *key, void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -080092 long cmp;
93
94 if (node == NULL) {
95 return NULL;
96 }
97
yang-g59ef6482017-07-17 13:52:24 -070098 cmp = vtable->compare_keys(node->key, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -080099 if (cmp == 0) {
100 return node;
101 } else if (cmp > 0) {
yang-g59ef6482017-07-17 13:52:24 -0700102 return get(vtable, node->left, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800103 } else {
yang-g59ef6482017-07-17 13:52:24 -0700104 return get(vtable, node->right, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800105 }
106}
107
yang-g59ef6482017-07-17 13:52:24 -0700108void *gpr_avl_get(gpr_avl avl, void *key, void *user_data) {
109 gpr_avl_node *node = get(avl.vtable, avl.root, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800110 return node ? node->value : NULL;
111}
112
yang-g59ef6482017-07-17 13:52:24 -0700113int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value, void *user_data) {
114 gpr_avl_node *node = get(avl.vtable, avl.root, key, user_data);
Craig Tiller965eab32016-05-07 22:11:37 -0700115 if (node != NULL) {
116 *value = node->value;
117 return 1;
118 }
119 return 0;
120}
121
Craig Tillerfba79f22015-11-23 11:06:55 -0800122static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key,
123 void *value, gpr_avl_node *left,
yang-g59ef6482017-07-17 13:52:24 -0700124 gpr_avl_node *right, void *user_data) {
yang-gd66ee1a2017-07-18 08:11:10 -0700125 gpr_avl_node *n = new_node(vtable->copy_key(right->key, user_data),
126 vtable->copy_value(right->value, user_data),
127 new_node(key, value, left, ref_node(right->left)),
128 ref_node(right->right));
yang-g59ef6482017-07-17 13:52:24 -0700129 unref_node(vtable, right, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800130 return n;
131}
132
133static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key,
134 void *value, gpr_avl_node *left,
yang-g59ef6482017-07-17 13:52:24 -0700135 gpr_avl_node *right, void *user_data) {
136 gpr_avl_node *n =
137 new_node(vtable->copy_key(left->key, user_data),
yang-gd66ee1a2017-07-18 08:11:10 -0700138 vtable->copy_value(left->value, user_data), ref_node(left->left),
139 new_node(key, value, ref_node(left->right), right));
yang-g59ef6482017-07-17 13:52:24 -0700140 unref_node(vtable, left, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800141 return n;
142}
143
144static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key,
145 void *value, gpr_avl_node *left,
yang-g59ef6482017-07-17 13:52:24 -0700146 gpr_avl_node *right, void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800147 /* rotate_right(..., rotate_left(left), right) */
yang-gd66ee1a2017-07-18 08:11:10 -0700148 gpr_avl_node *n =
149 new_node(vtable->copy_key(left->right->key, user_data),
150 vtable->copy_value(left->right->value, user_data),
151 new_node(vtable->copy_key(left->key, user_data),
152 vtable->copy_value(left->value, user_data),
153 ref_node(left->left), ref_node(left->right->left)),
154 new_node(key, value, ref_node(left->right->right), right));
yang-g59ef6482017-07-17 13:52:24 -0700155 unref_node(vtable, left, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800156 return n;
157}
158
159static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key,
160 void *value, gpr_avl_node *left,
yang-g59ef6482017-07-17 13:52:24 -0700161 gpr_avl_node *right, void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800162 /* rotate_left(..., left, rotate_right(right)) */
yang-gd66ee1a2017-07-18 08:11:10 -0700163 gpr_avl_node *n =
164 new_node(vtable->copy_key(right->left->key, user_data),
165 vtable->copy_value(right->left->value, user_data),
166 new_node(key, value, left, ref_node(right->left->left)),
167 new_node(vtable->copy_key(right->key, user_data),
168 vtable->copy_value(right->value, user_data),
169 ref_node(right->left->right), ref_node(right->right)));
yang-g59ef6482017-07-17 13:52:24 -0700170 unref_node(vtable, right, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800171 return n;
172}
173
Craig Tiller05936222015-11-23 14:56:46 -0800174static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key,
175 void *value, gpr_avl_node *left,
yang-g59ef6482017-07-17 13:52:24 -0700176 gpr_avl_node *right, void *user_data) {
Craig Tiller05936222015-11-23 14:56:46 -0800177 switch (node_height(left) - node_height(right)) {
178 case 2:
179 if (node_height(left->left) - node_height(left->right) == -1) {
180 return assert_invariants(
yang-g59ef6482017-07-17 13:52:24 -0700181 rotate_left_right(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800182 } else {
yang-g59ef6482017-07-17 13:52:24 -0700183 return assert_invariants(
184 rotate_right(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800185 }
186 case -2:
187 if (node_height(right->left) - node_height(right->right) == 1) {
188 return assert_invariants(
yang-g59ef6482017-07-17 13:52:24 -0700189 rotate_right_left(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800190 } else {
yang-g59ef6482017-07-17 13:52:24 -0700191 return assert_invariants(
192 rotate_left(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800193 }
194 default:
195 return assert_invariants(new_node(key, value, left, right));
196 }
197}
198
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200199static gpr_avl_node *add_key(const gpr_avl_vtable *vtable, gpr_avl_node *node,
yang-g59ef6482017-07-17 13:52:24 -0700200 void *key, void *value, void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800201 long cmp;
Craig Tillerfba79f22015-11-23 11:06:55 -0800202 if (node == NULL) {
203 return new_node(key, value, NULL, NULL);
204 }
yang-g59ef6482017-07-17 13:52:24 -0700205 cmp = vtable->compare_keys(node->key, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800206 if (cmp == 0) {
yang-gd66ee1a2017-07-18 08:11:10 -0700207 return new_node(key, value, ref_node(node->left), ref_node(node->right));
Craig Tiller22d11e12015-11-23 15:33:54 -0800208 } else if (cmp > 0) {
yang-g59ef6482017-07-17 13:52:24 -0700209 return rebalance(vtable, vtable->copy_key(node->key, user_data),
210 vtable->copy_value(node->value, user_data),
211 add_key(vtable, node->left, key, value, user_data),
yang-gd66ee1a2017-07-18 08:11:10 -0700212 ref_node(node->right), user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800213 } else {
yang-gd66ee1a2017-07-18 08:11:10 -0700214 return rebalance(
215 vtable, vtable->copy_key(node->key, user_data),
216 vtable->copy_value(node->value, user_data), ref_node(node->left),
217 add_key(vtable, node->right, key, value, user_data), user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800218 }
Craig Tillerfba79f22015-11-23 11:06:55 -0800219}
220
yang-g59ef6482017-07-17 13:52:24 -0700221gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value, void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800222 gpr_avl_node *old_root = avl.root;
yang-g59ef6482017-07-17 13:52:24 -0700223 avl.root = add_key(avl.vtable, avl.root, key, value, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800224 assert_invariants(avl.root);
yang-g59ef6482017-07-17 13:52:24 -0700225 unref_node(avl.vtable, old_root, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800226 return avl;
227}
228
Craig Tiller05936222015-11-23 14:56:46 -0800229static gpr_avl_node *in_order_head(gpr_avl_node *node) {
230 while (node->left != NULL) {
231 node = node->left;
232 }
233 return node;
234}
235
236static gpr_avl_node *in_order_tail(gpr_avl_node *node) {
237 while (node->right != NULL) {
238 node = node->right;
239 }
240 return node;
241}
242
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200243static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable,
yang-g59ef6482017-07-17 13:52:24 -0700244 gpr_avl_node *node, void *key,
245 void *user_data) {
Craig Tiller05936222015-11-23 14:56:46 -0800246 long cmp;
Craig Tiller05936222015-11-23 14:56:46 -0800247 if (node == NULL) {
248 return NULL;
249 }
yang-g59ef6482017-07-17 13:52:24 -0700250 cmp = vtable->compare_keys(node->key, key, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800251 if (cmp == 0) {
252 if (node->left == NULL) {
yang-gd66ee1a2017-07-18 08:11:10 -0700253 return ref_node(node->right);
Craig Tiller05936222015-11-23 14:56:46 -0800254 } else if (node->right == NULL) {
yang-gd66ee1a2017-07-18 08:11:10 -0700255 return ref_node(node->left);
Craig Tiller05936222015-11-23 14:56:46 -0800256 } else if (node->left->height < node->right->height) {
257 gpr_avl_node *h = in_order_head(node->right);
yang-gd66ee1a2017-07-18 08:11:10 -0700258 return rebalance(
259 vtable, vtable->copy_key(h->key, user_data),
260 vtable->copy_value(h->value, user_data), ref_node(node->left),
261 remove_key(vtable, node->right, h->key, user_data), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800262 } else {
263 gpr_avl_node *h = in_order_tail(node->left);
yang-g59ef6482017-07-17 13:52:24 -0700264 return rebalance(vtable, vtable->copy_key(h->key, user_data),
265 vtable->copy_value(h->value, user_data),
266 remove_key(vtable, node->left, h->key, user_data),
yang-gd66ee1a2017-07-18 08:11:10 -0700267 ref_node(node->right), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800268 }
Craig Tiller22d11e12015-11-23 15:33:54 -0800269 } else if (cmp > 0) {
yang-g59ef6482017-07-17 13:52:24 -0700270 return rebalance(vtable, vtable->copy_key(node->key, user_data),
271 vtable->copy_value(node->value, user_data),
272 remove_key(vtable, node->left, key, user_data),
yang-gd66ee1a2017-07-18 08:11:10 -0700273 ref_node(node->right), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800274 } else {
yang-gd66ee1a2017-07-18 08:11:10 -0700275 return rebalance(
276 vtable, vtable->copy_key(node->key, user_data),
277 vtable->copy_value(node->value, user_data), ref_node(node->left),
278 remove_key(vtable, node->right, key, user_data), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800279 }
Craig Tiller05936222015-11-23 14:56:46 -0800280}
281
yang-g59ef6482017-07-17 13:52:24 -0700282gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data) {
Craig Tiller05936222015-11-23 14:56:46 -0800283 gpr_avl_node *old_root = avl.root;
yang-g59ef6482017-07-17 13:52:24 -0700284 avl.root = remove_key(avl.vtable, avl.root, key, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800285 assert_invariants(avl.root);
yang-g59ef6482017-07-17 13:52:24 -0700286 unref_node(avl.vtable, old_root, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800287 return avl;
288}
289
yang-g59ef6482017-07-17 13:52:24 -0700290gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data) {
yang-gd66ee1a2017-07-18 08:11:10 -0700291 ref_node(avl.root);
Craig Tiller05936222015-11-23 14:56:46 -0800292 return avl;
293}
294
yang-g59ef6482017-07-17 13:52:24 -0700295void gpr_avl_unref(gpr_avl avl, void *user_data) {
296 unref_node(avl.vtable, avl.root, user_data);
297}
Craig Tiller1c51edc2016-05-07 16:18:43 -0700298
299int gpr_avl_is_empty(gpr_avl avl) { return avl.root == NULL; }