Explorar o código

* Added hash table functions from egglib

svn: 1892
Eggheads Development Team (Ported by Bryan) %!s(int64=21) %!d(string=hai) anos
pai
achega
ced0ca4ac7
Modificáronse 3 ficheiros con 314 adicións e 0 borrados
  1. 1 0
      src/Makefile.in
  2. 265 0
      src/hash_table.c
  3. 48 0
      src/hash_table.h

+ 1 - 0
src/Makefile.in

@@ -33,6 +33,7 @@ OBJS = auth.o \
 	enclink.o \
 	flags.o \
 	garble.o \
+	hash_table.o \
 	log.o \
 	main.o \
 	match.o \

+ 265 - 0
src/hash_table.c

@@ -0,0 +1,265 @@
+/* hash_table.c: hash table implementation
+ *
+ */
+
+
+#include "common.h"
+#include "hash_table.h"
+
+static unsigned int my_string_hash(const void *key);
+static unsigned int my_int_hash(const void *key);
+static unsigned int my_mixed_hash (const void *key);
+static int my_int_cmp(const void *left, const void *right);
+
+hash_table_t *hash_table_create(hash_table_hash_alg alg, hash_table_cmp_alg cmp, int nrows, int flags)
+{
+	hash_table_t *ht = NULL;
+
+	if (nrows <= 0) nrows = 13; /* Give them a small table to start with. */
+
+	ht = (hash_table_t *) my_calloc(1, sizeof(*ht));
+	ht->rows = (hash_table_row_t *) my_calloc(nrows, sizeof(*ht->rows));
+
+	if (alg) ht->hash = alg;
+	else {
+		if (flags & HASH_TABLE_STRINGS) ht->hash = my_string_hash;
+		else if (flags & HASH_TABLE_INTS) ht->hash = my_int_hash;
+		else ht->hash = my_mixed_hash;
+	}
+	if (cmp) ht->cmp = cmp;
+	else {
+		if (flags & HASH_TABLE_INTS) ht->cmp = my_int_cmp;
+		else ht->cmp = (hash_table_cmp_alg) strcmp;
+	}
+	ht->flags = flags;
+	ht->max_rows = nrows;
+	return(ht);
+}
+
+int hash_table_delete(hash_table_t *ht)
+{
+	hash_table_entry_t *entry = NULL, *next = NULL;
+	hash_table_row_t *row = NULL;
+	int i;
+
+	if (!ht) return(-1);
+
+	for (i = 0; i < ht->max_rows; i++) {
+		row = ht->rows+i;
+		for (entry = row->head; entry; entry = next) {
+			next = entry->next;
+			free(entry);
+		}
+	}
+	free(ht->rows);
+	free(ht);
+
+	return(0);
+}
+
+int hash_table_check_resize(hash_table_t *ht)
+{
+	if (!ht) return(-1);
+
+	if (ht->cells_in_use / ht->max_rows > 100) {
+		hash_table_resize(ht, ht->max_rows * 3);
+	}
+	return(0);
+}
+
+int hash_table_resize(hash_table_t *ht, int nrows)
+{
+	int i, newidx;
+	hash_table_row_t *oldrow = NULL, *newrows = NULL;
+	hash_table_entry_t *entry = NULL, *next = NULL;
+
+	if (!ht) return(-1);
+
+	/* First allocate the new rows. */
+	newrows = (hash_table_row_t *) my_calloc(nrows, sizeof(*newrows));
+
+	/* Now populate it with the old entries. */
+	for (i = 0; i < ht->max_rows; i++) {
+		oldrow = ht->rows+i;
+		for (entry = oldrow->head; entry; entry = next) {
+			next = entry->next;
+			newidx = entry->hash % nrows;
+			entry->next = newrows[newidx].head;
+			newrows[newidx].head = entry;
+			newrows[newidx].len++;
+		}
+	}
+
+	free(ht->rows);
+	ht->rows = newrows;
+	ht->max_rows = nrows;
+	return(0);
+}
+
+int hash_table_insert(hash_table_t *ht, const void *key, void *data)
+{
+	unsigned int hash;
+	int idx;
+	hash_table_entry_t *entry = NULL;
+	hash_table_row_t *row = NULL;
+
+	if (!ht) return(-1);
+
+	hash = ht->hash(key);
+	idx = hash % ht->max_rows;
+	row = ht->rows+idx;
+
+	/* Allocate an entry. */
+	entry = (hash_table_entry_t *) calloc(1, sizeof(*entry));
+	entry->key = key;
+	entry->data = data;
+	entry->hash = hash;
+
+	/* Insert it into the list. */
+	entry->next = row->head;
+	row->head = entry;
+
+	/* Update stats. */
+	row->len++;
+	ht->cells_in_use++;
+
+	/* See if we need to update the table. */
+	if (!(ht->flags & HASH_TABLE_NORESIZE)) {
+		hash_table_check_resize(ht);
+	}
+
+	return(0);
+}
+
+int hash_table_find(hash_table_t *ht, const void *key, void *dataptr)
+{
+	int idx;
+	unsigned int hash;
+	hash_table_entry_t *entry = NULL;
+	hash_table_row_t *row = NULL;
+
+	if (!ht) return (-1);
+
+	hash = ht->hash(key);
+	idx = hash % ht->max_rows;
+	row = ht->rows+idx;
+
+	for (entry = row->head; entry; entry = entry->next) {
+		if (hash == entry->hash && !ht->cmp(key, entry->key)) {
+			*(void **)dataptr = entry->data;
+			return(0);
+		}
+	}
+	return(-1);
+}
+
+int hash_table_remove(hash_table_t *ht, const void *key, void *dataptr)
+{
+	int idx;
+	unsigned int hash;
+	hash_table_entry_t *entry = NULL, *last = NULL;
+	hash_table_row_t *row = NULL;
+
+	if (!ht) return(-1);
+
+	hash = ht->hash(key);
+	idx = hash % ht->max_rows;
+	row = ht->rows+idx;
+
+	last = NULL;
+	for (entry = row->head; entry; entry = entry->next) {
+		if (hash == entry->hash && !ht->cmp(key, entry->key)) {
+			if (dataptr) *(void **)dataptr = entry->data;
+
+			/* Remove it from the row's list. */
+			if (last) last->next = entry->next;
+			else row->head = entry->next;
+
+			free(entry);
+			ht->cells_in_use--;
+			return(0);
+		}
+		last = entry;
+	}
+	return(-1);
+}
+
+int hash_table_walk(hash_table_t *ht, hash_table_node_func callback, void *param)
+{
+	hash_table_row_t *row = NULL;
+	hash_table_entry_t *entry = NULL, *next = NULL;
+	int i;
+
+	if (!ht) return(-1);
+
+	for (i = 0; i < ht->max_rows; i++) {
+		row = ht->rows+i;
+		for (entry = row->head; entry;) {
+			next = entry->next;
+			callback(entry->key, &entry->data, param);
+			entry = next;
+		}
+	}
+	return(0);
+}
+
+static int my_int_cmp(const void *left, const void *right)
+{
+	return((int) left - (int) right);
+}
+
+static unsigned int my_string_hash(const void *key)
+{
+	int hash, loop;
+        size_t keylen;
+	const unsigned char *k = NULL;
+
+#define HASHC hash = *k++ + 65599 * hash
+	hash = 0;
+	k = (const unsigned char *) key;
+	keylen = strlen((const char *) key);
+
+	if (!keylen) return(0);
+
+	loop = (keylen + 8 - 1) >> 3;
+	switch (keylen & (8 - 1)) {
+		case 0:
+			do {
+				HASHC;
+		case 7:
+				HASHC;
+		case 6:
+				HASHC;
+		case 5:
+				HASHC;
+		case 4:
+				HASHC;
+		case 3:
+				HASHC;
+		case 2:
+				HASHC;
+		case 1:
+				HASHC;
+			} while (--loop);
+	}
+	return(hash);
+}
+
+static unsigned int my_int_hash(const void *key)
+{
+	return((unsigned int)key);
+}
+
+static unsigned int my_mixed_hash (const void *key)
+{
+	const unsigned char *k = NULL;
+	unsigned int hash;
+
+        k = (const unsigned char *) key;
+	hash = 0;
+	while (*k) {
+		hash *= 16777619;
+		hash ^= *k++;
+	}
+	return(hash);
+}

