1 | /* |
1 | /* |
2 | * dictionary.C: Dictionary-backed trees. |
2 | * dictionary.C: Dictionary-backed trees. |
3 | * Rights to this code are documented in doc/pod/license.pod. |
3 | * Rights to this code are documented in doc/pod/license.pod. |
4 | * |
4 | * |
5 | * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) |
5 | * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) |
6 | */ |
6 | */ |
7 | |
7 | |
8 | static char const rcsid[] = "$Id: dictionary.C,v 1.3 2007/07/21 13:23:21 pippijn Exp $"; |
8 | static char const rcsid[] = "$Id: dictionary.C,v 1.4 2007/08/28 17:08:12 pippijn Exp $"; |
9 | |
9 | |
10 | #include "atheme.h" |
10 | #include "atheme.h" |
11 | |
11 | |
12 | list_t dictionarylist; |
12 | list_t dictionarylist; |
13 | |
13 | |
… | |
… | |
15 | { |
15 | { |
16 | object_t parent; |
16 | object_t parent; |
17 | |
17 | |
18 | int resolution; |
18 | int resolution; |
19 | list_t *hashv; /* dynamically allocated by dictionary_create() */ |
19 | list_t *hashv; /* dynamically allocated by dictionary_create() */ |
20 | int (*compare_cb) (const char *a, const char *b); |
20 | int (*compare_cb) (char const * const a, char const * const b); |
21 | node_t node; |
21 | node_t node; |
22 | }; |
22 | }; |
23 | |
23 | |
24 | /* |
24 | /* |
|
|
25 | * This generates a hash value, based on chongo's hash algo, |
|
|
26 | * located at http://www.isthe.com/chongo/tech/comp/fnv/ |
|
|
27 | * |
|
|
28 | * The difference between FNV and Atheme's hash algorithm is |
|
|
29 | * that FNV uses a random key for toasting, we just use |
|
|
30 | * 16 instead. |
|
|
31 | */ |
|
|
32 | static unsigned int |
|
|
33 | shash (const unsigned char *p) |
|
|
34 | { |
|
|
35 | unsigned int hval = HASHINIT; |
|
|
36 | |
|
|
37 | if (!p) |
|
|
38 | return (0); |
|
|
39 | for (; *p != '\0'; ++p) |
|
|
40 | { |
|
|
41 | hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); |
|
|
42 | hval ^= (ToLower (*p) ^ 16); |
|
|
43 | } |
|
|
44 | |
|
|
45 | return ((hval >> HASHBITS) ^ (hval & ((1 << HASHBITS) - 1)) % HASHSIZE); |
|
|
46 | } |
|
|
47 | |
|
|
48 | /* |
25 | * dictionary_create(const char *name, int resolution, |
49 | * dictionary_create(char const * const name, int resolution, |
26 | * int (*compare_cb)(const char *a, const char *b) |
50 | * int (*compare_cb)(char const * const a, char const * const b) |
27 | * |
51 | * |
28 | * DTree object factory. |
52 | * DTree object factory. |
29 | * |
53 | * |
30 | * Inputs: |
54 | * Inputs: |
31 | * - name of dictionary tree |
55 | * - name of dictionary tree |
… | |
… | |
38 | * Side Effects: |
62 | * Side Effects: |
39 | * - if services runs out of memory and cannot allocate the object, |
63 | * - if services runs out of memory and cannot allocate the object, |
40 | * the program will abort. |
64 | * the program will abort. |
41 | */ |
65 | */ |
42 | dictionary_tree_t * |
66 | dictionary_tree_t * |
43 | dictionary_create (const char *name, int resolution, int (*compare_cb) (const char *a, const char *b)) |
67 | dictionary_create (char const * const name, int resolution, int (*compare_cb) (char const * const a, char const * const b)) |
44 | { |
68 | { |
45 | dictionary_tree_t *dtree = static_cast<dictionary_tree_t *> (smalloc (sizeof (dictionary_tree_t))); |
69 | dictionary_tree_t *dtree = static_cast<dictionary_tree_t *> (malloc (sizeof (dictionary_tree_t))); |
46 | |
70 | |
47 | object_init (&dtree->parent, name, NULL); |
71 | object_init (&dtree->parent, name, NULL); |
48 | dtree->resolution = resolution; |
72 | dtree->resolution = resolution; |
49 | dtree->hashv = static_cast<list_t *> (smalloc (sizeof (list_t) * resolution)); |
73 | dtree->hashv = static_cast<list_t *> (malloc (sizeof (list_t) * resolution)); |
50 | dtree->compare_cb = compare_cb; |
74 | dtree->compare_cb = compare_cb; |
51 | memset (dtree->hashv, '\0', sizeof (list_t) * resolution); |
75 | memset (dtree->hashv, '\0', sizeof (list_t) * resolution); |
52 | node_add (dtree, &dtree->node, &dictionarylist); |
76 | node_add (dtree, &dtree->node, &dictionarylist); |
53 | |
77 | |
54 | return dtree; |
78 | return dtree; |
… | |
… | |
299 | return; |
323 | return; |
300 | } |
324 | } |
301 | } |
325 | } |
302 | |
326 | |
303 | /* |
327 | /* |
304 | * dictionary_find(dictionary_tree_t *dtree, const char *key) |
328 | * dictionary_find(dictionary_tree_t *dtree, char const * const key) |
305 | * |
329 | * |
306 | * Looks up a DTree node by name. |
330 | * Looks up a DTree node by name. |
307 | * |
331 | * |
308 | * Inputs: |
332 | * Inputs: |
309 | * - dictionary tree object |
333 | * - dictionary tree object |
… | |
… | |
315 | * |
339 | * |
316 | * Side Effects: |
340 | * Side Effects: |
317 | * - none |
341 | * - none |
318 | */ |
342 | */ |
319 | dictionary_elem_t * |
343 | dictionary_elem_t * |
320 | dictionary_find (dictionary_tree_t *dtree, const char *key) |
344 | dictionary_find (dictionary_tree_t *dtree, char const * const key) |
321 | { |
345 | { |
322 | node_t *n; |
346 | node_t *n; |
323 | int i; |
347 | int i; |
324 | |
348 | |
325 | if (dtree == NULL || key == NULL) |
349 | if (dtree == NULL || key == NULL) |
… | |
… | |
338 | |
362 | |
339 | return NULL; |
363 | return NULL; |
340 | } |
364 | } |
341 | |
365 | |
342 | /* |
366 | /* |
343 | * dictionary_add(dictionary_tree_t *dtree, const char *key, void *data) |
367 | * dictionary_add(dictionary_tree_t *dtree, char const * const key, void *data) |
344 | * |
368 | * |
345 | * Creates a new DTree node and binds data to it. |
369 | * Creates a new DTree node and binds data to it. |
346 | * |
370 | * |
347 | * Inputs: |
371 | * Inputs: |
348 | * - dictionary tree object |
372 | * - dictionary tree object |
… | |
… | |
355 | * |
379 | * |
356 | * Side Effects: |
380 | * Side Effects: |
357 | * - data is inserted into the DTree. |
381 | * - data is inserted into the DTree. |
358 | */ |
382 | */ |
359 | dictionary_elem_t * |
383 | dictionary_elem_t * |
360 | dictionary_add (dictionary_tree_t *dtree, const char *key, void *data) |
384 | dictionary_add (dictionary_tree_t *dtree, char const * const key, void *data) |
361 | { |
385 | { |
362 | dictionary_elem_t *delem; |
386 | dictionary_elem_t *delem; |
363 | int i; |
387 | int i; |
364 | |
388 | |
365 | if (dtree == NULL || key == NULL || data == NULL) |
389 | if (dtree == NULL || key == NULL || data == NULL) |
… | |
… | |
370 | slog (LG_DEBUG, "dictionary_add(): entry already exists in dtree<%p> for key '%s'!", dtree, key); |
394 | slog (LG_DEBUG, "dictionary_add(): entry already exists in dtree<%p> for key '%s'!", dtree, key); |
371 | return NULL; |
395 | return NULL; |
372 | } |
396 | } |
373 | |
397 | |
374 | i = shash ((const unsigned char *) key) % dtree->resolution; |
398 | i = shash ((const unsigned char *) key) % dtree->resolution; |
375 | delem = static_cast<dictionary_elem_t *> (smalloc (sizeof (dictionary_elem_t))); |
399 | delem = static_cast<dictionary_elem_t *> (malloc (sizeof (dictionary_elem_t))); |
376 | memset (delem, '\0', sizeof (dictionary_elem_t)); |
400 | memset (delem, '\0', sizeof (dictionary_elem_t)); |
377 | |
401 | |
378 | delem->key = sstrdup (key); |
402 | delem->key = sstrdup (key); |
379 | node_add (data, &delem->node, &dtree->hashv[i]); |
403 | node_add (data, &delem->node, &dtree->hashv[i]); |
380 | |
404 | |
381 | return delem; |
405 | return delem; |
382 | } |
406 | } |
383 | |
407 | |
384 | /* |
408 | /* |
385 | * dictionary_delete(dictionary_tree_t *dtree, const char *key) |
409 | * dictionary_delete(dictionary_tree_t *dtree, char const * const key) |
386 | * |
410 | * |
387 | * Deletes data from a dictionary tree. |
411 | * Deletes data from a dictionary tree. |
388 | * |
412 | * |
389 | * Inputs: |
413 | * Inputs: |
390 | * - dictionary tree object |
414 | * - dictionary tree object |
… | |
… | |
399 | * |
423 | * |
400 | * Notes: |
424 | * Notes: |
401 | * - the returned data needs to be freed/released manually! |
425 | * - the returned data needs to be freed/released manually! |
402 | */ |
426 | */ |
403 | void * |
427 | void * |
404 | dictionary_delete (dictionary_tree_t *dtree, const char *key) |
428 | dictionary_delete (dictionary_tree_t *dtree, char const * const key) |
405 | { |
429 | { |
406 | dictionary_elem_t *delem = dictionary_find (dtree, key); |
430 | dictionary_elem_t *delem = dictionary_find (dtree, key); |
407 | void *data; |
431 | void *data; |
408 | int i; |
432 | int i; |
409 | |
433 | |
… | |
… | |
424 | |
448 | |
425 | return data; |
449 | return data; |
426 | } |
450 | } |
427 | |
451 | |
428 | /* |
452 | /* |
429 | * dictionary_retrieve(dictionary_tree_t *dtree, const char *key) |
453 | * dictionary_retrieve(dictionary_tree_t *dtree, char const * const key) |
430 | * |
454 | * |
431 | * Retrieves data from a dictionary tree. |
455 | * Retrieves data from a dictionary tree. |
432 | * |
456 | * |
433 | * Inputs: |
457 | * Inputs: |
434 | * - dictionary tree object |
458 | * - dictionary tree object |
… | |
… | |
440 | * |
464 | * |
441 | * Side Effects: |
465 | * Side Effects: |
442 | * - none |
466 | * - none |
443 | */ |
467 | */ |
444 | void * |
468 | void * |
445 | dictionary_retrieve (dictionary_tree_t *dtree, const char *key) |
469 | dictionary_retrieve (dictionary_tree_t *dtree, char const * const key) |
446 | { |
470 | { |
447 | dictionary_elem_t *delem = dictionary_find (dtree, key); |
471 | dictionary_elem_t *delem = dictionary_find (dtree, key); |
448 | |
472 | |
449 | if (delem != NULL) |
473 | if (delem != NULL) |
450 | return delem->node.data; |
474 | return delem->node.data; |
… | |
… | |
453 | } |
477 | } |
454 | |
478 | |
455 | #define MAXCOUNT 10 |
479 | #define MAXCOUNT 10 |
456 | |
480 | |
457 | /* |
481 | /* |
458 | * dictionary_stats(void (*stats_cb)(const char *line, void *privdata), void *privdata) |
482 | * dictionary_stats(void (*stats_cb)(char const * const line, void *privdata), void *privdata) |
459 | * |
483 | * |
460 | * Displays statistics about all of the registered DTrees. |
484 | * Displays statistics about all of the registered DTrees. |
461 | * |
485 | * |
462 | * Inputs: |
486 | * Inputs: |
463 | * - callback function |
487 | * - callback function |
… | |
… | |
468 | * |
492 | * |
469 | * Side Effects: |
493 | * Side Effects: |
470 | * - data is passed to the callback function about the dtree system. |
494 | * - data is passed to the callback function about the dtree system. |
471 | */ |
495 | */ |
472 | void |
496 | void |
473 | dictionary_stats (void (*stats_cb) (const char *line, void *privdata), void *privdata) |
497 | dictionary_stats (void (*stats_cb) (char const * const line, void *privdata), void *privdata) |
474 | { |
498 | { |
475 | node_t *n; |
499 | node_t *n; |
476 | dictionary_tree_t *dtree; |
500 | dictionary_tree_t *dtree; |
477 | char buf[120]; |
501 | char buf[120]; |
478 | int i, count1, totalcount, maxdepth; |
502 | int i, count1, totalcount, maxdepth; |