openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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 }