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