avl.c (17205B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Generic AVL Tree 8 * 9 * On creating a tree, the user specifies the size of the datum and the 10 * FIXED maximum number of entries. On insert/delete/lookup, the user 11 * supplies the datum compare function. 12 * 13 * NOTE: These routines are NOT thread-safe. If multiple threads could 14 * access an AVL tree, external locks must be used to mutually exclude 15 * each call to the shr_avl routines, including shr_avl_traverse(). 16 * 17 * AVL tree code is derived from Paul Vixie's code (24-July-1987), which 18 * used algorithms from "Algorithms & Data Structures," Niklaus Wirth, 19 * Prentice-Hall 1986, ISBN 0-13-022005-1. 20 */ 21 22 #include <sal/types.h> 23 #include <shared/alloc.h> 24 #include <sal/core/libc.h> 25 #include <shared/avl.h> 26 #include <assert.h> 27 28 /* 29 * Function: 30 * _shr_avl_entry_free 31 * Purpose: 32 * Internal routine to put an entry back on the free list. 33 * The 'left' pointer is used as the free list 'next' pointer. 34 */ 35 36 STATIC INLINE void 37 _shr_avl_entry_free(shr_avl_t *avl, shr_avl_entry_t *t) 38 { 39 assert(avl->count > 0); 40 41 t->left = avl->free_list; 42 avl->free_list = t; 43 44 avl->count--; 45 } 46 47 /* 48 * Function: 49 * _shr_avl_entry_alloc 50 * Purpose: 51 * Internal routine to get an entry from free list. 52 */ 53 54 STATIC INLINE shr_avl_entry_t * 55 _shr_avl_entry_alloc(shr_avl_t *avl) 56 { 57 shr_avl_entry_t *t; 58 59 t = avl->free_list; 60 61 if (t != NULL) { 62 avl->free_list = t->left; 63 avl->count++; 64 } 65 66 return t; 67 } 68 69 /* 70 * Function: 71 * _shr_avl_sprout 72 * Purpose: 73 * Internal support routine 74 */ 75 76 STATIC int 77 _shr_avl_sprout(shr_avl_t *avl, 78 shr_avl_entry_t **pt, 79 shr_avl_compare_fn cmp_fn, 80 shr_avl_datum_t *datum, 81 int *balance) 82 { 83 shr_avl_entry_t *p1, *p2; 84 int i, rv; 85 86 /* 87 * Are we grounded? If so, add the node "here", 88 * set the rebalance flag, then exit. 89 */ 90 91 if (*pt == NULL) { 92 *pt = _shr_avl_entry_alloc(avl); 93 94 if (*pt == NULL) { 95 return -1; 96 } 97 98 (*pt)->left = NULL; 99 (*pt)->right = NULL; 100 (*pt)->balance = 0; 101 102 sal_memcpy(&(*pt)->datum, datum, avl->datum_bytes); 103 104 *balance = 1; 105 106 return 0; 107 } 108 109 /* 110 * If less, prepare to move to the left. 111 */ 112 113 i = (*cmp_fn)(avl->user_data, datum, &(*pt)->datum); 114 115 if (i < 0) { 116 rv = _shr_avl_sprout(avl, &(*pt)->left, cmp_fn, datum, balance); 117 118 if (rv < 0) { 119 return rv; 120 } 121 122 if (*balance == 0) { 123 return 0; 124 } 125 126 /* Left branch has grown longer */ 127 128 switch ((*pt)->balance) { 129 case 1: /* Right branch was longer; balance is ok now */ 130 (*pt)->balance = 0; 131 *balance = 0; 132 break; 133 case 0: /* Balance was okay; now left branch longer */ 134 (*pt)->balance = -1; 135 break; 136 case -1: 137 /* Left branch was already too long. rebalance */ 138 p1 = (*pt)->left; 139 140 if (p1->balance == -1) { /* LL */ 141 (*pt)->left = p1->right; 142 p1->right = *pt; 143 (*pt)->balance = 0; 144 *pt = p1; 145 } else { /* Double LR */ 146 p2 = p1->right; 147 p1->right = p2->left; 148 p2->left = p1; 149 150 (*pt)->left = p2->right; 151 p2->right = *pt; 152 153 if (p2->balance == -1) { 154 (*pt)->balance = 1; 155 } else { 156 (*pt)->balance = 0; 157 } 158 159 if (p2->balance == 1) { 160 p1->balance = -1; 161 } else { 162 p1->balance = 0; 163 } 164 165 *pt = p2; 166 } 167 168 (*pt)->balance = 0; 169 *balance = 0; 170 } 171 172 return 0; 173 } 174 175 /* 176 * If more, prepare to move to the right. 177 */ 178 179 if (i > 0) { 180 rv = _shr_avl_sprout(avl, &(*pt)->right, cmp_fn, datum, balance); 181 182 if (rv < 0) { 183 return rv; 184 } 185 186 if (*balance == 0) { 187 return 0; 188 } 189 190 /* Right branch has grown longer */ 191 192 switch ((*pt)->balance) { 193 case -1: 194 (*pt)->balance = 0; 195 *balance = 0; 196 break; 197 case 0: 198 (*pt)->balance = 1; 199 break; 200 case 1: 201 p1 = (*pt)->right; 202 203 if (p1->balance == 1) { /* RR */ 204 (*pt)->right = p1->left; 205 p1->left = *pt; 206 (*pt)->balance = 0; 207 *pt = p1; 208 } else { /* Double RL */ 209 p2 = p1->left; 210 p1->left = p2->right; 211 p2->right = p1; 212 213 (*pt)->right = p2->left; 214 p2->left = *pt; 215 216 if (p2->balance == 1) { 217 (*pt)->balance = -1; 218 } else { 219 (*pt)->balance = 0; 220 } 221 222 if (p2->balance == -1) { 223 p1->balance = 1; 224 } else { 225 p1->balance = 0; 226 } 227 228 *pt = p2; 229 } 230 231 (*pt)->balance = 0; 232 *balance = 0; 233 } 234 235 return 0; 236 } 237 238 /* 239 * If same, just gets replaced. 240 */ 241 242 *balance = 0; 243 244 sal_memcpy(&(*pt)->datum, datum, avl->datum_bytes); 245 246 return 0; 247 } 248 249 /* 250 * Function: 251 * _shr_avl_balance_l 252 * Purpose: 253 * Internal support routine 254 */ 255 256 STATIC void 257 _shr_avl_balance_l(shr_avl_entry_t **pt, int *balance) 258 { 259 shr_avl_entry_t *p1, *p2; 260 int b1, b2; 261 262 switch ((*pt)->balance) { 263 case -1: 264 (*pt)->balance = 0; 265 break; 266 case 0: 267 (*pt)->balance = 1; 268 *balance = 0; 269 break; 270 case 1: 271 p1 = (*pt)->right; 272 b1 = p1->balance; 273 274 if (b1 >= 0) { 275 (*pt)->right = p1->left; 276 p1->left = *pt; 277 278 if (b1 == 0) { 279 (*pt)->balance = 1; 280 p1->balance = -1; 281 *balance = 0; 282 } else { 283 (*pt)->balance = 0; 284 p1->balance = 0; 285 } 286 287 *pt = p1; 288 } else { 289 p2 = p1->left; 290 b2 = p2->balance; 291 p1->left = p2->right; 292 p2->right = p1; 293 (*pt)->right = p2->left; 294 p2->left = *pt; 295 296 if (b2 == 1) { 297 (*pt)->balance = -1; 298 } else { 299 (*pt)->balance = 0; 300 } 301 302 if (b2 == -1) { 303 p1->balance = 1; 304 } else { 305 p1->balance = 0; 306 } 307 308 *pt = p2; 309 p2->balance = 0; 310 } 311 } 312 } 313 314 /* 315 * Function: 316 * _shr_avl_balance_r 317 * Purpose: 318 * Internal support routine 319 */ 320 321 STATIC void 322 _shr_avl_balance_r(shr_avl_entry_t **pt, int *balance) 323 { 324 shr_avl_entry_t *p1, *p2; 325 int b1, b2; 326 327 switch ((*pt)->balance) { 328 case 1: 329 (*pt)->balance = 0; 330 break; 331 case 0: 332 (*pt)->balance = -1; 333 *balance = 0; 334 break; 335 case -1: 336 p1 = (*pt)->left; 337 b1 = p1->balance; 338 339 if (b1 <= 0) { 340 (*pt)->left = p1->right; 341 p1->right = *pt; 342 343 if (b1 == 0) { 344 (*pt)->balance = -1; 345 p1->balance = 1; 346 *balance = 0; 347 } else { 348 (*pt)->balance = 0; 349 p1->balance = 0; 350 } 351 352 *pt = p1; 353 } else { 354 p2 = p1->right; 355 b2 = p2->balance; 356 p1->right = p2->left; 357 p2->left = p1; 358 (*pt)->left = p2->right; 359 p2->right = *pt; 360 361 if (b2 == -1) { 362 (*pt)->balance = 1; 363 } else { 364 (*pt)->balance = 0; 365 } 366 367 if (b2 == 1) { 368 p1->balance = -1; 369 } else { 370 p1->balance = 0; 371 } 372 373 *pt = p2; 374 p2->balance = 0; 375 } 376 } 377 } 378 379 /* 380 * Function: 381 * _shr_avl_del 382 * Purpose: 383 * Internal support routine 384 */ 385 386 STATIC void 387 _shr_avl_del(shr_avl_t *avl, 388 shr_avl_entry_t **pt, 389 int *balance, 390 shr_avl_entry_t **qqt) 391 { 392 if ((*pt)->right != 0) { 393 _shr_avl_del(avl, &(*pt)->right, balance, qqt); 394 395 if (*balance) { 396 _shr_avl_balance_r(pt, balance); 397 } 398 } else { 399 if(avl->datum_copy_fn) { 400 avl->datum_copy_fn(avl->user_data, &(*qqt)->datum, &(*pt)->datum); 401 } else { 402 sal_memcpy(&(*qqt)->datum, &(*pt)->datum, avl->datum_bytes); 403 } 404 *qqt = *pt; 405 *pt = (*pt)->left; 406 *balance = 1; 407 } 408 } 409 410 /* 411 * Function: 412 * _shr_avl_delete 413 * Purpose: 414 * Internal support routine 415 */ 416 417 STATIC int 418 _shr_avl_delete(shr_avl_t *avl, 419 shr_avl_entry_t **pt, 420 shr_avl_compare_fn cmp_fn, 421 shr_avl_datum_t *datum, 422 int *balance) 423 { 424 shr_avl_entry_t *t; 425 int ret; 426 int i; 427 428 if (*pt == 0) { 429 return 0; 430 } 431 432 i = (*cmp_fn)(avl->user_data, datum, &(*pt)->datum); 433 434 if (i < 0) { 435 ret = _shr_avl_delete(avl, &(*pt)->left, cmp_fn, datum, balance); 436 437 if (*balance) { 438 _shr_avl_balance_l(pt, balance); 439 } 440 441 return ret; 442 } 443 444 if (i > 0) { 445 ret = _shr_avl_delete(avl, &(*pt)->right, cmp_fn, datum, balance); 446 447 if (*balance) { 448 _shr_avl_balance_r(pt, balance); 449 } 450 451 return ret; 452 } 453 454 t = *pt; 455 456 if (t->right == NULL) { 457 *pt = t->left; 458 *balance = 1; 459 } else if (t->left == NULL) { 460 *pt = t->right; 461 *balance = 1; 462 } else { 463 _shr_avl_del(avl, &t->left, balance, &t); 464 465 if (*balance) { 466 _shr_avl_balance_l(pt, balance); 467 } 468 } 469 470 _shr_avl_entry_free(avl, t); 471 472 return 1; 473 } 474 475 /* 476 * Function: 477 * shr_avl_insert 478 * Purpose: 479 * Insert a datum into the AVL tree. 480 * Parameters: 481 * avl - AVL tree handle 482 * cmp_fn - Datum comparison function 483 * datum - Datum to insert 484 * Returns: 485 * 0 Success 486 * -1 Out of memory (tree full) 487 * Notes: 488 * A duplicate key overwrites the old contents of the datum. 489 */ 490 491 int 492 shr_avl_insert(shr_avl_t *avl, 493 shr_avl_compare_fn cmp_fn, 494 shr_avl_datum_t *datum) 495 { 496 int rv, balance = 0; 497 498 rv = _shr_avl_sprout(avl, &avl->root, cmp_fn, datum, &balance); 499 500 return rv; 501 } 502 503 /* 504 * Function: 505 * shr_avl_delete 506 * Purpose: 507 * Delete a datum from the AVL tree. 508 * Parameters: 509 * avl - AVL tree handle 510 * cmp_fn - Datum comparison function 511 * datum - Datum to delete; only key portion is used 512 * Returns: 513 * 0 Success, did not find datum 514 * 1 Success, found and deleted datum 515 */ 516 517 int 518 shr_avl_delete(shr_avl_t *avl, 519 shr_avl_compare_fn key_cmp_fn, 520 shr_avl_datum_t *datum) 521 { 522 int rv, balance = 0; 523 524 rv = _shr_avl_delete(avl, &avl->root, key_cmp_fn, datum, &balance); 525 526 return rv; 527 } 528 529 /* 530 * Function: 531 * _shr_avl_lookup 532 * Purpose: 533 * Internal support routine 534 */ 535 536 STATIC int 537 _shr_avl_lookup(shr_avl_t *avl, shr_avl_entry_t *t, 538 shr_avl_compare_fn key_cmp_fn, 539 shr_avl_datum_t *datum) 540 { 541 int i; 542 543 if (t == NULL) { 544 return 0; 545 } 546 547 i = (*key_cmp_fn)(avl->user_data, datum, &t->datum); 548 549 if (i < 0) { 550 return _shr_avl_lookup(avl, t->left, key_cmp_fn, datum); 551 } 552 553 if (i > 0) { 554 return _shr_avl_lookup(avl, t->right, key_cmp_fn, datum); 555 } 556 557 sal_memcpy(datum, &t->datum, avl->datum_bytes); 558 559 return 1; 560 } 561 562 /* 563 * Function: 564 * shr_avl_lookup 565 * Purpose: 566 * Look up a datum in the AVL tree. 567 * Parameters: 568 * avl - AVL tree handle 569 * datum - (IN) Datum in which key portion is valid 570 * (OUT) Datum in which key and data portion is valid if found 571 * key_cmp_fn - Compare function which should compare only the 572 * key portion of the datum. 573 * Returns: 574 * 0 Success, did not find datum 575 * 1 Success, found key and updated rest of datum 576 */ 577 578 int 579 shr_avl_lookup(shr_avl_t *avl, 580 shr_avl_compare_fn key_cmp_fn, 581 shr_avl_datum_t *datum) 582 { 583 if (avl->root == NULL) { 584 return 0; 585 } 586 587 return _shr_avl_lookup(avl, avl->root, key_cmp_fn, datum); 588 } 589 590 /* 591 * Function: 592 * _shr_avl_lookup_lkupdata 593 * Purpose: 594 * Internal support routine 595 */ 596 597 STATIC int 598 _shr_avl_lookup_lkupdata(shr_avl_t *avl, shr_avl_entry_t *t, 599 shr_avl_compare_fn_lkupdata key_cmp_fn, 600 shr_avl_datum_t *datum, 601 void *lkupdata) 602 { 603 int i; 604 605 if (t == NULL) { 606 return 0; 607 } 608 609 i = (*key_cmp_fn)(avl->user_data, datum, &t->datum, lkupdata); 610 611 if (i < 0) { 612 return _shr_avl_lookup_lkupdata(avl, t->left, key_cmp_fn, datum, lkupdata); 613 } 614 615 if (i > 0) { 616 return _shr_avl_lookup_lkupdata(avl, t->right, key_cmp_fn, datum, lkupdata); 617 } 618 619 sal_memcpy(datum, &t->datum, avl->datum_bytes); 620 621 return 1; 622 } 623 624 /* 625 * Function: 626 * shr_avl_lookup_lkupdata 627 * Purpose: 628 * Look up a datum in the AVL tree. This function takes an additional argument 629 * lookup data. Users can for example capture the Pointer of the tree element inside 630 * compare function using user data. This facilitates return by address + value of 631 * tree element datum 632 * Parameters: 633 * avl - AVL tree handle 634 * datum - (IN) Datum in which key portion is valid 635 * (OUT) Datum in which key and data portion is valid if found 636 * key_cmp_fn - Compare function which should compare only the 637 * key portion of the datum. 638 * Returns: 639 * 0 Success, did not find datum 640 * 1 Success, found key and updated rest of datum 641 */ 642 643 int 644 shr_avl_lookup_lkupdata(shr_avl_t *avl, 645 shr_avl_compare_fn_lkupdata key_cmp_fn, 646 shr_avl_datum_t *datum, /* KEY */ 647 void *lkupdata) /* User Data */ 648 { 649 if (avl->root == NULL) { 650 return 0; 651 } 652 653 return _shr_avl_lookup_lkupdata(avl, avl->root, key_cmp_fn, datum, lkupdata); 654 } 655 656 /* 657 * Function: 658 * shr_avl_lookup_min 659 * Purpose: 660 * Return the minimum element in the tree. 661 * Parameters: 662 * avl - AVL tree 663 * datum - Datum to receive element. 664 * Returns: 665 * 0 Success, found and retrieved datum. 666 * -1 Tree empty. 667 */ 668 669 int shr_avl_lookup_min(shr_avl_t *avl, 670 shr_avl_datum_t *datum) 671 { 672 shr_avl_entry_t *t; 673 674 if (avl->root == NULL) { 675 return -1; 676 } 677 678 for (t = avl->root; t->left != NULL; t = t->left) 679 ; 680 681 sal_memcpy(datum, &t->datum, avl->datum_bytes); 682 683 return 0; 684 } 685 686 /* 687 * Function: 688 * shr_avl_lookup_max 689 * Purpose: 690 * Return the maximum element in the tree. 691 * Parameters: 692 * avl - AVL tree 693 * datum - Datum to receive element. 694 * Returns: 695 * 0 Success, found and retrieved datum. 696 * -1 Tree empty. 697 */ 698 699 int shr_avl_lookup_max(shr_avl_t *avl, 700 shr_avl_datum_t *datum) 701 { 702 shr_avl_entry_t *t; 703 704 if (avl->root == NULL) { 705 return -1; 706 } 707 708 for (t = avl->root; t->right != NULL; t = t->right) 709 ; 710 711 sal_memcpy(datum, &t->datum, avl->datum_bytes); 712 713 return 0; 714 } 715 716 /* 717 * Function: 718 * _shr_avl_delete_node 719 * Purpose: 720 * Internal routine 721 */ 722 723 STATIC void 724 _shr_avl_delete_node(shr_avl_t *avl, shr_avl_entry_t **pt) 725 { 726 if ((*pt) != NULL) { 727 _shr_avl_delete_node(avl, &(*pt)->left); 728 _shr_avl_delete_node(avl, &(*pt)->right); 729 730 _shr_avl_entry_free(avl, (*pt)); 731 732 (*pt) = NULL; 733 } 734 } 735 736 /* 737 * Function: 738 * shr_avl_delete_all 739 * Purpose: 740 * Reset an AVL tree to empty. 741 * Also used during tree creation to initialize free list. 742 * Parameters: 743 * avl - AVL tree handle 744 * Returns: 745 * 0 Success 746 */ 747 748 int 749 shr_avl_delete_all(shr_avl_t *avl) 750 { 751 _shr_avl_delete_node(avl, &avl->root); 752 753 assert(avl->count == 0); 754 755 return 0; 756 } 757 758 /* 759 * Function: 760 * shr_avl_count 761 * Purpose: 762 * Return the number of data in an AVL tree 763 * Parameters: 764 * avl - AVL tree handle 765 * Returns: 766 * Number of entries (0 if avl is NULL) 767 */ 768 769 int 770 shr_avl_count(shr_avl_t *avl) 771 { 772 return ((avl == NULL) ? 0 : avl->count); 773 } 774 775 /* 776 * Function: 777 * shr_avl_create 778 * Purpose: 779 * Create an empty AVL tree 780 * Parameters: 781 * avl_ptr - Return pointer (handle) to new AVL tree 782 * user_data - Arbitrary user data passed to compare routines 783 * datum_bytes - Size of datum being stored 784 * datum_max - Limit for number of data in table 785 * flags - Logical OR of SHR_AVL_FLAG_xxx 786 * Returns: 787 * 0 Success 788 * -1 Out of memory (system allocator) 789 */ 790 791 int 792 shr_avl_create(shr_avl_t **avl_ptr, 793 void *user_data, 794 int datum_bytes, 795 int datum_max) 796 { 797 shr_avl_t *avl; 798 shr_avl_entry_t *t; 799 int i; 800 801 avl = sal_alloc(sizeof (shr_avl_t), "avl"); 802 803 if (avl == NULL) { 804 return -1; 805 } 806 807 sal_memset(avl, 0, sizeof (*avl)); 808 809 avl->user_data = user_data; 810 avl->datum_bytes = datum_bytes; 811 avl->datum_max = datum_max; 812 avl->entry_bytes = (sizeof (shr_avl_entry_t) - 813 sizeof (shr_avl_datum_t) + datum_bytes); 814 avl->root = NULL; 815 avl->datum_copy_fn = NULL; 816 817 /* Pre-allocate maximum number of entries and put on free list. */ 818 819 avl->datum_base = sal_alloc(avl->entry_bytes * datum_max, "avl_ent"); 820 821 if (avl->datum_base == NULL) { 822 sal_free(avl); 823 return -1; 824 } 825 826 /* Initialize free list and put all entries on it */ 827 828 avl->free_list = NULL; 829 avl->count = datum_max; 830 831 for (i = 0; i < datum_max; i++) { 832 t = (shr_avl_entry_t *) (avl->datum_base + i * avl->entry_bytes); 833 _shr_avl_entry_free(avl, t); 834 } 835 836 assert(avl->count == 0); 837 838 *avl_ptr = avl; 839 840 return 0; 841 } 842 843 /* 844 * Function: 845 * shr_avl_destroy 846 * Purpose: 847 * Release the space occupied by AVL tree structure. 848 * Parameters: 849 * avl - AVL tree handle 850 */ 851 852 int 853 shr_avl_destroy(shr_avl_t *avl) 854 { 855 if (avl != NULL) { 856 sal_free(avl->datum_base); 857 sal_free(avl); 858 } 859 860 return 0; 861 } 862 863 /* 864 * Function: 865 * _shr_avl_traverse 866 * Purpose: 867 * Internal support routine 868 * Notes: 869 * The callback routine may not modify the AVL tree being traversed. 870 */ 871 872 STATIC int 873 _shr_avl_traverse(shr_avl_t *avl, 874 shr_avl_entry_t *t, 875 shr_avl_traverse_fn trav_fn, 876 void *trav_data) 877 { 878 int rv; 879 880 if (t != NULL) { 881 if ((rv = _shr_avl_traverse(avl, t->left, trav_fn, trav_data)) < 0) { 882 return rv; 883 } 884 885 if ((rv = (*trav_fn)(avl->user_data, &t->datum, trav_data)) < 0) { 886 return rv; 887 } 888 889 if ((rv = _shr_avl_traverse(avl, t->right, trav_fn, trav_data)) < 0) { 890 return rv; 891 } 892 } 893 894 return 0; 895 } 896 897 /* 898 * Function: 899 * shr_avl_traverse 900 * Purpose: 901 * Call a callback function for each datum in an AVL tree 902 * Parameters: 903 * avl - AVL tree handle 904 * trav_fn - User callback function, called once per datum 905 * trav_data - Arbitrary user data passed to callback routine 906 * Returns: 907 * If the user callback ever returns a negative value, the traversal 908 * is stopped and that value is returned. Otherwise 0 is returned. 909 */ 910 911 int 912 shr_avl_traverse(shr_avl_t *avl, 913 shr_avl_traverse_fn trav_fn, 914 void *trav_data) 915 { 916 if (avl == NULL) { 917 return 0; 918 } 919 return _shr_avl_traverse(avl, avl->root, trav_fn, trav_data); 920 }