Robot Agent  1.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
dictionary.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------*/
11 /*--------------------------------------------------------------------------*/
12 
13 /*---------------------------------------------------------------------------
14  Includes
15  ---------------------------------------------------------------------------*/
16 #include "dictionary.h"
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 
24 #define MAXVALSZ 1024
25 
27 #define DICTMINSZ 128
28 
30 #define DICT_INVALID_KEY ((char*)-1)
31 
32 /*---------------------------------------------------------------------------
33  Private functions
34  ---------------------------------------------------------------------------*/
35 
36 /* Doubles the allocated size associated to a pointer */
37 /* 'size' is the current allocated size. */
38 static void * mem_double(void * ptr, int size)
39 {
40  void * newptr ;
41 
42  newptr = calloc(2*size, 1);
43  if (newptr==NULL) {
44  return NULL ;
45  }
46  memcpy(newptr, ptr, size);
47  free(ptr);
48  return newptr ;
49 }
50 
51 /*-------------------------------------------------------------------------*/
60 /*--------------------------------------------------------------------------*/
61 static char * xstrdup(const char * s)
62 {
63  char * t ;
64  if (!s)
65  return NULL ;
66  t = (char*)malloc(strlen(s)+1) ;
67  if (t) {
68  strcpy(t,s);
69  }
70  return t ;
71 }
72 
73 /*---------------------------------------------------------------------------
74  Function codes
75  ---------------------------------------------------------------------------*/
76 /*-------------------------------------------------------------------------*/
87 /*--------------------------------------------------------------------------*/
88 unsigned dictionary_hash(const char * key)
89 {
90  int len ;
91  unsigned hash ;
92  int i ;
93 
94  len = strlen(key);
95  for (hash=0, i=0 ; i<len ; i++) {
96  hash += (unsigned)key[i] ;
97  hash += (hash<<10);
98  hash ^= (hash>>6) ;
99  }
100  hash += (hash <<3);
101  hash ^= (hash >>11);
102  hash += (hash <<15);
103  return hash ;
104 }
105 
106 /*-------------------------------------------------------------------------*/
116 /*--------------------------------------------------------------------------*/
118 {
119  dictionary * d ;
120 
121  /* If no size was specified, allocate space for DICTMINSZ */
122  if (size<DICTMINSZ) size=DICTMINSZ ;
123 
124  if (!(d = (dictionary *)calloc(1, sizeof(dictionary)))) {
125  return NULL;
126  }
127  d->size = size ;
128  d->val = (char **)calloc(size, sizeof(char*));
129  d->key = (char **)calloc(size, sizeof(char*));
130  d->hash = (unsigned int *)calloc(size, sizeof(unsigned));
131  return d ;
132 }
133 
134 /*-------------------------------------------------------------------------*/
142 /*--------------------------------------------------------------------------*/
144 {
145  int i ;
146 
147  if (d==NULL) return ;
148  for (i=0 ; i<d->size ; i++) {
149  if (d->key[i]!=NULL)
150  free(d->key[i]);
151  if (d->val[i]!=NULL)
152  free(d->val[i]);
153  }
154  free(d->val);
155  free(d->key);
156  free(d->hash);
157  free(d);
158  return ;
159 }
160 
161 /*-------------------------------------------------------------------------*/
174 /*--------------------------------------------------------------------------*/
175 char * dictionary_get(dictionary * d, const char * key, char * def)
176 {
177  unsigned hash ;
178  int i ;
179 
180  hash = dictionary_hash(key);
181  for (i=0 ; i<d->size ; i++) {
182  if (d->key[i]==NULL)
183  continue ;
184  /* Compare hash */
185  if (hash==d->hash[i]) {
186  /* Compare string, to avoid hash collisions */
187  if (!strcmp(key, d->key[i])) {
188  return d->val[i] ;
189  }
190  }
191  }
192  return def ;
193 }
194 
195 /*-------------------------------------------------------------------------*/
220 /*--------------------------------------------------------------------------*/
221 int dictionary_set(dictionary * d, const char * key, const char * val)
222 {
223  int i ;
224  unsigned hash ;
225 
226  if (d==NULL || key==NULL) return -1 ;
227 
228  /* Compute hash for this key */
229  hash = dictionary_hash(key) ;
230  /* Find if value is already in dictionary */
231  if (d->n>0) {
232  for (i=0 ; i<d->size ; i++) {
233  if (d->key[i]==NULL)
234  continue ;
235  if (hash==d->hash[i]) { /* Same hash value */
236  if (!strcmp(key, d->key[i])) { /* Same key */
237  /* Found a value: modify and return */
238  if (d->val[i]!=NULL)
239  free(d->val[i]);
240  d->val[i] = val ? xstrdup(val) : NULL ;
241  /* Value has been modified: return */
242  return 0 ;
243  }
244  }
245  }
246  }
247  /* Add a new value */
248  /* See if dictionary needs to grow */
249  if (d->n==d->size) {
250 
251  /* Reached maximum size: reallocate dictionary */
252  d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ;
253  d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ;
254  d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ;
255  if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) {
256  /* Cannot grow dictionary */
257  return -1 ;
258  }
259  /* Double size */
260  d->size *= 2 ;
261  }
262 
263  /* Insert key in the first empty slot. Start at d->n and wrap at
264  d->size. Because d->n < d->size this will necessarily
265  terminate. */
266  for (i=d->n ; d->key[i] ; ) {
267  if(++i == d->size) i = 0;
268  }
269  /* Copy key */
270  d->key[i] = xstrdup(key);
271  d->val[i] = val ? xstrdup(val) : NULL ;
272  d->hash[i] = hash;
273  d->n ++ ;
274  return 0 ;
275 }
276 
277 /*-------------------------------------------------------------------------*/
287 /*--------------------------------------------------------------------------*/
288 void dictionary_unset(dictionary * d, const char * key)
289 {
290  unsigned hash ;
291  int i ;
292 
293  if (key == NULL) {
294  return;
295  }
296 
297  hash = dictionary_hash(key);
298  for (i=0 ; i<d->size ; i++) {
299  if (d->key[i]==NULL)
300  continue ;
301  /* Compare hash */
302  if (hash==d->hash[i]) {
303  /* Compare string, to avoid hash collisions */
304  if (!strcmp(key, d->key[i])) {
305  /* Found key */
306  break ;
307  }
308  }
309  }
310  if (i>=d->size)
311  /* Key not found */
312  return ;
313 
314  free(d->key[i]);
315  d->key[i] = NULL ;
316  if (d->val[i]!=NULL) {
317  free(d->val[i]);
318  d->val[i] = NULL ;
319  }
320  d->hash[i] = 0 ;
321  d->n -- ;
322  return ;
323 }
324 
325 /*-------------------------------------------------------------------------*/
336 /*--------------------------------------------------------------------------*/
337 void dictionary_dump(dictionary * d, FILE * out)
338 {
339  int i ;
340 
341  if (d==NULL || out==NULL) return ;
342  if (d->n<1) {
343  fprintf(out, "empty dictionary\n");
344  return ;
345  }
346  for (i=0 ; i<d->size ; i++) {
347  if (d->key[i]) {
348  fprintf(out, "%20s\t[%s]\n",
349  d->key[i],
350  d->val[i] ? d->val[i] : "UNDEF");
351  }
352  }
353  return ;
354 }
355 
356 
357 /* Test code */
358 #ifdef TESTDIC
359 #define NVALS 20000
360 int main(int argc, char *argv[])
361 {
362  dictionary * d ;
363  char * val ;
364  int i ;
365  char cval[90] ;
366 
367  /* Allocate dictionary */
368  printf("allocating...\n");
369  d = dictionary_new(0);
370 
371  /* Set values in dictionary */
372  printf("setting %d values...\n", NVALS);
373  for (i=0 ; i<NVALS ; i++) {
374  sprintf(cval, "%04d", i);
375  dictionary_set(d, cval, "salut");
376  }
377  printf("getting %d values...\n", NVALS);
378  for (i=0 ; i<NVALS ; i++) {
379  sprintf(cval, "%04d", i);
380  val = dictionary_get(d, cval, DICT_INVALID_KEY);
381  if (val==DICT_INVALID_KEY) {
382  printf("cannot get value for key [%s]\n", cval);
383  }
384  }
385  printf("unsetting %d values...\n", NVALS);
386  for (i=0 ; i<NVALS ; i++) {
387  sprintf(cval, "%04d", i);
388  dictionary_unset(d, cval);
389  }
390  if (d->n != 0) {
391  printf("error deleting values\n");
392  }
393  printf("deallocating...\n");
394  dictionary_del(d);
395  return 0 ;
396 }
397 #endif
398 /* vim: set ts=4 et sw=4 tw=75 */
char ** val
Definition: dictionary.h:44
char * dictionary_get(dictionary *d, const char *key, char *def)
Get a value from a dictionary.
Definition: dictionary.c:175
int main()
Main application.
Definition: main.c:32
void dictionary_unset(dictionary *d, const char *key)
Delete a key in a dictionary.
Definition: dictionary.c:288
unsigned dictionary_hash(const char *key)
Compute the hash key for a string.
Definition: dictionary.c:88
void dictionary_dump(dictionary *d, FILE *out)
Dump a dictionary to an opened file pointer.
Definition: dictionary.c:337
unsigned * hash
Definition: dictionary.h:46
#define DICT_INVALID_KEY
Definition: dictionary.c:30
char ** key
Definition: dictionary.h:45
dictionary * dictionary_new(int size)
Create a new dictionary object.
Definition: dictionary.c:117
void dictionary_del(dictionary *d)
Delete a dictionary object.
Definition: dictionary.c:143
int dictionary_set(dictionary *d, const char *key, const char *val)
Set a value in a dictionary.
Definition: dictionary.c:221
Dictionary object.
Definition: dictionary.h:41
#define DICTMINSZ
Definition: dictionary.c:27
Implements a dictionary for string variables.