Blender  V2.93
DLRB_tree.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include "BLI_dlrbTree.h"
27 #include "BLI_listbase.h"
28 
29 /* *********************************************** */
30 /* Tree API */
31 
32 /* Create a new tree, and initialize as necessary */
34 {
35  /* just allocate for now */
36  return MEM_callocN(sizeof(DLRBT_Tree), "DLRBT_Tree");
37 }
38 
39 /* Just zero out the pointers used */
41 {
42  if (tree == NULL) {
43  return;
44  }
45 
46  tree->first = tree->last = tree->root = NULL;
47 }
48 
49 /* Helper for traversing tree and freeing sub-nodes */
51 {
52  /* sanity check */
53  if (node == NULL) {
54  return;
55  }
56 
57  /* free child nodes + subtrees */
60 
61  /* free self */
62  MEM_freeN(node);
63 }
64 
65 /* Free the given tree's data but not the tree itself */
67 {
68  if (tree == NULL) {
69  return;
70  }
71 
72  /* if the list-base stuff is set, just use that (and assume its set),
73  * otherwise, we'll need to traverse the tree...
74  */
75  if (tree->first) {
76  /* free list */
78  }
79  else {
80  /* traverse tree, freeing sub-nodes */
82  }
83 
84  /* clear pointers */
85  tree->first = tree->last = tree->root = NULL;
86 }
87 
88 /* ------- */
89 
90 /* Helper function - used for traversing down the tree from the root to add nodes in order */
92 {
93  /* sanity checks */
94  if ((tree == NULL) || (node == NULL)) {
95  return;
96  }
97 
98  /* add left-node (and its subtree) */
100 
101  /* now add self
102  * - must remove detach from other links first
103  * (for now, only clear own pointers)
104  */
105  node->prev = node->next = NULL;
107 
108  /* finally, add right node (and its subtree) */
110 }
111 
112 /* Make sure the tree's Double-Linked list representation is valid */
114 {
115  /* sanity checks */
116  if (tree == NULL) {
117  return;
118  }
119 
120  /* clear list-base pointers so that the new list can be added properly */
121  tree->first = tree->last = NULL;
122 
123  /* start adding items from the root */
125 }
126 
127 /* *********************************************** */
128 /* Tree Search Utilities */
129 
130 /* Find the node which matches or is the closest to the requested node */
132 {
133  DLRBT_Node *node = (tree) ? tree->root : NULL;
134  short found = 0;
135 
136  /* check that there is a comparator to use */
137  /* TODO: if no comparator is supplied, try using the one supplied with the tree... */
138  if (cmp_cb == NULL) {
139  return NULL;
140  }
141 
142  /* iteratively perform this search */
143  while (node && found == 0) {
144  /* check if traverse further or not
145  * NOTE: it is assumed that the values will be unit values only
146  */
147  switch (cmp_cb(node, search_data)) {
148  case -1: /* data less than node */
149  if (node->left) {
150  node = node->left;
151  }
152  else {
153  found = 1;
154  }
155  break;
156 
157  case 1: /* data greater than node */
158  if (node->right) {
159  node = node->right;
160  }
161  else {
162  found = 1;
163  }
164  break;
165 
166  default: /* data equals node */
167  found = 1;
168  break;
169  }
170  }
171 
172  /* return the nearest matching node */
173  return node;
174 }
175 
176 /* Find the node which exactly matches the required data */
178  DLRBT_Comparator_FP cmp_cb,
179  void *search_data)
180 {
181  DLRBT_Node *node = (tree) ? tree->root : NULL;
182  short found = 0;
183 
184  /* check that there is a comparator to use */
185  /* TODO: if no comparator is supplied, try using the one supplied with the tree... */
186  if (cmp_cb == NULL) {
187  return NULL;
188  }
189 
190  /* iteratively perform this search */
191  while (node && found == 0) {
192  /* check if traverse further or not
193  * NOTE: it is assumed that the values will be unit values only
194  */
195  switch (cmp_cb(node, search_data)) {
196  case -1: /* data less than node */
197  if (node->left) {
198  node = node->left;
199  }
200  else {
201  found = -1;
202  }
203  break;
204 
205  case 1: /* data greater than node */
206  if (node->right) {
207  node = node->right;
208  }
209  else {
210  found = -1;
211  }
212  break;
213 
214  default: /* data equals node */
215  found = 1;
216  break;
217  }
218  }
219 
220  /* return the exactly matching node */
221  return (found == 1) ? (node) : (NULL);
222 }
223 
224 /* Find the node which occurs immediately before the best matching node */
226  DLRBT_Comparator_FP cmp_cb,
227  void *search_data)
228 {
229  DLRBT_Node *node;
230 
231  /* check that there is a comparator to use */
232  /* TODO: if no comparator is supplied, try using the one supplied with the tree... */
233  if (cmp_cb == NULL) {
234  return NULL;
235  }
236 
237  /* get the node which best matches this description */
238  node = BLI_dlrbTree_search(tree, cmp_cb, search_data);
239 
240  if (node) {
241  /* if the item we're searching for is greater than the node found, we've found the match */
242  if (cmp_cb(node, search_data) > 0) {
243  return node;
244  }
245 
246  /* return the previous node otherwise */
247  /* NOTE: what happens if there is no previous node? */
248  return node->prev;
249  }
250 
251  /* nothing matching was found */
252  return NULL;
253 }
254 
255 /* Find the node which occurs immediately after the best matching node */
257  DLRBT_Comparator_FP cmp_cb,
258  void *search_data)
259 {
260  DLRBT_Node *node;
261 
262  /* check that there is a comparator to use */
263  /* TODO: if no comparator is supplied, try using the one supplied with the tree... */
264  if (cmp_cb == NULL) {
265  return NULL;
266  }
267 
268  /* get the node which best matches this description */
269  node = BLI_dlrbTree_search(tree, cmp_cb, search_data);
270 
271  if (node) {
272  /* if the item we're searching for is less than the node found, we've found the match */
273  if (cmp_cb(node, search_data) < 0) {
274  return node;
275  }
276 
277  /* return the previous node otherwise */
278  /* NOTE: what happens if there is no previous node? */
279  return node->next;
280  }
281 
282  /* nothing matching was found */
283  return NULL;
284 }
285 
286 /* Check whether there is a node matching the requested node */
287 short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
288 {
289  /* check if an exact search throws up anything... */
290  return (BLI_dlrbTree_search_exact(tree, cmp_cb, search_data) != NULL);
291 }
292 
293 /* *********************************************** */
294 /* Tree Relationships Utilities */
295 
296 /* get the 'grandparent' - the parent of the parent - of the given node */
298 {
299  if (node && node->parent) {
300  return node->parent->parent;
301  }
302  return NULL;
303 }
304 
305 /* get the sibling node (e.g. if node is left child of parent, return right child of parent) */
307 {
308  if (node && node->parent) {
309  if (node == node->parent->left) {
310  return node->parent->right;
311  }
312  return node->parent->left;
313  }
314 
315  /* sibling not found */
316  return NULL;
317 }
318 
319 /* get the 'uncle' - the sibling of the parent - of the given node */
321 {
322  if (node) {
323  /* return the child of the grandparent which isn't the node's parent */
324  return get_sibling(node->parent);
325  }
326 
327  /* uncle not found */
328  return NULL;
329 }
330 
331 /* *********************************************** */
332 /* Tree Rotation Utilities */
333 
334 /* make right child of 'root' the new root */
335 static void rotate_left(DLRBT_Tree *tree, DLRBT_Node *root)
336 {
337  DLRBT_Node **root_slot, *pivot;
338 
339  /* pivot is simply the root's right child, to become the root's parent */
340  pivot = root->right;
341  if (pivot == NULL) {
342  return;
343  }
344 
345  if (root->parent) {
346  if (root == root->parent->left) {
347  root_slot = &root->parent->left;
348  }
349  else {
350  root_slot = &root->parent->right;
351  }
352  }
353  else {
354  root_slot = ((DLRBT_Node **)&tree->root); /* &((DLRBT_Node *)tree->root); */
355  }
356 
357  /* - pivot's left child becomes root's right child
358  * - root now becomes pivot's left child
359  */
360  root->right = pivot->left;
361  if (pivot->left) {
362  pivot->left->parent = root;
363  }
364 
365  pivot->left = root;
366  pivot->parent = root->parent;
367  root->parent = pivot;
368 
369  /* make the pivot the new root */
370  if (root_slot) {
371  *root_slot = pivot;
372  }
373 }
374 
375 /* make the left child of the 'root' the new root */
377 {
378  DLRBT_Node **root_slot, *pivot;
379 
380  /* pivot is simply the root's left child, to become the root's parent */
381  pivot = root->left;
382  if (pivot == NULL) {
383  return;
384  }
385 
386  if (root->parent) {
387  if (root == root->parent->left) {
388  root_slot = &root->parent->left;
389  }
390  else {
391  root_slot = &root->parent->right;
392  }
393  }
394  else {
395  root_slot = ((DLRBT_Node **)&tree->root); /* &((DLRBT_Node *)tree->root); */
396  }
397 
398  /* - pivot's right child becomes root's left child
399  * - root now becomes pivot's right child
400  */
401  root->left = pivot->right;
402  if (pivot->right) {
403  pivot->right->parent = root;
404  }
405 
406  pivot->right = root;
407  pivot->parent = root->parent;
408  root->parent = pivot;
409 
410  /* make the pivot the new root */
411  if (root_slot) {
412  *root_slot = pivot;
413  }
414 }
415 
416 /* *********************************************** */
417 /* Post-Insertion Balancing */
418 
419 /* forward defines for insertion checks */
423 
424 /* ----- */
425 
426 /* W. 1) Root must be black (so that the 2nd-generation can have a black parent) */
428 {
429  if (node) {
430  /* if this is the root, just ensure that it is black */
431  if (node->parent == NULL) {
432  node->tree_col = DLRBT_BLACK;
433  }
434  else {
436  }
437  }
438 }
439 
440 /* W. 2+3) Parent of node must be black, otherwise recolor and flush */
442 {
443  /* if the parent is not black, we need to change that... */
444  if (node && node->parent && node->parent->tree_col) {
445  DLRBT_Node *unc = get_uncle(node);
446 
447  /* if uncle and parent are both red, need to change them to black and make
448  * the parent black in order to satisfy the criteria of each node having the
449  * same number of black nodes to its leaves
450  */
451  if (unc && unc->tree_col) {
453 
454  /* make the n-1 generation nodes black */
455  node->parent->tree_col = unc->tree_col = DLRBT_BLACK;
456 
457  /* - make the grandparent red, so that we maintain alternating red/black property
458  * (it must exist, so no need to check for NULL here),
459  * - as the grandparent may now cause inconsistencies with the rest of the tree,
460  * we must flush up the tree and perform checks/re-balancing/re-painting, using the
461  * grandparent as the node of interest
462  */
463  gp->tree_col = DLRBT_RED;
464  insert_check_1(tree, gp);
465  }
466  else {
467  /* we've got an unbalanced branch going down the grandparent to the parent,
468  * so need to perform some rotations to re-balance the tree
469  */
471  }
472  }
473 }
474 
475 /* W. 4+5) Perform rotation on sub-tree containing the 'new' node, then do any */
477 {
479 
480  /* check that grandparent and node->parent exist
481  * (jut in case... really shouldn't happen on a good tree) */
482  if (node && node->parent && gp) {
483  /* a left rotation will switch the roles of node and its parent, assuming that
484  * the parent is the left child of the grandparent... otherwise, rotation direction
485  * should be swapped
486  */
487  if ((node == node->parent->right) && (node->parent == gp->left)) {
489  node = node->left;
490  }
491  else if ((node == node->parent->left) && (node->parent == gp->right)) {
493  node = node->right;
494  }
495 
496  /* fix old parent's color-tagging, and perform rotation on the old parent in the
497  * opposite direction if needed for the current situation
498  * NOTE: in the code above, node pointer is changed to point to the old parent
499  */
500  if (node) {
501  /* get 'new' grandparent (i.e. grandparent for old-parent (node)) */
502  gp = get_grandparent(node);
503 
504  /* modify the coloring of the grandparent and parent
505  * so that they still satisfy the constraints */
506  node->parent->tree_col = DLRBT_BLACK;
507  gp->tree_col = DLRBT_RED;
508 
509  /* if there are several nodes that all form a left chain, do a right rotation to correct
510  * this (or a rotation in the opposite direction if they all form a right chain) */
511  if ((node == node->parent->left) && (node->parent == gp->left)) {
512  rotate_right(tree, gp);
513  }
514  else { // if ((node == node->parent->right) && (node->parent == gp->right))
515  rotate_left(tree, gp);
516  }
517  }
518  }
519 }
520 
521 /* ----- */
522 
523 /* Balance the tree after the given element has been added to it
524  * (using custom code, in the Binary Tree way).
525  */
527 {
528  /* sanity checks */
529  if ((tree == NULL) || (node == NULL)) {
530  return;
531  }
532 
533  /* firstly, the node we just added should be red by default */
534  node->tree_col = DLRBT_RED;
535 
536  /* start from case 1, an trek through the tail-recursive insertion checks */
538 }
539 
540 /* ----- */
541 
542 /* Add the given data to the tree, and return the node added */
543 /* NOTE: for duplicates, the update_cb is called (if available),
544  * and the existing node is returned */
546  DLRBT_Comparator_FP cmp_cb,
547  DLRBT_NAlloc_FP new_cb,
549  void *data)
550 {
551  DLRBT_Node *parNode, *node = NULL;
552  short new_node = 0;
553 
554  /* sanity checks */
555  if (tree == NULL) {
556  return NULL;
557  }
558 
559  /* TODO: if no comparator is supplied, try using the one supplied with the tree... */
560  if (cmp_cb == NULL) {
561  return NULL;
562  }
563  /* TODO: if no allocator is supplied, try using the one supplied with the tree... */
564  if (new_cb == NULL) {
565  return NULL;
566  }
567  /* TODO: if no updater is supplied, try using the one supplied with the tree... */
568 
569  /* try to find the nearest node to this one */
570  parNode = BLI_dlrbTree_search(tree, cmp_cb, data);
571 
572  /* add new node to the BST in the 'standard way' as appropriate
573  * NOTE: we do not support duplicates in our tree...
574  */
575  if (parNode) {
576  /* check how this new node compares with the existing ones
577  * NOTE: it is assumed that the values will be unit values only
578  */
579  switch (cmp_cb(parNode, data)) {
580  case -1: /* add new node as left child */
581  {
582  node = new_cb(data);
583  new_node = 1;
584 
585  parNode->left = node;
586  node->parent = parNode;
587  break;
588  }
589  case 1: /* add new node as right child */
590  {
591  node = new_cb(data);
592  new_node = 1;
593 
594  parNode->right = node;
595  node->parent = parNode;
596  break;
597  }
598  default: /* update the duplicate node as appropriate */
599  {
600  if (update_cb) {
601  update_cb(parNode, data);
602  }
603  break;
604  }
605  }
606  }
607  else {
608  /* no nodes in the tree yet... add a new node as the root */
609  node = new_cb(data);
610  new_node = 1;
611 
612  tree->root = node;
613  }
614 
615  /* if a new node was added, it should be tagged as red, and then balanced as appropriate */
616  if (new_node) {
617  /* tag this new node as being 'red' */
618  node->tree_col = DLRBT_RED;
619 
620  /* perform BST balancing steps:
621  * start from case 1, an trek through the tail-recursive insertion checks
622  */
624  }
625 
626  /* return the node added */
627  return node;
628 }
629 
630 /* *********************************************** */
631 /* Remove */
632 
633 /* TODO: this hasn't been coded yet, since this functionality was not needed by the author */
634 
635 /* *********************************************** */
DLRBT_Node *(* DLRBT_NAlloc_FP)(void *data)
Definition: BLI_dlrbTree.h:85
void(* DLRBT_NUpdate_FP)(void *node, void *data)
Definition: BLI_dlrbTree.h:92
short(* DLRBT_Comparator_FP)(void *node, void *data)
Definition: BLI_dlrbTree.h:80
@ DLRBT_BLACK
Definition: BLI_dlrbTree.h:57
@ DLRBT_RED
Definition: BLI_dlrbTree.h:58
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
static void recursive_tree_free_nodes(DLRBT_Node *node)
Definition: DLRB_tree.c:50
void BLI_dlrbTree_init(DLRBT_Tree *tree)
Definition: DLRB_tree.c:40
DLRBT_Tree * BLI_dlrbTree_new(void)
Definition: DLRB_tree.c:33
static void rotate_left(DLRBT_Tree *tree, DLRBT_Node *root)
Definition: DLRB_tree.c:335
DLRBT_Node * BLI_dlrbTree_add(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, DLRBT_NAlloc_FP new_cb, DLRBT_NUpdate_FP update_cb, void *data)
Definition: DLRB_tree.c:545
static void insert_check_1(DLRBT_Tree *tree, DLRBT_Node *node)
Definition: DLRB_tree.c:427
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
Definition: DLRB_tree.c:113
DLRBT_Node * BLI_dlrbTree_search(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
Definition: DLRB_tree.c:131
static void rotate_right(DLRBT_Tree *tree, DLRBT_Node *root)
Definition: DLRB_tree.c:376
static DLRBT_Node * get_uncle(DLRBT_Node *node)
Definition: DLRB_tree.c:320
short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
Definition: DLRB_tree.c:287
void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node)
Definition: DLRB_tree.c:526
static void insert_check_2(DLRBT_Tree *tree, DLRBT_Node *node)
Definition: DLRB_tree.c:441
static void insert_check_3(DLRBT_Tree *tree, DLRBT_Node *node)
Definition: DLRB_tree.c:476
static void linkedlist_sync_add_node(DLRBT_Tree *tree, DLRBT_Node *node)
Definition: DLRB_tree.c:91
DLRBT_Node * BLI_dlrbTree_search_exact(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
Definition: DLRB_tree.c:177
static DLRBT_Node * get_grandparent(DLRBT_Node *node)
Definition: DLRB_tree.c:297
void BLI_dlrbTree_free(DLRBT_Tree *tree)
Definition: DLRB_tree.c:66
DLRBT_Node * BLI_dlrbTree_search_next(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
Definition: DLRB_tree.c:256
static DLRBT_Node * get_sibling(DLRBT_Node *node)
Definition: DLRB_tree.c:306
DLRBT_Node * BLI_dlrbTree_search_prev(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
Definition: DLRB_tree.c:225
Read Guarded memory(de)allocation.
OperationNode * node
void * tree
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static void update_cb(PBVHNode *node, void *rebuild)
Definition: sculpt_undo.c:120
struct DLRBT_Node * parent
Definition: BLI_dlrbTree.h:49
struct DLRBT_Node * left
Definition: BLI_dlrbTree.h:48
struct DLRBT_Node * right
Definition: BLI_dlrbTree.h:48
char tree_col
Definition: BLI_dlrbTree.h:51