Python-like Dictionary Library
Dictionary library similar to Python dict functionality
Loading...
Searching...
No Matches
cdict.c
Go to the documentation of this file.
1
2
3#include <cdict.h>
4
5/*declare static functions*/
6static void free_hash_table(WORD * hash_table);
7static int cto_lower(int c);
8static WORD * init_hash_table(void);
9static void shuffle(WORD * table, unsigned int);
10static unsigned int hashme(cdict_ctx*, char *);
11static int cstr_ccmp(const char * str1, const char * str2);
12/*****************************************/
13
14
15static int cto_lower(int c){
16 return c >= 'A' && c <= 'Z'? c + 'a' - 'A':c;
17}
18
19static int cstr_ccmp(const char * str1, const char * str2){
20 char * s1 = (char *) str1;
21 char * s2 = (char *) str2;
22 while (*s1 != '\0' && *s2 != '\0' && cto_lower(*s1) == cto_lower(*s2)){
23 s2++;
24 s1++;
25 }
26 return cto_lower(*s1) - cto_lower(*s2);
27}
28
29
30
31
41static WORD * init_hash_table(void){
42 WORD * hash_table = (WORD *) malloc(TABLE_SIZE * sizeof(WORD));
43 if (NULL == hash_table){
44 return NULL;
45 }
46 for (unsigned long int i=0;i<TABLE_SIZE -1; i++)
47 hash_table[i] = i;
48 shuffle(hash_table, TABLE_SIZE - 1);
49 return hash_table;
50}
51
59static void free_hash_table(WORD * hash_table){
60 if (NULL == hash_table)
61 return;
62 else
63 free(hash_table);
64 return;
65}
66
67
71static void shuffle(WORD * table, unsigned int n){
72 srand(time(NULL));
73 //srand(1);
74 unsigned int i,j, tmp;
75 for (i = n-1; i> 0; i--){
76 j = rand() % (i+1);
77 tmp = table[j];
78 table[j] = table[i];
79 table[i] = tmp;
80 }
81}
82
83
84
109cdict_ctx* cdict_init(void(*free_func)(void*), void*(*copy_func)(void*)){
110 if (copy_func == NULL){
111 return NULL;
112 }
113 WORD * hash_table = init_hash_table();
114 if (NULL == hash_table)
115 return NULL;
116 cdict_ctx * ctx = (cdict_ctx*) malloc (sizeof(cdict_ctx));
117 if (NULL == ctx)
118 return NULL;
119 ctx->hash_table = hash_table;
120 ctx->table = (PNODE) malloc(TABLE_SIZE * sizeof(NODE));
121
122 if (ctx->table == NULL){
123 free(ctx);
124 return NULL;
125 }
126 ctx->free_func = free_func;
127 ctx->copy_func = copy_func;
128 for (unsigned long int i=0; i< TABLE_SIZE; i++){
129 ctx->table[i].key = NULL;
130 ctx->table[i].value = NULL;
131 ctx->table[i].next = NULL;
132 }
133
134 ctx->errmsg = (char *) malloc(sizeof(char) * 0xFF);
135 ctx->err = 0;
136 //let's assign functions to pointers
137 return ctx;
138}
139
140
146static unsigned int hashme(cdict_ctx * ctx, char * key){
147 if (key == NULL){
148 ctx->err = ERROR_NULL_VALUE_FOR_KEY;
149 strcpy(ctx->errmsg, "Key can not be NULL for a dictionary!");
150 return 0;
151 }
152 unsigned long long int j;
153 j=1;
154 unsigned int key_len = strlen(key);
155 for (unsigned int i=0; i< key_len; ++i){
156 j *= (WORD)key[i];
157 j = (j % (TABLE_SIZE)) & 0xFFFF;
158 }
159 return ctx->hash_table[j];
160}
161
170void * cdict_get(cdict_ctx* ctx, char * key){
171 if (NULL == ctx)
172 return NULL;
173 if (NULL == key){
174 ctx->err = ERROR_NULL_VALUE_FOR_KEY;
175 strcpy(ctx->errmsg, "The key can not be null for a dictionary!");
176 return NULL;
177 }
178 WORD index = hashme(ctx, key);
179 if (ctx->err != ERROR_OK)
180 return NULL;
181 PNODE tmp = &(ctx->table[index]);
182 if (NULL == tmp){
183 return NULL;
184 }
185 while(1){
186 if (NULL == tmp)
187 return NULL;
188 if (tmp->key == NULL)
189 return NULL;
190 if (strcmp(tmp->key, key) == 0){
191 return (void*)tmp->value;
192 }else{
193 tmp = tmp->next;
194 continue;
195 }
196 }
197}
198
199
200
209void * cdict_get_nocase(cdict_ctx* ctx, char * key){
210 if (NULL == ctx)
211 return NULL;
212 if (NULL == key){
213 ctx->err = ERROR_NULL_VALUE_FOR_KEY;
214 strcpy(ctx->errmsg, "The key can not be null for a dictionary!");
215 return NULL;
216 }
217 // make sure you lower case the key first
218 char * clone_key = strdup(key);
219 for (int i=0; clone_key[i]; i++)
220 clone_key[i] = cto_lower(clone_key[i]);
221
222 WORD index = hashme(ctx, clone_key);
223 if (ctx->err != ERROR_OK){
224 free(clone_key);
225 return NULL;
226 }
227 PNODE tmp = &(ctx->table[index]);
228 if (NULL == tmp){
229 free(clone_key);
230 return NULL;
231 }
232 while(1){
233 if (NULL == tmp){
234 free(clone_key);
235 return NULL;
236 }
237 if (tmp->key == NULL){
238 free(clone_key);
239 return NULL;
240 }
241 if (cstr_ccmp(tmp->key, clone_key) == 0){
242 free(clone_key);
243 return (void*)tmp->value;
244 }else{
245 tmp = tmp->next;
246 continue;
247 }
248 }
249}
250
251
263int cdict_set_nocase(cdict_ctx *ctx, char * key, void * value){
264 if (NULL == ctx)
265 return ERROR_DICT_POINTER_IS_NULL;
266 if (NULL == key){
267 ctx->err = ERROR_NULL_VALUE_FOR_KEY;
268 strcpy(ctx->errmsg, "Key can not be NULL!");
269 return ERROR_NULL_VALUE_FOR_KEY;
270 }
271
272 char * clone_key = strdup(key);
273
274 // this is here to make sure we make it lower case for hash table
275 for (int i=0; clone_key[i]; i++)
276 clone_key[i] = cto_lower(clone_key[i]);
277
278 WORD hash_val = hashme(ctx, clone_key);
279
280 void * clone_val = ctx->copy_func(value);
281
282 if (NULL == ctx->table[hash_val].key){
283 // no collision
284 ctx->table[hash_val].key = clone_key;
285 ctx->table[hash_val].value = clone_val;
286 ctx->table[hash_val].next = NULL;
287 return ERROR_OK;
288 }else{
289 // we have collision
290 PNODE tmp = &(ctx->table[hash_val]);
291 while(tmp->next != NULL){
292 if (strcmp(tmp->key, clone_key) != 0){
293 tmp = tmp->next;
294 continue;
295 }else{
296 break;
297 }
298 }
299 if (strcmp(tmp->key, clone_key) == 0){
300 if (tmp->value != NULL)
301 ctx->free_func(tmp->value);
302 // we don't need the clone_key
303 free(clone_key);
304 tmp->value = clone_val;
305 return ERROR_OK;
306 }else{
307 tmp->next = (PNODE) malloc(sizeof(NODE));
308 if (NULL == tmp->next){
309 ctx->err = CDICT_ERROR_CAN_NOT_ALLOCATE_MEMORY;
310 ctx->free_func(clone_val);
311 free(clone_key);
312 strcpy(ctx->errmsg, "Can not allocate memory for the new key-value pair!");
313 return CDICT_ERROR_CAN_NOT_ALLOCATE_MEMORY;
314 }
315 tmp = tmp->next;
316 tmp->key = clone_key;
317 tmp->value = clone_val;
318 tmp->next = NULL;
319 return ERROR_OK;
320 }
321 }
322}
323
324
325
326
327
339int cdict_set(cdict_ctx *ctx, char * key, void * value){
340 if (NULL == ctx)
341 return ERROR_DICT_POINTER_IS_NULL;
342 if (NULL == key){
343 ctx->err = ERROR_NULL_VALUE_FOR_KEY;
344 strcpy(ctx->errmsg, "Key can not be NULL!");
345 return ERROR_NULL_VALUE_FOR_KEY;
346 }
347
348 WORD hash_val = hashme(ctx, key);
349
350 char * clone_key = strdup(key);
351 void * clone_val = ctx->copy_func(value);
352
353 if (NULL == ctx->table[hash_val].key){
354 // no collision
355 ctx->table[hash_val].key = clone_key;
356 ctx->table[hash_val].value = clone_val;
357 ctx->table[hash_val].next = NULL;
358 return ERROR_OK;
359 }else{
360 // we have collision
361 PNODE tmp = &(ctx->table[hash_val]);
362 while(tmp->next != NULL){
363 if (strcmp(tmp->key, clone_key) != 0){
364 tmp = tmp->next;
365 continue;
366 }else{
367 break;
368 }
369 }
370 if (strcmp(tmp->key, clone_key) == 0){
371 if (tmp->value != NULL)
372 ctx->free_func(tmp->value);
373 // we don't need the clone_key
374 free(clone_key);
375 tmp->value = clone_val;
376 return ERROR_OK;
377 }else{
378 tmp->next = (PNODE) malloc(sizeof(NODE));
379 if (NULL == tmp->next){
380 ctx->err = CDICT_ERROR_CAN_NOT_ALLOCATE_MEMORY;
381 ctx->free_func(clone_val);
382 free(clone_key);
383 strcpy(ctx->errmsg, "Can not allocate memory for the new key-value pair!");
384 return CDICT_ERROR_CAN_NOT_ALLOCATE_MEMORY;
385 }
386 tmp = tmp->next;
387 tmp->key = clone_key;
388 tmp->value = clone_val;
389 tmp->next = NULL;
390 return ERROR_OK;
391 }
392 }
393}
394
395
404 PNODE tmp = NULL;
405 PNODE tmp_1 = NULL;
406 if (NULL == ctx)
407 return;
408 //free the pointer to errmsg
409 free(ctx->errmsg);
410 // we need to empty the hash_table
411 if (ctx->table != NULL){
412 for (unsigned int i=0; i< TABLE_SIZE; i++){
413 if (ctx->table[i].key == NULL)
414 continue;
415 tmp = ctx->table[i].next;
416 free(ctx->table[i].key);
417 ctx->free_func(ctx->table[i].value);
418 while (tmp){
419 tmp_1 = tmp;
420 free(tmp_1->key);
421 ctx->free_func(tmp_1->value);
422 tmp = tmp_1->next;
423 free(tmp_1);
424 }
425 }
426 }
427 free(ctx->table);
428 free_hash_table(ctx->hash_table);
429 free(ctx);
430 return;
431}
432
439int cdict_has_key(cdict_ctx* ctx, char * key){
440 if (NULL == ctx)
441 return 0;
442 if (NULL == key){
443 ctx->err = ERROR_NULL_VALUE_FOR_KEY;
444 strcpy(ctx->errmsg, "The key can not be null for a dictionary");
445 return 0;
446 }
447 WORD index = hashme(ctx, key);
448 if (ctx->err != ERROR_OK)
449 return 0;
450 PNODE tmp = &(ctx->table[index]);
451 while(1){
452 if (NULL == tmp)
453 return 0;
454 if (tmp->key == NULL)
455 return 0;
456 if (strcmp(tmp->key, key) == 0){
457 return 1;
458 }else{
459 tmp = tmp->next;
460 continue;
461 }
462 }
463 return 0;
464}
465
466
473int cdict_has_key_nocase(cdict_ctx* ctx, char * key){
474 if (NULL == ctx)
475 return 0;
476 if (NULL == key){
477 ctx->err = ERROR_NULL_VALUE_FOR_KEY;
478 strcpy(ctx->errmsg, "The key can not be null for a dictionary");
479 return 0;
480 }
481 WORD index = hashme(ctx, key);
482 if (ctx->err != ERROR_OK)
483 return 0;
484 PNODE tmp = &(ctx->table[index]);
485 while(1){
486 if (NULL == tmp)
487 return 0;
488 if (tmp->key == NULL)
489 return 0;
490 if (cstr_ccmp(tmp->key, key) == 0){
491 return 1;
492 }else{
493 tmp = tmp->next;
494 continue;
495 }
496 }
497 return 0;
498}
499
500
501
502
509void cdict_free_keylist(cdict_keylist* klst, int clone_keys){
510 if (clone_keys)
511 for (unsigned int i=0; i< klst->len; ++i)
512 free(klst->lst[i]);
513 free(klst->lst);
514 free(klst);
515 return;
516}
517
518
519
533cdict_keylist * cdict_keys(cdict_ctx* ctx, int clone_keys){
534 unsigned long int cnt = 0;
535 PNODE tmp = NULL;
536 for (unsigned long int i=0; i< TABLE_SIZE; i++){
537 if (ctx->table[i].key != NULL){
538 cnt += 1;
539 tmp = ctx->table[i].next;
540 while(tmp && tmp->key){
541 cnt += 1;
542 tmp = tmp->next;
543 }
544 }
545 }
546 cdict_keylist *klst = (cdict_keylist*) malloc(sizeof(cdict_keylist));
547 if (!klst){
548 ctx->err = CDICT_ERROR_CAN_NOT_ALLOCATE_MEMORY;
549 strcpy(ctx->errmsg, "Can not allocate memory for keys");
550 return NULL;
551 }
552 klst->len = cnt;
553 if (cnt == 0)
554 return klst;
555 // allocate cnt * (sizeof(char *))
556 klst->lst = (char**) malloc (cnt * sizeof(char*));
557 if (NULL == klst->lst){
558 ctx->err = CDICT_ERROR_CAN_NOT_ALLOCATE_MEMORY;
559 strcpy(ctx->errmsg, "Can not allocate memory for keys");
560 free(klst);
561 return NULL;
562 }
563 tmp = NULL;
564 cnt = 0;
565 ctx->err = ERROR_OK;
566 for (unsigned long int i=0; i< TABLE_SIZE; ++i){
567 if (ctx->table[i].key != NULL){
568 klst->lst[cnt] = clone_keys?strdup(ctx->table[i].key):ctx->table[i].key;
569 cnt += 1;
570 tmp = ctx->table[i].next;
571 while (tmp && tmp->key){
572 klst->lst[cnt] = clone_keys?strdup(tmp->key):tmp->key;
573 cnt += 1;
574 tmp = tmp->next;
575 }
576 }
577 }
578 return klst;
579}
580
588void cdict_remove(cdict_ctx * ctx, char * key){
589 if (!ctx)
590 return;
591 if (!key)
592 return;
593 PNODE tmp, tmp_1;
594 WORD index = hashme(ctx, key);
595 // if key is not there return
596 if (!cdict_has_key(ctx, key))
597 return;
598 // key is there
599 tmp = &(ctx->table[index]);
600 if (strcmp(key, tmp->key) == 0){
601 // in the main chain
602 if (tmp->next == NULL){
603 free(tmp->key);
604 tmp->key = NULL;
605 ctx->free_func(tmp->value);
606 tmp->value = NULL;
607 return;
608 }else{
609 // with link
610 free(tmp->key);
611 ctx->free_func(tmp->value);
612 tmp->key = strdup(tmp->next->key);
613 tmp->value = ctx->copy_func(tmp->next->value);
614 tmp_1 = tmp->next;
615 tmp->next = tmp_1->next;
616 // now remove tmp_1
617 free(tmp_1->key);
618 ctx->free_func(tmp_1->value);
619 free(tmp_1);
620 return;
621 }
622 }
623 // not in the main chain
624 tmp_1 = tmp;
625 tmp = tmp->next;
626 while (tmp){
627 if (strcmp(tmp->key, key) == 0){
628 break;
629 }
630 tmp_1 = tmp;
631 tmp = tmp->next;
632 }
633 // tmp is the candidate, tmp_1 is its parent
634 if (tmp->next == NULL){
635 // it's a leaf
636 free(tmp->key);
637 ctx->free_func(tmp->value);
638 free(tmp);
639 tmp_1->next = NULL;
640 return;
641 }else{
642 // it's in the middle
643 tmp_1->next = tmp->next;
644 free(tmp->key);
645 ctx->free_func(tmp->value);
646 free(tmp);
647 return;
648 }
649 return;
650}
651
void * cdict_get_nocase(cdict_ctx *ctx, char *key)
get a value from the dictionary by providing the key (case-insensitive key)
Definition cdict.c:209
int cdict_has_key_nocase(cdict_ctx *ctx, char *key)
Checks if the key exists in the dictionary (case-insensitive comparison)
Definition cdict.c:473
void cdict_free_keylist(cdict_keylist *klst, int clone_keys)
This function free the keylist structure returned by cdict_keys()
Definition cdict.c:509
void cdict_free(cdict_ctx *ctx)
Frees the memory allocated for the dictionary.
Definition cdict.c:403
int cdict_has_key(cdict_ctx *ctx, char *key)
Checks if the key exists in the dictionary.
Definition cdict.c:439
int cdict_set_nocase(cdict_ctx *ctx, char *key, void *value)
Sets the new value for a given key (make key lower case first).
Definition cdict.c:263
cdict_ctx * cdict_init(void(*free_func)(void *), void *(*copy_func)(void *))
Initializes the Dictionary in the memory.
Definition cdict.c:109
void cdict_remove(cdict_ctx *ctx, char *key)
Removes a key-value pair from the dictionary.
Definition cdict.c:588
int cdict_set(cdict_ctx *ctx, char *key, void *value)
Sets the new value for a given key.
Definition cdict.c:339
void * cdict_get(cdict_ctx *ctx, char *key)
Definition cdict.c:170
cdict_keylist * cdict_keys(cdict_ctx *ctx, int clone_keys)
Get the list of keys from the dictionary.
Definition cdict.c:533
Definition cdict.h:40
PNODE table
Pointer to an array of NODE structure.
Definition cdict.h:41
int err
Possible Error code.
Definition cdict.h:44
WORD * hash_table
Pointer to the hash table for hashing.
Definition cdict.h:42
char * errmsg
Description of the possible error.
Definition cdict.h:43
void *(* copy_func)(void *)
a pointer to the copy function provided by user
Definition cdict.h:46
void(* free_func)(void *)
a pointer to the free function provided by user
Definition cdict.h:45
Definition cdict.h:28
char * key
key for finding matches. Key is a null-terminated string
Definition cdict.h:29
void * value
Value to store. value is a pointer to void so it can be any type.
Definition cdict.h:30
struct _NODE * next
A pointer points to the next node in case of collision.
Definition cdict.h:31