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