/*
* hash.c
*
* Copyright (C) 2007 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include "hash.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(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)
res = ((res<<1) + (int)(*(s++)));
while (*t)
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;
}