HAMMER VFS - Hack cursor iterator when locked cursor moved to parent
[dragonfly.git] / usr.sbin / installer / libaura / dict.c
blob3e36fd9a91caff2751b45ca5a39db7edc9be753d
1 /*
2 * Copyright (c) 2004 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Chris Pressey <cpressey@catseye.mine.nu>.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
36 * dict.c
37 * $Id: dict.c,v 1.4 2005/02/06 06:57:30 cpressey Exp $
38 * Routines to manipulate dictionaries.
41 #include <stdlib.h>
42 #include <string.h>
44 #include "mem.h"
46 #include "dict.h"
48 /*** INTERNAL PROTOTYPES ***/
50 size_t hashpjw(const void *key, size_t key_size, size_t table_size);
51 int keycmp(const void *key, size_t key_size, struct aura_bucket *b);
53 struct aura_bucket *aura_bucket_new(const void *key, size_t key_size,
54 const void *data, size_t data_size);
55 void aura_bucket_free(struct aura_bucket *b);
56 void aura_dict_locate_hash(struct aura_dict *d, const void *key, size_t key_size,
57 size_t *b_index, struct aura_bucket **b);
58 void aura_dict_locate_list(struct aura_dict *d, const void *key, size_t key_size,
59 struct aura_bucket **b);
60 void aura_dict_advance(struct aura_dict *d);
62 void aura_dict_fetch_hash(struct aura_dict *d, const void *key, size_t key_size,
63 void **data, size_t *data_size);
64 void aura_dict_store_hash(struct aura_dict *d, const void *key, size_t key_size,
65 const void *data, size_t data_size);
66 void aura_dict_fetch_list(struct aura_dict *d, const void *key, size_t key_size,
67 void **data, size_t *data_size);
68 void aura_dict_store_list(struct aura_dict *d, const void *key, size_t key_size,
69 const void *data, size_t data_size);
70 void aura_dict_store_list_sorted(struct aura_dict *d, const void *key, size_t key_size,
71 const void *data, size_t data_size);
73 /*** CONSTRUCTOR ***/
76 * Create a new dictionary with the given number of buckets.
78 struct aura_dict *
79 aura_dict_new(size_t num_buckets, int method)
81 struct aura_dict *d;
82 size_t i;
84 AURA_MALLOC(d, aura_dict);
86 d->num_buckets = num_buckets;
87 d->b = malloc(sizeof(struct bucket *) * num_buckets);
88 for (i = 0; i < num_buckets; i++) {
89 d->b[i] = NULL;
91 d->cursor = NULL;
92 d->cur_bucket = 0;
94 switch (method) {
95 case AURA_DICT_HASH:
96 d->fetch = aura_dict_fetch_hash;
97 d->store = aura_dict_store_hash;
98 break;
99 case AURA_DICT_LIST:
100 d->fetch = aura_dict_fetch_list;
101 d->store = aura_dict_store_list;
102 break;
103 case AURA_DICT_SORTED_LIST:
104 d->fetch = aura_dict_fetch_list;
105 d->store = aura_dict_store_list_sorted;
106 break;
109 return(d);
112 /*** DESTRUCTORS ***/
114 void
115 aura_bucket_free(struct aura_bucket *b)
117 if (b == NULL)
118 return;
119 if (b->key != NULL)
120 free(b->key);
121 if (b->data != NULL)
122 free(b->data);
123 AURA_FREE(b, aura_bucket);
126 void
127 aura_dict_free(struct aura_dict *d)
129 struct aura_bucket *b;
130 size_t bucket_no = 0;
132 while (bucket_no < d->num_buckets) {
133 b = d->b[bucket_no];
134 while (b != NULL) {
135 d->b[bucket_no] = b->next;
136 aura_bucket_free(b);
137 b = d->b[bucket_no];
139 bucket_no++;
141 AURA_FREE(d, aura_dict);
144 /*** UTILITIES ***/
147 * Hash function, taken from "Compilers: Principles, Techniques, and Tools"
148 * by Aho, Sethi, & Ullman (a.k.a. "The Dragon Book", 2nd edition.)
150 size_t
151 hashpjw(const void *key, size_t key_size, size_t table_size) {
152 const char *k = (const char *)key;
153 const char *p;
154 size_t h = 0, g;
156 for (p = k; p < k + key_size; p++) {
157 h = (h << 4) + (*p);
158 if ((g = h & 0xf0000000))
159 h = (h ^ (g >> 24)) ^ g;
162 return(h % table_size);
166 * Create a new bucket (not called directly by client code.)
167 * Uses a copy of key and data for the bucket, so the dictionary
168 * code is responsible for cleaning it up itself.
170 struct aura_bucket *
171 aura_bucket_new(const void *key, size_t key_size, const void *data, size_t data_size)
173 struct aura_bucket *b;
175 AURA_MALLOC(b, aura_bucket);
177 b->next = NULL;
178 b->key = aura_malloc(key_size, "dictionary key");
179 memcpy(b->key, key, key_size);
180 b->key_size = key_size;
181 b->data = aura_malloc(data_size, "dictionary value");
182 memcpy(b->data, data, data_size);
183 b->data_size = data_size;
185 return(b);
189 * Locate the bucket number a particular key would be located in, and the
190 * bucket itself if such a key exists (or NULL if it could not be found.)
192 void
193 aura_dict_locate_hash(struct aura_dict *d, const void *key, size_t key_size,
194 size_t *b_index, struct aura_bucket **b)
196 *b_index = hashpjw(key, key_size, d->num_buckets);
197 for (*b = d->b[*b_index]; *b != NULL; *b = (*b)->next) {
198 if (key_size == (*b)->key_size && memcmp(key, (*b)->key, key_size) == 0)
199 break;
204 * Locate the bucket a particular key would be located in
205 * if such a key exists (or NULL if it could not be found.)
207 void
208 aura_dict_locate_list(struct aura_dict *d, const void *key, size_t key_size,
209 struct aura_bucket **b)
211 for (*b = d->b[0]; *b != NULL; *b = (*b)->next) {
212 if (key_size == (*b)->key_size && memcmp(key, (*b)->key, key_size) == 0)
213 break;
217 /*** IMPLEMENTATIONS ***/
219 /***** HASH TABLE *****/
221 void
222 aura_dict_fetch_hash(struct aura_dict *d, const void *key, size_t key_size,
223 void **data, size_t *data_size)
225 struct aura_bucket *b;
226 size_t i;
228 aura_dict_locate_hash(d, key, key_size, &i, &b);
229 if (b != NULL) {
230 *data = b->data;
231 *data_size = b->data_size;
232 } else {
233 *data = NULL;
237 void
238 aura_dict_store_hash(struct aura_dict *d, const void *key, size_t key_size,
239 const void *data, size_t data_size)
241 struct aura_bucket *b;
242 size_t i;
244 aura_dict_locate_hash(d, key, key_size, &i, &b);
245 if (b == NULL) {
246 /* Bucket does not exist, add a new one. */
247 b = aura_bucket_new(key, key_size, data, data_size);
248 b->next = d->b[i];
249 d->b[i] = b;
250 } else {
251 /* Bucket already exists, replace the value. */
252 aura_free(b->data, "dictionary value");
253 b->data = aura_malloc(data_size, "dictionary value");
254 memcpy(b->data, data, data_size);
255 b->data_size = data_size;
259 /***** LIST *****/
261 void
262 aura_dict_fetch_list(struct aura_dict *d, const void *key, size_t key_size,
263 void **data, size_t *data_size)
265 struct aura_bucket *b;
267 for (b = d->b[0]; b != NULL; b = b->next) {
268 if (key_size == b->key_size && memcmp(key, b->key, key_size) == 0) {
269 *data = b->data;
270 *data_size = b->data_size;
271 return;
274 *data = NULL;
277 void
278 aura_dict_store_list(struct aura_dict *d, const void *key, size_t key_size,
279 const void *data, size_t data_size)
281 struct aura_bucket *b;
283 aura_dict_locate_list(d, key, key_size, &b);
284 if (b == NULL) {
285 /* Bucket does not exist, add a new one. */
286 b = aura_bucket_new(key, key_size, data, data_size);
287 b->next = d->b[0];
288 d->b[0] = b;
289 } else {
290 /* Bucket already exists, replace the value. */
291 aura_free(b->data, "dictionary value");
292 b->data = aura_malloc(data_size, "dictionary value");
293 memcpy(b->data, data, data_size);
294 b->data_size = data_size;
298 /***** SORTED LIST *****/
301 keycmp(const void *key, size_t key_size, struct aura_bucket *b)
303 int r;
305 if ((r = memcmp(key, b->key,
306 b->key_size < key_size ? b->key_size : key_size)) == 0) {
307 if (key_size < b->key_size)
308 return(-1);
309 if (key_size > b->key_size)
310 return(1);
311 return(0);
313 return(r);
316 void
317 aura_dict_store_list_sorted(struct aura_dict *d, const void *key, size_t key_size,
318 const void *data, size_t data_size)
320 struct aura_bucket *b, *new_b, *prev = NULL;
321 int added = 0;
323 /* XXX could be more efficient. */
324 aura_dict_locate_list(d, key, key_size, &b);
325 if (b == NULL) {
326 new_b = aura_bucket_new(key, key_size, data, data_size);
327 if (d->b[0] == NULL) {
329 * Special case: insert at head
330 * if bucket is empty.
332 new_b->next = NULL;
333 d->b[0] = new_b;
334 } else {
335 for (b = d->b[0]; b != NULL; b = b->next) {
336 /* XXX if identical - no need for above fetch */
337 if (keycmp(key, key_size, b) < 0) {
338 if (prev != NULL)
339 prev->next = new_b;
340 else
341 d->b[0] = new_b;
342 new_b->next = b;
343 added = 1;
344 break;
346 prev = b;
348 if (!added) {
349 prev->next = new_b;
350 new_b->next = NULL;
353 } else {
354 /* Bucket already exists, replace the value. */
355 aura_free(b->data, "dictionary value");
356 b->data = aura_malloc(data_size, "dictionary value");
357 memcpy(b->data, data, data_size);
358 b->data_size = data_size;
362 /*** INTERFACE ***/
365 * Retrieve a value from a dictionary, give its key. The value and its
366 * size are returned in *data and *data_size. If no value could be
367 * found, *data is set to NULL.
369 void
370 aura_dict_fetch(struct aura_dict *d, const void *key, size_t key_size,
371 void **data, size_t *data_size)
373 d->fetch(d, key, key_size, data, data_size);
377 aura_dict_exists(struct aura_dict *d, const void *key, size_t key_size)
379 void *data;
380 size_t data_size;
382 d->fetch(d, key, key_size, &data, &data_size);
383 return(data != NULL);
387 * Insert a value into a dictionary, if it does not exist.
389 void
390 aura_dict_store(struct aura_dict *d, const void *key, size_t key_size,
391 const void *data, size_t data_size)
393 d->store(d, key, key_size, data, data_size);
397 * Finds the next bucket with data in it.
398 * If d->cursor == NULL after this, there is no more data.
400 void
401 aura_dict_advance(struct aura_dict *d)
403 while (d->cursor == NULL) {
404 if (d->cur_bucket == d->num_buckets - 1) {
405 /* We're at eof. Do nothing. */
406 break;
407 } else {
408 d->cur_bucket++;
409 d->cursor = d->b[d->cur_bucket];
414 void
415 aura_dict_rewind(struct aura_dict *d)
417 d->cur_bucket = 0;
418 d->cursor = d->b[d->cur_bucket];
419 aura_dict_advance(d);
423 aura_dict_eof(struct aura_dict *d)
425 return(d->cursor == NULL);
428 void
429 aura_dict_get_current_key(struct aura_dict *d, void **key, size_t *key_size)
431 if (d->cursor == NULL) {
432 *key = NULL;
433 } else {
434 *key = d->cursor->key;
435 *key_size = d->cursor->key_size;
439 void
440 aura_dict_next(struct aura_dict *d)
442 if (d->cursor != NULL)
443 d->cursor = d->cursor->next;
444 aura_dict_advance(d);
447 size_t
448 aura_dict_size(struct aura_dict *d)
450 struct aura_bucket *b;
451 size_t bucket_no = 0;
452 size_t count = 0;
454 while (bucket_no < d->num_buckets) {
455 b = d->b[bucket_no];
456 while (b != NULL) {
457 b = b->next;
458 count++;
460 bucket_no++;
463 return(count);