/** \ingroup python * \file python/hash.c */ #include "system.h" #include "hash.h" #include "debug.h" #define CHUNK 1 struct filePath { char * dir; char * base; } ; struct bucket { struct filePath * data; int allocated; int firstFree; /* as in data[firstFree] */ }; struct hash_table { int size; int entries; int overHead; struct bucket *bucket; }; struct hash_table *htNewTable(int size) { struct hash_table *res; int i = 0; res = malloc(sizeof(struct hash_table)); res->bucket = malloc(sizeof(struct bucket) * size); res->size = size; res->entries = 0; res->overHead = sizeof(struct bucket) * size + CHUNK * sizeof(char *); while (i < size) { res->bucket[i].data = malloc(CHUNK * sizeof(*res->bucket[i].data)); res->bucket[i].allocated = CHUNK; res->bucket[i].firstFree = 0; i++; } return res; } void htFreeHashTable(struct hash_table *ht) { struct bucket * b; int item; b = ht->bucket; while (ht->size--) { for (item = 0; item < b->firstFree; item++) { free(b->data[item].dir); free(b->data[item].base); } free(b->data); b++; } free(ht->bucket); free(ht); } void htHashStats(const struct hash_table *t) { int i = 0; int empty = 0; while (i < t->size) { if (t->bucket[i].firstFree != 0) { /*printf("Bucket %d used %d\n", i, t->bucket[i].firstFree);*/ } else { empty++; } i++; } printf("Total Buckets : %d\n", t->size); printf("Empty Buckets : %d\n", empty); printf("Total Entries : %d\n", t->entries); printf("Total Overhead: %d\n", t->overHead); printf("Avergage Depth: %f\n", (double)t->entries / (double)t->size); } static unsigned int htHashStrings(const char * s, const char * t) { unsigned int res = 0; while (*s != '\0') res = ((res<<1) + (int)(*(s++))); while (*t != '\0') res = ((res<<1) + (int)(*(t++))); return res; } /* returns bucket # containing item, or -1 */ static int in_table_aux(struct hash_table *t, int hash, const char * dir, const char * base) { int x; x = 0; while (x < t->bucket[hash].firstFree) { if (! strcmp(t->bucket[hash].data[x].dir, dir) && ! strcmp(t->bucket[hash].data[x].base, base)) { return x; } x++; } return -1; } int htInTable(struct hash_table *t, const char * dir, const char * base) { int hash; hash = htHashStrings(dir, base) % t->size; if (in_table_aux(t, hash, dir, base) == -1) return 0; return 1; } void htAddToTable(struct hash_table *t, const char * dir, const char * base) { static int hash = 1; if (!dir || !base) return; hash = htHashStrings(dir, base) % t->size; if (in_table_aux(t, hash, dir, base) != -1) return; if (t->bucket[hash].firstFree == t->bucket[hash].allocated) { t->bucket[hash].allocated += CHUNK; t->bucket[hash].data = realloc(t->bucket[hash].data, t->bucket[hash].allocated * sizeof(*(t->bucket->data))); /*printf("Bucket %d grew to %d\n", hash, t->bucket[hash].allocated);*/ t->overHead += sizeof(char *) * CHUNK; } /*printf("In bucket %d, item %d\n", hash, t->bucket[hash].firstFree);*/ t->bucket[hash].data[t->bucket[hash].firstFree].dir = strdup(dir); t->bucket[hash].data[t->bucket[hash].firstFree++].base = strdup(base); t->entries++; } void htRemoveFromTable(struct hash_table *t, const char * dir, const char * base) { int hash; int item; int last; hash = htHashStrings(dir, base) % t->size; if ((item = in_table_aux(t, hash, dir, base)) == -1) { return; } free(t->bucket[hash].data[item].dir); free(t->bucket[hash].data[item].base); last = --t->bucket[hash].firstFree; t->bucket[hash].data[item] = t->bucket[hash].data[last]; } int htNumEntries(struct hash_table *t) { return t->entries; } void htIterStart(htIterator * iter) { iter->bucket = 0; iter->item = -1; } int htIterGetNext(struct hash_table * t, htIterator * iter, const char ** dir, const char ** base) { iter->item++; while (iter->bucket < t->size) { if (iter->item < t->bucket[iter->bucket].firstFree) { *dir = t->bucket[iter->bucket].data[iter->item].dir; *base = t->bucket[iter->bucket].data[iter->item].base; return 1; } iter->item++; if (iter->item >= t->bucket[iter->bucket].firstFree) { iter->bucket++; iter->item = 0; } } return 0; }