xref: /titanic_52/usr/src/cmd/fm/eversholt/common/lut.c (revision 6cb1ca52bfd0f546d1001d9204d8ab93039de44b)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50d10a7a8Srobj  * Common Development and Distribution License (the "License").
60d10a7a8Srobj  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
220d10a7a8Srobj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * lut.c -- simple lookup table module
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  * this file contains a very simple lookup table (lut) implementation.
287c478bd9Sstevel@tonic-gate  * the tables only support insert & lookup, no delete, and can
297c478bd9Sstevel@tonic-gate  * only be walked in one order.  if the key already exists
307c478bd9Sstevel@tonic-gate  * for something being inserted, the previous entry is simply
317c478bd9Sstevel@tonic-gate  * replaced.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <stdio.h>
377c478bd9Sstevel@tonic-gate #include "alloc.h"
387c478bd9Sstevel@tonic-gate #include "out.h"
397c478bd9Sstevel@tonic-gate #include "stats.h"
407c478bd9Sstevel@tonic-gate #include "lut.h"
41*6cb1ca52Saf #include "lut_impl.h"
427c478bd9Sstevel@tonic-gate #include "tree.h"
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static struct stats *Addtotal;
457c478bd9Sstevel@tonic-gate static struct stats *Lookuptotal;
467c478bd9Sstevel@tonic-gate static struct stats *Freetotal;
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate void
497c478bd9Sstevel@tonic-gate lut_init(void)
507c478bd9Sstevel@tonic-gate {
517c478bd9Sstevel@tonic-gate 	Addtotal = stats_new_counter("lut.adds", "total adds", 1);
527c478bd9Sstevel@tonic-gate 	Lookuptotal = stats_new_counter("lut.lookup", "total lookups", 1);
537c478bd9Sstevel@tonic-gate 	Freetotal = stats_new_counter("lut.frees", "total frees", 1);
547c478bd9Sstevel@tonic-gate }
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate void
577c478bd9Sstevel@tonic-gate lut_fini(void)
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate 	stats_delete(Addtotal);
607c478bd9Sstevel@tonic-gate 	stats_delete(Lookuptotal);
617c478bd9Sstevel@tonic-gate 	stats_delete(Freetotal);
627c478bd9Sstevel@tonic-gate }
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * lut_add -- add an entry to the table
667c478bd9Sstevel@tonic-gate  *
677c478bd9Sstevel@tonic-gate  * use it like this:
687c478bd9Sstevel@tonic-gate  *	struct lut *root = NULL;
697c478bd9Sstevel@tonic-gate  *	root = lut_add(root, key, value, cmp_func);
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  * the cmp_func can be strcmp().  pass in NULL and instead of
727c478bd9Sstevel@tonic-gate  * calling a cmp_func the routine will just look at the difference
737c478bd9Sstevel@tonic-gate  * between key pointers (useful when all strings are kept in a
747c478bd9Sstevel@tonic-gate  * string table so they are equal if their pointers are equal).
757c478bd9Sstevel@tonic-gate  *
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate struct lut *
787c478bd9Sstevel@tonic-gate lut_add(struct lut *root, void *lhs, void *rhs, lut_cmp cmp_func)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate 	int diff;
810d10a7a8Srobj 	struct lut **tmp_hdl = &root, *parent = NULL, *tmp = root;
827c478bd9Sstevel@tonic-gate 
830d10a7a8Srobj 	while (tmp) {
847c478bd9Sstevel@tonic-gate 		if (cmp_func)
850d10a7a8Srobj 			diff = (*cmp_func)(tmp->lut_lhs, lhs);
867c478bd9Sstevel@tonic-gate 		else
870d10a7a8Srobj 			diff = (const char *)lhs - (const char *)tmp->lut_lhs;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 		if (diff == 0) {
907c478bd9Sstevel@tonic-gate 			/* already in tree, replace node */
910d10a7a8Srobj 			tmp->lut_rhs = rhs;
920d10a7a8Srobj 			return (root);
930d10a7a8Srobj 		} else if (diff > 0) {
940d10a7a8Srobj 			tmp_hdl = &(tmp->lut_left);
950d10a7a8Srobj 			parent = tmp;
960d10a7a8Srobj 			tmp = tmp->lut_left;
970d10a7a8Srobj 		} else {
980d10a7a8Srobj 			tmp_hdl = &(tmp->lut_right);
990d10a7a8Srobj 			parent = tmp;
1000d10a7a8Srobj 			tmp = tmp->lut_right;
1010d10a7a8Srobj 		}
1020d10a7a8Srobj 	}
1030d10a7a8Srobj 
1040d10a7a8Srobj 	/* either empty tree or not in tree, so create new node */
1050d10a7a8Srobj 	*tmp_hdl = MALLOC(sizeof (*root));
1060d10a7a8Srobj 	(*tmp_hdl)->lut_lhs = lhs;
1070d10a7a8Srobj 	(*tmp_hdl)->lut_rhs = rhs;
1080d10a7a8Srobj 	(*tmp_hdl)->lut_parent = parent;
1090d10a7a8Srobj 	(*tmp_hdl)->lut_left = (*tmp_hdl)->lut_right = NULL;
1100d10a7a8Srobj 	stats_counter_bump(Addtotal);
1110d10a7a8Srobj 
1127c478bd9Sstevel@tonic-gate 	return (root);
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate void *
1167c478bd9Sstevel@tonic-gate lut_lookup(struct lut *root, void *lhs, lut_cmp cmp_func)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate 	int diff;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	stats_counter_bump(Lookuptotal);
1217c478bd9Sstevel@tonic-gate 
1220d10a7a8Srobj 	while (root) {
1237c478bd9Sstevel@tonic-gate 		if (cmp_func)
1247c478bd9Sstevel@tonic-gate 			diff = (*cmp_func)(root->lut_lhs, lhs);
1257c478bd9Sstevel@tonic-gate 		else
1267c478bd9Sstevel@tonic-gate 			diff = (const char *)lhs - (const char *)root->lut_lhs;
1277c478bd9Sstevel@tonic-gate 
1280d10a7a8Srobj 		if (diff == 0)
1297c478bd9Sstevel@tonic-gate 			return (root->lut_rhs);
1300d10a7a8Srobj 		else if (diff > 0)
1310d10a7a8Srobj 			root = root->lut_left;
1327c478bd9Sstevel@tonic-gate 		else
1330d10a7a8Srobj 			root = root->lut_right;
1340d10a7a8Srobj 	}
1350d10a7a8Srobj 	return (NULL);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate void *
1397c478bd9Sstevel@tonic-gate lut_lookup_lhs(struct lut *root, void *lhs, lut_cmp cmp_func)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	int diff;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	stats_counter_bump(Lookuptotal);
1447c478bd9Sstevel@tonic-gate 
1450d10a7a8Srobj 	while (root) {
1467c478bd9Sstevel@tonic-gate 		if (cmp_func)
1477c478bd9Sstevel@tonic-gate 			diff = (*cmp_func)(root->lut_lhs, lhs);
1487c478bd9Sstevel@tonic-gate 		else
1497c478bd9Sstevel@tonic-gate 			diff = (const char *)lhs - (const char *)root->lut_lhs;
1507c478bd9Sstevel@tonic-gate 
1510d10a7a8Srobj 		if (diff == 0)
1527c478bd9Sstevel@tonic-gate 			return (root->lut_lhs);
1530d10a7a8Srobj 		else if (diff > 0)
1540d10a7a8Srobj 			root = root->lut_left;
1557c478bd9Sstevel@tonic-gate 		else
1560d10a7a8Srobj 			root = root->lut_right;
1570d10a7a8Srobj 	}
1580d10a7a8Srobj 	return (NULL);
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate  * lut_walk -- walk the table in lexical order
1637c478bd9Sstevel@tonic-gate  */
1647c478bd9Sstevel@tonic-gate void
1657c478bd9Sstevel@tonic-gate lut_walk(struct lut *root, lut_cb callback, void *arg)
1667c478bd9Sstevel@tonic-gate {
1670d10a7a8Srobj 	struct lut *tmp = root;
1680d10a7a8Srobj 	struct lut *prev_child = NULL;
1690d10a7a8Srobj 
1700d10a7a8Srobj 	if (root == NULL)
1710d10a7a8Srobj 		return;
1720d10a7a8Srobj 
1730d10a7a8Srobj 	while (tmp->lut_left != NULL)
1740d10a7a8Srobj 		tmp = tmp->lut_left;
1750d10a7a8Srobj 
1760d10a7a8Srobj 	/* do callback on leftmost node */
1770d10a7a8Srobj 	(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
1780d10a7a8Srobj 
1790d10a7a8Srobj 	for (;;) {
1800d10a7a8Srobj 		if (tmp->lut_right != NULL && tmp->lut_right != prev_child) {
1810d10a7a8Srobj 			tmp = tmp->lut_right;
1820d10a7a8Srobj 			while (tmp->lut_left != NULL)
1830d10a7a8Srobj 				tmp = tmp->lut_left;
1840d10a7a8Srobj 
1850d10a7a8Srobj 			/* do callback on leftmost node */
1860d10a7a8Srobj 			(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
1870d10a7a8Srobj 		} else if (tmp->lut_parent != NULL) {
1880d10a7a8Srobj 			prev_child = tmp;
1890d10a7a8Srobj 			tmp = tmp->lut_parent;
1900d10a7a8Srobj 			/*
1910d10a7a8Srobj 			 * do callback on parent only if we're coming up
1920d10a7a8Srobj 			 * from the left
1930d10a7a8Srobj 			 */
1940d10a7a8Srobj 			if (tmp->lut_right != prev_child)
1950d10a7a8Srobj 				(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
1960d10a7a8Srobj 		} else
1970d10a7a8Srobj 			return;
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * lut_free -- free the lut
2037c478bd9Sstevel@tonic-gate  */
2047c478bd9Sstevel@tonic-gate void
2057c478bd9Sstevel@tonic-gate lut_free(struct lut *root, lut_cb callback, void *arg)
2067c478bd9Sstevel@tonic-gate {
2070d10a7a8Srobj 	struct lut *tmp = root;
2080d10a7a8Srobj 	struct lut *prev_child = NULL;
2090d10a7a8Srobj 
2100d10a7a8Srobj 	if (root == NULL)
2110d10a7a8Srobj 		return;
2120d10a7a8Srobj 
2130d10a7a8Srobj 	while (tmp->lut_left != NULL)
2140d10a7a8Srobj 		tmp = tmp->lut_left;
2150d10a7a8Srobj 
2160d10a7a8Srobj 	/* do callback on leftmost node */
2177c478bd9Sstevel@tonic-gate 	if (callback)
2180d10a7a8Srobj 		(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
2190d10a7a8Srobj 
2200d10a7a8Srobj 	for (;;) {
2210d10a7a8Srobj 		if (tmp->lut_right != NULL && tmp->lut_right != prev_child) {
2220d10a7a8Srobj 			tmp = tmp->lut_right;
2230d10a7a8Srobj 			while (tmp->lut_left != NULL)
2240d10a7a8Srobj 				tmp = tmp->lut_left;
2250d10a7a8Srobj 
2260d10a7a8Srobj 			/* do callback on leftmost node */
2270d10a7a8Srobj 			if (callback)
2280d10a7a8Srobj 				(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
2290d10a7a8Srobj 		} else if (tmp->lut_parent != NULL) {
2300d10a7a8Srobj 			prev_child = tmp;
2310d10a7a8Srobj 			tmp = tmp->lut_parent;
2320d10a7a8Srobj 			FREE(prev_child);
2330d10a7a8Srobj 			/*
2340d10a7a8Srobj 			 * do callback on parent only if we're coming up
2350d10a7a8Srobj 			 * from the left
2360d10a7a8Srobj 			 */
2370d10a7a8Srobj 			if (tmp->lut_right != prev_child && callback)
2380d10a7a8Srobj 				(*callback)(tmp->lut_lhs, tmp->lut_rhs, arg);
2390d10a7a8Srobj 		} else {
2400d10a7a8Srobj 			/*
2410d10a7a8Srobj 			 * free the root node and then we're done
2420d10a7a8Srobj 			 */
2430d10a7a8Srobj 			FREE(tmp);
2440d10a7a8Srobj 			return;
2450d10a7a8Srobj 		}
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate }
248