summaryrefslogtreecommitdiff
path: root/rts/Hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'rts/Hash.c')
-rw-r--r--rts/Hash.c124
1 files changed, 87 insertions, 37 deletions
diff --git a/rts/Hash.c b/rts/Hash.c
index 2f611c9079..4e11228961 100644
--- a/rts/Hash.c
+++ b/rts/Hash.c
@@ -49,22 +49,25 @@ struct hashtable {
HashList **dir[HDIRSIZE]; /* Directory of segments */
HashList *freeList; /* free list of HashLists */
HashListChunk *chunks;
- HashFunction *hash; /* hash function */
- CompareFunction *compare; /* key comparison function */
};
+/* Create an identical structure, but is distinct on a type level,
+ * for string hash table. Since it's a direct embedding of
+ * a hashtable and not a reference, there shouldn't be
+ * any overhead post-compilation. */
+struct strhashtable { struct hashtable table; };
+
/* -----------------------------------------------------------------------------
* Hash first using the smaller table. If the bucket is less than the
* next bucket to be split, re-hash using the larger table.
* -------------------------------------------------------------------------- */
-
int
hashWord(const HashTable *table, StgWord key)
{
int bucket;
/* Strip the boring zero bits */
- key /= sizeof(StgWord);
+ key >>= sizeof(StgWord);
/* Mod the size of the hash table (a power of 2) */
bucket = key & table->mask1;
@@ -97,13 +100,13 @@ hashStr(const HashTable *table, StgWord w)
return bucket;
}
-static int
+STATIC_INLINE int
compareWord(StgWord key1, StgWord key2)
{
return (key1 == key2);
}
-static int
+STATIC_INLINE int
compareStr(StgWord key1, StgWord key2)
{
return (strcmp((char *)key1, (char *)key2) == 0);
@@ -114,7 +117,7 @@ compareStr(StgWord key1, StgWord key2)
* Allocate a new segment of the dynamically growing hash table.
* -------------------------------------------------------------------------- */
-static void
+STATIC_INLINE void
allocSegment(HashTable *table, int segment)
{
table->dir[segment] = stgMallocBytes(HSEGSIZE * sizeof(HashList *),
@@ -128,8 +131,8 @@ allocSegment(HashTable *table, int segment)
* by @table->split@ is affected by the expansion.
* -------------------------------------------------------------------------- */
-static void
-expand(HashTable *table)
+STATIC_INLINE void
+expand(HashTable *table, HashFunction f)
{
int oldsegment;
int oldindex;
@@ -170,7 +173,7 @@ expand(HashTable *table)
old = new = NULL;
for (hl = table->dir[oldsegment][oldindex]; hl != NULL; hl = next) {
next = hl->next;
- if (table->hash(table, hl->key) == newbucket) {
+ if (f(table, hl->key) == newbucket) {
hl->next = new;
new = hl;
} else {
@@ -184,19 +187,20 @@ expand(HashTable *table)
return;
}
-void *
-lookupHashTable(const HashTable *table, StgWord key)
+STATIC_INLINE void*
+lookupHashTable_inlined(const HashTable *table, StgWord key,
+ HashFunction f, CompareFunction cmp)
{
int bucket;
int segment;
int index;
+
HashList *hl;
- bucket = table->hash(table, key);
+ bucket = f(table, key);
segment = bucket / HSEGSIZE;
index = bucket % HSEGSIZE;
- CompareFunction *cmp = table->compare;
for (hl = table->dir[segment][index]; hl != NULL; hl = hl->next) {
if (cmp(hl->key, key))
return (void *) hl->data;
@@ -206,6 +210,26 @@ lookupHashTable(const HashTable *table, StgWord key)
return NULL;
}
+void *
+lookupHashTable_(const HashTable *table, StgWord key,
+ HashFunction f, CompareFunction cmp)
+{
+ return lookupHashTable_inlined(table, key, f, cmp);
+}
+
+void *
+lookupHashTable(const HashTable *table, StgWord key)
+{
+ return lookupHashTable_inlined(table, key, hashWord, compareWord);
+}
+
+void *
+lookupStrHashTable(const StrHashTable* table, const char* key)
+{
+ return lookupHashTable_inlined(&table->table, (StgWord) key,
+ hashStr, compareStr);
+}
+
// Puts up to szKeys keys of the hash table into the given array. Returns the
// actual amount of keys that have been retrieved.
//
@@ -273,8 +297,9 @@ freeHashList (HashTable *table, HashList *hl)
table->freeList = hl;
}
-void
-insertHashTable(HashTable *table, StgWord key, const void *data)
+STATIC_INLINE void
+insertHashTable_inlined(HashTable *table, StgWord key,
+ const void *data, HashFunction f)
{
int bucket;
int segment;
@@ -287,9 +312,9 @@ insertHashTable(HashTable *table, StgWord key, const void *data)
/* When the average load gets too high, we expand the table */
if (++table->kcount >= HLOAD * table->bcount)
- expand(table);
+ expand(table, f);
- bucket = table->hash(table, key);
+ bucket = f(table, key);
segment = bucket / HSEGSIZE;
index = bucket % HSEGSIZE;
@@ -299,11 +324,30 @@ insertHashTable(HashTable *table, StgWord key, const void *data)
hl->data = data;
hl->next = table->dir[segment][index];
table->dir[segment][index] = hl;
+}
+void
+insertHashTable_(HashTable *table, StgWord key,
+ const void *data, HashFunction f)
+{
+ return insertHashTable_inlined(table, key, data, f);
}
-void *
-removeHashTable(HashTable *table, StgWord key, const void *data)
+void
+insertHashTable(HashTable *table, StgWord key, const void *data)
+{
+ insertHashTable_inlined(table, key, data, hashWord);
+}
+
+void
+insertStrHashTable(StrHashTable *table, const char * key, const void *data)
+{
+ insertHashTable_inlined(&table->table, (StgWord) key, data, hashStr);
+}
+
+STATIC_INLINE void*
+removeHashTable_inlined(HashTable *table, StgWord key, const void *data,
+ HashFunction f, CompareFunction cmp)
{
int bucket;
int segment;
@@ -311,12 +355,12 @@ removeHashTable(HashTable *table, StgWord key, const void *data)
HashList *hl;
HashList *prev = NULL;
- bucket = table->hash(table, key);
+ bucket = f(table, key);
segment = bucket / HSEGSIZE;
index = bucket % HSEGSIZE;
for (hl = table->dir[segment][index]; hl != NULL; hl = hl->next) {
- if (table->compare(hl->key,key) && (data == NULL || hl->data == data)) {
+ if (cmp(hl->key, key) && (data == NULL || hl->data == data)) {
if (prev == NULL)
table->dir[segment][index] = hl->next;
else
@@ -333,6 +377,26 @@ removeHashTable(HashTable *table, StgWord key, const void *data)
return NULL;
}
+void*
+removeHashTable_(HashTable *table, StgWord key, const void *data,
+ HashFunction f, CompareFunction cmp)
+{
+ return removeHashTable_inlined(table, key, data, f, cmp);
+}
+
+void *
+removeHashTable(HashTable *table, StgWord key, const void *data)
+{
+ return removeHashTable_inlined(table, key, data, hashWord, compareWord);
+}
+
+void *
+removeStrHashTable(StrHashTable *table, const char * key, const void *data)
+{
+ return removeHashTable_inlined(&table->table, (StgWord) key,
+ data, hashStr, compareStr);
+}
+
/* -----------------------------------------------------------------------------
* When we free a hash table, we are also good enough to free the
* data part of each (key, data) pair, as long as our caller can tell
@@ -406,7 +470,7 @@ mapHashTable(HashTable *table, void *data, MapHashFn fn)
* -------------------------------------------------------------------------- */
HashTable *
-allocHashTable_(HashFunction *hash, CompareFunction *compare)
+allocHashTable(void)
{
HashTable *table;
HashList **hb;
@@ -426,24 +490,10 @@ allocHashTable_(HashFunction *hash, CompareFunction *compare)
table->bcount = HSEGSIZE;
table->freeList = NULL;
table->chunks = NULL;
- table->hash = hash;
- table->compare = compare;
return table;
}
-HashTable *
-allocHashTable(void)
-{
- return allocHashTable_(hashWord, compareWord);
-}
-
-HashTable *
-allocStrHashTable(void)
-{
- return allocHashTable_(hashStr, compareStr);
-}
-
void
exitHashTable(void)
{