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
43struct alist {
44	hash_t *al_elements;
45	void (*al_namefree)(void *);
46	void (*al_valfree)(void *);
47};
48
49typedef struct alist_el {
50	void *ale_name;
51	void *ale_value;
52} alist_el_t;
53
54static int
55alist_hash(int nbuckets, void *arg)
56{
57	alist_el_t *el = arg;
58	uintptr_t num = (uintptr_t)el->ale_name;
59
60	return (num % nbuckets);
61}
62
63static int
64alist_cmp(void *arg1, void *arg2)
65{
66	alist_el_t *el1 = arg1;
67	alist_el_t *el2 = arg2;
68	return ((uintptr_t)el1->ale_name != (uintptr_t)el2->ale_name);
69}
70
71alist_t *
72alist_xnew(int nbuckets, void (*namefree)(void *),
73    void (*valfree)(void *), int (*hashfn)(int, void *),
74    int (*cmpfn)(void *, void *))
75{
76	alist_t *alist;
77
78	alist = xcalloc(sizeof (alist_t));
79	alist->al_elements = hash_new(nbuckets, hashfn, cmpfn);
80	alist->al_namefree = namefree;
81	alist->al_valfree = valfree;
82
83	return (alist);
84}
85
86alist_t *
87alist_new(void (*namefree)(void *), void (*valfree)(void *))
88{
89	return (alist_xnew(ALIST_HASH_SIZE, namefree, valfree,
90	    alist_hash, alist_cmp));
91}
92
93static void
94alist_free_cb(void *arg1, void *arg2)
95{
96	alist_el_t *el = arg1;
97	alist_t *alist = arg2;
98	if (alist->al_namefree)
99		alist->al_namefree(el->ale_name);
100	if (alist->al_valfree)
101		alist->al_valfree(el->ale_name);
102	free(el);
103}
104
105void
106alist_free(alist_t *alist)
107{
108	hash_free(alist->al_elements, alist_free_cb, alist);
109	free(alist);
110}
111
112void
113alist_add(alist_t *alist, void *name, void *value)
114{
115	alist_el_t *el;
116
117	el = xmalloc(sizeof (alist_el_t));
118	el->ale_name = name;
119	el->ale_value = value;
120	hash_add(alist->al_elements, el);
121}
122
123int
124alist_find(alist_t *alist, void *name, void **value)
125{
126	alist_el_t template, *retx;
127	void *ret;
128
129	template.ale_name = name;
130	if (!hash_find(alist->al_elements, &template, &ret))
131		return (0);
132
133	if (value) {
134		retx = ret;
135		*value = retx->ale_value;
136	}
137
138	return (1);
139}
140
141typedef struct alist_iter_data {
142	int (*aid_func)(void *, void *, void *);
143	void *aid_priv;
144} alist_iter_data_t;
145
146static int
147alist_iter_cb(void *arg1, void *arg2)
148{
149	alist_el_t *el = arg1;
150	alist_iter_data_t *aid = arg2;
151	return (aid->aid_func(el->ale_name, el->ale_value, aid->aid_priv));
152}
153
154int
155alist_iter(alist_t *alist, int (*func)(void *, void *, void *), void *private)
156{
157	alist_iter_data_t aid;
158
159	aid.aid_func = func;
160	aid.aid_priv = private;
161
162	return (hash_iter(alist->al_elements, alist_iter_cb, &aid));
163}
164
165/*
166 * Debugging support.  Used to print the contents of an alist.
167 */
168
169void
170alist_stats(alist_t *alist, int verbose)
171{
172	printf("Alist statistics\n");
173	hash_stats(alist->al_elements, verbose);
174}
175
176static int alist_def_print_cb_key_int = 1;
177static int alist_def_print_cb_value_int = 1;
178
179static int
180alist_def_print_cb(void *key, void *value)
181{
182	printf("Key: ");
183	if (alist_def_print_cb_key_int == 1)
184		printf("%5lu ", (ulong_t)key);
185	else
186		printf("%s\n", (char *)key);
187
188	printf("Value: ");
189	if (alist_def_print_cb_value_int == 1)
190		printf("%5lu\n", (ulong_t)value);
191	else
192		printf("%s\n", (char *)key);
193
194	return (1);
195}
196
197static int
198alist_dump_cb(void *node, void *private)
199{
200	int (*printer)(void *, void *) = private;
201	alist_el_t *el = node;
202
203	printer(el->ale_name, el->ale_value);
204
205	return (1);
206}
207
208int
209alist_dump(alist_t *alist, int (*printer)(void *, void *))
210{
211	if (!printer)
212		printer = alist_def_print_cb;
213
214	return (hash_iter(alist->al_elements, alist_dump_cb, (void *)printer));
215}
216