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
lut_init(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
lut_fini(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 *
lut_add(struct lut * root,void * lhs,void * rhs,lut_cmp cmp_func)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 *
lut_lookup(struct lut * root,void * lhs,lut_cmp cmp_func)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 *
lut_lookup_lhs(struct lut * root,void * lhs,lut_cmp cmp_func)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
lut_walk(struct lut * root,lut_cb callback,void * arg)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
lut_free(struct lut * root,lut_cb callback,void * arg)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