blob: ca0e4c6372d78e170c72fe4211d2b48f76a4b101 [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
Craig Tillerbaa14a92017-11-03 09:09:36 -070028gpr_avl gpr_avl_create(const gpr_avl_vtable* vtable) {
Craig Tillerfba79f22015-11-23 11:06:55 -080029 gpr_avl out;
30 out.vtable = vtable;
Craig Tiller4782d922017-11-10 09:53:21 -080031 out.root = nullptr;
Craig Tillerfba79f22015-11-23 11:06:55 -080032 return out;
33}
34
Craig Tillerbaa14a92017-11-03 09:09:36 -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
Craig Tillerbaa14a92017-11-03 09:09:36 -070042static void unref_node(const gpr_avl_vtable* vtable, gpr_avl_node* node,
43 void* user_data) {
Craig Tiller4782d922017-11-10 09:53:21 -080044 if (node == nullptr) {
Craig Tillerfba79f22015-11-23 11:06:55 -080045 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
Craig Tillerbaa14a92017-11-03 09:09:36 -070056static long node_height(gpr_avl_node* node) {
Craig Tiller4782d922017-11-10 09:53:21 -080057 return node == nullptr ? 0 : node->height;
Craig Tillerfba79f22015-11-23 11:06:55 -080058}
59
Craig Tiller05936222015-11-23 14:56:46 -080060#ifndef NDEBUG
Craig Tillerbaa14a92017-11-03 09:09:36 -070061static long calculate_height(gpr_avl_node* node) {
Craig Tiller4782d922017-11-10 09:53:21 -080062 return node == nullptr ? 0
Craig Tillerbaa14a92017-11-03 09:09:36 -070063 : 1 + GPR_MAX(calculate_height(node->left),
64 calculate_height(node->right));
Craig Tillerfba79f22015-11-23 11:06:55 -080065}
66
Craig Tillerbaa14a92017-11-03 09:09:36 -070067static gpr_avl_node* assert_invariants(gpr_avl_node* n) {
Craig Tiller4782d922017-11-10 09:53:21 -080068 if (n == nullptr) return nullptr;
Craig Tillerfba79f22015-11-23 11:06:55 -080069 assert_invariants(n->left);
70 assert_invariants(n->right);
71 assert(calculate_height(n) == n->height);
72 assert(labs(node_height(n->left) - node_height(n->right)) <= 1);
Craig Tiller05936222015-11-23 14:56:46 -080073 return n;
Craig Tillerfba79f22015-11-23 11:06:55 -080074}
Craig Tiller9c721ff2015-11-23 15:16:12 -080075#else
Craig Tillerbaa14a92017-11-03 09:09:36 -070076static gpr_avl_node* assert_invariants(gpr_avl_node* n) { return n; }
Craig Tiller9c721ff2015-11-23 15:16:12 -080077#endif
Craig Tillerfba79f22015-11-23 11:06:55 -080078
Craig Tillerbaa14a92017-11-03 09:09:36 -070079gpr_avl_node* new_node(void* key, void* value, gpr_avl_node* left,
80 gpr_avl_node* right) {
81 gpr_avl_node* node = (gpr_avl_node*)gpr_malloc(sizeof(*node));
Craig Tillerfba79f22015-11-23 11:06:55 -080082 gpr_ref_init(&node->refs, 1);
83 node->key = key;
84 node->value = value;
Craig Tiller05936222015-11-23 14:56:46 -080085 node->left = assert_invariants(left);
86 node->right = assert_invariants(right);
Craig Tillerfba79f22015-11-23 11:06:55 -080087 node->height = 1 + GPR_MAX(node_height(left), node_height(right));
88 return node;
89}
90
Craig Tillerbaa14a92017-11-03 09:09:36 -070091static gpr_avl_node* get(const gpr_avl_vtable* vtable, gpr_avl_node* node,
92 void* key, void* user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -080093 long cmp;
94
Craig Tiller4782d922017-11-10 09:53:21 -080095 if (node == nullptr) {
96 return nullptr;
Craig Tillerfba79f22015-11-23 11:06:55 -080097 }
98
yang-g59ef6482017-07-17 13:52:24 -070099 cmp = vtable->compare_keys(node->key, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800100 if (cmp == 0) {
101 return node;
102 } else if (cmp > 0) {
yang-g59ef6482017-07-17 13:52:24 -0700103 return get(vtable, node->left, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800104 } else {
yang-g59ef6482017-07-17 13:52:24 -0700105 return get(vtable, node->right, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800106 }
107}
108
Craig Tillerbaa14a92017-11-03 09:09:36 -0700109void* gpr_avl_get(gpr_avl avl, void* key, void* user_data) {
110 gpr_avl_node* node = get(avl.vtable, avl.root, key, user_data);
Craig Tiller4782d922017-11-10 09:53:21 -0800111 return node ? node->value : nullptr;
Craig Tillerfba79f22015-11-23 11:06:55 -0800112}
113
Craig Tillerbaa14a92017-11-03 09:09:36 -0700114int gpr_avl_maybe_get(gpr_avl avl, void* key, void** value, void* user_data) {
115 gpr_avl_node* node = get(avl.vtable, avl.root, key, user_data);
Craig Tiller4782d922017-11-10 09:53:21 -0800116 if (node != nullptr) {
Craig Tiller965eab32016-05-07 22:11:37 -0700117 *value = node->value;
118 return 1;
119 }
120 return 0;
121}
122
Craig Tillerbaa14a92017-11-03 09:09:36 -0700123static gpr_avl_node* rotate_left(const gpr_avl_vtable* vtable, void* key,
124 void* value, gpr_avl_node* left,
125 gpr_avl_node* right, void* user_data) {
126 gpr_avl_node* n = new_node(vtable->copy_key(right->key, user_data),
yang-gd66ee1a2017-07-18 08:11:10 -0700127 vtable->copy_value(right->value, user_data),
128 new_node(key, value, left, ref_node(right->left)),
129 ref_node(right->right));
yang-g59ef6482017-07-17 13:52:24 -0700130 unref_node(vtable, right, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800131 return n;
132}
133
Craig Tillerbaa14a92017-11-03 09:09:36 -0700134static gpr_avl_node* rotate_right(const gpr_avl_vtable* vtable, void* key,
135 void* value, gpr_avl_node* left,
136 gpr_avl_node* right, void* user_data) {
137 gpr_avl_node* n =
yang-g59ef6482017-07-17 13:52:24 -0700138 new_node(vtable->copy_key(left->key, user_data),
yang-gd66ee1a2017-07-18 08:11:10 -0700139 vtable->copy_value(left->value, user_data), ref_node(left->left),
140 new_node(key, value, ref_node(left->right), right));
yang-g59ef6482017-07-17 13:52:24 -0700141 unref_node(vtable, left, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800142 return n;
143}
144
Craig Tillerbaa14a92017-11-03 09:09:36 -0700145static gpr_avl_node* rotate_left_right(const gpr_avl_vtable* vtable, void* key,
146 void* value, gpr_avl_node* left,
147 gpr_avl_node* right, void* user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800148 /* rotate_right(..., rotate_left(left), right) */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700149 gpr_avl_node* n =
yang-gd66ee1a2017-07-18 08:11:10 -0700150 new_node(vtable->copy_key(left->right->key, user_data),
151 vtable->copy_value(left->right->value, user_data),
152 new_node(vtable->copy_key(left->key, user_data),
153 vtable->copy_value(left->value, user_data),
154 ref_node(left->left), ref_node(left->right->left)),
155 new_node(key, value, ref_node(left->right->right), right));
yang-g59ef6482017-07-17 13:52:24 -0700156 unref_node(vtable, left, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800157 return n;
158}
159
Craig Tillerbaa14a92017-11-03 09:09:36 -0700160static gpr_avl_node* rotate_right_left(const gpr_avl_vtable* vtable, void* key,
161 void* value, gpr_avl_node* left,
162 gpr_avl_node* right, void* user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800163 /* rotate_left(..., left, rotate_right(right)) */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700164 gpr_avl_node* n =
yang-gd66ee1a2017-07-18 08:11:10 -0700165 new_node(vtable->copy_key(right->left->key, user_data),
166 vtable->copy_value(right->left->value, user_data),
167 new_node(key, value, left, ref_node(right->left->left)),
168 new_node(vtable->copy_key(right->key, user_data),
169 vtable->copy_value(right->value, user_data),
170 ref_node(right->left->right), ref_node(right->right)));
yang-g59ef6482017-07-17 13:52:24 -0700171 unref_node(vtable, right, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800172 return n;
173}
174
Craig Tillerbaa14a92017-11-03 09:09:36 -0700175static gpr_avl_node* rebalance(const gpr_avl_vtable* vtable, void* key,
176 void* value, gpr_avl_node* left,
177 gpr_avl_node* right, void* user_data) {
Craig Tiller05936222015-11-23 14:56:46 -0800178 switch (node_height(left) - node_height(right)) {
179 case 2:
180 if (node_height(left->left) - node_height(left->right) == -1) {
181 return assert_invariants(
yang-g59ef6482017-07-17 13:52:24 -0700182 rotate_left_right(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800183 } else {
yang-g59ef6482017-07-17 13:52:24 -0700184 return assert_invariants(
185 rotate_right(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800186 }
187 case -2:
188 if (node_height(right->left) - node_height(right->right) == 1) {
189 return assert_invariants(
yang-g59ef6482017-07-17 13:52:24 -0700190 rotate_right_left(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800191 } else {
yang-g59ef6482017-07-17 13:52:24 -0700192 return assert_invariants(
193 rotate_left(vtable, key, value, left, right, user_data));
Craig Tiller05936222015-11-23 14:56:46 -0800194 }
195 default:
196 return assert_invariants(new_node(key, value, left, right));
197 }
198}
199
Craig Tillerbaa14a92017-11-03 09:09:36 -0700200static gpr_avl_node* add_key(const gpr_avl_vtable* vtable, gpr_avl_node* node,
201 void* key, void* value, void* user_data) {
Craig Tillerfba79f22015-11-23 11:06:55 -0800202 long cmp;
Craig Tiller4782d922017-11-10 09:53:21 -0800203 if (node == nullptr) {
204 return new_node(key, value, nullptr, nullptr);
Craig Tillerfba79f22015-11-23 11:06:55 -0800205 }
yang-g59ef6482017-07-17 13:52:24 -0700206 cmp = vtable->compare_keys(node->key, key, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800207 if (cmp == 0) {
yang-gd66ee1a2017-07-18 08:11:10 -0700208 return new_node(key, value, ref_node(node->left), ref_node(node->right));
Craig Tiller22d11e12015-11-23 15:33:54 -0800209 } else if (cmp > 0) {
yang-g59ef6482017-07-17 13:52:24 -0700210 return rebalance(vtable, vtable->copy_key(node->key, user_data),
211 vtable->copy_value(node->value, user_data),
212 add_key(vtable, node->left, key, value, user_data),
yang-gd66ee1a2017-07-18 08:11:10 -0700213 ref_node(node->right), user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800214 } else {
yang-gd66ee1a2017-07-18 08:11:10 -0700215 return rebalance(
216 vtable, vtable->copy_key(node->key, user_data),
217 vtable->copy_value(node->value, user_data), ref_node(node->left),
218 add_key(vtable, node->right, key, value, user_data), user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800219 }
Craig Tillerfba79f22015-11-23 11:06:55 -0800220}
221
Craig Tillerbaa14a92017-11-03 09:09:36 -0700222gpr_avl gpr_avl_add(gpr_avl avl, void* key, void* value, void* user_data) {
223 gpr_avl_node* old_root = avl.root;
yang-g59ef6482017-07-17 13:52:24 -0700224 avl.root = add_key(avl.vtable, avl.root, key, value, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800225 assert_invariants(avl.root);
yang-g59ef6482017-07-17 13:52:24 -0700226 unref_node(avl.vtable, old_root, user_data);
Craig Tillerfba79f22015-11-23 11:06:55 -0800227 return avl;
228}
229
Craig Tillerbaa14a92017-11-03 09:09:36 -0700230static gpr_avl_node* in_order_head(gpr_avl_node* node) {
Craig Tiller4782d922017-11-10 09:53:21 -0800231 while (node->left != nullptr) {
Craig Tiller05936222015-11-23 14:56:46 -0800232 node = node->left;
233 }
234 return node;
235}
236
Craig Tillerbaa14a92017-11-03 09:09:36 -0700237static gpr_avl_node* in_order_tail(gpr_avl_node* node) {
Craig Tiller4782d922017-11-10 09:53:21 -0800238 while (node->right != nullptr) {
Craig Tiller05936222015-11-23 14:56:46 -0800239 node = node->right;
240 }
241 return node;
242}
243
Craig Tillerbaa14a92017-11-03 09:09:36 -0700244static gpr_avl_node* remove_key(const gpr_avl_vtable* vtable,
245 gpr_avl_node* node, void* key,
246 void* user_data) {
Craig Tiller05936222015-11-23 14:56:46 -0800247 long cmp;
Craig Tiller4782d922017-11-10 09:53:21 -0800248 if (node == nullptr) {
249 return nullptr;
Craig Tiller05936222015-11-23 14:56:46 -0800250 }
yang-g59ef6482017-07-17 13:52:24 -0700251 cmp = vtable->compare_keys(node->key, key, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800252 if (cmp == 0) {
Craig Tiller4782d922017-11-10 09:53:21 -0800253 if (node->left == nullptr) {
yang-gd66ee1a2017-07-18 08:11:10 -0700254 return ref_node(node->right);
Craig Tiller4782d922017-11-10 09:53:21 -0800255 } else if (node->right == nullptr) {
yang-gd66ee1a2017-07-18 08:11:10 -0700256 return ref_node(node->left);
Craig Tiller05936222015-11-23 14:56:46 -0800257 } else if (node->left->height < node->right->height) {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700258 gpr_avl_node* h = in_order_head(node->right);
yang-gd66ee1a2017-07-18 08:11:10 -0700259 return rebalance(
260 vtable, vtable->copy_key(h->key, user_data),
261 vtable->copy_value(h->value, user_data), ref_node(node->left),
262 remove_key(vtable, node->right, h->key, user_data), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800263 } else {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700264 gpr_avl_node* h = in_order_tail(node->left);
yang-g59ef6482017-07-17 13:52:24 -0700265 return rebalance(vtable, vtable->copy_key(h->key, user_data),
266 vtable->copy_value(h->value, user_data),
267 remove_key(vtable, node->left, h->key, user_data),
yang-gd66ee1a2017-07-18 08:11:10 -0700268 ref_node(node->right), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800269 }
Craig Tiller22d11e12015-11-23 15:33:54 -0800270 } else if (cmp > 0) {
yang-g59ef6482017-07-17 13:52:24 -0700271 return rebalance(vtable, vtable->copy_key(node->key, user_data),
272 vtable->copy_value(node->value, user_data),
273 remove_key(vtable, node->left, key, user_data),
yang-gd66ee1a2017-07-18 08:11:10 -0700274 ref_node(node->right), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800275 } else {
yang-gd66ee1a2017-07-18 08:11:10 -0700276 return rebalance(
277 vtable, vtable->copy_key(node->key, user_data),
278 vtable->copy_value(node->value, user_data), ref_node(node->left),
279 remove_key(vtable, node->right, key, user_data), user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800280 }
Craig Tiller05936222015-11-23 14:56:46 -0800281}
282
Craig Tillerbaa14a92017-11-03 09:09:36 -0700283gpr_avl gpr_avl_remove(gpr_avl avl, void* key, void* user_data) {
284 gpr_avl_node* old_root = avl.root;
yang-g59ef6482017-07-17 13:52:24 -0700285 avl.root = remove_key(avl.vtable, avl.root, key, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800286 assert_invariants(avl.root);
yang-g59ef6482017-07-17 13:52:24 -0700287 unref_node(avl.vtable, old_root, user_data);
Craig Tiller05936222015-11-23 14:56:46 -0800288 return avl;
289}
290
Craig Tillerbaa14a92017-11-03 09:09:36 -0700291gpr_avl gpr_avl_ref(gpr_avl avl, void* user_data) {
yang-gd66ee1a2017-07-18 08:11:10 -0700292 ref_node(avl.root);
Craig Tiller05936222015-11-23 14:56:46 -0800293 return avl;
294}
295
Craig Tillerbaa14a92017-11-03 09:09:36 -0700296void gpr_avl_unref(gpr_avl avl, void* user_data) {
yang-g59ef6482017-07-17 13:52:24 -0700297 unref_node(avl.vtable, avl.root, user_data);
298}
Craig Tiller1c51edc2016-05-07 16:18:43 -0700299
Craig Tiller4782d922017-11-10 09:53:21 -0800300int gpr_avl_is_empty(gpr_avl avl) { return avl.root == nullptr; }