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