-/***********************************************************
-* Artsoft Retro-Game Library *
-*----------------------------------------------------------*
-* (c) 1994-2006 Artsoft Entertainment *
-* Holger Schemel *
-* Detmolder Strasse 189 *
-* 33604 Bielefeld *
-* Germany *
-* e-mail: info@artsoft.org *
-*----------------------------------------------------------*
-* hash.c *
-***********************************************************/
+// ============================================================================
+// Artsoft Retro-Game Library
+// ----------------------------------------------------------------------------
+// (c) 1995-2014 by Artsoft Entertainment
+// Holger Schemel
+// info@artsoft.org
+// https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// hash.c
+// ============================================================================
/*
* Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk>
/*****************************************************************************/
struct hashtable *
-create_hashtable(unsigned int minsize, float maxloadfactor,
- unsigned int (*hashf) (void*),
- int (*eqf) (void*,void*))
+create_hashtable_ext(unsigned int minsize, float maxloadfactor,
+ unsigned int (*hashf) (void*),
+ int (*eqf) (void*, void*),
+ void (*freekfn) (void*),
+ void (*freevfn) (void*))
{
struct hashtable *h;
unsigned int i, size = 1u;
return NULL;
}
- for (i=0; i < size; i++)
+ for (i = 0; i < size; i++)
h->table[i] = NULL;
h->tablelength = size;
h->hashfn = hashf;
h->eqfn = eqf;
h->loadlimit = (unsigned int) ((float)size * maxloadfactor);
+ h->freekfn = freekfn;
+ h->freevfn = freevfn;
return h;
}
+struct hashtable *
+create_hashtable(unsigned int (*hashf) (void*),
+ int (*eqf) (void*, void*),
+ void (*freekfn) (void*),
+ void (*freevfn) (void*))
+{
+ return create_hashtable_ext(16, 0.75, hashf, eqf, freekfn, freevfn);
+}
+
/*****************************************************************************/
static unsigned int
hash(struct hashtable *h, void *k)
while ((e = h->table[i]) != NULL)
{
h->table[i] = e->next;
- index = indexFor(newsize,e->h);
+ index = indexFor(newsize, e->h);
e->next = newtable[index];
newtable[index] = e;
}
{
for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE)
{
- index = indexFor(newsize,e->h);
+ index = indexFor(newsize, e->h);
if (index == i)
{
return 0;
}
- e->h = hash(h,k);
- index = indexFor(h->tablelength,e->h);
+ e->h = hash(h, k);
+ index = indexFor(h->tablelength, e->h);
e->k = k;
e->v = v;
e->next = h->table[index];
struct entry *e;
unsigned int hashvalue, index;
- hashvalue = hash(h,k);
- index = indexFor(h->tablelength,hashvalue);
+ hashvalue = hash(h, k);
+ index = indexFor(h->tablelength, hashvalue);
e = h->table[index];
while (e != NULL)
/* Check hash value to short circuit heavier comparison */
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
{
- free(e->v);
+ if (h->freevfn != NULL)
+ h->freevfn(e->v);
e->v = v;
return -1;
return 0;
}
+/*****************************************************************************/
+int /* checks if key exists */
+hashtable_exists(struct hashtable *h, void *k)
+{
+ struct entry *e;
+ unsigned int hashvalue, index;
+
+ hashvalue = hash(h, k);
+ index = indexFor(h->tablelength, hashvalue);
+ e = h->table[index];
+
+ while (e != NULL)
+ {
+ /* Check hash value to short circuit heavier comparison */
+ if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+ return 1;
+
+ e = e->next;
+ }
+
+ return 0;
+}
+
/*****************************************************************************/
void * /* returns value associated with key */
hashtable_search(struct hashtable *h, void *k)
struct entry *e;
unsigned int hashvalue, index;
- hashvalue = hash(h,k);
- index = indexFor(h->tablelength,hashvalue);
+ hashvalue = hash(h, k);
+ index = indexFor(h->tablelength, hashvalue);
e = h->table[index];
while (e != NULL)
struct entry *e;
struct entry **pE;
void *v;
- unsigned int index = indexFor(h->tablelength,hash(h,k));
+ unsigned int index = indexFor(h->tablelength, hash(h, k));
pE = &(h->table[index]);
e = *pE;
{
*pE = e->next;
h->entrycount--;
- v = e->v;
- free(e->k);
+ v = NULL;
+ if (h->freekfn != NULL)
+ h->freekfn(e->k);
+ if (h->freevfn != NULL)
+ h->freevfn(e->v);
+ else
+ v = e->v;
free(e);
return v;
/*****************************************************************************/
/* destroy */
void
-hashtable_destroy(struct hashtable *h, int free_values)
+hashtable_destroy(struct hashtable *h)
{
unsigned int i;
struct entry *e, *f;
{
f = e;
e = e->next;
- free(f->k);
-
- if (free_values)
- free(f->v);
+ if (h->freekfn != NULL)
+ h->freekfn(f->k);
+ if (h->freevfn != NULL)
+ h->freevfn(f->v);
free(f);
}
free(h);
}
-
/*****************************************************************************/
/* hashtable_iterator - iterator constructor */
}
/*****************************************************************************/
-/* key - return the key of the (key,value) pair at the current position */
+/* key - return the key of the (key, value) pair at the current position */
void *
-hashtable_iterator_key(struct hashtable_itr *i)
+hashtable_iterator_key(struct hashtable_itr *itr)
{
- return i->e->k;
+ if (itr == NULL || itr->e == NULL)
+ return NULL;
+
+ return itr->e->k;
}
/*****************************************************************************/
-/* value - return the value of the (key,value) pair at the current position */
+/* value - return the value of the (key, value) pair at the current position */
void *
-hashtable_iterator_value(struct hashtable_itr *i)
+hashtable_iterator_value(struct hashtable_itr *itr)
{
- return i->e->v;
+ if (itr == NULL || itr->e == NULL)
+ return NULL;
+
+ return itr->e->v;
}
/*****************************************************************************/
int
hashtable_iterator_advance(struct hashtable_itr *itr)
{
- unsigned int j,tablelength;
+ unsigned int j, tablelength;
struct entry **table;
struct entry *next;
return -1;
}
+
+/*****************************************************************************/
+/* call function for all hashtable entries */
+void
+hashtable_foreach(struct hashtable *h, hashtable_fn fn, void *userdata)
+{
+ if (h == NULL)
+ return;
+
+ if (hashtable_count(h) == 0)
+ return;
+
+ struct hashtable_itr *itr = hashtable_iterator(h);
+
+ do
+ {
+ fn(hashtable_iterator_key(itr), hashtable_iterator_value(itr), userdata);
+ }
+ while (hashtable_iterator_advance(itr));
+
+ free(itr);
+}
+
+/*****************************************************************************/
+/* call function for all hashtable entries and remove them, if function returned 1 */
+unsigned int
+hashtable_foreach_remove(struct hashtable *h, hashtable_remove_fn fn, void *userdata)
+{
+ if (h == NULL)
+ return 0;
+
+ if (hashtable_count(h) == 0)
+ return 0;
+
+ struct hashtable *remove = create_hashtable(h->hashfn, h->eqfn, NULL, NULL);
+ struct hashtable_itr *itr = hashtable_iterator(h);
+
+ do
+ {
+ if (fn(hashtable_iterator_key(itr), hashtable_iterator_value(itr), userdata))
+ hashtable_insert(remove, hashtable_iterator_key(itr), "1");
+ }
+ while (hashtable_iterator_advance(itr));
+
+ free(itr);
+
+ unsigned int num_removed = 0;
+
+ if (hashtable_count(remove) > 0)
+ {
+ struct hashtable_itr *itr_remove = hashtable_iterator(remove);
+
+ do
+ {
+ hashtable_remove(h, hashtable_iterator_key(itr_remove));
+ num_removed++;
+ }
+ while (hashtable_iterator_advance(itr_remove));
+
+ free(itr_remove);
+ }
+
+ hashtable_destroy(remove);
+
+ return num_removed;
+}
+
+/*****************************************************************************/
+/* remove_all hashtable entries */
+unsigned int
+hashtable_remove_all(struct hashtable *h)
+{
+ /* TODO: this function should directly remove all hashtable entries */
+
+ if (h == NULL)
+ return 0;
+
+ if (hashtable_count(h) == 0)
+ return 0;
+
+ struct hashtable *remove = create_hashtable(h->hashfn, h->eqfn, NULL, NULL);
+ struct hashtable_itr *itr = hashtable_iterator(h);
+
+ do
+ {
+ hashtable_insert(remove, hashtable_iterator_key(itr), "1");
+ }
+ while (hashtable_iterator_advance(itr));
+
+ free(itr);
+
+ struct hashtable_itr *itr_remove = hashtable_iterator(remove);
+ unsigned int num_removed = 0;
+
+ do
+ {
+ hashtable_remove(h, hashtable_iterator_key(itr_remove));
+ num_removed++;
+ }
+ while (hashtable_iterator_advance(itr_remove));
+
+ free(itr_remove);
+
+ hashtable_destroy(remove);
+
+ return num_removed;
+}