General Purpose C Dictionary

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
4
down vote

favorite












I'm trying to create a general purpose C dictionary (as an opaque data type) capable of dynamically allocating basic types (ints, floats, strings and longs) as well as accepting void pointers to already allocated custom types. It works as far as my testing shows but I question the basic architecture and can't help but to feel like it's missing something or that I may be overlooking something that's very obviously wrong with it. Is there a better way to go about doing this?



Note: mem_free() and mem_alloc() are simple malloc/free wrappers and serialize_type does what it says.



dictionary.c



#include "dictionary.h"

#define DICT_VOID_PTR_TYPE 0
#define DICT_FUNC_PTR_TYPE 1
#define DICT_INT_TYPE 5
#define DICT_LONG_TYPE 6
#define DICT_FLOAT_TYPE 7
#define DICT_STR_TYPE 8

#define DICT_MAX_KEY_LEN 32

#define SERIALIZE_IN 100
#define SERIALIZE_OUT 101


typedef struct dict_node_s
int_t type;
int_t alloc_size;
char_t *key;
void *value;
struct dict_node_s *next;
dict_node_t;


struct dictionary
dict_node_t **entries;
int_t size;
int_t cnt;
;


uint_t dict_hash(dict_t *dict, char_t *s)

uint_t hash_val;
for (hash_val = 0; *s != ''; s++)
hash_val = *s + 31 * hash_val;
return hash_val % (dict->size);



void dict_clr(dict_t *dict)

int_t cntr = 0;
for (int_t i = 0; i < dict->size; i++)
dict_node_t *n = dict->entries[i];
while (n != NULL)
dict_node_t *next = n->next;
if (n->alloc_size > 0)
mem_free(n->value);

mem_free(n->key);
mem_free(n);

cntr++;
n = next;

dict->entries[i] = NULL;

dict->cnt -= cntr;



bool_t dict_remove(dict_t *dict, char_t *key)

dict_node_t *prev = NULL;
uint_t hash = dict_hash(dict, key);

for (dict_node_t *np = dict->entries[hash]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0)
dict_node_t *next = np->next;

if (np->alloc_size > 0)
mem_free(np->value);

mem_free(np->key);
mem_free(np);

if (prev != NULL)
prev->next = next;
else if (next != NULL)
dict->entries[hash] = next;
else
dict->entries[hash] = NULL;
dict->cnt--;
return TRUE;

prev = np;

return FALSE;



int_t dict_size(dict_t *dict)

if (dict != NULL)
return dict->cnt;

return 0;


dict_t *dict_init(int_t size)

dict_t *dict = mem_alloc(sizeof(dict_t));

ASSERT(dict != NULL);
dict->size = size;
dict->cnt = 0;
dict->entries = mem_alloc(size * sizeof(dict_node_t*));
for (int_t i = 0; i < size; i++)
dict->entries[i] = NULL;

return dict;




void serialize_dict(dict_t *dict, FILE *fp, int_t kind)

ASSERT(dict != NULL);

if (kind == SERIALIZE_OUT)
serialize_int(&dict->size, fp, kind);
serialize_int(&dict->cnt, fp, kind);

for (int_t i = 0; i < dict->size; i++)
for (dict_node_t *node = dict->entries[i]; node != NULL; node = node->next)
serialize_int(&node->type, fp, kind);
serialize_int(&node->alloc_size, fp, kind);
for (int_t i = 0; i < DICT_MAX_KEY_LEN; i++)
serialize_char(&node->key[i], fp, kind);

switch (node->type)
case DICT_INT_TYPE:
serialize_int((int_t*)node->value, fp, kind);
break;
case DICT_FLOAT_TYPE:
serialize_float((float_t*)node->value, fp, kind);
break;
case DICT_LONG_TYPE:
serialize_long((long_t*)node->value, fp, kind);
break;
case DICT_STR_TYPE:
for (int_t i = 0; i < node->alloc_size; i++)
serialize_char((char_t*)&node->value[i], fp, kind);

break;
default:
break;




else if (kind == SERIALIZE_IN)
char_t key[DICT_MAX_KEY_LEN];
int_t size, cnt;
int_t alloc_size = 0, type = 0, key_len = -1;
int_t ival;
float_t fval;
long_t lval;
char_t *s;

dict_clr(dict);

serialize_int(&size, fp, kind);
serialize_int(&cnt, fp, kind);

dict->size = size;

for (int_t i = 0; i < cnt; i++)
serialize_int(&type, fp, kind);
serialize_int(&alloc_size, fp, kind);
for (int_t j = 0; j < DICT_MAX_KEY_LEN; j++)
serialize_char(&key[j], fp, kind);


switch (type)
case DICT_INT_TYPE:
serialize_int(&ival, fp, kind);
dict_add_int(dict, key, ival);
break;
case DICT_FLOAT_TYPE:
serialize_float(&fval, fp, kind);
dict_add_float(dict, key, fval);
break;
case DICT_LONG_TYPE:
serialize_long(&lval, fp, kind);
dict_add_long(dict, key, lval);
break;
case DICT_STR_TYPE:
s = mem_alloc(alloc_size);
for (int_t j = 0; j < alloc_size; j++)
serialize_char(&s[j], fp, kind);

