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