+ 48 - 0
src/hash_table.h

@@ -0,0 +1,48 @@
+#ifndef _HASH_TABLE_H_
+#define _HASH_TABLE_H_
+
+#define HASH_TABLE_STRINGS	BIT0
+#define HASH_TABLE_INTS		BIT1
+#define HASH_TABLE_MIXED	BIT2
+#define HASH_TABLE_NORESIZE	BIT3
+
+/* Turns a key into an unsigned int. */
+typedef unsigned int (*hash_table_hash_alg)(const void *key);
+
+/* Returns -1, 0, or 1 if left is <, =, or > than right. */
+typedef int (*hash_table_cmp_alg)(const void *left, const void *right);
+
+typedef int (*hash_table_node_func)(const void *key, void *data, void *param);
+
+typedef struct hash_table_entry_b {
+	struct hash_table_entry_b *next;
+	const void *key;
+	void *data;
+	unsigned int hash;
+} hash_table_entry_t;
+
+typedef struct {
+	int len;
+	hash_table_entry_t *head;
+} hash_table_row_t;
+
+typedef struct hash_table_b {
+	int flags;
+	int max_rows;
+	int cells_in_use;
+	hash_table_hash_alg hash;
+	hash_table_cmp_alg cmp;
+	hash_table_row_t *rows;
+} hash_table_t;
+
+hash_table_t *hash_table_create(hash_table_hash_alg alg, hash_table_cmp_alg cmp, int nrows, int flags);
+int hash_table_delete(hash_table_t *ht);
+int hash_table_check_resize(hash_table_t *ht);
+int hash_table_resize(hash_table_t *ht, int nrows);
+int hash_table_insert(hash_table_t *ht, const void *key, void *data);
+int hash_table_replace(hash_table_t *ht, const void *key, void *data);
+int hash_table_find(hash_table_t *ht, const void *key, void *dataptr);
+int hash_table_remove(hash_table_t *ht, const void *key, void *dataptr);
+int hash_table_walk(hash_table_t *ht, hash_table_node_func callback, void *param);
+
+#endif /* !_HASH_TABLE_H_ */