KTH framework for Nek5000 toolboxes; testing version  0.0.1
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 /*-------------------------------------------------------------------------*/
45 /*--------------------------------------------------------------------------*/
46 static char * xstrdup(const char * s)
47 {
48  char * t ;
49  size_t len ;
50  if (!s)
51  return NULL ;
52 
53  len = strlen(s) + 1 ;
54  t = (char*) malloc(len) ;
55  if (t) {
56  memcpy(t, s, len) ;
57  }
58  return t ;
59 }
60 
61 /*-------------------------------------------------------------------------*/
67 /*--------------------------------------------------------------------------*/
68 static int dictionary_grow(dictionary * d)
69 {
70  char ** new_val ;
71  char ** new_key ;
72  unsigned * new_hash ;
73 
74  new_val = (char**) calloc(d->size * 2, sizeof *d->val);
75  new_key = (char**) calloc(d->size * 2, sizeof *d->key);
76  new_hash = (unsigned*) calloc(d->size * 2, sizeof *d->hash);
77  if (!new_val || !new_key || !new_hash) {
78  /* An allocation failed, leave the dictionary unchanged */
79  if (new_val)
80  free(new_val);
81  if (new_key)
82  free(new_key);
83  if (new_hash)
84  free(new_hash);
85  return -1 ;
86  }
87  /* Initialize the newly allocated space */
88  memcpy(new_val, d->val, d->size * sizeof(char *));
89  memcpy(new_key, d->key, d->size * sizeof(char *));
90  memcpy(new_hash, d->hash, d->size * sizeof(unsigned));
91  /* Delete previous data */
92  free(d->val);
93  free(d->key);
94  free(d->hash);
95  /* Actually update the dictionary */
96  d->size *= 2 ;
97  d->val = new_val;
98  d->key = new_key;
99  d->hash = new_hash;
100  return 0 ;
101 }
102 
103 /*---------------------------------------------------------------------------
104  Function codes
105  ---------------------------------------------------------------------------*/
106 /*-------------------------------------------------------------------------*/
117 /*--------------------------------------------------------------------------*/
118 unsigned dictionary_hash(const char * key)
119 {
120  size_t len ;
121  unsigned hash ;
122  size_t i ;
123 
124  if (!key)
125  return 0 ;
126 
127  len = strlen(key);
128  for (hash=0, i=0 ; i<len ; i++) {
129  hash += (unsigned)key[i] ;
130  hash += (hash<<10);
131  hash ^= (hash>>6) ;
132  }
133  hash += (hash <<3);
134  hash ^= (hash >>11);
135  hash += (hash <<15);
136  return hash ;
137 }
138 
139 /*-------------------------------------------------------------------------*/
149 /*-------------------------------------------------------------------------*/
151 {
152  dictionary * d ;
153 
154  /* If no size was specified, allocate space for DICTMINSZ */
155  if (size<DICTMINSZ) size=DICTMINSZ ;
156 
157  d = (dictionary*) calloc(1, sizeof *d) ;
158 
159  if (d) {
160  d->size = size ;
161  d->val = (char**) calloc(size, sizeof *d->val);
162  d->key = (char**) calloc(size, sizeof *d->key);
163  d->hash = (unsigned*) calloc(size, sizeof *d->hash);
164  }
165  return d ;
166 }
167 
168 /*-------------------------------------------------------------------------*/
176 /*--------------------------------------------------------------------------*/
178 {
179  ssize_t i ;
180 
181  if (d==NULL) return ;
182  for (i=0 ; i<d->size ; i++) {
183  if (d->key[i]!=NULL)
184  free(d->key[i]);
185  if (d->val[i]!=NULL)
186  free(d->val[i]);
187  }
188  free(d->val);
189  free(d->key);
190  free(d->hash);
191  free(d);
192  return ;
193 }
194 
195 /*-------------------------------------------------------------------------*/
208 /*--------------------------------------------------------------------------*/
209 const char * dictionary_get(const dictionary * d, const char * key, const char * def)
210 {
211  unsigned hash ;
212  ssize_t i ;
213 
214  hash = dictionary_hash(key);
215  for (i=0 ; i<d->size ; i++) {
216  if (d->key[i]==NULL)
217  continue ;
218  /* Compare hash */
219  if (hash==d->hash[i]) {
220  /* Compare string, to avoid hash collisions */
221  if (!strcmp(key, d->key[i])) {
222  return d->val[i] ;
223  }
224  }
225  }
226  return def ;
227 }
228 
229 /*-------------------------------------------------------------------------*/
254 /*--------------------------------------------------------------------------*/
255 int dictionary_set(dictionary * d, const char * key, const char * val)
256 {
257  ssize_t i ;
258  unsigned hash ;
259 
260  if (d==NULL || key==NULL) return -1 ;
261 
262  /* Compute hash for this key */
263  hash = dictionary_hash(key) ;
264  /* Find if value is already in dictionary */
265  if (d->n>0) {
266  for (i=0 ; i<d->size ; i++) {
267  if (d->key[i]==NULL)
268  continue ;
269  if (hash==d->hash[i]) { /* Same hash value */
270  if (!strcmp(key, d->key[i])) { /* Same key */
271  /* Found a value: modify and return */
272  if (d->val[i]!=NULL)
273  free(d->val[i]);
274  d->val[i] = (val ? xstrdup(val) : NULL);
275  /* Value has been modified: return */
276  return 0 ;
277  }
278  }
279  }
280  }
281  /* Add a new value */
282  /* See if dictionary needs to grow */
283  if (d->n==d->size) {
284  /* Reached maximum size: reallocate dictionary */
285  if (dictionary_grow(d) != 0)
286  return -1;
287  }
288 
289  /* Insert key in the first empty slot. Start at d->n and wrap at
290  d->size. Because d->n < d->size this will necessarily
291  terminate. */
292  for (i=d->n ; d->key[i] ; ) {
293  if(++i == d->size) i = 0;
294  }
295  /* Copy key */
296  d->key[i] = xstrdup(key);
297  d->val[i] = (val ? xstrdup(val) : NULL) ;
298  d->hash[i] = hash;
299  d->n ++ ;
300  return 0 ;
301 }
302 
303 /*-------------------------------------------------------------------------*/
313 /*--------------------------------------------------------------------------*/
314 void dictionary_unset(dictionary * d, const char * key)
315 {
316  unsigned hash ;
317  ssize_t i ;
318 
319  if (key == NULL || d == NULL) {
320  return;
321  }
322 
323  hash = dictionary_hash(key);
324  for (i=0 ; i<d->size ; i++) {
325  if (d->key[i]==NULL)
326  continue ;
327  /* Compare hash */
328  if (hash==d->hash[i]) {
329  /* Compare string, to avoid hash collisions */
330  if (!strcmp(key, d->key[i])) {
331  /* Found key */
332  break ;
333  }
334  }
335  }
336  if (i>=d->size)
337  /* Key not found */
338  return ;
339 
340  free(d->key[i]);
341  d->key[i] = NULL ;
342  if (d->val[i]!=NULL) {
343  free(d->val[i]);
344  d->val[i] = NULL ;
345  }
346  d->hash[i] = 0 ;
347  d->n -- ;
348  return ;
349 }
350 
351 /*-------------------------------------------------------------------------*/
362 /*--------------------------------------------------------------------------*/
363 void dictionary_dump(const dictionary * d, FILE * out)
364 {
365  ssize_t i ;
366 
367  if (d==NULL || out==NULL) return ;
368  if (d->n<1) {
369  fprintf(out, "empty dictionary\n");
370  return ;
371  }
372  for (i=0 ; i<d->size ; i++) {
373  if (d->key[i]) {
374  fprintf(out, "%20s\t[%s]\n",
375  d->key[i],
376  d->val[i] ? d->val[i] : "UNDEF");
377  }
378  }
379  return ;
380 }
void dictionary_del(dictionary *d)
Delete a dictionary object.
Definition: dictionary.c:177
void dictionary_unset(dictionary *d, const char *key)
Delete a key in a dictionary.
Definition: dictionary.c:314
unsigned dictionary_hash(const char *key)
Compute the hash key for a string.
Definition: dictionary.c:118
const char * dictionary_get(const dictionary *d, const char *key, const char *def)
Get a value from a dictionary.
Definition: dictionary.c:209
#define DICTMINSZ
Definition: dictionary.c:27
int dictionary_set(dictionary *d, const char *key, const char *val)
Set a value in a dictionary.
Definition: dictionary.c:255
void dictionary_dump(const dictionary *d, FILE *out)
Dump a dictionary to an opened file pointer.
Definition: dictionary.c:363
dictionary * dictionary_new(size_t size)
Create a new dictionary object.
Definition: dictionary.c:150
Implements a dictionary for string variables.
Dictionary object.
Definition: dictionary.h:45
unsigned * hash
Definition: dictionary.h:50
char ** key
Definition: dictionary.h:49
char ** val
Definition: dictionary.h:48
ssize_t size
Definition: dictionary.h:47