xref: /onnv-gate/usr/src/cmd/fm/eversholt/common/lut.c (revision 5433:f231270422fc)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53524Srobj  * Common Development and Distribution License (the "License").
63524Srobj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223524Srobj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * lut.c -- simple lookup table module
260Sstevel@tonic-gate  *
270Sstevel@tonic-gate  * this file contains a very simple lookup table (lut) implementation.
280Sstevel@tonic-gate  * the tables only support insert & lookup, no delete, and can
290Sstevel@tonic-gate  * only be walked in one order.  if the key already exists
300Sstevel@tonic-gate  * for something being inserted, the previous entry is simply
310Sstevel@tonic-gate  * replaced.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include <stdio.h>
370Sstevel@tonic-gate #include "alloc.h"
380Sstevel@tonic-gate #include "out.h"
390Sstevel@tonic-gate #include "stats.h"
400Sstevel@tonic-gate #include "lut.h"
41*5433Saf #include "lut_impl.h"
420Sstevel@tonic-gate #include "tree.h"
430Sstevel@tonic-gate 
440Sstevel@tonic-gate static struct stats *Addtotal;
450Sstevel@tonic-gate static struct stats *Lookuptotal;
460Sstevel@tonic-gate static struct stats *Freetotal;
470Sstevel@tonic-gate 
480Sstevel@tonic-gate void
lut_init(void)490Sstevel@tonic-gate lut_init(void)
500Sstevel@tonic-gate {
510Sstevel@tonic-gate 	Addtotal = stats_new_counter("lut.adds", "total adds", 1);
520Sstevel@tonic-gate 	Lookuptotal = stats_new_counter("lut.lookup", "total lookups", 1);
530Sstevel@tonic-gate 	Freetotal = stats_new_counter("lut.frees", "total frees", 1);
540Sstevel@tonic-gate }
550Sstevel@tonic-gate 
560Sstevel@tonic-gate void
lut_fini(void)570Sstevel@tonic-gate lut_fini(void)
580Sstevel@tonic-gate {
590Sstevel@tonic-gate 	stats_delete(Addtotal);
600Sstevel@tonic-gate 	stats_delete(Lookuptotal);
610Sstevel@tonic-gate 	stats_delete(Freetotal);
620Sstevel@tonic-gate }
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /*
650Sstevel@tonic-gate  * lut_add -- add an entry to the table
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  * use it like this:
680Sstevel@tonic-gate  *	struct lut *root = NULL;
690Sstevel@tonic-gate  *	root = lut_add(root, key, value, cmp_func);
700Sstevel@tonic-gate  *
710Sstevel@tonic-gate  * the cmp_func can be strcmp().  pass in NULL and instead of
720Sstevel@tonic-gate  * calling a cmp_func the routine will just look at the difference
730Sstevel@tonic-gate  * between key pointers (useful when all strings are kept in a
740Sstevel@tonic-gate  * string table so they are equal if their pointers are equal).
750Sstevel@tonic-gate  *
760Sstevel@tonic-gate  */
770Sstevel@tonic-gate struct lut *
lut_add(struct lut * root,void * lhs,void * rhs,lut_cmp cmp_func)780Sstevel@tonic-gate lut_add(struct lut *root, void *lhs, void *rhs, lut_cmp cmp_func)
790Sstevel@tonic-gate {
800Sstevel@tonic-gate 	int diff;
813524Srobj 	struct lut **tmp_hdl = &root, *parent = NULL, *tmp = root;
820Sstevel@tonic-gate 
833524Srobj 	while (tmp) {
843524Srobj 		if (cmp_func)
853524Srobj 			diff = (*cmp_func)(tmp->lut_lhs, lhs);
863524Srobj 		else
873524Srobj 			diff = (const char *)lhs - (const char *)tmp->lut_lhs;
883524Srobj 
893524Srobj 		if (diff == 0) {
903524Srobj 			/* already in tree, replace node */
913524Srobj 			tmp->lut_rhs = rhs;
923524Srobj 			return (root);
933524Srobj 		} else if (diff > 0) {
943524Srobj 			tmp_hdl = &(tmp->lut_left);
953524Srobj 			parent = tmp;
963524Srobj 			tmp = tmp->lut_left;
973524Srobj 		} else {
983524Srobj 			tmp_hdl = &(tmp->lut_right);
993524Srobj 			parent = tmp;
1003524Srobj 			tmp = tmp->lut_right;
1013524Srobj 		}
1020Sstevel@tonic-gate 	}
1030Sstevel@tonic-gate 
1043524Srobj 	/* either empty tree or not in tree, so create new node */
1053524Srobj 	*tmp_hdl = MALLOC(sizeof (*root));
1063524Srobj 	(*tmp_hdl)->lut_lhs = lhs;
1073524Srobj 	(*tmp_hdl)->lut_rhs = rhs;
1083524Srobj 	(*tmp_hdl)->lut_parent = parent;
1093524Srobj 	(*tmp_hdl)->lut_left = (*tmp_hdl)->lut_right = NULL;
1103524Srobj 	stats_counter_bump(Addtotal);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	return (root);
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate void *
lut_lookup(struct lut * root,void * lhs,lut_cmp cmp_func)1160Sstevel@tonic-gate lut_lookup(struct lut *root, void *lhs, lut_cmp cmp_func)
1170Sstevel@tonic-gate {
1180Sstevel@tonic-gate 	int diff;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	stats_counter_bump(Lookuptotal);
1210Sstevel@tonic-gate 
1223524Srobj 	while (root) {
1233524Srobj 		if (cmp_func)
1243524Srobj 			diff = (*cmp_func)(root->lut_lhs, lhs);
1253524Srobj 		else
1263524Srobj 			diff = (const char *)lhs - (const char *)root->lut_lhs;
1270Sstevel@tonic-gate 
1283524Srobj 		if (diff == 0)
1293524Srobj 			return (root->lut_rhs);
1303524Srobj 		else if (diff > 0)
1313524Srobj 			root = root->lut_left;
1323524Srobj 		else
1333524Srobj 			root = root->lut_right;
1343524Srobj 	}
1353524Srobj 	return (NULL);
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate void *
lut_lookup_lhs(struct lut * root,void * lhs,lut_cmp cmp_func)1390Sstevel@tonic-gate lut_lookup_lhs(struct lut *root, void *lhs, lut_cmp cmp_func)
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate 	int diff;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	stats_counter_bump(Lookuptotal);
1440Sstevel@tonic-gate 
1453524Srobj 	while (root) {
1463524Srobj 		if (cmp_func)
1473524Srobj 			diff = (*cmp_func)(root->lut_lhs, lhs);
1483524Srobj 		else
1493524Srobj 			diff = (const char *)lhs - (const char *)root->lut_lhs;
1500Sstevel@tonic-gate 
1513524Srobj 		if (diff == 0)
1523524Srobj 			return (root->lut_lhs);
1533524Srobj 		else if (diff > 0)
1543524Srobj 			root = root->lut_left;
1553524Srobj 		else
1563524Srobj 			root = root->lut_right;
1573524Srobj 	}
1583524Srobj 	return (NULL);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate  * lut_walk -- walk the table in lexical order
1630Sstevel@tonic-gate  */
1640Sstevel@tonic-gate void
lut_walk(struct lut * root,lut_cb callback,void * arg)1650Sstevel@tonic-gate lut_walk(struct lut *root, lut_cb callback, void *arg)
1660Sstevel@tonic-gate {
1673524Srobj 	struct lut *tmp = root;
1683524Srobj 	struct lut *prev_child = NULL;
1693524Srobj 
1703524Srobj 	if (root == NULL)
1713524Srobj 		return;
1723524Srobj 
1733524Srobj 	while (tmp->lut_left != NULL)
1743524Srobj 		tmp = tmp->lut_left;
1753524Srobj 
1763524Srobj 	/* do callback on leftmost node */
1773524Srobj 	(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
1783524Srobj 
1793524Srobj 	for (;;) {
1803524Srobj 		if (tmp->lut_right != NULL && tmp->lut_right != prev_child) {
1813524Srobj 			tmp = tmp->lut_right;
1823524Srobj 			while (tmp->lut_left != NULL)
1833524Srobj 				tmp = tmp->lut_left;
1843524Srobj 
1853524Srobj 			/* do callback on leftmost node */
1863524Srobj 			(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
1873524Srobj 		} else if (tmp->lut_parent != NULL) {
1883524Srobj 			prev_child = tmp;
1893524Srobj 			tmp = tmp->lut_parent;
1903524Srobj 			/*
1913524Srobj 			 * do callback on parent only if we're coming up
1923524Srobj 			 * from the left
1933524Srobj 			 */
1943524Srobj 			if (tmp->lut_right != prev_child)
1953524Srobj 				(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
1963524Srobj 		} else
1973524Srobj 			return;
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate /*
2020Sstevel@tonic-gate  * lut_free -- free the lut
2030Sstevel@tonic-gate  */
2040Sstevel@tonic-gate void
lut_free(struct lut * root,lut_cb callback,void * arg)2050Sstevel@tonic-gate lut_free(struct lut *root, lut_cb callback, void *arg)
2060Sstevel@tonic-gate {
2073524Srobj 	struct lut *tmp = root;
2083524Srobj 	struct lut *prev_child = NULL;
2093524Srobj 
2103524Srobj 	if (root == NULL)
2113524Srobj 		return;
2123524Srobj 
2133524Srobj 	while (tmp->lut_left != NULL)
2143524Srobj 		tmp = tmp->lut_left;
2153524Srobj 
2163524Srobj 	/* do callback on leftmost node */
2173524Srobj 	if (callback)
2183524Srobj 		(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
2193524Srobj 
2203524Srobj 	for (;;) {
2213524Srobj 		if (tmp->lut_right != NULL && tmp->lut_right != prev_child) {
2223524Srobj 			tmp = tmp->lut_right;
2233524Srobj 			while (tmp->lut_left != NULL)
2243524Srobj 				tmp = tmp->lut_left;
2253524Srobj 
2263524Srobj 			/* do callback on leftmost node */
2273524Srobj 			if (callback)
2283524Srobj 				(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
2293524Srobj 		} else if (tmp->lut_parent != NULL) {
2303524Srobj 			prev_child = tmp;
2313524Srobj 			tmp = tmp->lut_parent;
2323524Srobj 			FREE(prev_child);
2333524Srobj 			/*
2343524Srobj 			 * do callback on parent only if we're coming up
2353524Srobj 			 * from the left
2363524Srobj 			 */
2373524Srobj 			if (tmp->lut_right != prev_child && callback)
2383524Srobj 				(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
2393524Srobj 		} else {
2403524Srobj 			/*
2413524Srobj 			 * free the root node and then we're done
2423524Srobj 			 */
2433524Srobj 			FREE(tmp);
2443524Srobj 			return;
2453524Srobj 		}
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate }
248