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	"@(#)alist.c	1.4	05/06/08 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, alist_el_t *el)
56{
57	uintptr_t num = (uintptr_t)el->ale_name;
58
59	return (num % nbuckets);
60}
61
62static int
63alist_cmp(alist_el_t *el1, alist_el_t *el2)
64{
65	return ((uintptr_t)el1->ale_name != (uintptr_t)el2->ale_name);
66}
67
68alist_t *
69alist_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
83alist_t *
84alist_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
90static void
91alist_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
100void
101alist_free(alist_t *alist)
102{
103	hash_free(alist->al_elements, (void (*)())alist_free_cb, alist);
104	free(alist);
105}
106
107void
108alist_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
118int
119alist_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
133typedef struct alist_iter_data {
134	int (*aid_func)(void *, void *, void *);
135	void *aid_priv;
136} alist_iter_data_t;
137
138static int
139alist_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
144int
145alist_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
159void
160alist_stats(alist_t *alist, int verbose)
161{
162	printf("Alist statistics\n");
163	hash_stats(alist->al_elements, verbose);
164}
165
166static int alist_def_print_cb_key_int = 1;
167static int alist_def_print_cb_value_int = 1;
168
169static int
170alist_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
187static int
188alist_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
198int
199alist_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}
206