blob: a58551e259ea895c1e2cc387641c8294df03ea25 [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-g59ef6482017-07-17 13:52:24 -070035static gpr_avl_node *ref_node(gpr_avl_node *node, void *user_data) {
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) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800125 gpr_avl_node *n =
yang-g59ef6482017-07-17 13:52:24 -0700126 new_node(vtable->copy_key(right->key, user_data),
127 vtable->copy_value(right->value, user_data),
128 new_node(key, value, left, ref_node(right->left, user_data)),
129 ref_node(right->right, user_data));
130 unref_node(vtable, right, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800131 return n;
132}
133
134static gpr_avl_node *rotate_right(const gpr_avl_vtable *vtable, void *key,
135 void *value, gpr_avl_node *left,
yang-g59ef6482017-07-17 13:52:24 -0700136 gpr_avl_node *right, void *user_data) {
137 gpr_avl_node *n =
138 new_node(vtable->copy_key(left->key, user_data),
139 vtable->copy_value(left->value, user_data),
140 ref_node(left->left, user_data),
141 new_node(key, value, ref_node(left->right, user_data), right));
142 unref_node(vtable, left, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800143 return n;
144}
145
146static gpr_avl_node *rotate_left_right(const gpr_avl_vtable *vtable, void *key,
147 void *value, gpr_avl_node *left,
yang-g59ef6482017-07-17 13:52:24 -0700148 gpr_avl_node *right, void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800149 /* rotate_right(..., rotate_left(left), right) */
Craig Tiller05936222015-11-23 14:56:46 -0800150 gpr_avl_node *n = new_node(
yang-g59ef6482017-07-17 13:52:24 -0700151 vtable->copy_key(left->right->key, user_data),
152 vtable->copy_value(left->right->value, user_data),
153 new_node(vtable->copy_key(left->key, user_data),
154 vtable->copy_value(left->value, user_data),
155 ref_node(left->left, user_data),
156 ref_node(left->right->left, user_data)),
157 new_node(key, value, ref_node(left->right->right, user_data), right));
158 unref_node(vtable, left, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800159 return n;
160}
161
162static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key,
163 void *value, gpr_avl_node *left,
yang-g59ef6482017-07-17 13:52:24 -0700164 gpr_avl_node *right, void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800165 /* rotate_left(..., left, rotate_right(right)) */
Craig Tiller05936222015-11-23 14:56:46 -0800166 gpr_avl_node *n = new_node(
yang-g59ef6482017-07-17 13:52:24 -0700167 vtable->copy_key(right->left->key, user_data),
168 vtable->copy_value(right->left->value, user_data),
169 new_node(key, value, left, ref_node(right->left->left, user_data)),
170 new_node(vtable->copy_key(right->key, user_data),
171 vtable->copy_value(right->value, user_data),
172 ref_node(right->left->right, user_data),
173 ref_node(right->right, user_data)));
174 unref_node(vtable, right, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800175 return n;
176}
177
Craig Tiller05936222015-11-23 14:56:46 -0800178static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key,
179 void *value, gpr_avl_node *left,
yang-g59ef6482017-07-17 13:52:24 -0700180 gpr_avl_node *right, void *user_data) {
Craig Tiller05936222015-11-23 14:56:46 -0800181 switch (node_height(left) - node_height(right)) {
182 case 2:
183 if (node_height(left->left) - node_height(left->right) == -1) {
184 return assert_invariants(
yang-g59ef6482017-07-17 13:52:24 -0700185 rotate_left_right(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800186 } else {
yang-g59ef6482017-07-17 13:52:24 -0700187 return assert_invariants(
188 rotate_right(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800189 }
190 case -2:
191 if (node_height(right->left) - node_height(right->right) == 1) {
192 return assert_invariants(
yang-g59ef6482017-07-17 13:52:24 -0700193 rotate_right_left(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800194 } else {
yang-g59ef6482017-07-17 13:52:24 -0700195 return assert_invariants(
196 rotate_left(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800197 }
198 default:
199 return assert_invariants(new_node(key, value, left, right));
200 }
201}
202
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200203static gpr_avl_node *add_key(const gpr_avl_vtable *vtable, gpr_avl_node *node,
yang-g59ef6482017-07-17 13:52:24 -0700204 void *key, void *value, void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800205 long cmp;
Craig Tillerfba79f22015-11-23 11:06:55 -0800206 if (node == NULL) {
207 return new_node(key, value, NULL, NULL);
208 }
yang-g59ef6482017-07-17 13:52:24 -0700209 cmp = vtable->compare_keys(node->key, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800210 if (cmp == 0) {
yang-g59ef6482017-07-17 13:52:24 -0700211 return new_node(key, value, ref_node(node->left, user_data),
212 ref_node(node->right, user_data));
Craig Tiller22d11e12015-11-23 15:33:54 -0800213 } else if (cmp > 0) {
yang-g59ef6482017-07-17 13:52:24 -0700214 return rebalance(vtable, vtable->copy_key(node->key, user_data),
215 vtable->copy_value(node->value, user_data),
216 add_key(vtable, node->left, key, value, user_data),
217 ref_node(node->right, user_data), user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800218 } else {
yang-g59ef6482017-07-17 13:52:24 -0700219 return rebalance(vtable, vtable->copy_key(node->key, user_data),
220 vtable->copy_value(node->value, user_data),
221 ref_node(node->left, user_data),
222 add_key(vtable, node->right, key, value, user_data),
223 user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800224 }
Craig Tillerfba79f22015-11-23 11:06:55 -0800225}
226
yang-g59ef6482017-07-17 13:52:24 -0700227gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value, void *user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800228 gpr_avl_node *old_root = avl.root;
yang-g59ef6482017-07-17 13:52:24 -0700229 avl.root = add_key(avl.vtable, avl.root, key, value, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800230 assert_invariants(avl.root);
yang-g59ef6482017-07-17 13:52:24 -0700231 unref_node(avl.vtable, old_root, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800232 return avl;
233}
234
Craig Tiller05936222015-11-23 14:56:46 -0800235static gpr_avl_node *in_order_head(gpr_avl_node *node) {
236 while (node->left != NULL) {
237 node = node->left;
238 }
239 return node;
240}
241
242static gpr_avl_node *in_order_tail(gpr_avl_node *node) {
243 while (node->right != NULL) {
244 node = node->right;
245 }
246 return node;
247}
248
Zoltan Kuscsikfcb56a72017-04-19 15:47:37 +0200249static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable,
yang-g59ef6482017-07-17 13:52:24 -0700250 gpr_avl_node *node, void *key,
251 void *user_data) {
Craig Tiller05936222015-11-23 14:56:46 -0800252 long cmp;
Craig Tiller05936222015-11-23 14:56:46 -0800253 if (node == NULL) {
254 return NULL;
255 }
yang-g59ef6482017-07-17 13:52:24 -0700256 cmp = vtable->compare_keys(node->key, key, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800257 if (cmp == 0) {
258 if (node->left == NULL) {
yang-g59ef6482017-07-17 13:52:24 -0700259 return ref_node(node->right, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800260 } else if (node->right == NULL) {
yang-g59ef6482017-07-17 13:52:24 -0700261 return ref_node(node->left, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800262 } else if (node->left->height < node->right->height) {
263 gpr_avl_node *h = in_order_head(node->right);
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 ref_node(node->left, user_data),
267 remove_key(vtable, node->right, h->key, user_data),
268 user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800269 } else {
270 gpr_avl_node *h = in_order_tail(node->left);
yang-g59ef6482017-07-17 13:52:24 -0700271 return rebalance(vtable, vtable->copy_key(h->key, user_data),
272 vtable->copy_value(h->value, user_data),
273 remove_key(vtable, node->left, h->key, user_data),
274 ref_node(node->right, user_data), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800275 }
Craig Tiller22d11e12015-11-23 15:33:54 -0800276 } else if (cmp > 0) {
yang-g59ef6482017-07-17 13:52:24 -0700277 return rebalance(vtable, vtable->copy_key(node->key, user_data),
278 vtable->copy_value(node->value, user_data),
279 remove_key(vtable, node->left, key, user_data),
280 ref_node(node->right, user_data), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800281 } else {
yang-g59ef6482017-07-17 13:52:24 -0700282 return rebalance(vtable, vtable->copy_key(node->key, user_data),
283 vtable->copy_value(node->value, user_data),
284 ref_node(node->left, user_data),
285 remove_key(vtable, node->right, key, user_data),
286 user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800287 }
Craig Tiller05936222015-11-23 14:56:46 -0800288}
289
yang-g59ef6482017-07-17 13:52:24 -0700290gpr_avl gpr_avl_remove(gpr_avl avl, void *key, void *user_data) {
Craig Tiller05936222015-11-23 14:56:46 -0800291 gpr_avl_node *old_root = avl.root;
yang-g59ef6482017-07-17 13:52:24 -0700292 avl.root = remove_key(avl.vtable, avl.root, key, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800293 assert_invariants(avl.root);
yang-g59ef6482017-07-17 13:52:24 -0700294 unref_node(avl.vtable, old_root, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800295 return avl;
296}
297
yang-g59ef6482017-07-17 13:52:24 -0700298gpr_avl gpr_avl_ref(gpr_avl avl, void *user_data) {
299 ref_node(avl.root, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800300 return avl;
301}
302
yang-g59ef6482017-07-17 13:52:24 -0700303void gpr_avl_unref(gpr_avl avl, void *user_data) {
304 unref_node(avl.vtable, avl.root, user_data);
305}
Craig Tiller1c51edc2016-05-07 16:18:43 -0700306
307int gpr_avl_is_empty(gpr_avl avl) { return avl.root == NULL; }