1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It is one of the source files comprising zwgc, the Zephyr WindowGram
5 * Created by: Marc Horowitz <marc@athena.mit.edu>
7 * $Id: dictionary.c,v 1.2 1999/01/22 23:20:14 ghudson Exp $
9 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_dictionary_c[] = "$Id: dictionary.c,v 1.2 1999/01/22 23:20:14 ghudson Exp $";
21 * dictionary - a module implementing a generic dictionary. That is,
22 * any type can be used for the values that keys are bound to.
23 * Keys are always strings.
27 * A dictionary is a set of bindings which bind values of some
28 * type (this type is the generic parameter of the dictionary) to
29 * strings. At most one value can be bound to any one string.
30 * The value that a string is bound to can be changed later.
31 * Bindings can also be deleted later. It is also possible to
32 * enumerate all of the bindings in a dictionary. Dictionarys
33 * are heap based and must be created & destroyed accordingly.
35 * Note: This module assumes that malloc NEVER returns 0 for reasonable
36 * requests. It is the users responsibility to either ensure that
37 * this happens or supply a version of malloc with error
40 * Dictionarys are mutable.
44 * A standard chaining hash table is used to implement dictionarys.
45 * Each dictionary has an associated size (# of slots), allowing
46 * different size dictionaries as needed.
49 #include "TYPE_T_dictionary.h"
50 #include "new_string.h"
51 #include "new_memory.h"
58 * TYPE_T_dictionary TYPE_T_dictionary_Create(int size):
60 * Effects: Returns a new empty dictionary containing no bindings.
61 * The returned dictionary must be destroyed using
62 * TYPE_T_dictionary_Destroy. Size is a time vs space
63 * parameter. For this implementation, space used is
64 * proportional to size and time used is proportional
65 * to number of bindings divided by size. It is preferable
66 * that size is a prime number.
69 TYPE_T_dictionary TYPE_T_dictionary_Create(size)
73 TYPE_T_dictionary result;
75 result = (TYPE_T_dictionary)malloc(sizeof(struct _TYPE_T_dictionary));
77 result->slots = (TYPE_T_dictionary_binding **)malloc(
78 size*sizeof(TYPE_T_dictionary_binding *));
80 for (i=0; i<size; i++)
81 result->slots[i] = NULL;
87 * void TYPE_T_dictionary_Destroy(TYPE_T_dictionary d):
88 * Requires: d is a non-destroyed TYPE_T_dictionary
90 * Effects: Destroys dictionary d freeing up the space it consumes.
91 * Dictionary d should never be referenced again. Note that
92 * free is NOT called on the values of the bindings. If
93 * this is needed, the client must do this first using
94 * TYPE_T_dictionary_Enumerate.
97 void TYPE_T_dictionary_Destroy(d)
101 TYPE_T_dictionary_binding *binding_ptr, *new_binding_ptr;
103 for (i=0; i<d->size; i++) {
104 binding_ptr = d->slots[i];
105 while (binding_ptr) {
106 new_binding_ptr = binding_ptr->next;
107 free(binding_ptr->key);
109 binding_ptr = new_binding_ptr;
117 * void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary d; void (*proc)()):
118 * Requires: proc is a void procedure taking 1 argument, a
119 * TYPE_T_dictionary_binding pointer, which does not
120 * make any calls using dictionary d.
121 * Effects: Calls proc once with each binding in dictionary d.
122 * Order of bindings passed is undefined. Note that
123 * only the value field of the binding should be considered
127 void TYPE_T_dictionary_Enumerate(d, proc)
129 void (*proc)(/* TYPE_T_dictionary_binding *b */);
132 TYPE_T_dictionary_binding *binding_ptr;
134 for (i=0; i<d->size; i++) {
135 binding_ptr = d->slots[i];
136 while (binding_ptr) {
138 binding_ptr = binding_ptr->next;
146 * unsigned int dictionary__hash(char *s):
147 * Effects: Hashs s to an unsigned integer. This number mod the
148 * hash table size is supposed to roughly evenly distribute
149 * keys over the table's slots.
152 static unsigned int dictionary__hash(s)
155 unsigned int result = 0;
170 * TYPE_T_dictionary_binding *TYPE_T_dictionary_Lookup(TYPE_T_dictionary d,
172 * Effects: If key is not bound in d, returns 0. Othersize,
173 * returns a pointer to the binding that binds key.
174 * Note the access restrictions on bindings...
177 TYPE_T_dictionary_binding *TYPE_T_dictionary_Lookup(d, key)
181 TYPE_T_dictionary_binding *binding_ptr;
183 binding_ptr = d->slots[dictionary__hash(key)%(d->size)];
184 while (binding_ptr) {
185 if (string_Eq(key, binding_ptr->key))
187 binding_ptr = binding_ptr->next;
194 * TYPE_T_dictionary_binding *TYPE_T_dictionary_Define(TYPE_T_dictionary d,
196 * int *already_existed):
198 * Effects: If key is bound in d, returns a pointer to the binding
199 * that binds key. Otherwise, adds a binding of key to
200 * d and returns its address. If already_existed is non-zero
201 * then *already_existed is set to 0 if key was not
202 * previously bound in d and 1 otherwise.
203 * Note the access restrictions on bindings... Note also
204 * that the value that key is bounded to if a binding is
205 * created is undefined. The caller should set the value
209 TYPE_T_dictionary_binding *TYPE_T_dictionary_Define(d, key, already_existed)
212 int *already_existed;
214 TYPE_T_dictionary_binding **ptr_to_the_slot, *binding_ptr;
216 ptr_to_the_slot = &(d->slots[dictionary__hash(key)%(d->size)]);
218 binding_ptr = *ptr_to_the_slot;
219 while (binding_ptr) {
220 if (string_Eq(binding_ptr->key, key)) {
222 *already_existed = 1;
225 binding_ptr = binding_ptr->next;
229 *already_existed = 0;
230 binding_ptr = (TYPE_T_dictionary_binding *)malloc(
231 sizeof(TYPE_T_dictionary_binding));
232 binding_ptr->next = *ptr_to_the_slot;
233 binding_ptr->key = string_Copy(key);
234 *ptr_to_the_slot = binding_ptr;
239 * void TYPE_T_dictionary_Delete(TYPE_T_dictionary d,
240 * TYPE_T_dictionary_binding *b):
241 * Requires: *b is a binding in d.
243 * Effects: Removes the binding *b from d. Note that if
244 * b->value needs to be freed, it should be freed
245 * before making this call.
248 void TYPE_T_dictionary_Delete(d, b)
250 TYPE_T_dictionary_binding *b;
252 TYPE_T_dictionary_binding **ptr_to_binding_ptr;
254 ptr_to_binding_ptr = &(d->slots[dictionary__hash(b->key)%(d->size)]);
256 while (*ptr_to_binding_ptr != b)
257 ptr_to_binding_ptr = &((*ptr_to_binding_ptr)->next);
259 *ptr_to_binding_ptr = b->next;