| 1 | /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. |
| 2 | Copyright (c) 2010, 2016, MariaDB |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of the GNU General Public License as published by |
| 6 | the Free Software Foundation; version 2 of the License. |
| 7 | |
| 8 | This program is distributed in the hope that it will be useful, |
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | GNU General Public License for more details. |
| 12 | |
| 13 | You should have received a copy of the GNU General Public License |
| 14 | along with this program; if not, write to the Free Software |
| 15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
| 16 | |
| 17 | /* |
| 18 | Code for handling red-black (balanced) binary trees. |
| 19 | key in tree is allocated accrding to following: |
| 20 | |
| 21 | 1) If size < 0 then tree will not allocate keys and only a pointer to |
| 22 | each key is saved in tree. |
| 23 | compare and search functions uses and returns key-pointer |
| 24 | |
| 25 | 2) If size == 0 then there are two options: |
| 26 | - key_size != 0 to tree_insert: The key will be stored in the tree. |
| 27 | - key_size == 0 to tree_insert: A pointer to the key is stored. |
| 28 | compare and search functions uses and returns key-pointer. |
| 29 | |
| 30 | 3) if key_size is given to init_tree then each node will continue the |
| 31 | key and calls to insert_key may increase length of key. |
| 32 | if key_size > sizeof(pointer) and key_size is a multiple of 8 (double |
| 33 | align) then key will be put on a 8 aligned address. Else |
| 34 | the key will be on address (element+1). This is transparent for user |
| 35 | compare and search functions uses a pointer to given key-argument. |
| 36 | |
| 37 | - If you use a free function for tree-elements and you are freeing |
| 38 | the element itself, you should use key_size = 0 to init_tree and |
| 39 | tree_search |
| 40 | |
| 41 | The actual key in TREE_ELEMENT is saved as a pointer or after the |
| 42 | TREE_ELEMENT struct. |
| 43 | If one uses only pointers in tree one can use tree_set_pointer() to |
| 44 | change address of data. |
| 45 | |
| 46 | Implemented by monty. |
| 47 | */ |
| 48 | |
| 49 | /* |
| 50 | NOTE: |
| 51 | tree->compare function should be ALWAYS called as |
| 52 | (*tree->compare)(custom_arg, ELEMENT_KEY(tree,element), key) |
| 53 | and not other way around, as |
| 54 | (*tree->compare)(custom_arg, key, ELEMENT_KEY(tree,element)) |
| 55 | |
| 56 | ft_boolean_search.c (at least) relies on that. |
| 57 | */ |
| 58 | |
| 59 | #include "mysys_priv.h" |
| 60 | #include <m_string.h> |
| 61 | #include <my_tree.h> |
| 62 | #include "my_base.h" |
| 63 | |
| 64 | #define BLACK 1 |
| 65 | #define RED 0 |
| 66 | #define DEFAULT_ALLOC_SIZE 8192 |
| 67 | #define DEFAULT_ALIGN_SIZE 8192 |
| 68 | |
| 69 | static int delete_tree_element(TREE *,TREE_ELEMENT *, my_bool abort); |
| 70 | static int tree_walk_left_root_right(TREE *,TREE_ELEMENT *, |
| 71 | tree_walk_action,void *); |
| 72 | static int tree_walk_right_root_left(TREE *,TREE_ELEMENT *, |
| 73 | tree_walk_action,void *); |
| 74 | static void left_rotate(TREE_ELEMENT **parent,TREE_ELEMENT *leaf); |
| 75 | static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf); |
| 76 | static void rb_insert(TREE *tree,TREE_ELEMENT ***parent, |
| 77 | TREE_ELEMENT *leaf); |
| 78 | static void rb_delete_fixup(TREE *tree,TREE_ELEMENT ***parent); |
| 79 | |
| 80 | |
| 81 | /* The actual code for handling binary trees */ |
| 82 | |
| 83 | #ifndef DBUG_OFF |
| 84 | static int test_rb_tree(TREE_ELEMENT *element); |
| 85 | #endif |
| 86 | |
| 87 | void init_tree(TREE *tree, size_t default_alloc_size, size_t memory_limit, |
| 88 | int size, qsort_cmp2 compare, |
| 89 | tree_element_free free_element, void *custom_arg, |
| 90 | myf my_flags) |
| 91 | { |
| 92 | DBUG_ENTER("init_tree" ); |
| 93 | DBUG_PRINT("enter" ,("tree: %p size: %d" , tree, size)); |
| 94 | |
| 95 | if (default_alloc_size < DEFAULT_ALLOC_SIZE) |
| 96 | default_alloc_size= DEFAULT_ALLOC_SIZE; |
| 97 | default_alloc_size= MY_ALIGN(default_alloc_size, DEFAULT_ALIGN_SIZE); |
| 98 | bzero((uchar*) &tree->null_element,sizeof(tree->null_element)); |
| 99 | tree->root= &tree->null_element; |
| 100 | tree->compare=compare; |
| 101 | tree->size_of_element= size > 0 ? (uint) size : 0; |
| 102 | tree->memory_limit=memory_limit; |
| 103 | tree->free=free_element; |
| 104 | tree->allocated=0; |
| 105 | tree->elements_in_tree=0; |
| 106 | tree->custom_arg = custom_arg; |
| 107 | tree->null_element.colour=BLACK; |
| 108 | tree->null_element.left=tree->null_element.right=0; |
| 109 | tree->my_flags= my_flags; |
| 110 | tree->flag= 0; |
| 111 | if (!free_element && size >= 0 && |
| 112 | ((uint) size <= sizeof(void*) || ((uint) size & (sizeof(void*)-1)))) |
| 113 | { |
| 114 | /* |
| 115 | We know that the data doesn't have to be aligned (like if the key |
| 116 | contains a double), so we can store the data combined with the |
| 117 | TREE_ELEMENT. |
| 118 | */ |
| 119 | tree->offset_to_key=sizeof(TREE_ELEMENT); /* Put key after element */ |
| 120 | /* Fix allocation size so that we don't lose any memory */ |
| 121 | default_alloc_size/=(sizeof(TREE_ELEMENT)+size); |
| 122 | if (!default_alloc_size) |
| 123 | default_alloc_size=1; |
| 124 | default_alloc_size*=(sizeof(TREE_ELEMENT)+size); |
| 125 | } |
| 126 | else |
| 127 | { |
| 128 | tree->offset_to_key=0; /* use key through pointer */ |
| 129 | tree->size_of_element+=sizeof(void*); |
| 130 | } |
| 131 | if (!(tree->with_delete= MY_TEST(my_flags & MY_TREE_WITH_DELETE))) |
| 132 | { |
| 133 | init_alloc_root(&tree->mem_root, "tree" , default_alloc_size, 0, |
| 134 | MYF(my_flags)); |
| 135 | tree->mem_root.min_malloc= sizeof(TREE_ELEMENT)+tree->size_of_element; |
| 136 | } |
| 137 | DBUG_VOID_RETURN; |
| 138 | } |
| 139 | |
| 140 | static int free_tree(TREE *tree, my_bool abort, myf free_flags) |
| 141 | { |
| 142 | int error, first_error= 0; |
| 143 | DBUG_ENTER("free_tree" ); |
| 144 | DBUG_PRINT("enter" ,("tree: %p" , tree)); |
| 145 | |
| 146 | if (tree->root) /* If initialized */ |
| 147 | { |
| 148 | if (tree->with_delete) |
| 149 | { |
| 150 | if ((error= delete_tree_element(tree, tree->root, abort))) |
| 151 | { |
| 152 | first_error= first_error ? first_error : error; |
| 153 | abort= 1; |
| 154 | } |
| 155 | } |
| 156 | else |
| 157 | { |
| 158 | if (tree->free) |
| 159 | { |
| 160 | if (tree->memory_limit) |
| 161 | (*tree->free)(NULL, free_init, tree->custom_arg); |
| 162 | if ((error= delete_tree_element(tree, tree->root, abort))) |
| 163 | first_error= first_error ? first_error : error; |
| 164 | if (tree->memory_limit) |
| 165 | (*tree->free)(NULL, free_end, tree->custom_arg); |
| 166 | } |
| 167 | free_root(&tree->mem_root, free_flags); |
| 168 | } |
| 169 | } |
| 170 | tree->root= &tree->null_element; |
| 171 | tree->elements_in_tree=0; |
| 172 | tree->allocated=0; |
| 173 | |
| 174 | DBUG_RETURN(first_error); |
| 175 | } |
| 176 | |
| 177 | |
| 178 | /** |
| 179 | Delete tree. |
| 180 | |
| 181 | @param tree Tree |
| 182 | @param abort 0 if normal, 1 if tree->free should not be called. |
| 183 | |
| 184 | @return 0 ok |
| 185 | <> 0 Returns first <> 0 from (tree->free)(*,free_free,*) |
| 186 | |
| 187 | @Notes |
| 188 | If one (tree->free)(,free_free,) returns <> 0, no future |
| 189 | tree->free(*,free_free,*) will be called. |
| 190 | Other tree->free operations (free_init, free_end) will be called |
| 191 | */ |
| 192 | |
| 193 | |
| 194 | int delete_tree(TREE* tree, my_bool abort) |
| 195 | { |
| 196 | return free_tree(tree, abort, MYF(0)); /* my_free() mem_root if applicable */ |
| 197 | } |
| 198 | |
| 199 | int reset_tree(TREE* tree) |
| 200 | { |
| 201 | /* do not free mem_root, just mark blocks as free */ |
| 202 | return free_tree(tree, 0, MYF(MY_MARK_BLOCKS_FREE)); |
| 203 | } |
| 204 | |
| 205 | |
| 206 | static int delete_tree_element(TREE *tree, TREE_ELEMENT *element, |
| 207 | my_bool abort) |
| 208 | { |
| 209 | int error, first_error= 0; |
| 210 | if (element != &tree->null_element) |
| 211 | { |
| 212 | if ((first_error= delete_tree_element(tree, element->left, abort))) |
| 213 | abort= 1; |
| 214 | if (!abort && tree->free) |
| 215 | { |
| 216 | if ((error= (*tree->free)(ELEMENT_KEY(tree,element), free_free, |
| 217 | tree->custom_arg))) |
| 218 | { |
| 219 | first_error= first_error ? first_error : error; |
| 220 | abort= 1; |
| 221 | } |
| 222 | } |
| 223 | if ((error= delete_tree_element(tree, element->right, abort))) |
| 224 | first_error= first_error ? first_error : error; |
| 225 | if (tree->with_delete) |
| 226 | my_free(element); |
| 227 | } |
| 228 | return first_error; |
| 229 | } |
| 230 | |
| 231 | |
| 232 | /* |
| 233 | insert, search and delete of elements |
| 234 | |
| 235 | The following should be true: |
| 236 | parent[0] = & parent[-1][0]->left || |
| 237 | parent[0] = & parent[-1][0]->right |
| 238 | */ |
| 239 | |
| 240 | TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size, |
| 241 | void* custom_arg) |
| 242 | { |
| 243 | int cmp; |
| 244 | TREE_ELEMENT *element,***parent; |
| 245 | |
| 246 | parent= tree->parents; |
| 247 | *parent = &tree->root; element= tree->root; |
| 248 | for (;;) |
| 249 | { |
| 250 | if (element == &tree->null_element || |
| 251 | (cmp = (*tree->compare)(custom_arg, ELEMENT_KEY(tree,element), |
| 252 | key)) == 0) |
| 253 | break; |
| 254 | if (cmp < 0) |
| 255 | { |
| 256 | *++parent= &element->right; element= element->right; |
| 257 | } |
| 258 | else |
| 259 | { |
| 260 | *++parent = &element->left; element= element->left; |
| 261 | } |
| 262 | } |
| 263 | if (element == &tree->null_element) |
| 264 | { |
| 265 | uint alloc_size; |
| 266 | if (tree->flag & TREE_ONLY_DUPS) |
| 267 | return((TREE_ELEMENT *) 1); |
| 268 | alloc_size=sizeof(TREE_ELEMENT)+key_size+tree->size_of_element; |
| 269 | tree->allocated+=alloc_size; |
| 270 | |
| 271 | if (tree->memory_limit && tree->elements_in_tree |
| 272 | && tree->allocated > tree->memory_limit) |
| 273 | { |
| 274 | reset_tree(tree); |
| 275 | return tree_insert(tree, key, key_size, custom_arg); |
| 276 | } |
| 277 | |
| 278 | key_size+=tree->size_of_element; |
| 279 | if (tree->with_delete) |
| 280 | element=(TREE_ELEMENT *) my_malloc(alloc_size, |
| 281 | MYF(tree->my_flags | MY_WME)); |
| 282 | else |
| 283 | element=(TREE_ELEMENT *) alloc_root(&tree->mem_root,alloc_size); |
| 284 | if (!element) |
| 285 | return(NULL); |
| 286 | **parent=element; |
| 287 | element->left=element->right= &tree->null_element; |
| 288 | if (!tree->offset_to_key) |
| 289 | { |
| 290 | if (key_size == sizeof(void*)) /* no length, save pointer */ |
| 291 | *((void**) (element+1))=key; |
| 292 | else |
| 293 | { |
| 294 | *((void**) (element+1))= (void*) ((void **) (element+1)+1); |
| 295 | memcpy((uchar*) *((void **) (element+1)),key, |
| 296 | (size_t) (key_size-sizeof(void*))); |
| 297 | } |
| 298 | } |
| 299 | else |
| 300 | memcpy((uchar*) element+tree->offset_to_key,key,(size_t) key_size); |
| 301 | element->count=1; /* May give warning in purify */ |
| 302 | tree->elements_in_tree++; |
| 303 | rb_insert(tree,parent,element); /* rebalance tree */ |
| 304 | } |
| 305 | else |
| 306 | { |
| 307 | if (tree->flag & TREE_NO_DUPS) |
| 308 | return(NULL); |
| 309 | element->count++; |
| 310 | /* Avoid a wrap over of the count. */ |
| 311 | if (! element->count) |
| 312 | element->count--; |
| 313 | } |
| 314 | DBUG_EXECUTE("check_tree" , test_rb_tree(tree->root);); |
| 315 | return element; |
| 316 | } |
| 317 | |
| 318 | int tree_delete(TREE *tree, void *key, uint key_size, void *custom_arg) |
| 319 | { |
| 320 | int cmp,remove_colour; |
| 321 | TREE_ELEMENT *element,***parent, ***org_parent, *nod; |
| 322 | if (!tree->with_delete) |
| 323 | return 1; /* not allowed */ |
| 324 | |
| 325 | parent= tree->parents; |
| 326 | *parent= &tree->root; element= tree->root; |
| 327 | for (;;) |
| 328 | { |
| 329 | if (element == &tree->null_element) |
| 330 | return 1; /* Was not in tree */ |
| 331 | if ((cmp = (*tree->compare)(custom_arg, ELEMENT_KEY(tree,element), |
| 332 | key)) == 0) |
| 333 | break; |
| 334 | if (cmp < 0) |
| 335 | { |
| 336 | *++parent= &element->right; element= element->right; |
| 337 | } |
| 338 | else |
| 339 | { |
| 340 | *++parent = &element->left; element= element->left; |
| 341 | } |
| 342 | } |
| 343 | if (element->left == &tree->null_element) |
| 344 | { |
| 345 | (**parent)=element->right; |
| 346 | remove_colour= element->colour; |
| 347 | } |
| 348 | else if (element->right == &tree->null_element) |
| 349 | { |
| 350 | (**parent)=element->left; |
| 351 | remove_colour= element->colour; |
| 352 | } |
| 353 | else |
| 354 | { |
| 355 | org_parent= parent; |
| 356 | *++parent= &element->right; nod= element->right; |
| 357 | while (nod->left != &tree->null_element) |
| 358 | { |
| 359 | *++parent= &nod->left; nod= nod->left; |
| 360 | } |
| 361 | (**parent)=nod->right; /* unlink nod from tree */ |
| 362 | remove_colour= nod->colour; |
| 363 | org_parent[0][0]=nod; /* put y in place of element */ |
| 364 | org_parent[1]= &nod->right; |
| 365 | nod->left=element->left; |
| 366 | nod->right=element->right; |
| 367 | nod->colour=element->colour; |
| 368 | } |
| 369 | if (remove_colour == BLACK) |
| 370 | rb_delete_fixup(tree,parent); |
| 371 | if (tree->free) |
| 372 | (*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg); |
| 373 | tree->allocated-= sizeof(TREE_ELEMENT) + tree->size_of_element + key_size; |
| 374 | my_free(element); |
| 375 | tree->elements_in_tree--; |
| 376 | return 0; |
| 377 | } |
| 378 | |
| 379 | |
| 380 | void *tree_search(TREE *tree, void *key, void *custom_arg) |
| 381 | { |
| 382 | int cmp; |
| 383 | TREE_ELEMENT *element=tree->root; |
| 384 | |
| 385 | for (;;) |
| 386 | { |
| 387 | if (element == &tree->null_element) |
| 388 | return (void*) 0; |
| 389 | if ((cmp = (*tree->compare)(custom_arg, ELEMENT_KEY(tree,element), |
| 390 | key)) == 0) |
| 391 | return ELEMENT_KEY(tree,element); |
| 392 | if (cmp < 0) |
| 393 | element=element->right; |
| 394 | else |
| 395 | element=element->left; |
| 396 | } |
| 397 | } |
| 398 | |
| 399 | void *tree_search_key(TREE *tree, const void *key, |
| 400 | TREE_ELEMENT **parents, TREE_ELEMENT ***last_pos, |
| 401 | enum ha_rkey_function flag, void *custom_arg) |
| 402 | { |
| 403 | int cmp; |
| 404 | TREE_ELEMENT *element= tree->root; |
| 405 | TREE_ELEMENT **last_left_step_parent= NULL, **last_right_step_parent= NULL; |
| 406 | TREE_ELEMENT **last_equal_element= NULL; |
| 407 | |
| 408 | /* |
| 409 | TODO: support for HA_READ_KEY_OR_PREV, HA_READ_PREFIX flags if needed. |
| 410 | */ |
| 411 | |
| 412 | *parents = &tree->null_element; |
| 413 | while (element != &tree->null_element) |
| 414 | { |
| 415 | *++parents= element; |
| 416 | if ((cmp= (*tree->compare)(custom_arg, ELEMENT_KEY(tree, element), |
| 417 | key)) == 0) |
| 418 | { |
| 419 | switch (flag) { |
| 420 | case HA_READ_KEY_EXACT: |
| 421 | case HA_READ_KEY_OR_NEXT: |
| 422 | case HA_READ_BEFORE_KEY: |
| 423 | case HA_READ_KEY_OR_PREV: |
| 424 | last_equal_element= parents; |
| 425 | cmp= 1; |
| 426 | break; |
| 427 | case HA_READ_AFTER_KEY: |
| 428 | cmp= -1; |
| 429 | break; |
| 430 | case HA_READ_PREFIX_LAST: |
| 431 | case HA_READ_PREFIX_LAST_OR_PREV: |
| 432 | last_equal_element= parents; |
| 433 | cmp= -1; |
| 434 | break; |
| 435 | default: |
| 436 | return NULL; |
| 437 | } |
| 438 | } |
| 439 | if (cmp < 0) /* element < key */ |
| 440 | { |
| 441 | last_right_step_parent= parents; |
| 442 | element= element->right; |
| 443 | } |
| 444 | else |
| 445 | { |
| 446 | last_left_step_parent= parents; |
| 447 | element= element->left; |
| 448 | } |
| 449 | } |
| 450 | switch (flag) { |
| 451 | case HA_READ_KEY_EXACT: |
| 452 | case HA_READ_PREFIX_LAST: |
| 453 | *last_pos= last_equal_element; |
| 454 | break; |
| 455 | case HA_READ_KEY_OR_NEXT: |
| 456 | *last_pos= last_equal_element ? last_equal_element : last_left_step_parent; |
| 457 | break; |
| 458 | case HA_READ_AFTER_KEY: |
| 459 | *last_pos= last_left_step_parent; |
| 460 | break; |
| 461 | case HA_READ_PREFIX_LAST_OR_PREV: |
| 462 | *last_pos= last_equal_element ? last_equal_element : last_right_step_parent; |
| 463 | break; |
| 464 | case HA_READ_BEFORE_KEY: |
| 465 | *last_pos= last_right_step_parent; |
| 466 | break; |
| 467 | case HA_READ_KEY_OR_PREV: |
| 468 | *last_pos= last_equal_element ? last_equal_element : last_right_step_parent; |
| 469 | break; |
| 470 | default: |
| 471 | return NULL; |
| 472 | } |
| 473 | return *last_pos ? ELEMENT_KEY(tree, **last_pos) : NULL; |
| 474 | } |
| 475 | |
| 476 | /* |
| 477 | Search first (the most left) or last (the most right) tree element |
| 478 | */ |
| 479 | void *tree_search_edge(TREE *tree, TREE_ELEMENT **parents, |
| 480 | TREE_ELEMENT ***last_pos, int child_offs) |
| 481 | { |
| 482 | TREE_ELEMENT *element= tree->root; |
| 483 | |
| 484 | *parents= &tree->null_element; |
| 485 | while (element != &tree->null_element) |
| 486 | { |
| 487 | *++parents= element; |
| 488 | element= ELEMENT_CHILD(element, child_offs); |
| 489 | } |
| 490 | *last_pos= parents; |
| 491 | return **last_pos != &tree->null_element ? |
| 492 | ELEMENT_KEY(tree, **last_pos) : NULL; |
| 493 | } |
| 494 | |
| 495 | void *tree_search_next(TREE *tree, TREE_ELEMENT ***last_pos, int l_offs, |
| 496 | int r_offs) |
| 497 | { |
| 498 | TREE_ELEMENT *x= **last_pos; |
| 499 | |
| 500 | if (ELEMENT_CHILD(x, r_offs) != &tree->null_element) |
| 501 | { |
| 502 | x= ELEMENT_CHILD(x, r_offs); |
| 503 | *++*last_pos= x; |
| 504 | while (ELEMENT_CHILD(x, l_offs) != &tree->null_element) |
| 505 | { |
| 506 | x= ELEMENT_CHILD(x, l_offs); |
| 507 | *++*last_pos= x; |
| 508 | } |
| 509 | return ELEMENT_KEY(tree, x); |
| 510 | } |
| 511 | else |
| 512 | { |
| 513 | TREE_ELEMENT *y= *--*last_pos; |
| 514 | while (y != &tree->null_element && x == ELEMENT_CHILD(y, r_offs)) |
| 515 | { |
| 516 | x= y; |
| 517 | y= *--*last_pos; |
| 518 | } |
| 519 | return y == &tree->null_element ? NULL : ELEMENT_KEY(tree, y); |
| 520 | } |
| 521 | } |
| 522 | |
| 523 | /* |
| 524 | Expected that tree is fully balanced |
| 525 | (each path from root to leaf has the same length) |
| 526 | */ |
| 527 | ha_rows tree_record_pos(TREE *tree, const void *key, |
| 528 | enum ha_rkey_function flag, void *custom_arg) |
| 529 | { |
| 530 | int cmp; |
| 531 | TREE_ELEMENT *element= tree->root; |
| 532 | double left= 1; |
| 533 | double right= tree->elements_in_tree; |
| 534 | |
| 535 | while (element != &tree->null_element) |
| 536 | { |
| 537 | if ((cmp= (*tree->compare)(custom_arg, ELEMENT_KEY(tree, element), |
| 538 | key)) == 0) |
| 539 | { |
| 540 | switch (flag) { |
| 541 | case HA_READ_KEY_EXACT: |
| 542 | case HA_READ_BEFORE_KEY: |
| 543 | cmp= 1; |
| 544 | break; |
| 545 | case HA_READ_AFTER_KEY: |
| 546 | cmp= -1; |
| 547 | break; |
| 548 | default: |
| 549 | return HA_POS_ERROR; |
| 550 | } |
| 551 | } |
| 552 | if (cmp < 0) /* element < key */ |
| 553 | { |
| 554 | element= element->right; |
| 555 | left= (left + right) / 2; |
| 556 | } |
| 557 | else |
| 558 | { |
| 559 | element= element->left; |
| 560 | right= (left + right) / 2; |
| 561 | } |
| 562 | } |
| 563 | switch (flag) { |
| 564 | case HA_READ_KEY_EXACT: |
| 565 | case HA_READ_BEFORE_KEY: |
| 566 | return (ha_rows) right; |
| 567 | case HA_READ_AFTER_KEY: |
| 568 | return (ha_rows) left; |
| 569 | default: |
| 570 | return HA_POS_ERROR; |
| 571 | } |
| 572 | } |
| 573 | |
| 574 | int tree_walk(TREE *tree, tree_walk_action action, void *argument, TREE_WALK visit) |
| 575 | { |
| 576 | switch (visit) { |
| 577 | case left_root_right: |
| 578 | return tree_walk_left_root_right(tree,tree->root,action,argument); |
| 579 | case right_root_left: |
| 580 | return tree_walk_right_root_left(tree,tree->root,action,argument); |
| 581 | } |
| 582 | return 0; /* Keep gcc happy */ |
| 583 | } |
| 584 | |
| 585 | static int tree_walk_left_root_right(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument) |
| 586 | { |
| 587 | int error; |
| 588 | if (element->left) /* Not null_element */ |
| 589 | { |
| 590 | if ((error=tree_walk_left_root_right(tree,element->left,action, |
| 591 | argument)) == 0 && |
| 592 | (error=(*action)(ELEMENT_KEY(tree,element), |
| 593 | (element_count) element->count, |
| 594 | argument)) == 0) |
| 595 | error=tree_walk_left_root_right(tree,element->right,action,argument); |
| 596 | return error; |
| 597 | } |
| 598 | return 0; |
| 599 | } |
| 600 | |
| 601 | static int tree_walk_right_root_left(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument) |
| 602 | { |
| 603 | int error; |
| 604 | if (element->right) /* Not null_element */ |
| 605 | { |
| 606 | if ((error=tree_walk_right_root_left(tree,element->right,action, |
| 607 | argument)) == 0 && |
| 608 | (error=(*action)(ELEMENT_KEY(tree,element), |
| 609 | (element_count) element->count, |
| 610 | argument)) == 0) |
| 611 | error=tree_walk_right_root_left(tree,element->left,action,argument); |
| 612 | return error; |
| 613 | } |
| 614 | return 0; |
| 615 | } |
| 616 | |
| 617 | |
| 618 | /* Functions to fix up the tree after insert and delete */ |
| 619 | |
| 620 | static void left_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf) |
| 621 | { |
| 622 | TREE_ELEMENT *y; |
| 623 | |
| 624 | y=leaf->right; |
| 625 | leaf->right=y->left; |
| 626 | parent[0]=y; |
| 627 | y->left=leaf; |
| 628 | } |
| 629 | |
| 630 | static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf) |
| 631 | { |
| 632 | TREE_ELEMENT *x; |
| 633 | |
| 634 | x=leaf->left; |
| 635 | leaf->left=x->right; |
| 636 | parent[0]=x; |
| 637 | x->right=leaf; |
| 638 | } |
| 639 | |
| 640 | static void rb_insert(TREE *tree, TREE_ELEMENT ***parent, TREE_ELEMENT *leaf) |
| 641 | { |
| 642 | TREE_ELEMENT *y,*par,*par2; |
| 643 | |
| 644 | leaf->colour=RED; |
| 645 | while (leaf != tree->root && (par=parent[-1][0])->colour == RED) |
| 646 | { |
| 647 | if (par == (par2=parent[-2][0])->left) |
| 648 | { |
| 649 | y= par2->right; |
| 650 | if (y->colour == RED) |
| 651 | { |
| 652 | par->colour=BLACK; |
| 653 | y->colour=BLACK; |
| 654 | leaf=par2; |
| 655 | parent-=2; |
| 656 | leaf->colour=RED; /* And the loop continues */ |
| 657 | } |
| 658 | else |
| 659 | { |
| 660 | if (leaf == par->right) |
| 661 | { |
| 662 | left_rotate(parent[-1],par); |
| 663 | par=leaf; /* leaf is now parent to old leaf */ |
| 664 | } |
| 665 | par->colour=BLACK; |
| 666 | par2->colour=RED; |
| 667 | right_rotate(parent[-2],par2); |
| 668 | break; |
| 669 | } |
| 670 | } |
| 671 | else |
| 672 | { |
| 673 | y= par2->left; |
| 674 | if (y->colour == RED) |
| 675 | { |
| 676 | par->colour=BLACK; |
| 677 | y->colour=BLACK; |
| 678 | leaf=par2; |
| 679 | parent-=2; |
| 680 | leaf->colour=RED; /* And the loop continues */ |
| 681 | } |
| 682 | else |
| 683 | { |
| 684 | if (leaf == par->left) |
| 685 | { |
| 686 | right_rotate(parent[-1],par); |
| 687 | par=leaf; |
| 688 | } |
| 689 | par->colour=BLACK; |
| 690 | par2->colour=RED; |
| 691 | left_rotate(parent[-2],par2); |
| 692 | break; |
| 693 | } |
| 694 | } |
| 695 | } |
| 696 | tree->root->colour=BLACK; |
| 697 | } |
| 698 | |
| 699 | static void rb_delete_fixup(TREE *tree, TREE_ELEMENT ***parent) |
| 700 | { |
| 701 | TREE_ELEMENT *x,*w,*par; |
| 702 | |
| 703 | x= **parent; |
| 704 | while (x != tree->root && x->colour == BLACK) |
| 705 | { |
| 706 | if (x == (par=parent[-1][0])->left) |
| 707 | { |
| 708 | w=par->right; |
| 709 | if (w->colour == RED) |
| 710 | { |
| 711 | w->colour=BLACK; |
| 712 | par->colour=RED; |
| 713 | left_rotate(parent[-1],par); |
| 714 | parent[0]= &w->left; |
| 715 | *++parent= &par->left; |
| 716 | w=par->right; |
| 717 | } |
| 718 | if (w->left->colour == BLACK && w->right->colour == BLACK) |
| 719 | { |
| 720 | w->colour=RED; |
| 721 | x=par; |
| 722 | parent--; |
| 723 | } |
| 724 | else |
| 725 | { |
| 726 | if (w->right->colour == BLACK) |
| 727 | { |
| 728 | w->left->colour=BLACK; |
| 729 | w->colour=RED; |
| 730 | right_rotate(&par->right,w); |
| 731 | w=par->right; |
| 732 | } |
| 733 | w->colour=par->colour; |
| 734 | par->colour=BLACK; |
| 735 | w->right->colour=BLACK; |
| 736 | left_rotate(parent[-1],par); |
| 737 | x=tree->root; |
| 738 | break; |
| 739 | } |
| 740 | } |
| 741 | else |
| 742 | { |
| 743 | w=par->left; |
| 744 | if (w->colour == RED) |
| 745 | { |
| 746 | w->colour=BLACK; |
| 747 | par->colour=RED; |
| 748 | right_rotate(parent[-1],par); |
| 749 | parent[0]= &w->right; |
| 750 | *++parent= &par->right; |
| 751 | w=par->left; |
| 752 | } |
| 753 | if (w->right->colour == BLACK && w->left->colour == BLACK) |
| 754 | { |
| 755 | w->colour=RED; |
| 756 | x=par; |
| 757 | parent--; |
| 758 | } |
| 759 | else |
| 760 | { |
| 761 | if (w->left->colour == BLACK) |
| 762 | { |
| 763 | w->right->colour=BLACK; |
| 764 | w->colour=RED; |
| 765 | left_rotate(&par->left,w); |
| 766 | w=par->left; |
| 767 | } |
| 768 | w->colour=par->colour; |
| 769 | par->colour=BLACK; |
| 770 | w->left->colour=BLACK; |
| 771 | right_rotate(parent[-1],par); |
| 772 | x=tree->root; |
| 773 | break; |
| 774 | } |
| 775 | } |
| 776 | } |
| 777 | x->colour=BLACK; |
| 778 | } |
| 779 | |
| 780 | #ifndef DBUG_OFF |
| 781 | |
| 782 | /* Test that the proporties for a red-black tree holds */ |
| 783 | |
| 784 | static int test_rb_tree(TREE_ELEMENT *element) |
| 785 | { |
| 786 | int count_l,count_r; |
| 787 | |
| 788 | if (!element->left) |
| 789 | return 0; /* Found end of tree */ |
| 790 | if (element->colour == RED && |
| 791 | (element->left->colour == RED || element->right->colour == RED)) |
| 792 | { |
| 793 | printf("Wrong tree: Found two red in a row\n" ); |
| 794 | return -1; |
| 795 | } |
| 796 | count_l=test_rb_tree(element->left); |
| 797 | count_r=test_rb_tree(element->right); |
| 798 | if (count_l >= 0 && count_r >= 0) |
| 799 | { |
| 800 | if (count_l == count_r) |
| 801 | return count_l+(element->colour == BLACK); |
| 802 | printf("Wrong tree: Incorrect black-count: %d - %d\n" ,count_l,count_r); |
| 803 | } |
| 804 | return -1; |
| 805 | } |
| 806 | #endif |
| 807 | |