]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/zwgc/dictionary.c
r4264@bucket (orig r254): kcr | 2008-01-20 22:11:44 -0500
[1ts-debian.git] / zephyr / zwgc / dictionary.c
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
3  * client.
4  *
5  *      Created by:     Marc Horowitz <marc@athena.mit.edu>
6  *
7  *      $Id$
8  *
9  *      Copyright (c) 1989 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h".
12  */
13
14 #include <sysdep.h>
15
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_dictionary_c[] = "$Id$";
18 #endif
19
20 /*
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.
24  *
25  * Overview:
26  *
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.
34  *
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
38  *          handling.
39  *
40  *    Dictionarys are mutable.
41  *
42  * Implementation:
43  *
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.
47  */
48
49 #include "TYPE_T_dictionary.h"
50 #include "new_string.h"
51 #include "new_memory.h"
52
53 #ifndef NULL
54 #define NULL 0
55 #endif
56
57 /*
58  *    TYPE_T_dictionary TYPE_T_dictionary_Create(int size):
59  *        Requires: size > 0
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.
67  */
68
69 TYPE_T_dictionary
70 TYPE_T_dictionary_Create(int size)
71 {
72     int i;
73     TYPE_T_dictionary result;
74
75     result = (TYPE_T_dictionary)malloc(sizeof(struct _TYPE_T_dictionary));
76     result->size = size;
77     result->slots = (TYPE_T_dictionary_binding **)malloc(
78                      size*sizeof(TYPE_T_dictionary_binding *));
79
80     for (i=0; i<size; i++)
81       result->slots[i] = NULL;
82
83     return(result);
84 }
85
86 /*
87  *    void TYPE_T_dictionary_Destroy(TYPE_T_dictionary d):
88  *        Requires: d is a non-destroyed TYPE_T_dictionary
89  *        Modifies: d
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.
95  */
96
97 void
98 TYPE_T_dictionary_Destroy(TYPE_T_dictionary d)
99 {
100     int i;
101     TYPE_T_dictionary_binding *binding_ptr, *new_binding_ptr;
102
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);
108             free(binding_ptr);
109             binding_ptr = new_binding_ptr;
110         }
111     }
112     free(d->slots);
113     free(d);
114 }
115
116 /*
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
124  *                 writable by proc.
125  */
126
127 void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary d,
128                                  void (*proc)(TYPE_T_dictionary_binding *))
129 {
130     int i;
131     TYPE_T_dictionary_binding *binding_ptr;
132
133     for (i=0; i<d->size; i++) {
134         binding_ptr = d->slots[i];
135         while (binding_ptr) {
136             proc(binding_ptr);
137             binding_ptr = binding_ptr->next;
138         }
139     }
140 }
141
142 /*
143  *  Private routine:
144  *
145  *    unsigned int dictionary__hash(char *s):
146  *        Effects: Hashs s to an unsigned integer.  This number mod the
147  *                 hash table size is supposed to roughly evenly distribute
148  *                 keys over the table's slots.
149  */
150
151 static unsigned int
152 dictionary__hash(char *s)
153 {
154     unsigned int result = 0;
155
156     if (!s)
157       return(result);
158
159     while (s[0]) {
160         result <<= 1;
161         result += s[0];
162         s++;
163     }
164
165     return(result);
166 }
167
168 /*
169  *    TYPE_T_dictionary_binding *TYPE_T_dictionary_Lookup(TYPE_T_dictionary d,
170  *                                                        char *key):
171  *        Effects: If key is not bound in d, returns 0.  Othersize,
172  *                 returns a pointer to the binding that binds key.
173  *                 Note the access restrictions on bindings...
174  */
175
176 TYPE_T_dictionary_binding *
177 TYPE_T_dictionary_Lookup(TYPE_T_dictionary d,
178                          char *key)
179 {
180     TYPE_T_dictionary_binding *binding_ptr;
181
182     binding_ptr = d->slots[dictionary__hash(key)%(d->size)];
183     while (binding_ptr) {
184         if (string_Eq(key, binding_ptr->key))
185           return(binding_ptr);
186         binding_ptr = binding_ptr->next;
187     }
188
189     return(NULL);
190 }
191
192 /*
193  *    TYPE_T_dictionary_binding *TYPE_T_dictionary_Define(TYPE_T_dictionary d,
194  *                                            char *key,
195  *                                            int *already_existed):
196  *        Modifies: d
197  *        Effects: If key is bound in d, returns a pointer to the binding
198  *                 that binds key.  Otherwise, adds a binding of key to
199  *                 d and returns its address.  If already_existed is non-zero
200  *                 then *already_existed is set to 0 if key was not
201  *                 previously bound in d and 1 otherwise.
202  *                 Note the access restrictions on bindings...  Note also
203  *                 that the value that key is bounded to if a binding is
204  *                 created is undefined.  The caller should set the value
205  *                 in this case.
206  */
207
208 TYPE_T_dictionary_binding *
209 TYPE_T_dictionary_Define(TYPE_T_dictionary d,
210                          char *key,
211                          int *already_existed)
212 {
213     TYPE_T_dictionary_binding **ptr_to_the_slot, *binding_ptr;
214
215     ptr_to_the_slot = &(d->slots[dictionary__hash(key)%(d->size)]);
216
217     binding_ptr = *ptr_to_the_slot;
218     while (binding_ptr) {
219         if (string_Eq(binding_ptr->key, key)) {
220             if (already_existed)
221               *already_existed = 1;
222             return(binding_ptr);
223         }
224         binding_ptr = binding_ptr->next;
225     }
226
227     if (already_existed)
228       *already_existed = 0;
229     binding_ptr = (TYPE_T_dictionary_binding *)malloc(
230                                         sizeof(TYPE_T_dictionary_binding));
231     binding_ptr->next = *ptr_to_the_slot;
232     binding_ptr->key = string_Copy(key);
233     *ptr_to_the_slot = binding_ptr;
234     return(binding_ptr);
235 }
236
237 /*
238  *    void TYPE_T_dictionary_Delete(TYPE_T_dictionary d,
239  *                                  TYPE_T_dictionary_binding *b):
240  *        Requires: *b is a binding in d.
241  *        Modifies: d
242  *        Effects: Removes the binding *b from d.  Note that if 
243  *                 b->value needs to be freed, it should be freed
244  *                 before making this call.
245  */
246
247 void TYPE_T_dictionary_Delete(TYPE_T_dictionary d,
248                               TYPE_T_dictionary_binding *b)
249 {
250     TYPE_T_dictionary_binding **ptr_to_binding_ptr;
251
252     ptr_to_binding_ptr = &(d->slots[dictionary__hash(b->key)%(d->size)]);
253
254     while (*ptr_to_binding_ptr != b)
255       ptr_to_binding_ptr = &((*ptr_to_binding_ptr)->next);
256
257     *ptr_to_binding_ptr = b->next;
258     free(b->key);
259     free(b);
260 }