dict_add_str(dict, key, s, alloc_size);
mem_free(s);
break;
default:
break;






int_t dict_atmoic_size(dict_t *dict, char_t *key)

for (dict_node_t *np = dict->entries[dict_hash(dict, key)]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0)
return np->alloc_size;


return -1;


void *dict_atmoic_ptr(dict_t *dict,
char_t *key,
int_t type,
void *func_param)

for (dict_node_t *np = dict->entries[dict_hash(dict, key)]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0 && np->type == type)

if (type == DICT_VOID_PTR_TYPE)
if (np->alloc_size > 0)
return &np->value;
else
return np->value;

else if (type == DICT_FUNC_PTR_TYPE)
dict_func_ptr func_ptr = np->value;
func_ptr(func_param);

else
return np->value;



return NULL;


void *dict_atomic_add(dict_t *dict,
char_t *name,
void *ptr,
int_t type,
int_t alloc_size)

dict_node_t *node;
uint_t hashval;

for (node = dict->entries[dict_hash(dict, name)]; node != NULL; node = node->next)
if (strcmp(name, node->key) == 0)
return NULL;



ASSERT((ptr != NULL


int_t dict_int(dict_t *dict, char_t *key)

return *(int_t*)dict_atmoic_ptr(dict, key, DICT_INT_TYPE, NULL);



void dict_set_int(dict_t *dict, char_t *key, int_t value)

*(int_t*)dict_atmoic_ptr(dict, key, DICT_INT_TYPE, NULL) = value;



bool_t dict_add_int(dict_t *dict, char_t *name, int_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_INT_TYPE, sizeof(int_t));
if (success)
dict_set_int(dict, name, initial_val);
return success;



float_t dict_float(dict_t *dict, char_t *key)

return *(float_t*)dict_atmoic_ptr(dict, key, DICT_FLOAT_TYPE, NULL);



void dict_set_float(dict_t *dict, char_t *key, float_t value)

*(float_t*)dict_atmoic_ptr(dict, key, DICT_FLOAT_TYPE, NULL) = value;



bool_t dict_add_float(dict_t *dict, char_t *name, float_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_FLOAT_TYPE, sizeof(float_t));
if (success)
dict_set_float(dict, name, initial_val);
return success;



long_t dict_long(dict_t *dict, char_t *key)

return *(long_t*)dict_atmoic_ptr(dict, key, DICT_LONG_TYPE, NULL);



void dict_set_long(dict_t *dict, char_t *key, long_t value)

*(long_t*)dict_atmoic_ptr(dict, key, DICT_LONG_TYPE, NULL) = value;



bool_t dict_add_long(dict_t *dict, char_t *name, long_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_LONG_TYPE, sizeof(long_t));
if (success)
dict_set_long(dict, name, initial_val);
return success;



char_t *dict_str(dict_t *dict, char_t *key)

return (char_t*)dict_atmoic_ptr(dict, key, DICT_STR_TYPE, NULL);


void dict_set_str(dict_t *dict, char_t *key, char_t *value)

if (strlen(value) < dict_atmoic_size(dict, key)-1)
strcpy((char_t*)dict_atmoic_ptr(dict, key, DICT_STR_TYPE, NULL), value);




bool_t dict_add_str(dict_t *dict, char_t *key, char_t *initial_str, int_t max_len)

int_t str_size = max_len;

if (str_size <= 0 && initial_str != NULL)
str_size = strlen(initial_str)+1;

bool_t success = dict_atomic_add(dict, key, NULL, DICT_STR_TYPE, str_size);
if (success && initial_str != NULL)
dict_set_str(dict, key, initial_str);
return success;



void dict_func(dict_t *dict, char_t *key, void *param)

dict_atmoic_ptr(dict, key, DICT_FUNC_PTR_TYPE, param);



bool_t dict_add_func(dict_t *dict, char_t *name, dict_func_ptr func)

return dict_atomic_add(dict, name, func, DICT_FUNC_PTR_TYPE, 0);




void *dict_ptr(dict_t *dict, char_t *name)

return dict_atmoic_ptr(dict, name, DICT_VOID_PTR_TYPE, NULL);



bool_t dict_add_ptr(dict_t *dict, char_t* name, void *data)

return (dict_atomic_add(dict, name, data, DICT_VOID_PTR_TYPE, 0) != NULL);







share|improve this question





















  • Spelling: should dict_atmoic_ptr be dict_atomic_ptr?
    – Toby Speight
    Mar 26 at 10:23






  • 1




    Do you have a matching dictionary.h and runnable main() that exercises this code, so we can compile it and try it out ourselves?
    – Toby Speight
    Mar 26 at 10:25
















up vote
4
down vote

favorite












I'm trying to create a general purpose C dictionary (as an opaque data type) capable of dynamically allocating basic types (ints, floats, strings and longs) as well as accepting void pointers to already allocated custom types. It works as far as my testing shows but I question the basic architecture and can't help but to feel like it's missing something or that I may be overlooking something that's very obviously wrong with it. Is there a better way to go about doing this?



Note: mem_free() and mem_alloc() are simple malloc/free wrappers and serialize_type does what it says.



dictionary.c



#include "dictionary.h"

#define DICT_VOID_PTR_TYPE 0
#define DICT_FUNC_PTR_TYPE 1
#define DICT_INT_TYPE 5
#define DICT_LONG_TYPE 6
#define DICT_FLOAT_TYPE 7
#define DICT_STR_TYPE 8

#define DICT_MAX_KEY_LEN 32

#define SERIALIZE_IN 100
#define SERIALIZE_OUT 101


typedef struct dict_node_s
int_t type;
int_t alloc_size;
char_t *key;
void *value;
struct dict_node_s *next;
dict_node_t;


struct dictionary
dict_node_t **entries;
int_t size;
int_t cnt;
;


uint_t dict_hash(dict_t *dict, char_t *s)

uint_t hash_val;
for (hash_val = 0; *s != ''; s++)
hash_val = *s + 31 * hash_val;
return hash_val % (dict->size);



void dict_clr(dict_t *dict)

int_t cntr = 0;
for (int_t i = 0; i < dict->size; i++)
dict_node_t *n = dict->entries[i];
while (n != NULL)
dict_node_t *next = n->next;
if (n->alloc_size > 0)
mem_free(n->value);

mem_free(n->key);
mem_free(n);

cntr++;
n = next;

dict->entries[i] = NULL;

dict->cnt -= cntr;



bool_t dict_remove(dict_t *dict, char_t *key)

dict_node_t *prev = NULL;
uint_t hash = dict_hash(dict, key);

for (dict_node_t *np = dict->entries[hash]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0)
dict_node_t *next = np->next;

if (np->alloc_size > 0)
mem_free(np->value);

mem_free(np->key);
mem_free(np);

if (prev != NULL)
prev->next = next;
else if (next != NULL)
dict->entries[hash] = next;
else
dict->entries[hash] = NULL;
dict->cnt--;
return TRUE;

prev = np;

return FALSE;



int_t dict_size(dict_t *dict)

if (dict != NULL)
return dict->cnt;

return 0;


dict_t *dict_init(int_t size)

dict_t *dict = mem_alloc(sizeof(dict_t));

ASSERT(dict != NULL);
dict->size = size;
dict->cnt = 0;
dict->entries = mem_alloc(size * sizeof(dict_node_t*));
for (int_t i = 0; i < size; i++)
dict->entries[i] = NULL;

return dict;




void serialize_dict(dict_t *dict, FILE *fp, int_t kind)

ASSERT(dict != NULL);

if (kind == SERIALIZE_OUT)
serialize_int(&dict->size, fp, kind);
serialize_int(&dict->cnt, fp, kind);

for (int_t i = 0; i < dict->size; i++)
for (dict_node_t *node = dict->entries[i]; node != NULL; node = node->next)
serialize_int(&node->type, fp, kind);
serialize_int(&node->alloc_size, fp, kind);
for (int_t i = 0; i < DICT_MAX_KEY_LEN; i++)
serialize_char(&node->key[i], fp, kind);

switch (node->type)
case DICT_INT_TYPE:
serialize_int((int_t*)node->value, fp, kind);
break;
case DICT_FLOAT_TYPE:
serialize_float((float_t*)node->value, fp, kind);
break;
case DICT_LONG_TYPE:
serialize_long((long_t*)node->value, fp, kind);
break;
case DICT_STR_TYPE:
for (int_t i = 0; i < node->alloc_size; i++)
serialize_char((char_t*)&node->value[i], fp, kind);

break;
default:
break;




else if (kind == SERIALIZE_IN)
char_t key[DICT_MAX_KEY_LEN];
int_t size, cnt;
int_t alloc_size = 0, type = 0, key_len = -1;
int_t ival;
float_t fval;
long_t lval;
char_t *s;

dict_clr(dict);

serialize_int(&size, fp, kind);
serialize_int(&cnt, fp, kind);

dict->size = size;

for (int_t i = 0; i < cnt; i++)
serialize_int(&type, fp, kind);
serialize_int(&alloc_size, fp, kind);
for (int_t j = 0; j < DICT_MAX_KEY_LEN; j++)
serialize_char(&key[j], fp, kind);


switch (type)
case DICT_INT_TYPE:
serialize_int(&ival, fp, kind);
dict_add_int(dict, key, ival);
break;
case DICT_FLOAT_TYPE:
serialize_float(&fval, fp, kind);
dict_add_float(dict, key, fval);
break;
case DICT_LONG_TYPE:
serialize_long(&lval, fp, kind);
dict_add_long(dict, key, lval);
break;
case DICT_STR_TYPE:
s = mem_alloc(alloc_size);
for (int_t j = 0; j < alloc_size; j++)
serialize_char(&s[j], fp, kind);

dict_add_str(dict, key, s, alloc_size);
mem_free(s);
break;
default:
break;






int_t dict_atmoic_size(dict_t *dict, char_t *key)

for (dict_node_t *np = dict->entries[dict_hash(dict, key)]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0)
return np->alloc_size;


return -1;


void *dict_atmoic_ptr(dict_t *dict,
char_t *key,
int_t type,
void *func_param)

for (dict_node_t *np = dict->entries[dict_hash(dict, key)]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0 && np->type == type)

if (type == DICT_VOID_PTR_TYPE)
if (np->alloc_size > 0)
return &np->value;
else
return np->value;

else if (type == DICT_FUNC_PTR_TYPE)
dict_func_ptr func_ptr = np->value;
func_ptr(func_param);

else
return np->value;



return NULL;


void *dict_atomic_add(dict_t *dict,
char_t *name,
void *ptr,
int_t type,
int_t alloc_size)

dict_node_t *node;
uint_t hashval;

for (node = dict->entries[dict_hash(dict, name)]; node != NULL; node = node->next)
if (strcmp(name, node->key) == 0)
return NULL;



ASSERT((ptr != NULL


int_t dict_int(dict_t *dict, char_t *key)

return *(int_t*)dict_atmoic_ptr(dict, key, DICT_INT_TYPE, NULL);



void dict_set_int(dict_t *dict, char_t *key, int_t value)

*(int_t*)dict_atmoic_ptr(dict, key, DICT_INT_TYPE, NULL) = value;



bool_t dict_add_int(dict_t *dict, char_t *name, int_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_INT_TYPE, sizeof(int_t));
if (success)
dict_set_int(dict, name, initial_val);
return success;



float_t dict_float(dict_t *dict, char_t *key)

return *(float_t*)dict_atmoic_ptr(dict, key, DICT_FLOAT_TYPE, NULL);



void dict_set_float(dict_t *dict, char_t *key, float_t value)

*(float_t*)dict_atmoic_ptr(dict, key, DICT_FLOAT_TYPE, NULL) = value;



bool_t dict_add_float(dict_t *dict, char_t *name, float_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_FLOAT_TYPE, sizeof(float_t));
if (success)
dict_set_float(dict, name, initial_val);
return success;



long_t dict_long(dict_t *dict, char_t *key)

return *(long_t*)dict_atmoic_ptr(dict, key, DICT_LONG_TYPE, NULL);



void dict_set_long(dict_t *dict, char_t *key, long_t value)

*(long_t*)dict_atmoic_ptr(dict, key, DICT_LONG_TYPE, NULL) = value;



bool_t dict_add_long(dict_t *dict, char_t *name, long_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_LONG_TYPE, sizeof(long_t));
if (success)
dict_set_long(dict, name, initial_val);
return success;



char_t *dict_str(dict_t *dict, char_t *key)

return (char_t*)dict_atmoic_ptr(dict, key, DICT_STR_TYPE, NULL);


void dict_set_str(dict_t *dict, char_t *key, char_t *value)

if (strlen(value) < dict_atmoic_size(dict, key)-1)
strcpy((char_t*)dict_atmoic_ptr(dict, key, DICT_STR_TYPE, NULL), value);




bool_t dict_add_str(dict_t *dict, char_t *key, char_t *initial_str, int_t max_len)

int_t str_size = max_len;

if (str_size <= 0 && initial_str != NULL)
str_size = strlen(initial_str)+1;

bool_t success = dict_atomic_add(dict, key, NULL, DICT_STR_TYPE, str_size);
if (success && initial_str != NULL)
dict_set_str(dict, key, initial_str);
return success;



void dict_func(dict_t *dict, char_t *key, void *param)

dict_atmoic_ptr(dict, key, DICT_FUNC_PTR_TYPE, param);



bool_t dict_add_func(dict_t *dict, char_t *name, dict_func_ptr func)

return dict_atomic_add(dict, name, func, DICT_FUNC_PTR_TYPE, 0);




void *dict_ptr(dict_t *dict, char_t *name)

return dict_atmoic_ptr(dict, name, DICT_VOID_PTR_TYPE, NULL);



bool_t dict_add_ptr(dict_t *dict, char_t* name, void *data)

return (dict_atomic_add(dict, name, data, DICT_VOID_PTR_TYPE, 0) != NULL);







share|improve this question





















  • Spelling: should dict_atmoic_ptr be dict_atomic_ptr?
    – Toby Speight
    Mar 26 at 10:23






  • 1




    Do you have a matching dictionary.h and runnable main() that exercises this code, so we can compile it and try it out ourselves?
    – Toby Speight
    Mar 26 at 10:25












up vote
4
down vote

favorite









up vote
4
down vote

favorite











I'm trying to create a general purpose C dictionary (as an opaque data type) capable of dynamically allocating basic types (ints, floats, strings and longs) as well as accepting void pointers to already allocated custom types. It works as far as my testing shows but I question the basic architecture and can't help but to feel like it's missing something or that I may be overlooking something that's very obviously wrong with it. Is there a better way to go about doing this?



Note: mem_free() and mem_alloc() are simple malloc/free wrappers and serialize_type does what it says.



dictionary.c



#include "dictionary.h"

#define DICT_VOID_PTR_TYPE 0
#define DICT_FUNC_PTR_TYPE 1
#define DICT_INT_TYPE 5
#define DICT_LONG_TYPE 6
#define DICT_FLOAT_TYPE 7
#define DICT_STR_TYPE 8

#define DICT_MAX_KEY_LEN 32

#define SERIALIZE_IN 100
#define SERIALIZE_OUT 101


typedef struct dict_node_s
int_t type;
int_t alloc_size;
char_t *key;
void *value;
struct dict_node_s *next;
dict_node_t;


struct dictionary
dict_node_t **entries;
int_t size;
int_t cnt;
;


uint_t dict_hash(dict_t *dict, char_t *s)

uint_t hash_val;
for (hash_val = 0; *s != ''; s++)
hash_val = *s + 31 * hash_val;
return hash_val % (dict->size);



void dict_clr(dict_t *dict)

int_t cntr = 0;
for (int_t i = 0; i < dict->size; i++)
dict_node_t *n = dict->entries[i];
while (n != NULL)
dict_node_t *next = n->next;
if (n->alloc_size > 0)
mem_free(n->value);

mem_free(n->key);
mem_free(n);

cntr++;
n = next;

dict->entries[i] = NULL;

dict->cnt -= cntr;



bool_t dict_remove(dict_t *dict, char_t *key)

dict_node_t *prev = NULL;
uint_t hash = dict_hash(dict, key);

for (dict_node_t *np = dict->entries[hash]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0)
dict_node_t *next = np->next;

if (np->alloc_size > 0)
mem_free(np->value);

mem_free(np->key);
mem_free(np);

if (prev != NULL)
prev->next = next;
else if (next != NULL)
dict->entries[hash] = next;
else
dict->entries[hash] = NULL;
dict->cnt--;
return TRUE;

prev = np;

return FALSE;



int_t dict_size(dict_t *dict)

if (dict != NULL)
return dict->cnt;

return 0;


dict_t *dict_init(int_t size)

dict_t *dict = mem_alloc(sizeof(dict_t));

ASSERT(dict != NULL);
dict->size = size;
dict->cnt = 0;
dict->entries = mem_alloc(size * sizeof(dict_node_t*));
for (int_t i = 0; i < size; i++)
dict->entries[i] = NULL;

return dict;




void serialize_dict(dict_t *dict, FILE *fp, int_t kind)

ASSERT(dict != NULL);

if (kind == SERIALIZE_OUT)
serialize_int(&dict->size, fp, kind);
serialize_int(&dict->cnt, fp, kind);

for (int_t i = 0; i < dict->size; i++)
for (dict_node_t *node = dict->entries[i]; node != NULL; node = node->next)
serialize_int(&node->type, fp, kind);
serialize_int(&node->alloc_size, fp, kind);
for (int_t i = 0; i < DICT_MAX_KEY_LEN; i++)
serialize_char(&node->key[i], fp, kind);

switch (node->type)
case DICT_INT_TYPE:
serialize_int((int_t*)node->value, fp, kind);
break;
case DICT_FLOAT_TYPE:
serialize_float((float_t*)node->value, fp, kind);
break;
case DICT_LONG_TYPE:
serialize_long((long_t*)node->value, fp, kind);
break;
case DICT_STR_TYPE:
for (int_t i = 0; i < node->alloc_size; i++)
serialize_char((char_t*)&node->value[i], fp, kind);

break;
default:
break;




else if (kind == SERIALIZE_IN)
char_t key[DICT_MAX_KEY_LEN];
int_t size, cnt;
int_t alloc_size = 0, type = 0, key_len = -1;
int_t ival;
float_t fval;
long_t lval;
char_t *s;

dict_clr(dict);

serialize_int(&size, fp, kind);
serialize_int(&cnt, fp, kind);

dict->size = size;

for (int_t i = 0; i < cnt; i++)
serialize_int(&type, fp, kind);
serialize_int(&alloc_size, fp, kind);
for (int_t j = 0; j < DICT_MAX_KEY_LEN; j++)
serialize_char(&key[j], fp, kind);


switch (type)
case DICT_INT_TYPE:
serialize_int(&ival, fp, kind);
dict_add_int(dict, key, ival);
break;
case DICT_FLOAT_TYPE:
serialize_float(&fval, fp, kind);
dict_add_float(dict, key, fval);
break;
case DICT_LONG_TYPE:
serialize_long(&lval, fp, kind);
dict_add_long(dict, key, lval);
break;
case DICT_STR_TYPE:
s = mem_alloc(alloc_size);
for (int_t j = 0; j < alloc_size; j++)
serialize_char(&s[j], fp, kind);

dict_add_str(dict, key, s, alloc_size);
mem_free(s);
break;
default:
break;






int_t dict_atmoic_size(dict_t *dict, char_t *key)

for (dict_node_t *np = dict->entries[dict_hash(dict, key)]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0)
return np->alloc_size;


return -1;


void *dict_atmoic_ptr(dict_t *dict,
char_t *key,
int_t type,
void *func_param)

for (dict_node_t *np = dict->entries[dict_hash(dict, key)]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0 && np->type == type)

if (type == DICT_VOID_PTR_TYPE)
if (np->alloc_size > 0)
return &np->value;
else
return np->value;

else if (type == DICT_FUNC_PTR_TYPE)
dict_func_ptr func_ptr = np->value;
func_ptr(func_param);

else
return np->value;



return NULL;


void *dict_atomic_add(dict_t *dict,
char_t *name,
void *ptr,
int_t type,
int_t alloc_size)

dict_node_t *node;
uint_t hashval;

for (node = dict->entries[dict_hash(dict, name)]; node != NULL; node = node->next)
if (strcmp(name, node->key) == 0)
return NULL;



ASSERT((ptr != NULL


int_t dict_int(dict_t *dict, char_t *key)

return *(int_t*)dict_atmoic_ptr(dict, key, DICT_INT_TYPE, NULL);



void dict_set_int(dict_t *dict, char_t *key, int_t value)

*(int_t*)dict_atmoic_ptr(dict, key, DICT_INT_TYPE, NULL) = value;



bool_t dict_add_int(dict_t *dict, char_t *name, int_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_INT_TYPE, sizeof(int_t));
if (success)
dict_set_int(dict, name, initial_val);
return success;



float_t dict_float(dict_t *dict, char_t *key)

return *(float_t*)dict_atmoic_ptr(dict, key, DICT_FLOAT_TYPE, NULL);



void dict_set_float(dict_t *dict, char_t *key, float_t value)

*(float_t*)dict_atmoic_ptr(dict, key, DICT_FLOAT_TYPE, NULL) = value;



bool_t dict_add_float(dict_t *dict, char_t *name, float_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_FLOAT_TYPE, sizeof(float_t));
if (success)
dict_set_float(dict, name, initial_val);
return success;



long_t dict_long(dict_t *dict, char_t *key)

return *(long_t*)dict_atmoic_ptr(dict, key, DICT_LONG_TYPE, NULL);



void dict_set_long(dict_t *dict, char_t *key, long_t value)

*(long_t*)dict_atmoic_ptr(dict, key, DICT_LONG_TYPE, NULL) = value;



bool_t dict_add_long(dict_t *dict, char_t *name, long_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_LONG_TYPE, sizeof(long_t));
if (success)
dict_set_long(dict, name, initial_val);
return success;



char_t *dict_str(dict_t *dict, char_t *key)

return (char_t*)dict_atmoic_ptr(dict, key, DICT_STR_TYPE, NULL);


void dict_set_str(dict_t *dict, char_t *key, char_t *value)

if (strlen(value) < dict_atmoic_size(dict, key)-1)
strcpy((char_t*)dict_atmoic_ptr(dict, key, DICT_STR_TYPE, NULL), value);




bool_t dict_add_str(dict_t *dict, char_t *key, char_t *initial_str, int_t max_len)

int_t str_size = max_len;

if (str_size <= 0 && initial_str != NULL)
str_size = strlen(initial_str)+1;

bool_t success = dict_atomic_add(dict, key, NULL, DICT_STR_TYPE, str_size);
if (success && initial_str != NULL)
dict_set_str(dict, key, initial_str);
return success;



void dict_func(dict_t *dict, char_t *key, void *param)

dict_atmoic_ptr(dict, key, DICT_FUNC_PTR_TYPE, param);



bool_t dict_add_func(dict_t *dict, char_t *name, dict_func_ptr func)

return dict_atomic_add(dict, name, func, DICT_FUNC_PTR_TYPE, 0);




void *dict_ptr(dict_t *dict, char_t *name)

return dict_atmoic_ptr(dict, name, DICT_VOID_PTR_TYPE, NULL);



bool_t dict_add_ptr(dict_t *dict, char_t* name, void *data)

return (dict_atomic_add(dict, name, data, DICT_VOID_PTR_TYPE, 0) != NULL);







share|improve this question













I'm trying to create a general purpose C dictionary (as an opaque data type) capable of dynamically allocating basic types (ints, floats, strings and longs) as well as accepting void pointers to already allocated custom types. It works as far as my testing shows but I question the basic architecture and can't help but to feel like it's missing something or that I may be overlooking something that's very obviously wrong with it. Is there a better way to go about doing this?



Note: mem_free() and mem_alloc() are simple malloc/free wrappers and serialize_type does what it says.



dictionary.c



#include "dictionary.h"

#define DICT_VOID_PTR_TYPE 0
#define DICT_FUNC_PTR_TYPE 1
#define DICT_INT_TYPE 5
#define DICT_LONG_TYPE 6
#define DICT_FLOAT_TYPE 7
#define DICT_STR_TYPE 8

#define DICT_MAX_KEY_LEN 32

#define SERIALIZE_IN 100
#define SERIALIZE_OUT 101


typedef struct dict_node_s
int_t type;
int_t alloc_size;
char_t *key;
void *value;
struct dict_node_s *next;
dict_node_t;


struct dictionary
dict_node_t **entries;
int_t size;
int_t cnt;
;


uint_t dict_hash(dict_t *dict, char_t *s)

uint_t hash_val;
for (hash_val = 0; *s != ''; s++)
hash_val = *s + 31 * hash_val;
return hash_val % (dict->size);



void dict_clr(dict_t *dict)

int_t cntr = 0;
for (int_t i = 0; i < dict->size; i++)
dict_node_t *n = dict->entries[i];
while (n != NULL)
dict_node_t *next = n->next;
if (n->alloc_size > 0)
mem_free(n->value);

mem_free(n->key);
mem_free(n);

cntr++;
n = next;

dict->entries[i] = NULL;

dict->cnt -= cntr;



bool_t dict_remove(dict_t *dict, char_t *key)

dict_node_t *prev = NULL;
uint_t hash = dict_hash(dict, key);

for (dict_node_t *np = dict->entries[hash]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0)
dict_node_t *next = np->next;

if (np->alloc_size > 0)
mem_free(np->value);

mem_free(np->key);
mem_free(np);

if (prev != NULL)
prev->next = next;
else if (next != NULL)
dict->entries[hash] = next;
else
dict->entries[hash] = NULL;
dict->cnt--;
return TRUE;

prev = np;

return FALSE;



int_t dict_size(dict_t *dict)

if (dict != NULL)
return dict->cnt;

return 0;


dict_t *dict_init(int_t size)

dict_t *dict = mem_alloc(sizeof(dict_t));

ASSERT(dict != NULL);
dict->size = size;
dict->cnt = 0;
dict->entries = mem_alloc(size * sizeof(dict_node_t*));
for (int_t i = 0; i < size; i++)
dict->entries[i] = NULL;

return dict;




void serialize_dict(dict_t *dict, FILE *fp, int_t kind)

ASSERT(dict != NULL);

if (kind == SERIALIZE_OUT)
serialize_int(&dict->size, fp, kind);
serialize_int(&dict->cnt, fp, kind);

for (int_t i = 0; i < dict->size; i++)
for (dict_node_t *node = dict->entries[i]; node != NULL; node = node->next)
serialize_int(&node->type, fp, kind);
serialize_int(&node->alloc_size, fp, kind);
for (int_t i = 0; i < DICT_MAX_KEY_LEN; i++)
serialize_char(&node->key[i], fp, kind);

switch (node->type)
case DICT_INT_TYPE:
serialize_int((int_t*)node->value, fp, kind);
break;
case DICT_FLOAT_TYPE:
serialize_float((float_t*)node->value, fp, kind);
break;
case DICT_LONG_TYPE:
serialize_long((long_t*)node->value, fp, kind);
break;
case DICT_STR_TYPE:
for (int_t i = 0; i < node->alloc_size; i++)
serialize_char((char_t*)&node->value[i], fp, kind);

break;
default:
break;




else if (kind == SERIALIZE_IN)
char_t key[DICT_MAX_KEY_LEN];
int_t size, cnt;
int_t alloc_size = 0, type = 0, key_len = -1;
int_t ival;
float_t fval;
long_t lval;
char_t *s;

dict_clr(dict);

serialize_int(&size, fp, kind);
serialize_int(&cnt, fp, kind);

dict->size = size;

for (int_t i = 0; i < cnt; i++)
serialize_int(&type, fp, kind);
serialize_int(&alloc_size, fp, kind);
for (int_t j = 0; j < DICT_MAX_KEY_LEN; j++)
serialize_char(&key[j], fp, kind);


switch (type)
case DICT_INT_TYPE:
serialize_int(&ival, fp, kind);
dict_add_int(dict, key, ival);
break;
case DICT_FLOAT_TYPE:
serialize_float(&fval, fp, kind);
dict_add_float(dict, key, fval);
break;
case DICT_LONG_TYPE:
serialize_long(&lval, fp, kind);
dict_add_long(dict, key, lval);
break;
case DICT_STR_TYPE:
s = mem_alloc(alloc_size);
for (int_t j = 0; j < alloc_size; j++)
serialize_char(&s[j], fp, kind);

dict_add_str(dict, key, s, alloc_size);
mem_free(s);
break;
default:
break;






int_t dict_atmoic_size(dict_t *dict, char_t *key)

for (dict_node_t *np = dict->entries[dict_hash(dict, key)]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0)
return np->alloc_size;


return -1;


void *dict_atmoic_ptr(dict_t *dict,
char_t *key,
int_t type,
void *func_param)

for (dict_node_t *np = dict->entries[dict_hash(dict, key)]; np != NULL; np = np->next)
if (strcmp(key, np->key) == 0 && np->type == type)

if (type == DICT_VOID_PTR_TYPE)
if (np->alloc_size > 0)
return &np->value;
else
return np->value;

else if (type == DICT_FUNC_PTR_TYPE)
dict_func_ptr func_ptr = np->value;
func_ptr(func_param);

else
return np->value;



return NULL;


void *dict_atomic_add(dict_t *dict,
char_t *name,
void *ptr,
int_t type,
int_t alloc_size)

dict_node_t *node;
uint_t hashval;

for (node = dict->entries[dict_hash(dict, name)]; node != NULL; node = node->next)
if (strcmp(name, node->key) == 0)
return NULL;



ASSERT((ptr != NULL


int_t dict_int(dict_t *dict, char_t *key)

return *(int_t*)dict_atmoic_ptr(dict, key, DICT_INT_TYPE, NULL);



void dict_set_int(dict_t *dict, char_t *key, int_t value)

*(int_t*)dict_atmoic_ptr(dict, key, DICT_INT_TYPE, NULL) = value;



bool_t dict_add_int(dict_t *dict, char_t *name, int_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_INT_TYPE, sizeof(int_t));
if (success)
dict_set_int(dict, name, initial_val);
return success;



float_t dict_float(dict_t *dict, char_t *key)

return *(float_t*)dict_atmoic_ptr(dict, key, DICT_FLOAT_TYPE, NULL);



void dict_set_float(dict_t *dict, char_t *key, float_t value)

*(float_t*)dict_atmoic_ptr(dict, key, DICT_FLOAT_TYPE, NULL) = value;



bool_t dict_add_float(dict_t *dict, char_t *name, float_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_FLOAT_TYPE, sizeof(float_t));
if (success)
dict_set_float(dict, name, initial_val);
return success;



long_t dict_long(dict_t *dict, char_t *key)

return *(long_t*)dict_atmoic_ptr(dict, key, DICT_LONG_TYPE, NULL);



void dict_set_long(dict_t *dict, char_t *key, long_t value)

*(long_t*)dict_atmoic_ptr(dict, key, DICT_LONG_TYPE, NULL) = value;



bool_t dict_add_long(dict_t *dict, char_t *name, long_t initial_val)

bool_t success = dict_atomic_add(dict, name, NULL, DICT_LONG_TYPE, sizeof(long_t));
if (success)
dict_set_long(dict, name, initial_val);
return success;



char_t *dict_str(dict_t *dict, char_t *key)

return (char_t*)dict_atmoic_ptr(dict, key, DICT_STR_TYPE, NULL);


void dict_set_str(dict_t *dict, char_t *key, char_t *value)

if (strlen(value) < dict_atmoic_size(dict, key)-1)
strcpy((char_t*)dict_atmoic_ptr(dict, key, DICT_STR_TYPE, NULL), value);




bool_t dict_add_str(dict_t *dict, char_t *key, char_t *initial_str, int_t max_len)

int_t str_size = max_len;

if (str_size <= 0 && initial_str != NULL)
str_size = strlen(initial_str)+1;

bool_t success = dict_atomic_add(dict, key, NULL, DICT_STR_TYPE, str_size);
if (success && initial_str != NULL)
dict_set_str(dict, key, initial_str);
return success;



void dict_func(dict_t *dict, char_t *key, void *param)

dict_atmoic_ptr(dict, key, DICT_FUNC_PTR_TYPE, param);



bool_t dict_add_func(dict_t *dict, char_t *name, dict_func_ptr func)

return dict_atomic_add(dict, name, func, DICT_FUNC_PTR_TYPE, 0);




void *dict_ptr(dict_t *dict, char_t *name)

return dict_atmoic_ptr(dict, name, DICT_VOID_PTR_TYPE, NULL);



bool_t dict_add_ptr(dict_t *dict, char_t* name, void *data)

return (dict_atomic_add(dict, name, data, DICT_VOID_PTR_TYPE, 0) != NULL);









share|improve this question












share|improve this question




share|improve this question








edited Mar 24 at 19:50









Sam Onela

5,82961544




5,82961544









asked Mar 24 at 18:07









user2418731

211




211











  • Spelling: should dict_atmoic_ptr be dict_atomic_ptr?
    – Toby Speight
    Mar 26 at 10:23






  • 1




    Do you have a matching dictionary.h and runnable main() that exercises this code, so we can compile it and try it out ourselves?
    – Toby Speight
    Mar 26 at 10:25
















  • Spelling: should dict_atmoic_ptr be dict_atomic_ptr?
    – Toby Speight
    Mar 26 at 10:23






  • 1




    Do you have a matching dictionary.h and runnable main() that exercises this code, so we can compile it and try it out ourselves?
    – Toby Speight
    Mar 26 at 10:25















Spelling: should dict_atmoic_ptr be dict_atomic_ptr?
– Toby Speight
Mar 26 at 10:23




Spelling: should dict_atmoic_ptr be dict_atomic_ptr?
– Toby Speight
Mar 26 at 10:23




1




1




Do you have a matching dictionary.h and runnable main() that exercises this code, so we can compile it and try it out ourselves?
– Toby Speight
Mar 26 at 10:25




Do you have a matching dictionary.h and runnable main() that exercises this code, so we can compile it and try it out ourselves?
– Toby Speight
Mar 26 at 10:25















active

oldest

votes











Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f190394%2fgeneral-purpose-c-dictionary%23new-answer', 'question_page');

);

Post as a guest



































active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes










 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f190394%2fgeneral-purpose-c-dictionary%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Python Lists

Aion

JavaScript Array Iteration Methods