/src/gnutls/gl/gl_anyrbtree_list2.h
Line | Count | Source |
1 | | /* Sequential list data type implemented by a binary tree. |
2 | | Copyright (C) 2006-2007, 2009-2026 Free Software Foundation, Inc. |
3 | | Written by Bruno Haible <bruno@clisp.org>, 2006. |
4 | | |
5 | | This file is free software: you can redistribute it and/or modify |
6 | | it under the terms of the GNU Lesser General Public License as |
7 | | published by the Free Software Foundation; either version 2.1 of the |
8 | | License, or (at your option) any later version. |
9 | | |
10 | | This file is distributed in the hope that it will be useful, |
11 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | GNU Lesser General Public License for more details. |
14 | | |
15 | | You should have received a copy of the GNU Lesser General Public License |
16 | | along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
17 | | |
18 | | /* Common code of gl_rbtree_list.c and gl_rbtreehash_list.c. */ |
19 | | |
20 | | /* -------------------------- gl_list_t Data Type -------------------------- */ |
21 | | |
22 | | /* Creates a subtree for count >= 1 elements. |
23 | | Its black-height bh is passed as argument, with |
24 | | 2^bh - 1 <= count <= 2^(bh+1) - 1. bh == 0 implies count == 1. |
25 | | Its height is h where 2^(h-1) <= count <= 2^h - 1. |
26 | | Return NULL upon out-of-memory. */ |
27 | | static gl_list_node_t |
28 | | create_subtree_with_contents (unsigned int bh, |
29 | | size_t count, const void **contents) |
30 | 0 | { |
31 | 0 | size_t half1 = (count - 1) / 2; |
32 | 0 | size_t half2 = count / 2; |
33 | | /* Note: half1 + half2 = count - 1. */ |
34 | 0 | gl_list_node_t node = |
35 | 0 | (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl)); |
36 | 0 | if (node == NULL) |
37 | 0 | return NULL; |
38 | | |
39 | 0 | if (half1 > 0) |
40 | 0 | { |
41 | | /* half1 > 0 implies count > 1, implies bh >= 1, implies |
42 | | 2^(bh-1) - 1 <= half1 <= 2^bh - 1. */ |
43 | 0 | node->left = |
44 | 0 | create_subtree_with_contents (bh - 1, half1, contents); |
45 | 0 | if (node->left == NULL) |
46 | 0 | goto fail1; |
47 | 0 | node->left->parent = node; |
48 | 0 | } |
49 | 0 | else |
50 | 0 | node->left = NULL; |
51 | | |
52 | 0 | node->value = contents[half1]; |
53 | |
|
54 | 0 | if (half2 > 0) |
55 | 0 | { |
56 | | /* half2 > 0 implies count > 1, implies bh >= 1, implies |
57 | | 2^(bh-1) - 1 <= half2 <= 2^bh - 1. */ |
58 | 0 | node->right = |
59 | 0 | create_subtree_with_contents (bh - 1, half2, contents + half1 + 1); |
60 | 0 | if (node->right == NULL) |
61 | 0 | goto fail2; |
62 | 0 | node->right->parent = node; |
63 | 0 | } |
64 | 0 | else |
65 | 0 | node->right = NULL; |
66 | | |
67 | 0 | node->color = (bh == 0 ? RED : BLACK); |
68 | |
|
69 | 0 | node->branch_size = count; |
70 | |
|
71 | 0 | return node; |
72 | | |
73 | 0 | fail2: |
74 | 0 | if (node->left != NULL) |
75 | 0 | free_subtree (node->left); |
76 | 0 | fail1: |
77 | 0 | free (node); |
78 | 0 | return NULL; |
79 | 0 | } |
80 | | |
81 | | static gl_list_t |
82 | | gl_tree_nx_create (gl_list_implementation_t implementation, |
83 | | gl_listelement_equals_fn equals_fn, |
84 | | gl_listelement_hashcode_fn hashcode_fn, |
85 | | gl_listelement_dispose_fn dispose_fn, |
86 | | bool allow_duplicates, |
87 | | size_t count, const void **contents) |
88 | 0 | { |
89 | 0 | struct gl_list_impl *list = |
90 | 0 | (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl)); |
91 | |
|
92 | 0 | if (list == NULL) |
93 | 0 | return NULL; |
94 | | |
95 | 0 | list->base.vtable = implementation; |
96 | 0 | list->base.equals_fn = equals_fn; |
97 | 0 | list->base.hashcode_fn = hashcode_fn; |
98 | 0 | list->base.dispose_fn = dispose_fn; |
99 | 0 | list->base.allow_duplicates = allow_duplicates; |
100 | | #if WITH_HASHTABLE |
101 | | { |
102 | | size_t estimate = xsum (count, count / 2); /* 1.5 * count */ |
103 | | if (estimate < 10) |
104 | | estimate = 10; |
105 | | list->table_size = next_prime (estimate); |
106 | | if (size_overflow_p (xtimes (list->table_size, sizeof (gl_hash_entry_t)))) |
107 | | goto fail1; |
108 | | list->table = |
109 | | (gl_hash_entry_t *) calloc (list->table_size, sizeof (gl_hash_entry_t)); |
110 | | if (list->table == NULL) |
111 | | goto fail1; |
112 | | } |
113 | | #endif |
114 | 0 | if (count > 0) |
115 | 0 | { |
116 | | /* Assuming 2^bh - 1 <= count <= 2^(bh+1) - 2, we create a tree whose |
117 | | upper bh levels are black, and only the partially present lowest |
118 | | level is red. */ |
119 | 0 | unsigned int bh; |
120 | 0 | { |
121 | 0 | size_t n; |
122 | 0 | for (n = count + 1, bh = 0; n > 1; n = n >> 1) |
123 | 0 | bh++; |
124 | 0 | } |
125 | |
|
126 | 0 | list->root = create_subtree_with_contents (bh, count, contents); |
127 | 0 | if (list->root == NULL) |
128 | 0 | goto fail2; |
129 | 0 | list->root->parent = NULL; |
130 | |
|
131 | | #if WITH_HASHTABLE |
132 | | /* Now that the tree is built, node_position() works. Now we can |
133 | | add the nodes to the hash table. */ |
134 | | if (add_nodes_to_buckets (list) < 0) |
135 | | goto fail3; |
136 | | #endif |
137 | 0 | } |
138 | 0 | else |
139 | 0 | list->root = NULL; |
140 | | |
141 | 0 | return list; |
142 | | |
143 | | #if WITH_HASHTABLE |
144 | | fail3: |
145 | | free_subtree (list->root); |
146 | | #endif |
147 | 0 | fail2: |
148 | | #if WITH_HASHTABLE |
149 | | free (list->table); |
150 | | fail1: |
151 | | #endif |
152 | 0 | free (list); |
153 | 0 | return NULL; |
154 | 0 | } |
155 | | |
156 | | /* Rotates left a subtree. |
157 | | |
158 | | B D |
159 | | / \ / \ |
160 | | A D --> B E |
161 | | / \ / \ |
162 | | C E A C |
163 | | |
164 | | Changes the tree structure, updates the branch sizes. |
165 | | The caller must update the colors and register D as child of its parent. */ |
166 | | static gl_list_node_t |
167 | | rotate_left (gl_list_node_t b_node, gl_list_node_t d_node) |
168 | 0 | { |
169 | 0 | gl_list_node_t a_node = b_node->left; |
170 | 0 | gl_list_node_t c_node = d_node->left; |
171 | 0 | gl_list_node_t e_node = d_node->right; |
172 | |
|
173 | 0 | b_node->right = c_node; |
174 | 0 | d_node->left = b_node; |
175 | |
|
176 | 0 | d_node->parent = b_node->parent; |
177 | 0 | b_node->parent = d_node; |
178 | 0 | if (c_node != NULL) |
179 | 0 | c_node->parent = b_node; |
180 | |
|
181 | 0 | b_node->branch_size = |
182 | 0 | (a_node != NULL ? a_node->branch_size : 0) |
183 | 0 | + 1 + (c_node != NULL ? c_node->branch_size : 0); |
184 | 0 | d_node->branch_size = |
185 | 0 | b_node->branch_size + 1 + (e_node != NULL ? e_node->branch_size : 0); |
186 | |
|
187 | 0 | return d_node; |
188 | 0 | } |
189 | | |
190 | | /* Rotates right a subtree. |
191 | | |
192 | | D B |
193 | | / \ / \ |
194 | | B E --> A D |
195 | | / \ / \ |
196 | | A C C E |
197 | | |
198 | | Changes the tree structure, updates the branch sizes. |
199 | | The caller must update the colors and register B as child of its parent. */ |
200 | | static gl_list_node_t |
201 | | rotate_right (gl_list_node_t b_node, gl_list_node_t d_node) |
202 | 0 | { |
203 | 0 | gl_list_node_t a_node = b_node->left; |
204 | 0 | gl_list_node_t c_node = b_node->right; |
205 | 0 | gl_list_node_t e_node = d_node->right; |
206 | |
|
207 | 0 | d_node->left = c_node; |
208 | 0 | b_node->right = d_node; |
209 | |
|
210 | 0 | b_node->parent = d_node->parent; |
211 | 0 | d_node->parent = b_node; |
212 | 0 | if (c_node != NULL) |
213 | 0 | c_node->parent = d_node; |
214 | |
|
215 | 0 | d_node->branch_size = |
216 | 0 | (c_node != NULL ? c_node->branch_size : 0) |
217 | 0 | + 1 + (e_node != NULL ? e_node->branch_size : 0); |
218 | 0 | b_node->branch_size = |
219 | 0 | (a_node != NULL ? a_node->branch_size : 0) + 1 + d_node->branch_size; |
220 | |
|
221 | 0 | return b_node; |
222 | 0 | } |
223 | | |
224 | | /* Ensures the tree is balanced, after an insertion operation. |
225 | | Also assigns node->color. |
226 | | parent is the given node's parent, known to be non-NULL. */ |
227 | | static void |
228 | | rebalance_after_add (gl_list_t list, gl_list_node_t node, gl_list_node_t parent) |
229 | 0 | { |
230 | 0 | for (;;) |
231 | 0 | { |
232 | | /* At this point, parent = node->parent != NULL. |
233 | | Think of node->color being RED (although node->color is not yet |
234 | | assigned.) */ |
235 | |
|
236 | 0 | if (parent->color == BLACK) |
237 | 0 | { |
238 | | /* A RED color for node is acceptable. */ |
239 | 0 | node->color = RED; |
240 | 0 | return; |
241 | 0 | } |
242 | | |
243 | 0 | gl_list_node_t grandparent = parent->parent; |
244 | | /* Since parent is RED, we know that |
245 | | grandparent is != NULL and colored BLACK. */ |
246 | |
|
247 | 0 | gl_list_node_t uncle; |
248 | 0 | if (grandparent->left == parent) |
249 | 0 | uncle = grandparent->right; |
250 | 0 | else if (grandparent->right == parent) |
251 | 0 | uncle = grandparent->left; |
252 | 0 | else |
253 | 0 | abort (); |
254 | | |
255 | 0 | if (uncle != NULL && uncle->color == RED) |
256 | 0 | { |
257 | | /* Change grandparent from BLACK to RED, and |
258 | | change parent and uncle from RED to BLACK. |
259 | | This makes it acceptable for node to be RED. */ |
260 | 0 | node->color = RED; |
261 | 0 | parent->color = uncle->color = BLACK; |
262 | 0 | node = grandparent; |
263 | 0 | } |
264 | 0 | else |
265 | 0 | { |
266 | | /* grandparent and uncle are BLACK. parent is RED. node wants |
267 | | to be RED too. |
268 | | In this case, recoloring is not sufficient. Need to perform |
269 | | one or two rotations. */ |
270 | 0 | gl_list_node_t *grandparentp; |
271 | |
|
272 | 0 | if (grandparent->parent == NULL) |
273 | 0 | grandparentp = &list->root; |
274 | 0 | else if (grandparent->parent->left == grandparent) |
275 | 0 | grandparentp = &grandparent->parent->left; |
276 | 0 | else if (grandparent->parent->right == grandparent) |
277 | 0 | grandparentp = &grandparent->parent->right; |
278 | 0 | else |
279 | 0 | abort (); |
280 | | |
281 | 0 | if (grandparent->left == parent) |
282 | 0 | { |
283 | 0 | if (parent->right == node) |
284 | 0 | { |
285 | | /* Rotation between node and parent. */ |
286 | 0 | grandparent->left = rotate_left (parent, node); |
287 | 0 | node = parent; |
288 | 0 | parent = grandparent->left; |
289 | 0 | } |
290 | | /* grandparent and uncle are BLACK. parent and node want to be |
291 | | RED. parent = grandparent->left. node = parent->left. |
292 | | |
293 | | grandparent parent |
294 | | bh+1 bh+1 |
295 | | / \ / \ |
296 | | parent uncle --> node grandparent |
297 | | bh bh bh bh |
298 | | / \ / \ |
299 | | node C C uncle |
300 | | bh bh bh bh |
301 | | */ |
302 | 0 | *grandparentp = rotate_right (parent, grandparent); |
303 | 0 | parent->color = BLACK; |
304 | 0 | node->color = grandparent->color = RED; |
305 | 0 | } |
306 | 0 | else /* grandparent->right == parent */ |
307 | 0 | { |
308 | 0 | if (parent->left == node) |
309 | 0 | { |
310 | | /* Rotation between node and parent. */ |
311 | 0 | grandparent->right = rotate_right (node, parent); |
312 | 0 | node = parent; |
313 | 0 | parent = grandparent->right; |
314 | 0 | } |
315 | | /* grandparent and uncle are BLACK. parent and node want to be |
316 | | RED. parent = grandparent->right. node = parent->right. |
317 | | |
318 | | grandparent parent |
319 | | bh+1 bh+1 |
320 | | / \ / \ |
321 | | uncle parent --> grandparent node |
322 | | bh bh bh bh |
323 | | / \ / \ |
324 | | C node uncle C |
325 | | bh bh bh bh |
326 | | */ |
327 | 0 | *grandparentp = rotate_left (grandparent, parent); |
328 | 0 | parent->color = BLACK; |
329 | 0 | node->color = grandparent->color = RED; |
330 | 0 | } |
331 | 0 | return; |
332 | 0 | } |
333 | | |
334 | | /* Start again with a new (node, parent) pair. */ |
335 | 0 | parent = node->parent; |
336 | |
|
337 | 0 | if (parent == NULL) |
338 | 0 | { |
339 | | /* Change node's color from RED to BLACK. This increases the |
340 | | tree's black-height. */ |
341 | 0 | node->color = BLACK; |
342 | 0 | return; |
343 | 0 | } |
344 | 0 | } |
345 | 0 | } |
346 | | |
347 | | /* Ensures the tree is balanced, after a deletion operation. |
348 | | CHILD was a grandchild of PARENT and is now its child. Between them, |
349 | | a black node was removed. CHILD is also black, or NULL. |
350 | | (CHILD can also be NULL. But PARENT is non-NULL.) */ |
351 | | static void |
352 | | rebalance_after_remove (gl_list_t list, gl_list_node_t child, gl_list_node_t parent) |
353 | 0 | { |
354 | 0 | for (;;) |
355 | 0 | { |
356 | | /* At this point, we reduced the black-height of the CHILD subtree by 1. |
357 | | To make up, either look for a possibility to turn a RED to a BLACK |
358 | | node, or try to reduce the black-height tree of CHILD's sibling |
359 | | subtree as well. */ |
360 | 0 | gl_list_node_t *parentp; |
361 | |
|
362 | 0 | if (parent->parent == NULL) |
363 | 0 | parentp = &list->root; |
364 | 0 | else if (parent->parent->left == parent) |
365 | 0 | parentp = &parent->parent->left; |
366 | 0 | else if (parent->parent->right == parent) |
367 | 0 | parentp = &parent->parent->right; |
368 | 0 | else |
369 | 0 | abort (); |
370 | | |
371 | 0 | if (parent->left == child) |
372 | 0 | { |
373 | 0 | gl_list_node_t sibling = parent->right; |
374 | | /* sibling's black-height is >= 1. In particular, |
375 | | sibling != NULL. |
376 | | |
377 | | parent |
378 | | / \ |
379 | | child sibling |
380 | | bh bh+1 |
381 | | */ |
382 | |
|
383 | 0 | if (sibling->color == RED) |
384 | 0 | { |
385 | | /* sibling is RED, hence parent is BLACK and sibling's children |
386 | | are non-NULL and BLACK. |
387 | | |
388 | | parent sibling |
389 | | bh+2 bh+2 |
390 | | / \ / \ |
391 | | child sibling --> parent SR |
392 | | bh bh+1 bh+1 bh+1 |
393 | | / \ / \ |
394 | | SL SR child SL |
395 | | bh+1 bh+1 bh bh+1 |
396 | | */ |
397 | 0 | *parentp = rotate_left (parent, sibling); |
398 | 0 | parent->color = RED; |
399 | 0 | sibling->color = BLACK; |
400 | | |
401 | | /* Concentrate on the subtree of parent. The new sibling is |
402 | | one of the old sibling's children, and known to be BLACK. */ |
403 | 0 | parentp = &sibling->left; |
404 | 0 | sibling = parent->right; |
405 | 0 | } |
406 | | /* Now we know that sibling is BLACK. |
407 | | |
408 | | parent |
409 | | / \ |
410 | | child sibling |
411 | | bh bh+1 |
412 | | */ |
413 | 0 | if (sibling->right != NULL && sibling->right->color == RED) |
414 | 0 | { |
415 | | /* |
416 | | parent sibling |
417 | | bh+1|bh+2 bh+1|bh+2 |
418 | | / \ / \ |
419 | | child sibling --> parent SR |
420 | | bh bh+1 bh+1 bh+1 |
421 | | / \ / \ |
422 | | SL SR child SL |
423 | | bh bh bh bh |
424 | | */ |
425 | 0 | *parentp = rotate_left (parent, sibling); |
426 | 0 | sibling->color = parent->color; |
427 | 0 | parent->color = BLACK; |
428 | 0 | sibling->right->color = BLACK; |
429 | 0 | return; |
430 | 0 | } |
431 | 0 | else if (sibling->left != NULL && sibling->left->color == RED) |
432 | 0 | { |
433 | | /* |
434 | | parent parent |
435 | | bh+1|bh+2 bh+1|bh+2 |
436 | | / \ / \ |
437 | | child sibling --> child SL |
438 | | bh bh+1 bh bh+1 |
439 | | / \ / \ |
440 | | SL SR SLL sibling |
441 | | bh bh bh bh |
442 | | / \ / \ |
443 | | SLL SLR SLR SR |
444 | | bh bh bh bh |
445 | | |
446 | | where SLL, SLR, SR are all black. |
447 | | */ |
448 | 0 | parent->right = rotate_right (sibling->left, sibling); |
449 | | /* Change sibling from BLACK to RED and SL from RED to BLACK. */ |
450 | 0 | sibling->color = RED; |
451 | 0 | sibling = parent->right; |
452 | 0 | sibling->color = BLACK; |
453 | | |
454 | | /* Now do as in the previous case. */ |
455 | 0 | *parentp = rotate_left (parent, sibling); |
456 | 0 | sibling->color = parent->color; |
457 | 0 | parent->color = BLACK; |
458 | 0 | sibling->right->color = BLACK; |
459 | 0 | return; |
460 | 0 | } |
461 | 0 | else |
462 | 0 | { |
463 | 0 | if (parent->color == BLACK) |
464 | 0 | { |
465 | | /* Change sibling from BLACK to RED. Then the entire |
466 | | subtree at parent has decreased its black-height. |
467 | | parent parent |
468 | | bh+2 bh+1 |
469 | | / \ / \ |
470 | | child sibling --> child sibling |
471 | | bh bh+1 bh bh |
472 | | */ |
473 | 0 | sibling->color = RED; |
474 | |
|
475 | 0 | child = parent; |
476 | 0 | } |
477 | 0 | else |
478 | 0 | { |
479 | | /* Change parent from RED to BLACK, but compensate by |
480 | | changing sibling from BLACK to RED. |
481 | | parent parent |
482 | | bh+1 bh+1 |
483 | | / \ / \ |
484 | | child sibling --> child sibling |
485 | | bh bh+1 bh bh |
486 | | */ |
487 | 0 | parent->color = BLACK; |
488 | 0 | sibling->color = RED; |
489 | 0 | return; |
490 | 0 | } |
491 | 0 | } |
492 | 0 | } |
493 | 0 | else if (parent->right == child) |
494 | 0 | { |
495 | 0 | gl_list_node_t sibling = parent->left; |
496 | | /* sibling's black-height is >= 1. In particular, |
497 | | sibling != NULL. |
498 | | |
499 | | parent |
500 | | / \ |
501 | | sibling child |
502 | | bh+1 bh |
503 | | */ |
504 | |
|
505 | 0 | if (sibling->color == RED) |
506 | 0 | { |
507 | | /* sibling is RED, hence parent is BLACK and sibling's children |
508 | | are non-NULL and BLACK. |
509 | | |
510 | | parent sibling |
511 | | bh+2 bh+2 |
512 | | / \ / \ |
513 | | sibling child --> SR parent |
514 | | bh+1 ch bh+1 bh+1 |
515 | | / \ / \ |
516 | | SL SR SL child |
517 | | bh+1 bh+1 bh+1 bh |
518 | | */ |
519 | 0 | *parentp = rotate_right (sibling, parent); |
520 | 0 | parent->color = RED; |
521 | 0 | sibling->color = BLACK; |
522 | | |
523 | | /* Concentrate on the subtree of parent. The new sibling is |
524 | | one of the old sibling's children, and known to be BLACK. */ |
525 | 0 | parentp = &sibling->right; |
526 | 0 | sibling = parent->left; |
527 | 0 | } |
528 | | /* Now we know that sibling is BLACK. |
529 | | |
530 | | parent |
531 | | / \ |
532 | | sibling child |
533 | | bh+1 bh |
534 | | */ |
535 | 0 | if (sibling->left != NULL && sibling->left->color == RED) |
536 | 0 | { |
537 | | /* |
538 | | parent sibling |
539 | | bh+1|bh+2 bh+1|bh+2 |
540 | | / \ / \ |
541 | | sibling child --> SL parent |
542 | | bh+1 bh bh+1 bh+1 |
543 | | / \ / \ |
544 | | SL SR SR child |
545 | | bh bh bh bh |
546 | | */ |
547 | 0 | *parentp = rotate_right (sibling, parent); |
548 | 0 | sibling->color = parent->color; |
549 | 0 | parent->color = BLACK; |
550 | 0 | sibling->left->color = BLACK; |
551 | 0 | return; |
552 | 0 | } |
553 | 0 | else if (sibling->right != NULL && sibling->right->color == RED) |
554 | 0 | { |
555 | | /* |
556 | | parent parent |
557 | | bh+1|bh+2 bh+1|bh+2 |
558 | | / \ / \ |
559 | | sibling child --> SR child |
560 | | bh+1 bh bh+1 bh |
561 | | / \ / \ |
562 | | SL SR sibling SRR |
563 | | bh bh bh bh |
564 | | / \ / \ |
565 | | SRL SRR SL SRL |
566 | | bh bh bh bh |
567 | | |
568 | | where SL, SRL, SRR are all black. |
569 | | */ |
570 | 0 | parent->left = rotate_left (sibling, sibling->right); |
571 | | /* Change sibling from BLACK to RED and SL from RED to BLACK. */ |
572 | 0 | sibling->color = RED; |
573 | 0 | sibling = parent->left; |
574 | 0 | sibling->color = BLACK; |
575 | | |
576 | | /* Now do as in the previous case. */ |
577 | 0 | *parentp = rotate_right (sibling, parent); |
578 | 0 | sibling->color = parent->color; |
579 | 0 | parent->color = BLACK; |
580 | 0 | sibling->left->color = BLACK; |
581 | 0 | return; |
582 | 0 | } |
583 | 0 | else |
584 | 0 | { |
585 | 0 | if (parent->color == BLACK) |
586 | 0 | { |
587 | | /* Change sibling from BLACK to RED. Then the entire |
588 | | subtree at parent has decreased its black-height. |
589 | | parent parent |
590 | | bh+2 bh+1 |
591 | | / \ / \ |
592 | | sibling child --> sibling child |
593 | | bh+1 bh bh bh |
594 | | */ |
595 | 0 | sibling->color = RED; |
596 | |
|
597 | 0 | child = parent; |
598 | 0 | } |
599 | 0 | else |
600 | 0 | { |
601 | | /* Change parent from RED to BLACK, but compensate by |
602 | | changing sibling from BLACK to RED. |
603 | | parent parent |
604 | | bh+1 bh+1 |
605 | | / \ / \ |
606 | | sibling child --> sibling child |
607 | | bh+1 bh bh bh |
608 | | */ |
609 | 0 | parent->color = BLACK; |
610 | 0 | sibling->color = RED; |
611 | 0 | return; |
612 | 0 | } |
613 | 0 | } |
614 | 0 | } |
615 | 0 | else |
616 | 0 | abort (); |
617 | | |
618 | | /* Start again with a new (child, parent) pair. */ |
619 | 0 | parent = child->parent; |
620 | |
|
621 | | #if 0 /* Already handled. */ |
622 | | if (child != NULL && child->color == RED) |
623 | | { |
624 | | child->color = BLACK; |
625 | | return; |
626 | | } |
627 | | #endif |
628 | |
|
629 | 0 | if (parent == NULL) |
630 | 0 | return; |
631 | 0 | } |
632 | 0 | } |
633 | | |
634 | | static void |
635 | | gl_tree_remove_node_from_tree (gl_list_t list, gl_list_node_t node) |
636 | 0 | { |
637 | 0 | gl_list_node_t parent = node->parent; |
638 | |
|
639 | 0 | if (node->left == NULL) |
640 | 0 | { |
641 | | /* Replace node with node->right. */ |
642 | 0 | gl_list_node_t child = node->right; |
643 | |
|
644 | 0 | if (child != NULL) |
645 | 0 | { |
646 | 0 | child->parent = parent; |
647 | | /* Since node->left == NULL, child must be RED and of height 1, |
648 | | hence node must have been BLACK. Recolor the child. */ |
649 | 0 | child->color = BLACK; |
650 | 0 | } |
651 | 0 | if (parent == NULL) |
652 | 0 | list->root = child; |
653 | 0 | else |
654 | 0 | { |
655 | 0 | if (parent->left == node) |
656 | 0 | parent->left = child; |
657 | 0 | else /* parent->right == node */ |
658 | 0 | parent->right = child; |
659 | | |
660 | | /* Update branch_size fields of the parent nodes. */ |
661 | 0 | for (gl_list_node_t p = parent; p != NULL; p = p->parent) |
662 | 0 | p->branch_size--; |
663 | |
|
664 | 0 | if (child == NULL && node->color == BLACK) |
665 | 0 | rebalance_after_remove (list, child, parent); |
666 | 0 | } |
667 | 0 | } |
668 | 0 | else if (node->right == NULL) |
669 | 0 | { |
670 | | /* It is not absolutely necessary to treat this case. But the more |
671 | | general case below is more complicated, hence slower. */ |
672 | | /* Replace node with node->left. */ |
673 | 0 | gl_list_node_t child = node->left; |
674 | |
|
675 | 0 | child->parent = parent; |
676 | | /* Since node->right == NULL, child must be RED and of height 1, |
677 | | hence node must have been BLACK. Recolor the child. */ |
678 | 0 | child->color = BLACK; |
679 | 0 | if (parent == NULL) |
680 | 0 | list->root = child; |
681 | 0 | else |
682 | 0 | { |
683 | 0 | if (parent->left == node) |
684 | 0 | parent->left = child; |
685 | 0 | else /* parent->right == node */ |
686 | 0 | parent->right = child; |
687 | | |
688 | | /* Update branch_size fields of the parent nodes. */ |
689 | 0 | for (gl_list_node_t p = parent; p != NULL; p = p->parent) |
690 | 0 | p->branch_size--; |
691 | 0 | } |
692 | 0 | } |
693 | 0 | else |
694 | 0 | { |
695 | | /* Replace node with the rightmost element of the node->left subtree. */ |
696 | |
|
697 | 0 | gl_list_node_t subst; |
698 | 0 | for (subst = node->left; subst->right != NULL; ) |
699 | 0 | subst = subst->right; |
700 | |
|
701 | 0 | gl_list_node_t subst_parent = subst->parent; |
702 | |
|
703 | 0 | gl_list_node_t child = subst->left; |
704 | |
|
705 | 0 | color_t removed_color = subst->color; |
706 | | |
707 | | /* The case subst_parent == node is special: If we do nothing special, |
708 | | we get confusion about node->left, subst->left and child->parent. |
709 | | subst_parent == node |
710 | | <==> The 'for' loop above terminated immediately. |
711 | | <==> subst == subst_parent->left |
712 | | [otherwise subst == subst_parent->right] |
713 | | In this case, we would need to first set |
714 | | child->parent = node; node->left = child; |
715 | | and later - when we copy subst into node's position - again |
716 | | child->parent = subst; subst->left = child; |
717 | | Altogether a no-op. */ |
718 | 0 | if (subst_parent != node) |
719 | 0 | { |
720 | 0 | if (child != NULL) |
721 | 0 | child->parent = subst_parent; |
722 | 0 | subst_parent->right = child; |
723 | 0 | } |
724 | | |
725 | | /* Update branch_size fields of the parent nodes. */ |
726 | 0 | for (gl_list_node_t p = subst_parent; p != NULL; p = p->parent) |
727 | 0 | p->branch_size--; |
728 | | |
729 | | /* Copy subst into node's position. |
730 | | (This is safer than to copy subst's value into node, keep node in |
731 | | place, and free subst.) */ |
732 | 0 | if (subst_parent != node) |
733 | 0 | { |
734 | 0 | subst->left = node->left; |
735 | 0 | subst->left->parent = subst; |
736 | 0 | } |
737 | 0 | subst->right = node->right; |
738 | 0 | subst->right->parent = subst; |
739 | 0 | subst->color = node->color; |
740 | 0 | subst->branch_size = node->branch_size; |
741 | 0 | subst->parent = parent; |
742 | 0 | if (parent == NULL) |
743 | 0 | list->root = subst; |
744 | 0 | else if (parent->left == node) |
745 | 0 | parent->left = subst; |
746 | 0 | else /* parent->right == node */ |
747 | 0 | parent->right = subst; |
748 | |
|
749 | 0 | if (removed_color == BLACK) |
750 | 0 | { |
751 | 0 | if (child != NULL && child->color == RED) |
752 | | /* Recolor the child. */ |
753 | 0 | child->color = BLACK; |
754 | 0 | else |
755 | | /* Rebalancing starts at child's parent, that is subst_parent - |
756 | | except when subst_parent == node. In this case, we need to use |
757 | | its replacement, subst. */ |
758 | 0 | rebalance_after_remove (list, child, |
759 | 0 | subst_parent != node ? subst_parent : subst); |
760 | 0 | } |
761 | 0 | } |
762 | 0 | } |
763 | | |
764 | | static gl_list_node_t |
765 | | gl_tree_nx_add_first (gl_list_t list, const void *elt) |
766 | 0 | { |
767 | | /* Create new node. */ |
768 | 0 | gl_list_node_t new_node = |
769 | 0 | (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl)); |
770 | |
|
771 | 0 | if (new_node == NULL) |
772 | 0 | return NULL; |
773 | | |
774 | 0 | new_node->left = NULL; |
775 | 0 | new_node->right = NULL; |
776 | 0 | new_node->branch_size = 1; |
777 | 0 | new_node->value = elt; |
778 | | #if WITH_HASHTABLE |
779 | | new_node->h.hashcode = |
780 | | (list->base.hashcode_fn != NULL |
781 | | ? list->base.hashcode_fn (new_node->value) |
782 | | : (size_t)(uintptr_t) new_node->value); |
783 | | #endif |
784 | | |
785 | | /* Add it to the tree. */ |
786 | 0 | if (list->root == NULL) |
787 | 0 | { |
788 | 0 | new_node->color = BLACK; |
789 | 0 | list->root = new_node; |
790 | 0 | new_node->parent = NULL; |
791 | 0 | } |
792 | 0 | else |
793 | 0 | { |
794 | 0 | gl_list_node_t node; |
795 | 0 | for (node = list->root; node->left != NULL; ) |
796 | 0 | node = node->left; |
797 | |
|
798 | 0 | node->left = new_node; |
799 | 0 | new_node->parent = node; |
800 | | |
801 | | /* Update branch_size fields of the parent nodes. */ |
802 | 0 | for (gl_list_node_t p = node; p != NULL; p = p->parent) |
803 | 0 | p->branch_size++; |
804 | | |
805 | | /* Color and rebalance. */ |
806 | 0 | rebalance_after_add (list, new_node, node); |
807 | 0 | } |
808 | |
|
809 | | #if WITH_HASHTABLE |
810 | | /* Add node to the hash table. |
811 | | Note that this is only possible _after_ the node has been added to the |
812 | | tree structure, because add_to_bucket() uses node_position(). */ |
813 | | if (add_to_bucket (list, new_node) < 0) |
814 | | { |
815 | | gl_tree_remove_node_from_tree (list, new_node); |
816 | | free (new_node); |
817 | | return NULL; |
818 | | } |
819 | | hash_resize_after_add (list); |
820 | | #endif |
821 | |
|
822 | 0 | return new_node; |
823 | 0 | } |
824 | | |
825 | | static gl_list_node_t |
826 | | gl_tree_nx_add_last (gl_list_t list, const void *elt) |
827 | 0 | { |
828 | | /* Create new node. */ |
829 | 0 | gl_list_node_t new_node = |
830 | 0 | (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl)); |
831 | |
|
832 | 0 | if (new_node == NULL) |
833 | 0 | return NULL; |
834 | | |
835 | 0 | new_node->left = NULL; |
836 | 0 | new_node->right = NULL; |
837 | 0 | new_node->branch_size = 1; |
838 | 0 | new_node->value = elt; |
839 | | #if WITH_HASHTABLE |
840 | | new_node->h.hashcode = |
841 | | (list->base.hashcode_fn != NULL |
842 | | ? list->base.hashcode_fn (new_node->value) |
843 | | : (size_t)(uintptr_t) new_node->value); |
844 | | #endif |
845 | | |
846 | | /* Add it to the tree. */ |
847 | 0 | if (list->root == NULL) |
848 | 0 | { |
849 | 0 | new_node->color = BLACK; |
850 | 0 | list->root = new_node; |
851 | 0 | new_node->parent = NULL; |
852 | 0 | } |
853 | 0 | else |
854 | 0 | { |
855 | 0 | gl_list_node_t node; |
856 | 0 | for (node = list->root; node->right != NULL; ) |
857 | 0 | node = node->right; |
858 | |
|
859 | 0 | node->right = new_node; |
860 | 0 | new_node->parent = node; |
861 | | |
862 | | /* Update branch_size fields of the parent nodes. */ |
863 | 0 | for (gl_list_node_t p = node; p != NULL; p = p->parent) |
864 | 0 | p->branch_size++; |
865 | | |
866 | | /* Color and rebalance. */ |
867 | 0 | rebalance_after_add (list, new_node, node); |
868 | 0 | } |
869 | |
|
870 | | #if WITH_HASHTABLE |
871 | | /* Add node to the hash table. |
872 | | Note that this is only possible _after_ the node has been added to the |
873 | | tree structure, because add_to_bucket() uses node_position(). */ |
874 | | if (add_to_bucket (list, new_node) < 0) |
875 | | { |
876 | | gl_tree_remove_node_from_tree (list, new_node); |
877 | | free (new_node); |
878 | | return NULL; |
879 | | } |
880 | | hash_resize_after_add (list); |
881 | | #endif |
882 | |
|
883 | 0 | return new_node; |
884 | 0 | } |
885 | | |
886 | | static gl_list_node_t |
887 | | gl_tree_nx_add_before (gl_list_t list, gl_list_node_t node, const void *elt) |
888 | 0 | { |
889 | | /* Create new node. */ |
890 | 0 | gl_list_node_t new_node = |
891 | 0 | (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl)); |
892 | |
|
893 | 0 | if (new_node == NULL) |
894 | 0 | return NULL; |
895 | | |
896 | 0 | new_node->left = NULL; |
897 | 0 | new_node->right = NULL; |
898 | 0 | new_node->branch_size = 1; |
899 | 0 | new_node->value = elt; |
900 | | #if WITH_HASHTABLE |
901 | | new_node->h.hashcode = |
902 | | (list->base.hashcode_fn != NULL |
903 | | ? list->base.hashcode_fn (new_node->value) |
904 | | : (size_t)(uintptr_t) new_node->value); |
905 | | #endif |
906 | | |
907 | | /* Add it to the tree. */ |
908 | 0 | if (node->left == NULL) |
909 | 0 | node->left = new_node; |
910 | 0 | else |
911 | 0 | { |
912 | 0 | for (node = node->left; node->right != NULL; ) |
913 | 0 | node = node->right; |
914 | 0 | node->right = new_node; |
915 | 0 | } |
916 | 0 | new_node->parent = node; |
917 | | |
918 | | /* Update branch_size fields of the parent nodes. */ |
919 | 0 | for (gl_list_node_t p = node; p != NULL; p = p->parent) |
920 | 0 | p->branch_size++; |
921 | | |
922 | | /* Color and rebalance. */ |
923 | 0 | rebalance_after_add (list, new_node, node); |
924 | |
|
925 | | #if WITH_HASHTABLE |
926 | | /* Add node to the hash table. |
927 | | Note that this is only possible _after_ the node has been added to the |
928 | | tree structure, because add_to_bucket() uses node_position(). */ |
929 | | if (add_to_bucket (list, new_node) < 0) |
930 | | { |
931 | | gl_tree_remove_node_from_tree (list, new_node); |
932 | | free (new_node); |
933 | | return NULL; |
934 | | } |
935 | | hash_resize_after_add (list); |
936 | | #endif |
937 | |
|
938 | 0 | return new_node; |
939 | 0 | } |
940 | | |
941 | | static gl_list_node_t |
942 | | gl_tree_nx_add_after (gl_list_t list, gl_list_node_t node, const void *elt) |
943 | 0 | { |
944 | | /* Create new node. */ |
945 | 0 | gl_list_node_t new_node = |
946 | 0 | (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl)); |
947 | |
|
948 | 0 | if (new_node == NULL) |
949 | 0 | return NULL; |
950 | | |
951 | 0 | new_node->left = NULL; |
952 | 0 | new_node->right = NULL; |
953 | 0 | new_node->branch_size = 1; |
954 | 0 | new_node->value = elt; |
955 | | #if WITH_HASHTABLE |
956 | | new_node->h.hashcode = |
957 | | (list->base.hashcode_fn != NULL |
958 | | ? list->base.hashcode_fn (new_node->value) |
959 | | : (size_t)(uintptr_t) new_node->value); |
960 | | #endif |
961 | | |
962 | | /* Add it to the tree. */ |
963 | 0 | if (node->right == NULL) |
964 | 0 | node->right = new_node; |
965 | 0 | else |
966 | 0 | { |
967 | 0 | for (node = node->right; node->left != NULL; ) |
968 | 0 | node = node->left; |
969 | 0 | node->left = new_node; |
970 | 0 | } |
971 | 0 | new_node->parent = node; |
972 | | |
973 | | /* Update branch_size fields of the parent nodes. */ |
974 | 0 | for (gl_list_node_t p = node; p != NULL; p = p->parent) |
975 | 0 | p->branch_size++; |
976 | | |
977 | | /* Color and rebalance. */ |
978 | 0 | rebalance_after_add (list, new_node, node); |
979 | |
|
980 | | #if WITH_HASHTABLE |
981 | | /* Add node to the hash table. |
982 | | Note that this is only possible _after_ the node has been added to the |
983 | | tree structure, because add_to_bucket() uses node_position(). */ |
984 | | if (add_to_bucket (list, new_node) < 0) |
985 | | { |
986 | | gl_tree_remove_node_from_tree (list, new_node); |
987 | | free (new_node); |
988 | | return NULL; |
989 | | } |
990 | | hash_resize_after_add (list); |
991 | | #endif |
992 | |
|
993 | 0 | return new_node; |
994 | 0 | } |