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