xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/base/dict.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
1*d3273b5bSchristos /*	$NetBSD: dict.c,v 1.2 2017/01/28 21:31:45 christos Exp $	*/
2b9d004c6Schristos 
3b9d004c6Schristos /*
4b9d004c6Schristos  * Copyright (c) 2002, 1997 Kungliga Tekniska Högskolan
5b9d004c6Schristos  * (Royal Institute of Technology, Stockholm, Sweden).
6b9d004c6Schristos  * All rights reserved.
7b9d004c6Schristos  *
8b9d004c6Schristos  * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
9b9d004c6Schristos  *
10b9d004c6Schristos  * Redistribution and use in source and binary forms, with or without
11b9d004c6Schristos  * modification, are permitted provided that the following conditions
12b9d004c6Schristos  * are met:
13b9d004c6Schristos  *
14b9d004c6Schristos  * 1. Redistributions of source code must retain the above copyright
15b9d004c6Schristos  *    notice, this list of conditions and the following disclaimer.
16b9d004c6Schristos  *
17b9d004c6Schristos  * 2. Redistributions in binary form must reproduce the above copyright
18b9d004c6Schristos  *    notice, this list of conditions and the following disclaimer in the
19b9d004c6Schristos  *    documentation and/or other materials provided with the distribution.
20b9d004c6Schristos  *
21b9d004c6Schristos  * 3. Neither the name of the Institute nor the names of its contributors
22b9d004c6Schristos  *    may be used to endorse or promote products derived from this software
23b9d004c6Schristos  *    without specific prior written permission.
24b9d004c6Schristos  *
25b9d004c6Schristos  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26b9d004c6Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27b9d004c6Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28b9d004c6Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29b9d004c6Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30b9d004c6Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31b9d004c6Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32b9d004c6Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33b9d004c6Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34b9d004c6Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35b9d004c6Schristos  * SUCH DAMAGE.
36b9d004c6Schristos  */
37b9d004c6Schristos 
38b9d004c6Schristos #include "baselocl.h"
39b9d004c6Schristos 
40b9d004c6Schristos struct hashentry {
41b9d004c6Schristos     struct hashentry **prev;
42b9d004c6Schristos     struct hashentry *next;
43b9d004c6Schristos     heim_object_t key;
44b9d004c6Schristos     heim_object_t value;
45b9d004c6Schristos };
46b9d004c6Schristos 
47b9d004c6Schristos struct heim_dict_data {
48b9d004c6Schristos     size_t size;
49b9d004c6Schristos     struct hashentry **tab;
50b9d004c6Schristos };
51b9d004c6Schristos 
52b9d004c6Schristos static void
dict_dealloc(void * ptr)53b9d004c6Schristos dict_dealloc(void *ptr)
54b9d004c6Schristos {
55b9d004c6Schristos     heim_dict_t dict = ptr;
56b9d004c6Schristos     struct hashentry **h, *g, *i;
57b9d004c6Schristos 
58b9d004c6Schristos     for (h = dict->tab; h < &dict->tab[dict->size]; ++h) {
59b9d004c6Schristos 	for (g = h[0]; g; g = i) {
60b9d004c6Schristos 	    i = g->next;
61b9d004c6Schristos 	    heim_release(g->key);
62b9d004c6Schristos 	    heim_release(g->value);
63b9d004c6Schristos 	    free(g);
64b9d004c6Schristos 	}
65b9d004c6Schristos     }
66b9d004c6Schristos     free(dict->tab);
67b9d004c6Schristos }
68b9d004c6Schristos 
69b9d004c6Schristos struct heim_type_data dict_object = {
70b9d004c6Schristos     HEIM_TID_DICT,
71b9d004c6Schristos     "dict-object",
72b9d004c6Schristos     NULL,
73b9d004c6Schristos     dict_dealloc,
74b9d004c6Schristos     NULL,
75b9d004c6Schristos     NULL,
76b9d004c6Schristos     NULL,
77b9d004c6Schristos     NULL
78b9d004c6Schristos };
79b9d004c6Schristos 
80b9d004c6Schristos static size_t
isprime(size_t p)81b9d004c6Schristos isprime(size_t p)
82b9d004c6Schristos {
83b9d004c6Schristos     size_t q, i;
84b9d004c6Schristos 
85b9d004c6Schristos     for(i = 2 ; i < p; i++) {
86b9d004c6Schristos 	q = p / i;
87b9d004c6Schristos 
88b9d004c6Schristos 	if (i * q == p)
89b9d004c6Schristos 	    return 0;
90b9d004c6Schristos 	if (i * i > p)
91b9d004c6Schristos 	    return 1;
92b9d004c6Schristos     }
93b9d004c6Schristos     return 1;
94b9d004c6Schristos }
95b9d004c6Schristos 
96b9d004c6Schristos static size_t
findprime(size_t p)97b9d004c6Schristos findprime(size_t p)
98b9d004c6Schristos {
99b9d004c6Schristos     if (p % 2 == 0)
100b9d004c6Schristos 	p++;
101b9d004c6Schristos 
102b9d004c6Schristos     while (isprime(p) == 0)
103b9d004c6Schristos 	p += 2;
104b9d004c6Schristos 
105b9d004c6Schristos     return p;
106b9d004c6Schristos }
107b9d004c6Schristos 
108b9d004c6Schristos /**
109b9d004c6Schristos  * Allocate an array
110b9d004c6Schristos  *
111b9d004c6Schristos  * @return A new allocated array, free with heim_release()
112b9d004c6Schristos  */
113b9d004c6Schristos 
114b9d004c6Schristos heim_dict_t
heim_dict_create(size_t size)115b9d004c6Schristos heim_dict_create(size_t size)
116b9d004c6Schristos {
117b9d004c6Schristos     heim_dict_t dict;
118b9d004c6Schristos 
119b9d004c6Schristos     dict = _heim_alloc_object(&dict_object, sizeof(*dict));
120b9d004c6Schristos 
121b9d004c6Schristos     dict->size = findprime(size);
122b9d004c6Schristos     if (dict->size == 0) {
123b9d004c6Schristos 	heim_release(dict);
124b9d004c6Schristos 	return NULL;
125b9d004c6Schristos     }
126b9d004c6Schristos 
127b9d004c6Schristos     dict->tab = calloc(dict->size, sizeof(dict->tab[0]));
128b9d004c6Schristos     if (dict->tab == NULL) {
129b9d004c6Schristos 	dict->size = 0;
130b9d004c6Schristos 	heim_release(dict);
131b9d004c6Schristos 	return NULL;
132b9d004c6Schristos     }
133b9d004c6Schristos 
134b9d004c6Schristos     return dict;
135b9d004c6Schristos }
136b9d004c6Schristos 
137b9d004c6Schristos /**
138b9d004c6Schristos  * Get type id of an dict
139b9d004c6Schristos  *
140b9d004c6Schristos  * @return the type id
141b9d004c6Schristos  */
142b9d004c6Schristos 
143b9d004c6Schristos heim_tid_t
heim_dict_get_type_id(void)144b9d004c6Schristos heim_dict_get_type_id(void)
145b9d004c6Schristos {
146b9d004c6Schristos     return HEIM_TID_DICT;
147b9d004c6Schristos }
148b9d004c6Schristos 
149b9d004c6Schristos /* Intern search function */
150b9d004c6Schristos 
151b9d004c6Schristos static struct hashentry *
_search(heim_dict_t dict,heim_object_t ptr)152b9d004c6Schristos _search(heim_dict_t dict, heim_object_t ptr)
153b9d004c6Schristos {
154b9d004c6Schristos     unsigned long v = heim_get_hash(ptr);
155b9d004c6Schristos     struct hashentry *p;
156b9d004c6Schristos 
157b9d004c6Schristos     for (p = dict->tab[v % dict->size]; p != NULL; p = p->next)
158b9d004c6Schristos 	if (heim_cmp(ptr, p->key) == 0)
159b9d004c6Schristos 	    return p;
160b9d004c6Schristos 
161b9d004c6Schristos     return NULL;
162b9d004c6Schristos }
163b9d004c6Schristos 
164b9d004c6Schristos /**
165b9d004c6Schristos  * Search for element in hash table
166b9d004c6Schristos  *
167b9d004c6Schristos  * @value dict the dict to search in
168b9d004c6Schristos  * @value key the key to search for
169b9d004c6Schristos  *
170b9d004c6Schristos  * @return a not-retained copy of the value for key or NULL if not found
171b9d004c6Schristos  */
172b9d004c6Schristos 
173b9d004c6Schristos heim_object_t
heim_dict_get_value(heim_dict_t dict,heim_object_t key)174b9d004c6Schristos heim_dict_get_value(heim_dict_t dict, heim_object_t key)
175b9d004c6Schristos {
176b9d004c6Schristos     struct hashentry *p;
177b9d004c6Schristos     p = _search(dict, key);
178b9d004c6Schristos     if (p == NULL)
179b9d004c6Schristos 	return NULL;
180b9d004c6Schristos 
181b9d004c6Schristos     return p->value;
182b9d004c6Schristos }
183b9d004c6Schristos 
184b9d004c6Schristos /**
185b9d004c6Schristos  * Search for element in hash table
186b9d004c6Schristos  *
187b9d004c6Schristos  * @value dict the dict to search in
188b9d004c6Schristos  * @value key the key to search for
189b9d004c6Schristos  *
190b9d004c6Schristos  * @return a retained copy of the value for key or NULL if not found
191b9d004c6Schristos  */
192b9d004c6Schristos 
193b9d004c6Schristos heim_object_t
heim_dict_copy_value(heim_dict_t dict,heim_object_t key)194b9d004c6Schristos heim_dict_copy_value(heim_dict_t dict, heim_object_t key)
195b9d004c6Schristos {
196b9d004c6Schristos     struct hashentry *p;
197b9d004c6Schristos     p = _search(dict, key);
198b9d004c6Schristos     if (p == NULL)
199b9d004c6Schristos 	return NULL;
200b9d004c6Schristos 
201b9d004c6Schristos     return heim_retain(p->value);
202b9d004c6Schristos }
203b9d004c6Schristos 
204b9d004c6Schristos /**
205b9d004c6Schristos  * Add key and value to dict
206b9d004c6Schristos  *
207b9d004c6Schristos  * @value dict the dict to add too
208b9d004c6Schristos  * @value key the key to add
209b9d004c6Schristos  * @value value the value to add
210b9d004c6Schristos  *
211b9d004c6Schristos  * @return 0 if added, errno if not
212b9d004c6Schristos  */
213b9d004c6Schristos 
214b9d004c6Schristos int
heim_dict_set_value(heim_dict_t dict,heim_object_t key,heim_object_t value)215b9d004c6Schristos heim_dict_set_value(heim_dict_t dict, heim_object_t key, heim_object_t value)
216b9d004c6Schristos {
217b9d004c6Schristos     struct hashentry **tabptr, *h;
218b9d004c6Schristos 
219b9d004c6Schristos     h = _search(dict, key);
220b9d004c6Schristos     if (h) {
221b9d004c6Schristos 	heim_release(h->value);
222b9d004c6Schristos 	h->value = heim_retain(value);
223b9d004c6Schristos     } else {
224b9d004c6Schristos 	unsigned long v;
225b9d004c6Schristos 
226b9d004c6Schristos 	h = malloc(sizeof(*h));
227b9d004c6Schristos 	if (h == NULL)
228b9d004c6Schristos 	    return ENOMEM;
229b9d004c6Schristos 
230b9d004c6Schristos 	h->key = heim_retain(key);
231b9d004c6Schristos 	h->value = heim_retain(value);
232b9d004c6Schristos 
233b9d004c6Schristos 	v = heim_get_hash(key);
234b9d004c6Schristos 
235b9d004c6Schristos 	tabptr = &dict->tab[v % dict->size];
236b9d004c6Schristos 	h->next = *tabptr;
237b9d004c6Schristos 	*tabptr = h;
238b9d004c6Schristos 	h->prev = tabptr;
239b9d004c6Schristos 	if (h->next)
240b9d004c6Schristos 	    h->next->prev = &h->next;
241b9d004c6Schristos     }
242b9d004c6Schristos 
243b9d004c6Schristos     return 0;
244b9d004c6Schristos }
245b9d004c6Schristos 
246b9d004c6Schristos /**
247b9d004c6Schristos  * Delete element with key key
248b9d004c6Schristos  *
249b9d004c6Schristos  * @value dict the dict to delete from
250b9d004c6Schristos  * @value key the key to delete
251b9d004c6Schristos  */
252b9d004c6Schristos 
253b9d004c6Schristos void
heim_dict_delete_key(heim_dict_t dict,heim_object_t key)254b9d004c6Schristos heim_dict_delete_key(heim_dict_t dict, heim_object_t key)
255b9d004c6Schristos {
256b9d004c6Schristos     struct hashentry *h = _search(dict, key);
257b9d004c6Schristos 
258b9d004c6Schristos     if (h == NULL)
259b9d004c6Schristos 	return;
260b9d004c6Schristos 
261b9d004c6Schristos     heim_release(h->key);
262b9d004c6Schristos     heim_release(h->value);
263b9d004c6Schristos 
264b9d004c6Schristos     if ((*(h->prev) = h->next) != NULL)
265b9d004c6Schristos 	h->next->prev = h->prev;
266b9d004c6Schristos 
267b9d004c6Schristos     free(h);
268b9d004c6Schristos }
269b9d004c6Schristos 
270b9d004c6Schristos /**
271b9d004c6Schristos  * Do something for each element
272b9d004c6Schristos  *
273b9d004c6Schristos  * @value dict the dict to interate over
274b9d004c6Schristos  * @value func the function to search for
275b9d004c6Schristos  * @value arg argument to func
276b9d004c6Schristos  */
277b9d004c6Schristos 
278b9d004c6Schristos void
heim_dict_iterate_f(heim_dict_t dict,void * arg,heim_dict_iterator_f_t func)279b9d004c6Schristos heim_dict_iterate_f(heim_dict_t dict, void *arg, heim_dict_iterator_f_t func)
280b9d004c6Schristos {
281b9d004c6Schristos     struct hashentry **h, *g;
282b9d004c6Schristos 
283b9d004c6Schristos     for (h = dict->tab; h < &dict->tab[dict->size]; ++h)
284b9d004c6Schristos 	for (g = *h; g; g = g->next)
285b9d004c6Schristos 	    func(g->key, g->value, arg);
286b9d004c6Schristos }
287b9d004c6Schristos 
288b9d004c6Schristos #ifdef __BLOCKS__
289b9d004c6Schristos /**
290b9d004c6Schristos  * Do something for each element
291b9d004c6Schristos  *
292b9d004c6Schristos  * @value dict the dict to interate over
293b9d004c6Schristos  * @value func the function to search for
294b9d004c6Schristos  */
295b9d004c6Schristos 
296b9d004c6Schristos void
297b9d004c6Schristos heim_dict_iterate(heim_dict_t dict, void (^func)(heim_object_t, heim_object_t))
298b9d004c6Schristos {
299b9d004c6Schristos     struct hashentry **h, *g;
300b9d004c6Schristos 
301b9d004c6Schristos     for (h = dict->tab; h < &dict->tab[dict->size]; ++h)
302b9d004c6Schristos 	for (g = *h; g; g = g->next)
303b9d004c6Schristos 	    func(g->key, g->value);
304b9d004c6Schristos }
305b9d004c6Schristos #endif
306