From 7c1921581d3d2535e58df1ae5c5f624df3d5f944 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 10 Jun 2008 16:21:52 +0000 Subject: [PATCH] Now actually hashing the data but no longer managing keys as strings --- include/System/hash.h | 20 ++++-- src/hash.c | 159 +++++++++++++++++++++++++++++++----------- 2 files changed, 134 insertions(+), 45 deletions(-) diff --git a/include/System/hash.h b/include/System/hash.h index 59dac92..83e6270 100644 --- a/include/System/hash.h +++ b/include/System/hash.h @@ -24,15 +24,27 @@ /* Hash */ /* types */ -typedef Array Hash; +typedef struct _Hash Hash; + +typedef unsigned int (*HashFunc)(void const * value); +typedef int (*HashCompare)(void const * value1, void const * value2); +typedef void (*HashForeach)(void const * key, void * value, void * data); /* functions */ -Hash * hash_new(void); +Hash * hash_new(HashFunc func, HashCompare compare); void hash_delete(Hash * h); +/* helpers */ +extern unsigned int hash_func_string(void const * value); +extern int hash_compare_string(void const * value1, void const * value2); + /* accessors */ -void * hash_get(Hash * h, char const * name); -int hash_set(Hash * h, char const * name, void * data); +void * hash_get(Hash * h, void const * key); +int hash_set(Hash * h, void const * key, void * value); +size_t hash_count(Hash * hash); + +/* useful */ +void hash_foreach(Hash * hash, HashForeach func, void * data); #endif /* !LIBSYSTEM_HASH_H */ diff --git a/src/hash.c b/src/hash.c index efa12e5..bcc0595 100644 --- a/src/hash.c +++ b/src/hash.c @@ -13,8 +13,6 @@ * You should have received a copy of the Creative Commons Attribution- * NonCommercial-ShareAlike 3.0 along with libSystem; if not, browse to * http://creativecommons.org/licenses/by-nc-sa/3.0/ */ -/* TODO: - * - actually hash the data... */ @@ -28,45 +26,97 @@ /* types */ typedef struct _HashEntry { - char * name; - void * data; + unsigned int hash; + void const * key; + void * value; } HashEntry; ARRAY(HashEntry, _hashentry); +#define HashEntryArray _hashentryArray + + +/* prototypes */ +static void _hashentry_init(HashEntry * he, HashFunc func, void const * key, + void * value); + +/* accessors */ +static void _hashentry_set_value(HashEntry * he, void * value); /* functions */ /* hashentry_init */ -static int _hashentry_init(HashEntry * he, char const * name, void * data) +static void _hashentry_init(HashEntry * he, HashFunc func, void const * key, + void * value) { - if((he->name = string_new(name)) == NULL) - return 1; - he->data = data; - return 0; -} - -static void _hashentry_destroy(HashEntry * he) -{ - free(he->name); + he->hash = (func != NULL) ? func(key) : 0; + he->key = key; + he->value = value; } -/* useful */ -static void _hashentry_set_data(HashEntry * he, void * data) +/* accessors */ +/* hashentry_set_value */ +static void _hashentry_set_value(HashEntry * he, void * value) { - he->data = data; + he->value = value; } /* Hash */ +/* protected */ +/* types */ +struct _Hash +{ + HashFunc func; + HashCompare compare; + HashEntryArray * entries; +}; + + +/* functions */ +/* hash_func_string */ +unsigned int hash_func_string(void const * key) +{ + String const * str = key; + size_t i; + unsigned int hash = 0; + + for(i = 0; i < sizeof(hash) && str[i] != '\0'; i++) + hash |= str[i] << (i << 3); + return hash; +} + + +/* hash_compare_string */ +int hash_compare_string(void const * value1, void const * value2) +{ + String const * str1 = value1; + String const * str2 = value2; + + return string_compare(str1, str2); +} + + /* public */ /* functions */ /* hash_new */ -Hash * hash_new(void) +Hash * hash_new(HashFunc func, HashCompare compare) { Hash * hash; - if((hash = _hashentryarray_new()) == NULL) + if(compare == NULL) + { + error_set_code(1, "%s", "Invalid comparison function"); return NULL; + } + if((hash = object_new(sizeof(*hash))) == NULL) + return NULL; + if((hash->entries = _hashentryarray_new()) == NULL) + { + object_delete(hash); + return NULL; + } + hash->func = func; + hash->compare = compare; return hash; } @@ -74,56 +124,83 @@ Hash * hash_new(void) /* hash_delete */ void hash_delete(Hash * hash) { - size_t i; - HashEntry * he; - - for(i = array_count(hash); i > 0; i--) - if((he = array_get(hash, i - 1)) != NULL) - _hashentry_destroy(he); - array_delete(hash); + array_delete(hash->entries); + object_delete(hash); } /* accessors */ /* hash_get */ -void * hash_get(Hash * hash, char const * name) +void * hash_get(Hash * hash, void const * key) { + unsigned int h; size_t i; HashEntry * he; - for(i = array_count(hash); i > 0; i--) + h = (hash->func != NULL) ? hash->func(key) : 0; + for(i = array_count(hash->entries); i > 0; i--) { - if((he = array_get(hash, i - 1)) == NULL) + if((he = array_get(hash->entries, i - 1)) == NULL) return NULL; - if(string_compare(he->name, name) == 0) - return he->data; + if(he->hash != h) + continue; + if(hash->compare(he->key, key) == 0) + return he->value; } - error_set_code(1, "%s%s", name, ": Not found"); + error_set_code(1, "%s", "Key not found"); return NULL; } /* hash_set */ -int hash_set(Hash * hash, char const * name, void * data) +int hash_set(Hash * hash, void const * key, void * value) { + unsigned int h; size_t i; HashEntry he; HashEntry * p; - for(i = array_count(hash); i > 0; i--) + h = (hash->func != NULL) ? hash->func(key) : 0; + for(i = array_count(hash->entries); i > 0; i--) { - if((p = array_get(hash, i - 1)) == NULL) + if((p = array_get(hash->entries, i - 1)) == NULL) return 1; - if(string_compare(p->name, name) == 0) + if(p->hash != h) + continue; + if(hash->compare(p->key, key) == 0) { - _hashentry_set_data(p, data); + _hashentry_set_value(p, value); return 0; } } - if(_hashentry_init(&he, name, data) != 0) - return 1; - if(array_append(hash, &he) == 0) + _hashentry_init(&he, hash->func, key, value); + if(array_append(hash->entries, &he) == 0) return 0; - _hashentry_destroy(&he); return 1; } + + +/* useful */ +static void _hash_foreach(void * value, void * data); + +/* FIXME ugly name */ +struct a +{ + HashForeach func; + void * data; +}; + +void hash_foreach(Hash * hash, HashForeach func, void * data) +{ + struct a ad = { func, data }; + + array_foreach(hash->entries, _hash_foreach, &ad); +} + +static void _hash_foreach(void * value, void * data) +{ + HashEntry * he = value; + struct a * ad = data; + + ad->func(he->key, he->value, ad->data); +}