1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 /*
  30  * Create, manage, and destroy association lists.  alists are arrays with
  31  * arbitrary index types, and are also commonly known as associative arrays.
  32  */
  33 
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 
  37 #include "alist.h"
  38 #include "memory.h"
  39 #include "hash.h"
  40 
  41 #define ALIST_HASH_SIZE 997
  42 
  43 struct alist {
  44         hash_t *al_elements;
  45         void (*al_namefree)(void *);
  46         void (*al_valfree)(void *);
  47 };
  48 
  49 typedef struct alist_el {
  50         void *ale_name;
  51         void *ale_value;
  52 } alist_el_t;
  53 
  54 static int
  55 alist_hash(int nbuckets, alist_el_t *el)
  56 {
  57         uintptr_t num = (uintptr_t)el->ale_name;
  58 
  59         return (num % nbuckets);
  60 }
  61 
  62 static int
  63 alist_cmp(alist_el_t *el1, alist_el_t *el2)
  64 {
  65         return ((uintptr_t)el1->ale_name != (uintptr_t)el2->ale_name);
  66 }
  67 
  68 alist_t *
  69 alist_xnew(int nbuckets, void (*namefree)(void *),
  70     void (*valfree)(void *), int (*hashfn)(int, void *),
  71     int (*cmpfn)(void *, void *))
  72 {
  73         alist_t *alist;
  74 
  75         alist = xcalloc(sizeof (alist_t));
  76         alist->al_elements = hash_new(nbuckets, hashfn, cmpfn);
  77         alist->al_namefree = namefree;
  78         alist->al_valfree = valfree;
  79 
  80         return (alist);
  81 }
  82 
  83 alist_t *
  84 alist_new(void (*namefree)(void *), void (*valfree)(void *))
  85 {
  86         return (alist_xnew(ALIST_HASH_SIZE, namefree, valfree,
  87             (int (*)())alist_hash, (int (*)())alist_cmp));
  88 }
  89 
  90 static void
  91 alist_free_cb(alist_el_t *el, alist_t *alist)
  92 {
  93         if (alist->al_namefree)
  94                 alist->al_namefree(el->ale_name);
  95         if (alist->al_valfree)
  96                 alist->al_valfree(el->ale_name);
  97         free(el);
  98 }
  99 
 100 void
 101 alist_free(alist_t *alist)
 102 {
 103         hash_free(alist->al_elements, (void (*)())alist_free_cb, alist);
 104         free(alist);
 105 }
 106 
 107 void
 108 alist_add(alist_t *alist, void *name, void *value)
 109 {
 110         alist_el_t *el;
 111 
 112         el = xmalloc(sizeof (alist_el_t));
 113         el->ale_name = name;
 114         el->ale_value = value;
 115         hash_add(alist->al_elements, el);
 116 }
 117 
 118 int
 119 alist_find(alist_t *alist, void *name, void **value)
 120 {
 121         alist_el_t template, *ret;
 122 
 123         template.ale_name = name;
 124         if (!hash_find(alist->al_elements, &template, (void **)&ret))
 125                 return (0);
 126 
 127         if (value)
 128                 *value = ret->ale_value;
 129 
 130         return (1);
 131 }
 132 
 133 typedef struct alist_iter_data {
 134         int (*aid_func)(void *, void *, void *);
 135         void *aid_priv;
 136 } alist_iter_data_t;
 137 
 138 static int
 139 alist_iter_cb(alist_el_t *el, alist_iter_data_t *aid)
 140 {
 141         return (aid->aid_func(el->ale_name, el->ale_value, aid->aid_priv));
 142 }
 143 
 144 int
 145 alist_iter(alist_t *alist, int (*func)(void *, void *, void *), void *private)
 146 {
 147         alist_iter_data_t aid;
 148 
 149         aid.aid_func = func;
 150         aid.aid_priv = private;
 151 
 152         return (hash_iter(alist->al_elements, (int (*)())alist_iter_cb, &aid));
 153 }
 154 
 155 /*
 156  * Debugging support.  Used to print the contents of an alist.
 157  */
 158 
 159 void
 160 alist_stats(alist_t *alist, int verbose)
 161 {
 162         printf("Alist statistics\n");
 163         hash_stats(alist->al_elements, verbose);
 164 }
 165 
 166 static int alist_def_print_cb_key_int = 1;
 167 static int alist_def_print_cb_value_int = 1;
 168 
 169 static int
 170 alist_def_print_cb(void *key, void *value)
 171 {
 172         printf("Key: ");
 173         if (alist_def_print_cb_key_int == 1)
 174                 printf("%5d ", (int)key);
 175         else
 176                 printf("%s\n", (char *)key);
 177 
 178         printf("Value: ");
 179         if (alist_def_print_cb_value_int == 1)
 180                 printf("%5d\n", (int)value);
 181         else
 182                 printf("%s\n", (char *)key);
 183 
 184         return (1);
 185 }
 186 
 187 static int
 188 alist_dump_cb(void *node, void *private)
 189 {
 190         int (*printer)(void *, void *) = (int (*)())private;
 191         alist_el_t *el = node;
 192 
 193         printer(el->ale_name, el->ale_value);
 194 
 195         return (1);
 196 }
 197 
 198 int
 199 alist_dump(alist_t *alist, int (*printer)(void *, void *))
 200 {
 201         if (!printer)
 202                 printer = alist_def_print_cb;
 203 
 204         return (hash_iter(alist->al_elements, alist_dump_cb, (void *)printer));
 205 }