From 92645ac0f89e581de91b4f76ddd7b03f94ffba22 Mon Sep 17 00:00:00 2001 From: Babak Behzad Date: Mon, 17 Jun 2013 21:58:27 -0500 Subject: [PATCH 1/8] add hash-functions feature to support different hash functions --- src/hash_functions.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ src/hash_functions.h | 11 +++++++ 2 files changed, 80 insertions(+) create mode 100644 src/hash_functions.c create mode 100644 src/hash_functions.h diff --git a/src/hash_functions.c b/src/hash_functions.c new file mode 100644 index 0000000..1588cfb --- /dev/null +++ b/src/hash_functions.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +#include "hash_functions.h" + +size_t hash_map_default_hash_func(const void *key, size_t capacity) { + return *((size_t *) key) % capacity; +} + +unsigned char xPear16(unsigned char *x, int len) { + int h, i, j; + unsigned char ch, hex[20]=""; + + // to store h values + struct { + int a; + } hh[8]; + + // 256 values 0-255 in any (random) order suffices + struct DAT { + int a; + } + + T[256] = { + 98, 6, 85,150, 36, 23,112,164,135,207,169, 5, 26, 64,165,219, // 1 + 61, 20, 68, 89,130, 63, 52,102, 24,229,132,245, 80,216,195,115, // 2 + 90,168,156,203,177,120, 2,190,188, 7,100,185,174,243,162, 10, // 3 + 237, 18,253,225, 8,208,172,244,255,126,101, 79,145,235,228,121, // 4 + 123,251, 67,250,161, 0,107, 97,241,111,181, 82,249, 33, 69, 55, // 5 + 59,153, 29, 9,213,167, 84, 93, 30, 46, 94, 75,151,114, 73,222, // 6 + 197, 96,210, 45, 16,227,248,202, 51,152,252,125, 81,206,215,186, // 7 + 39,158,178,187,131,136, 1, 49, 50, 17,141, 91, 47,129, 60, 99, // 8 + 154, 35, 86,171,105, 34, 38,200,147, 58, 77,118,173,246, 76,254, // 9 + 133,232,196,144,198,124, 53, 4,108, 74,223,234,134,230,157,139, // 10 + 189,205,199,128,176, 19,211,236,127,192,231, 70,233, 88,146, 44, // 11 + 183,201, 22, 83, 13,214,116,109,159, 32, 95,226,140,220, 57, 12, // 12 + 221, 31,209,182,143, 92,149,184,148, 62,113, 65, 37, 27,106,166, // 13 + 3, 14,204, 72, 21, 41, 56, 66, 28,193, 40,217, 25, 54,179,117, // 14 + 238, 87,240,155,180,170,242,212,191,163, 78,218,137,194,175,110, // 15 + 43,119,224, 71,122,142, 42,160,104, 48,247,103, 15, 11,138,239 // 16 + }; + + ch = x[0]; // save first byte + for(j = 0 ; j < 8; j++) { + // standard Pearson hash (output is h) + h=0; + + for(i = 0; i < len; i++) { + h=T[h ^ x[i]].a; + } + + hh[j].a=h; // store result + x[0]=x[0]+1; // increment first data byte by 1 + } + + x[0]=ch; // restore first byte + + // concatenate the 8 stored values of h + sprintf(hex,"%02X%02X%02X%02X%02X%02X%02X%02X", + hh[0].a, hh[1].a, + hh[2].a, hh[3].a, + hh[4].a, hh[5].a, + hh[6].a, hh[7].a); + + return hex; // output 64-bit 16 hex bytes hash +} diff --git a/src/hash_functions.h b/src/hash_functions.h new file mode 100644 index 0000000..8df4f8d --- /dev/null +++ b/src/hash_functions.h @@ -0,0 +1,11 @@ +/** + * @file + * Implementation of different hash functions. + */ + +#ifndef HASH_FUNCTIONS_H +#define HASH_FUNCTIONS_H + +size_t hash_map_default_hash_func(const void *key, size_t capacity); + +#endif /*HASH_FUNCTIONS_H*/ From 3c281ff110647cf35ccf494f17b12fd04a0eb690 Mon Sep 17 00:00:00 2001 From: Babak Behzad Date: Mon, 17 Jun 2013 22:05:22 -0500 Subject: [PATCH 2/8] add hash-functions feature to support different hash functions --- src/hash_map.c | 5 +---- test/test_hash_map.c | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/hash_map.c b/src/hash_map.c index 7ca7cc4..c16369e 100644 --- a/src/hash_map.c +++ b/src/hash_map.c @@ -7,6 +7,7 @@ #include "linked_list.h" #include "hash_map.h" +#include "hash_functions.h" // when "-g" is used redefine inline to static or else the linker will try to link the function and fail (since it's inline) #ifdef TEST @@ -17,10 +18,6 @@ inline int hash_map_default_comparator(const void *l, const void *r) { return *((unsigned long *) l) - *((unsigned long *) r); } -inline size_t hash_map_default_hash_func(const void *key, size_t capacity) { - return *((size_t *) key) % capacity; -} - void hash_map_init(hash_map *map, size_t capacity, hash_map_comparator comparator, hash_map_hash_func hash_func) { map->capacity = capacity; map->size = 0; diff --git a/test/test_hash_map.c b/test/test_hash_map.c index 82cc628..0a298d9 100644 --- a/test/test_hash_map.c +++ b/test/test_hash_map.c @@ -2,6 +2,7 @@ #include #include "hash_map.h" +#include "hash_functions.h" #include "linked_list.h" #include "memory.h" From f509d7d66577abb22b495ca79bb465d71c17b543 Mon Sep 17 00:00:00 2001 From: Babak Behzad Date: Thu, 20 Jun 2013 22:14:14 -0500 Subject: [PATCH 3/8] update test_hash_map to work for several hash_maps --- src/hash_functions.c | 6 +- src/hash_functions.h | 2 + test/test_hash_map.c | 143 +++++++++++++++++++++++++++++-------------- 3 files changed, 104 insertions(+), 47 deletions(-) diff --git a/src/hash_functions.c b/src/hash_functions.c index 1588cfb..92fc6ec 100644 --- a/src/hash_functions.c +++ b/src/hash_functions.c @@ -10,10 +10,14 @@ size_t hash_map_default_hash_func(const void *key, size_t capacity) { return *((size_t *) key) % capacity; } -unsigned char xPear16(unsigned char *x, int len) { +unsigned char xPear16(unsigned char *x) { int h, i, j; unsigned char ch, hex[20]=""; + + int len = sizeof(x) / sizeof(char); + printf("len = %d\n", len); + // to store h values struct { int a; diff --git a/src/hash_functions.h b/src/hash_functions.h index 8df4f8d..0986848 100644 --- a/src/hash_functions.h +++ b/src/hash_functions.h @@ -8,4 +8,6 @@ size_t hash_map_default_hash_func(const void *key, size_t capacity); +unsigned char xPear16(unsigned char *x); + #endif /*HASH_FUNCTIONS_H*/ diff --git a/test/test_hash_map.c b/test/test_hash_map.c index 0a298d9..57a3cdb 100644 --- a/test/test_hash_map.c +++ b/test/test_hash_map.c @@ -9,95 +9,146 @@ #include -static hash_map *map; +static hash_map **hash_map_array; +const int hash_map_array_size = 2; extern int __malloc_counter; void setUp() { - map = safe_malloc(sizeof(hash_map)); - hash_map_init(map, 1000, (hash_map_comparator) strcmp, NULL); + hash_map_array = (hash_map **) safe_malloc(sizeof(hash_map *) * hash_map_array_size); + // hash_map_array[0] : using default hash function + // hash_map_array[1] : using Pearson hash function + + for (int i = 0; i < hash_map_array_size; i++) { + hash_map_array[i] = safe_malloc(sizeof(hash_map)); + } + + hash_map_init(hash_map_array[0], 1000, (hash_map_comparator) strcmp, NULL); + hash_map_init(hash_map_array[1], 1000, (hash_map_comparator) strcmp, xPear16); } void test_size() { - TEST_ASSERT_EQUAL_UINT(0, hash_map_size(map)); + hash_map *this_hash_map; - hash_map_put(map, "key", "value"); - TEST_ASSERT_EQUAL_UINT(1, hash_map_size(map)); + for (int i = 0; i < hash_map_array_size; i++) { + this_hash_map = hash_map_array[i]; - hash_map_put(map, "key2", "value"); - TEST_ASSERT_EQUAL_UINT(2, hash_map_size(map)); + TEST_ASSERT_EQUAL_UINT(0, hash_map_size(this_hash_map)); - // if the same key was updated, size should not change - hash_map_put(map, "key", "value2"); - TEST_ASSERT_EQUAL_UINT(2, hash_map_size(map)); + hash_map_put(this_hash_map, "key", "value"); + TEST_ASSERT_EQUAL_UINT(1, hash_map_size(this_hash_map)); - // if hashs collide, size should still work - hash_map_put(map, "1234567890", "9090"); - hash_map_put(map, "1234567809", "0909"); - TEST_ASSERT_EQUAL_UINT(4, hash_map_size(map)); + hash_map_put(this_hash_map, "key2", "value"); + TEST_ASSERT_EQUAL_UINT(2, hash_map_size(this_hash_map)); + + // if the same key was updated, size should not change + hash_map_put(this_hash_map, "key", "value2"); + TEST_ASSERT_EQUAL_UINT(2, hash_map_size(this_hash_map)); + + // if hashs collide, size should still work + hash_map_put(this_hash_map, "1234567890", "9090"); + hash_map_put(this_hash_map, "1234567809", "0909"); + TEST_ASSERT_EQUAL_UINT(4, hash_map_size(this_hash_map)); + } } void test_put_get() { - hash_map_put(map, "key", "value"); - TEST_ASSERT_EQUAL_STRING("value", (char *) hash_map_get(map, "key")); + hash_map *this_hash_map; - hash_map_put(map, "key", "value2"); - TEST_ASSERT_EQUAL_STRING("value2", (char *) hash_map_get(map, "key")); + for (int i = 0; i < hash_map_array_size; i++) { + this_hash_map = hash_map_array[i]; - hash_map_put(map, "key2", "value3"); - TEST_ASSERT_EQUAL_STRING("value3", (char *) hash_map_get(map, "key2")); + hash_map_put(this_hash_map, "key", "value"); + TEST_ASSERT_EQUAL_STRING("value", (char *) hash_map_get(this_hash_map, "key")); + + hash_map_put(this_hash_map, "key", "value2"); + TEST_ASSERT_EQUAL_STRING("value2", (char *) hash_map_get(this_hash_map, "key")); + + hash_map_put(this_hash_map, "key2", "value3"); + TEST_ASSERT_EQUAL_STRING("value3", (char *) hash_map_get(this_hash_map, "key2")); + } } void test_get_invalid_key() { - TEST_ASSERT_NULL(hash_map_get(map, "invalid_key")); + hash_map *this_hash_map; + + for (int i = 0; i < hash_map_array_size; i++) { + this_hash_map = hash_map_array[i]; + + TEST_ASSERT_NULL(hash_map_get(this_hash_map, "invalid_key")); + } } void test_default_hash_func() { uint64_t i1 = 1, i2 = 1001; - // these two should collide because of the % - TEST_ASSERT_EQUAL_UINT(map->hash_func(&i1, map->capacity), - map->hash_func(&i2, map->capacity)); + hash_map *this_hash_map; - // these two hash obtained by default hash_func should be equal (since the first 8-byte is the same) - TEST_ASSERT_EQUAL_UINT(map->hash_func("1234567890", map->capacity), - map->hash_func("1234567809", map->capacity)); + for (int i = 0; i < hash_map_array_size; i++) { + this_hash_map = hash_map_array[i]; + + // these two should collide because of the % + TEST_ASSERT_EQUAL_UINT(this_hash_map->hash_func(&i1, this_hash_map->capacity), + this_hash_map->hash_func(&i2, this_hash_map->capacity)); + + // these two hash obtained by default hash_func should be equal (since the first 8-byte is the same) + TEST_ASSERT_EQUAL_UINT(this_hash_map->hash_func("1234567890", this_hash_map->capacity), + this_hash_map->hash_func("1234567809", this_hash_map->capacity)); + } } void test_collision() { - // these two would collide and chaining should come into play - hash_map_put(map, "1234567890", "9090"); - hash_map_put(map, "1234567809", "0909"); + hash_map *this_hash_map; - TEST_ASSERT_EQUAL_STRING("9090", hash_map_get(map, "1234567890")); - TEST_ASSERT_EQUAL_STRING("0909", hash_map_get(map, "1234567809")); + for (int i = 0; i < hash_map_array_size; i++) { + this_hash_map = hash_map_array[i]; + + // these two would collide and chaining should come into play + hash_map_put(this_hash_map, "1234567890", "9090"); + hash_map_put(this_hash_map, "1234567809", "0909"); + + TEST_ASSERT_EQUAL_STRING("9090", hash_map_get(this_hash_map, "1234567890")); + TEST_ASSERT_EQUAL_STRING("0909", hash_map_get(this_hash_map, "1234567809")); + } } void test_keys() { char *keys[] = { "key", "keys2", "1234567890", "1234567809" }; char *values[] = { "value", "value2", "9090", "0909" }; - linked_list *keys_list = hash_map_keys(map); - TEST_ASSERT_EQUAL_UINT(0, linked_list_size(keys_list)); + hash_map *this_hash_map; - for (int i = 0; i < sizeof(keys) / sizeof(*keys); i++) { - hash_map_put(map, keys[i], values[i]); - } + for (int i = 0; i < hash_map_array_size; i++) { + this_hash_map = hash_map_array[i]; + + linked_list *keys_list = hash_map_keys(this_hash_map); + TEST_ASSERT_EQUAL_UINT(0, linked_list_size(keys_list)); + + for (int i = 0; i < sizeof(keys) / sizeof(*keys); i++) { + hash_map_put(this_hash_map, keys[i], values[i]); + } - keys_list = hash_map_keys(map); - TEST_ASSERT_EQUAL_UINT(4, linked_list_size(keys_list)); + keys_list = hash_map_keys(this_hash_map); + TEST_ASSERT_EQUAL_UINT(4, linked_list_size(keys_list)); - linked_list_node *node = linked_list_head(keys_list); - for (int i = 0; i < sizeof(keys) / sizeof(*keys); i++) { - TEST_ASSERT_EQUAL_STRING(keys[i], node->data); - node = node->next; + linked_list_node *node = linked_list_head(keys_list); + for (int i = 0; i < sizeof(keys) / sizeof(*keys); i++) { + TEST_ASSERT_EQUAL_STRING(keys[i], node->data); + node = node->next; + } } } void tearDown() { - hash_map_free(map); + hash_map *this_hash_map; - TEST_ASSERT_EQUAL_INT(0, __malloc_counter); + for (int i = 0; i < hash_map_array_size; i++) { + this_hash_map = hash_map_array[i]; + + hash_map_free(this_hash_map); + + TEST_ASSERT_EQUAL_INT(0, __malloc_counter); + } } From 39f09aee7384a2cf8c3ffd6df560e8501c0a9af8 Mon Sep 17 00:00:00 2001 From: Babak Behzad Date: Mon, 24 Jun 2013 22:16:15 -0500 Subject: [PATCH 4/8] add size function to hash_map, fixed Pearson hash function --- src/hash_functions.c | 29 ++++++++++++++++++++--------- src/hash_functions.h | 3 ++- src/hash_map.c | 11 ++++++----- src/hash_map.h | 12 ++++++++++-- src/memory.c | 1 - test/test_hash_map.c | 36 +++++++++++++++++++++--------------- 6 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/hash_functions.c b/src/hash_functions.c index 92fc6ec..72cea7b 100644 --- a/src/hash_functions.c +++ b/src/hash_functions.c @@ -5,18 +5,16 @@ #include #include "hash_functions.h" +#include "memory.h" size_t hash_map_default_hash_func(const void *key, size_t capacity) { return *((size_t *) key) % capacity; } -unsigned char xPear16(unsigned char *x) { +size_t xPear16(unsigned char *x_copy, size_t capacity, int len) { int h, i, j; - unsigned char ch, hex[20]=""; - - - int len = sizeof(x) / sizeof(char); - printf("len = %d\n", len); + unsigned char ch; + size_t hex; // to store h values struct { @@ -47,13 +45,18 @@ unsigned char xPear16(unsigned char *x) { 43,119,224, 71,122,142, 42,160,104, 48,247,103, 15, 11,138,239 // 16 }; + char *x = safe_malloc(len); + memcpy(x, x_copy, len); + + int r; ch = x[0]; // save first byte for(j = 0 ; j < 8; j++) { // standard Pearson hash (output is h) h=0; for(i = 0; i < len; i++) { - h=T[h ^ x[i]].a; + r = abs(h ^ x[i]); + h=T[r].a; } hh[j].a=h; // store result @@ -62,12 +65,20 @@ unsigned char xPear16(unsigned char *x) { x[0]=ch; // restore first byte + safe_free(x); + // concatenate the 8 stored values of h - sprintf(hex,"%02X%02X%02X%02X%02X%02X%02X%02X", + /*sprintf(hex,"%02X%02X%02X%02X%02X%02X%02X%02X", hh[0].a, hh[1].a, hh[2].a, hh[3].a, hh[4].a, hh[5].a, - hh[6].a, hh[7].a); + hh[6].a, hh[7].a);*/ + + // For now let me do it this way, but Liu doesn't think this is a good thing + for(int i = 0; i < 8; i++) { + hex = hex << 8; + hex = hex & hh[i].a; + } return hex; // output 64-bit 16 hex bytes hash } diff --git a/src/hash_functions.h b/src/hash_functions.h index 0986848..8436d65 100644 --- a/src/hash_functions.h +++ b/src/hash_functions.h @@ -8,6 +8,7 @@ size_t hash_map_default_hash_func(const void *key, size_t capacity); -unsigned char xPear16(unsigned char *x); +size_t xPear16(unsigned char *x, size_t capacity, int len); +unsigned char xPear16_helper(unsigned char *x, size_t capacity, int len); #endif /*HASH_FUNCTIONS_H*/ diff --git a/src/hash_map.c b/src/hash_map.c index c16369e..96186d1 100644 --- a/src/hash_map.c +++ b/src/hash_map.c @@ -18,7 +18,7 @@ inline int hash_map_default_comparator(const void *l, const void *r) { return *((unsigned long *) l) - *((unsigned long *) r); } -void hash_map_init(hash_map *map, size_t capacity, hash_map_comparator comparator, hash_map_hash_func hash_func) { +void hash_map_init(hash_map *map, size_t capacity, hash_map_comparator comparator, hash_map_hash_func hash_func, hash_map_key_size key_size) { map->capacity = capacity; map->size = 0; @@ -37,6 +37,8 @@ void hash_map_init(hash_map *map, size_t capacity, hash_map_comparator comparato map->hash_func = hash_map_default_hash_func; } + map->key_size = key_size; + map->keys = (linked_list *) safe_malloc(sizeof(linked_list)); linked_list_init(map->keys, map->comparator, NULL); // no free_data func here because keys will be free'd by linked_list_free for **table } @@ -56,7 +58,7 @@ void hash_map_free(hash_map *map) { } void *hash_map_get(hash_map *map, void *key) { - linked_list *list = map->table[map->hash_func(key, map->capacity)]; + linked_list *list = map->table[map->hash_func(key, map->capacity, map->key_size())]; if (!list) { return NULL; @@ -78,12 +80,12 @@ void *hash_map_get(hash_map *map, void *key) { } void hash_map_put(hash_map *map, void *key, void *value) { - linked_list *list = map->table[map->hash_func(key, map->capacity)]; + linked_list *list = map->table[map->hash_func(key, map->capacity, map->key_size())]; if (!list) { list = (linked_list *) safe_malloc(sizeof(linked_list)); linked_list_init(list, map->comparator, (linked_list_destructor) safe_free); - map->table[map->hash_func(key, map->capacity)] = list; + map->table[map->hash_func(key, map->capacity, map->key_size())] = list; } linked_list_node *head = linked_list_head(list); @@ -120,4 +122,3 @@ size_t hash_map_size(hash_map *map) { linked_list *hash_map_keys(hash_map *map) { return map->keys; } - diff --git a/src/hash_map.h b/src/hash_map.h index 812ae6e..f9ff68a 100644 --- a/src/hash_map.h +++ b/src/hash_map.h @@ -23,7 +23,13 @@ typedef int (*hash_map_comparator)(const void *l, const void *r); * @param capacity maximum size of the map * @return an offset within the range `[0, capacity)` */ -typedef size_t (*hash_map_hash_func)(const void *key, size_t capacity); +typedef size_t (*hash_map_hash_func)(const void *key, size_t capacity, int len); + +/** + * Size function to determine the size of each keys in the hash function + * @return the size of each key` + */ +typedef size_t (*hash_map_key_size)(); /** * Hash map object @@ -39,6 +45,8 @@ typedef struct { hash_map_comparator comparator; /** Key hash function */ hash_map_hash_func hash_func; + /** Key size function */ + hash_map_key_size key_size; /** Keys */ linked_list *keys; } hash_map; @@ -60,7 +68,7 @@ typedef struct { * @param comparator key comparator function * @param hash_func key hash function */ -void hash_map_init(hash_map *map, size_t capacity, hash_map_comparator comparator, hash_map_hash_func hash_func); +void hash_map_init(hash_map *map, size_t capacity, hash_map_comparator comparator, hash_map_hash_func hash_func, hash_map_key_size); /** * Free the hash map. diff --git a/src/memory.c b/src/memory.c index c2da311..3abae2d 100644 --- a/src/memory.c +++ b/src/memory.c @@ -1,5 +1,4 @@ #include "memory.h" - #include #include diff --git a/test/test_hash_map.c b/test/test_hash_map.c index 57a3cdb..834acd4 100644 --- a/test/test_hash_map.c +++ b/test/test_hash_map.c @@ -23,12 +23,12 @@ void setUp() { hash_map_array[i] = safe_malloc(sizeof(hash_map)); } - hash_map_init(hash_map_array[0], 1000, (hash_map_comparator) strcmp, NULL); - hash_map_init(hash_map_array[1], 1000, (hash_map_comparator) strcmp, xPear16); + hash_map_init(hash_map_array[0], 1000, (hash_map_comparator) strcmp, NULL, strlen); + hash_map_init(hash_map_array[1], 1000, (hash_map_comparator) strcmp, xPear16, strlen); } void test_size() { - hash_map *this_hash_map; + hash_map *this_hash_map; for (int i = 0; i < hash_map_array_size; i++) { this_hash_map = hash_map_array[i]; @@ -53,7 +53,7 @@ void test_size() { } void test_put_get() { - hash_map *this_hash_map; + hash_map *this_hash_map; for (int i = 0; i < hash_map_array_size; i++) { this_hash_map = hash_map_array[i]; @@ -70,7 +70,7 @@ void test_put_get() { } void test_get_invalid_key() { - hash_map *this_hash_map; + hash_map *this_hash_map; for (int i = 0; i < hash_map_array_size; i++) { this_hash_map = hash_map_array[i]; @@ -79,27 +79,32 @@ void test_get_invalid_key() { } } +int int_size() { + return sizeof(uint64_t); +} + + void test_default_hash_func() { uint64_t i1 = 1, i2 = 1001; - hash_map *this_hash_map; + hash_map *this_hash_map; for (int i = 0; i < hash_map_array_size; i++) { this_hash_map = hash_map_array[i]; // these two should collide because of the % - TEST_ASSERT_EQUAL_UINT(this_hash_map->hash_func(&i1, this_hash_map->capacity), - this_hash_map->hash_func(&i2, this_hash_map->capacity)); + TEST_ASSERT_EQUAL_UINT(this_hash_map->hash_func(&i1, this_hash_map->capacity, int_size()), + this_hash_map->hash_func(&i2, this_hash_map->capacity, int_size())); // these two hash obtained by default hash_func should be equal (since the first 8-byte is the same) - TEST_ASSERT_EQUAL_UINT(this_hash_map->hash_func("1234567890", this_hash_map->capacity), - this_hash_map->hash_func("1234567809", this_hash_map->capacity)); + TEST_ASSERT_EQUAL_UINT(this_hash_map->hash_func("1234567890", this_hash_map->capacity, int_size()), + this_hash_map->hash_func("1234567809", this_hash_map->capacity, int_size())); } } void test_collision() { - hash_map *this_hash_map; + hash_map *this_hash_map; for (int i = 0; i < hash_map_array_size; i++) { this_hash_map = hash_map_array[i]; @@ -117,7 +122,7 @@ void test_keys() { char *keys[] = { "key", "keys2", "1234567890", "1234567809" }; char *values[] = { "value", "value2", "9090", "0909" }; - hash_map *this_hash_map; + hash_map *this_hash_map; for (int i = 0; i < hash_map_array_size; i++) { this_hash_map = hash_map_array[i]; @@ -141,14 +146,15 @@ void test_keys() { } void tearDown() { - hash_map *this_hash_map; + hash_map *this_hash_map; for (int i = 0; i < hash_map_array_size; i++) { this_hash_map = hash_map_array[i]; - hash_map_free(this_hash_map); - TEST_ASSERT_EQUAL_INT(0, __malloc_counter); } + safe_free(hash_map_array); + + TEST_ASSERT_EQUAL_INT(0, __malloc_counter); } From 41a22c058557b0546131ff547c0c7fdc3b9c85e8 Mon Sep 17 00:00:00 2001 From: Babak Behzad Date: Mon, 24 Jun 2013 22:23:15 -0500 Subject: [PATCH 5/8] fix two warnings regarding hash function signature --- src/hash_functions.c | 4 ++-- src/hash_functions.h | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hash_functions.c b/src/hash_functions.c index 72cea7b..94490d7 100644 --- a/src/hash_functions.c +++ b/src/hash_functions.c @@ -7,11 +7,11 @@ #include "hash_functions.h" #include "memory.h" -size_t hash_map_default_hash_func(const void *key, size_t capacity) { +size_t hash_map_default_hash_func(const void *key, size_t capacity, int len) { return *((size_t *) key) % capacity; } -size_t xPear16(unsigned char *x_copy, size_t capacity, int len) { +size_t xPear16(const void *x_copy, size_t capacity, int len) { int h, i, j; unsigned char ch; size_t hex; diff --git a/src/hash_functions.h b/src/hash_functions.h index 8436d65..066a0d7 100644 --- a/src/hash_functions.h +++ b/src/hash_functions.h @@ -6,9 +6,8 @@ #ifndef HASH_FUNCTIONS_H #define HASH_FUNCTIONS_H -size_t hash_map_default_hash_func(const void *key, size_t capacity); +size_t hash_map_default_hash_func(const void *key, size_t capacity, int len); -size_t xPear16(unsigned char *x, size_t capacity, int len); -unsigned char xPear16_helper(unsigned char *x, size_t capacity, int len); +size_t xPear16(const void *x, size_t capacity, int len); #endif /*HASH_FUNCTIONS_H*/ From c1f5a53280a2d466d201dcb49e9a28514420fee0 Mon Sep 17 00:00:00 2001 From: Babak Behzad Date: Thu, 27 Jun 2013 20:50:45 -0500 Subject: [PATCH 6/8] fix a bug thrown by gcc --- src/hash_map.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/hash_map.c b/src/hash_map.c index 182440b..3ecd32f 100644 --- a/src/hash_map.c +++ b/src/hash_map.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "memory.h" #include "linked_list.h" @@ -59,7 +60,7 @@ void hash_map_free(hash_map *map) { } void *hash_map_get(hash_map *map, void *key) { - linked_list *list = map->table[map->hash_func(key, map->capacity, map->key_size())]; + linked_list *list = map->table[map->hash_func(key, map->capacity, map->key_size(key))]; if (!list) { return NULL; @@ -81,13 +82,13 @@ void *hash_map_get(hash_map *map, void *key) { } void hash_map_put(hash_map *map, void *key, void *value) { - linked_list *list = map->table[map->hash_func(key, map->capacity, map->key_size())]; + linked_list *list = map->table[map->hash_func(key, map->capacity, map->key_size(key))]; if (!list) { list = (linked_list *) safe_malloc(sizeof(linked_list)); linked_list_init(list, (linked_list_destructor) safe_free); - map->table[map->hash_func(key, map->capacity, map->key_size())] = list; + map->table[map->hash_func(key, map->capacity, map->key_size(key))] = list; } linked_list_node *head = linked_list_head(list); @@ -118,7 +119,7 @@ void hash_map_put(hash_map *map, void *key, void *value) { } void hash_map_remove(hash_map *map, void *key) { - size_t offset = map->hash_func(key, map->capacity, map->key_size()); + size_t offset = map->hash_func(key, map->capacity, map->key_size(key)); linked_list *list = map->table[offset]; if (!list) { @@ -175,7 +176,7 @@ void hash_map_clear(hash_map *map) { } bool hash_map_contains_key(hash_map *map, void *key) { - linked_list *list = map->table[map->hash_func(key, map->capacity, map->key_size())]; + linked_list *list = map->table[map->hash_func(key, map->capacity, map->key_size(key))]; if (!list) { return false; From 1af432542f24924e9b466b50491dd2d4a0acd997 Mon Sep 17 00:00:00 2001 From: Babak Behzad Date: Thu, 27 Jun 2013 21:10:27 -0500 Subject: [PATCH 7/8] update doxygen for the new stuff --- src/hash_functions.h | 14 ++++++++++++++ src/hash_map.h | 1 + 2 files changed, 15 insertions(+) diff --git a/src/hash_functions.h b/src/hash_functions.h index 066a0d7..3dcfb57 100644 --- a/src/hash_functions.h +++ b/src/hash_functions.h @@ -6,8 +6,22 @@ #ifndef HASH_FUNCTIONS_H #define HASH_FUNCTIONS_H +/** + * The default hash function. This is the function to be used if the user does not explicitly provide any hash function. It is a basic mod operator. + * @param key key to hash + * @param capacity maximum size of the map + * @param len the size of the key passed as the first argument + * @return an offset within the range `[0, capacity)` + */ size_t hash_map_default_hash_func(const void *key, size_t capacity, int len); +/** + * The Pearson hash function. Both the explanation and code are derived from Wikipedia + * @param key key to hash + * @param capacity maximum size of the map + * @param len the size of the key passed as the first argument + * @return an offset within the range `[0, capacity)` + */ size_t xPear16(const void *x, size_t capacity, int len); #endif /*HASH_FUNCTIONS_H*/ diff --git a/src/hash_map.h b/src/hash_map.h index 8efcf46..4b59d87 100644 --- a/src/hash_map.h +++ b/src/hash_map.h @@ -22,6 +22,7 @@ typedef int (*hash_map_comparator)(const void *l, const void *r); * Hash function * @param key key to hash * @param capacity maximum size of the map + * @param len the size of the key passed as the first argument * @return an offset within the range `[0, capacity)` */ typedef size_t (*hash_map_hash_func)(const void *key, size_t capacity, int len); From e0bde7ad87c4c2d5fd9fb7e4d38dfa3c4c4e7f5b Mon Sep 17 00:00:00 2001 From: Babak Behzad Date: Mon, 15 Jul 2013 21:04:51 -0500 Subject: [PATCH 8/8] address Seans comments --- src/hash_functions.c | 14 +++++++++++++- src/hash_functions.h | 18 ++++++++++++++---- test/test_hash_map.c | 2 +- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/hash_functions.c b/src/hash_functions.c index 78125da..cdee613 100644 --- a/src/hash_functions.c +++ b/src/hash_functions.c @@ -11,7 +11,19 @@ size_t hash_map_default_hash_func(const void *key, size_t capacity, int len) { return *((size_t *) key) % capacity; } -size_t xPear16(const void *x_copy, size_t capacity, int len) { +size_t additive(const void *key, size_t capacity, int len) { + const char *key2 = (const char *) key; + int hash = len; + + for (int i = 0; i < len; ++i) { + hash += key2[i]; + } + + + return (hash % capacity); +} + +size_t pearson_hash(const void *x_copy, size_t capacity, int len) { int h, i, j; unsigned char ch; size_t hex; diff --git a/src/hash_functions.h b/src/hash_functions.h index 3dcfb57..58ef0c9 100644 --- a/src/hash_functions.h +++ b/src/hash_functions.h @@ -7,7 +7,7 @@ #define HASH_FUNCTIONS_H /** - * The default hash function. This is the function to be used if the user does not explicitly provide any hash function. It is a basic mod operator. + * The default hash function. This is the function to be used if the user does not explicitly provide any hash function. It is a basic `mod` operator. * @param key key to hash * @param capacity maximum size of the map * @param len the size of the key passed as the first argument @@ -16,12 +16,22 @@ size_t hash_map_default_hash_func(const void *key, size_t capacity, int len); /** - * The Pearson hash function. Both the explanation and code are derived from Wikipedia + * The additive hash function. Both the explanation and code are based on [Chasan Chouse](http://www.chasanc.com/old/hashing_func.htm) * @param key key to hash * @param capacity maximum size of the map * @param len the size of the key passed as the first argument * @return an offset within the range `[0, capacity)` */ -size_t xPear16(const void *x, size_t capacity, int len); +size_t additive(const void *x, size_t capacity, int len); -#endif /*HASH_FUNCTIONS_H*/ +/** + * The Pearson hash function. Both the explanation and code are based on [Wikipedia](http://en.wikipedia.org/wiki/Pearson_hashing) + * @param key key to hash + * @param capacity maximum size of the map + * @param len the size of the key passed as the first argument + * @return an offset within the range `[0, capacity)` + */ +size_t pearson_hash(const void *x, size_t capacity, int len); + + +#endif diff --git a/test/test_hash_map.c b/test/test_hash_map.c index e6073ae..36a81ca 100644 --- a/test/test_hash_map.c +++ b/test/test_hash_map.c @@ -24,7 +24,7 @@ void setUp() { } hash_map_init(hash_map_array[0], 1000, (hash_map_comparator) strcmp, NULL, strlen); - hash_map_init(hash_map_array[1], 1000, (hash_map_comparator) strcmp, xPear16, strlen); + hash_map_init(hash_map_array[1], 1000, (hash_map_comparator) strcmp, pearson_hash, strlen); } void test_size() {