Skip to content

Instantly share code, notes, and snippets.

@gyakoo
Last active August 29, 2015 14:27
Show Gist options
  • Save gyakoo/a87c8ade3e0ca7306744 to your computer and use it in GitHub Desktop.
Save gyakoo/a87c8ade3e0ca7306744 to your computer and use it in GitHub Desktop.
Small C dictionary I created for a home project. Not totally perfect but gives me more performance than std::map<> in my scenario
////////////////////////////////////////////////////////////////////////////////////////////////
// DICTIONARY : DATA
////////////////////////////////////////////////////////////////////////////////////////////////
typedef unsigned long (*flt_dict_hash)(const unsigned char*, int);
typedef int (*flt_dict_keycomp)(const char*, const char*, int);
typedef void (*flt_dict_visitor)(char* key, void* value);
typedef struct flt_dict_node
{
char* key;
unsigned long keyhash;
void* value;
struct flt_dict_node* next;
}flt_dict_node;
typedef struct flt_dict
{
struct flt_dict_node** hasht;
struct flt_critsec* cs;
flt_dict_hash hashf;
flt_dict_keycomp keycomp;
fltatom32 ref;
int capacity; // no of entries in hash table
int count; // no of actual elements
}flt_dict;
////////////////////////////////////////////////////////////////////////////////////////////////
// DICTIONARY : FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////
// djb2
unsigned long flt_dict_hash_djb2(const unsigned char* str, int unused)
{
unused;
unsigned long hash = 5381;
int c;
while (c = *str++) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
unsigned long flt_dict_hash_face_djb2(const unsigned char* data, int size)
{
unsigned long hash = 5381;
int c,i;
for (i=0;i<size;++i)
{
c=*data++;
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
return hash;
}
int flt_dict_keycomp_string(const char* a, const char* b, int extra)
{
return strcmp(a,b);
}
int flt_dict_keycomp_face(const char* a, const char* b, int size)
{
return memcmp(a,b,size);
}
// create_cs==1 to create a critical section object
void flt_dict_create(int capacity, int create_cs, flt_dict** dict, flt_dict_hash hashf, flt_dict_keycomp keycomp)
{
flt_dict* d = (flt_dict*)flt_malloc(sizeof(flt_dict));
d->cs = create_cs ? flt_critsec_create() : FLT_NULL;
d->hasht = (flt_dict_node**)flt_calloc(capacity,sizeof(flt_dict_node*));
d->capacity = capacity;
d->count = 0;
d->hashf = hashf;
d->keycomp = keycomp;
d->ref = 1;
*dict = d;
}
void flt_dict_visit(flt_dict*dict, flt_dict_visitor visitor)
{
int i;
flt_dict_node *n;
if ( dict->cs ) flt_critsec_enter(dict->cs);
i=dict->capacity;
while(i--)
{
n=dict->hasht[i];
while (n)
{
visitor(n->key, n->value);
n=n->next;
}
}
if ( dict->cs ) flt_critsec_leave(dict->cs);
}
void flt_dict_destroy(flt_dict** dict, int free_elms, flt_dict_visitor destructor)
{
int i;
flt_dict_node *n, *nn;
if ( (*dict)->cs ) flt_critsec_enter((*dict)->cs);
// entries and their lists
for (i=0;i<(*dict)->capacity;++i)
{
n=(*dict)->hasht[i];
while (n)
{
nn=n->next;
if ( destructor )
destructor(n->key, n->value);
if ( free_elms )
flt_safefree(n->value);
flt_free(n->key);
flt_free(n);
n=nn;
}
}
flt_safefree((*dict)->hasht);
if ( (*dict)->cs )
{
flt_critsec_leave((*dict)->cs);
flt_critsec_destroy((*dict)->cs);
}
flt_safefree(*dict);
}
void* flt_dict_get(flt_dict* dict, const char* key, int size, flt_optional unsigned long hash)
{
flt_dict_node *n;
const unsigned long hashk = !hash ? dict->hashf((const unsigned char*)key,size) : hash;
const int entry = hashk % dict->capacity;
if ( dict->cs ) flt_critsec_enter(dict->cs);
n = dict->hasht[entry];
while(n)
{
if ( n->keyhash == hashk && dict->keycomp(n->key,key,size)==0 ){ break; }
n=n->next;
}
if ( dict->cs ) flt_critsec_leave(dict->cs);
return n ? n->value : FLT_NULL;
}
flt_dict_node* flt_dict_create_node(const char* key, unsigned long keyhash, void* value, int size)
{
flt_dict_node *n = (flt_dict_node*)flt_malloc(sizeof(flt_dict_node));
if ( size ) // we got size, just alloc+memcpy the key
{
n->key = (char*)flt_malloc(size);
memcpy(n->key,key,size);
}
else
{
n->key = flt_strdup(key); // 0 size is for strings
}
n->keyhash = keyhash;
n->value = value;
n->next = FLT_NULL;
return n;
}
int flt_dict_insert(flt_dict* dict, const char* key, void* value, int size, flt_optional unsigned long hash)
{
flt_dict_node *n, *ln;
unsigned long hashk;
int entry;
if ( !value || !dict )
return FLT_FALSE; // must insert non-null value.
hashk = !hash ? dict->hashf((const unsigned char*)key, size) : hash;
if ( dict->cs ) flt_critsec_enter(dict->cs); // acquire
entry = hashk % dict->capacity;
n=dict->hasht[entry];
++dict->count;
if ( !n )
{
dict->hasht[entry]=flt_dict_create_node(key,hashk,value,size); // not found in entry, add it
}
else
{
ln=n;
// entry collision: append to the end of list: new entry, just hash collision || or already exists element
while (n)
{
// same keyhash and same keyname (exists)
if ( n->keyhash == hashk && dict->keycomp(n->key,key,size)==0 ) { n->value = value; ln=0; --dict->count; break; }
ln=n;
n=n->next;
}
if (ln) ln->next = flt_dict_create_node(key,hashk,value,size);
}
if ( dict->cs ) flt_critsec_leave(dict->cs);
return FLT_TRUE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment