diff --git a/hashtable.c b/hashtable.c index 23c17ce8631fc88901aed4c43ff0ac2f7e458a2c..7e2c0dd9c5ef9d6a94b36e894d66dafc4419a3ea 100644 --- a/hashtable.c +++ b/hashtable.c @@ -8,41 +8,156 @@ #include <stdlib.h> #include <string.h> +int hash(char *key, int64_t length) { + // If the size of the int is too low the hash methods will generate overflow errors + int64_t val = 0; + for (size_t i = 0; i < strlen(key); i++) { + val = 43 * val + key[i]; + } + return (val % length); +} + +entry *entry_create_empty() { + entry *e = malloc(sizeof(entry)); + e->key = NULL; + e->value = NULL; + e->next = NULL; + return e; +} + hm *hm_create(unsigned int length) { hm *hashmap = malloc(sizeof(hm)); hashmap->length = length; hashmap->entries = malloc(sizeof(entry) * length); - for (int i = 0; i < length; i++) { - hashmap->entries[i] = malloc(sizeof(entry)); + for (size_t i = 0; i < length; i++) { + hashmap->entries[i] = entry_create_empty(); } return hashmap; } +entry *get_entry_by_key(entry *e, char *key) { + if (e->key == key) { + return e; + } else if (e->next != NULL) { + return get_entry_by_key(e->next, key); + } else { + return e; + } +} + void hm_destroy(hm **hm) { for (int i = 0; i < (*hm)->length; i++) { - free((*hm)->entries[i]); + entry *e = (*hm)->entries[i]; + while (e != NULL) { + entry *to_free = e; + e = e->next; + free(to_free); + } } free((*hm)->entries); free((*hm)); + (*hm) = NULL; } hm *hm_set(hm *hm, const char *const key, const char *const value) { - return NULL; + // Hash the key and get the corresponding entry + int key_index = hash((char *)key, hm->length); + entry *e = get_entry_by_key(hm->entries[key_index], (char *)key); + + // Set the key and create the next entry if the key is not existing + if (e->key != key) { + e->key = (char *)key; + if (e->next == NULL) { + e->next = entry_create_empty(); + } + } + + // Set the entry value and return the hashmap + e->value = (char *)value; + return hm; } char *hm_get(const hm *const hm, const char *const key) { - return NULL; + int key_index = hash((char *)key, hm->length); + char *c = get_entry_by_key(hm->entries[key_index], (char *)key)->value; + return c; } char *hm_rm(hm *hm, const char *const key) { - return NULL; + int key_index = hash((char *)key, hm->length); + entry *e = get_entry_by_key(hm->entries[key_index], (char *)key); + entry *previous_entry = NULL; + entry *current_entry = hm->entries[key_index]; + int entry_index = 0; + + while (current_entry != e) { + previous_entry = current_entry; + current_entry = current_entry->next; + entry_index++; + } + + if (entry_index == 0) { + hm->entries[key_index] = hm->entries[key_index]->next; + } else if (previous_entry != NULL) { + previous_entry->next = e->next; + } + + char *entry_key = e->key; + free(e); + e = NULL; + return entry_key; +} + +int get_entry_list_size(entry *e) { + int size = 0; + size += sizeof(e->key) + sizeof(e->value) + 16; + if (e->next != NULL) { + size += get_entry_list_size(e->next); + } + return size; } -char *hmo_str(const hm *const hm) { - return NULL; +char *hm_to_str(const hm *const hm) { + int str_size = sizeof(hm) * hm->length; + for (int i = 0; i < hm->length; i++) { + str_size += get_entry_list_size(hm->entries[i]); + } + + char *hm_str = malloc(str_size); + // Ensure that the string is empty before doing anything + hm_str[0] = '\0'; + + strcat(hm_str, "[\n"); + for (int i = 0; i < hm->length; i++) { + strcat(hm_str, " [\n"); + entry *e = hm->entries[i]; + while (e != NULL && e->key != NULL) { + strcat(hm_str, " [\""); + strcat(hm_str, e->key); + strcat(hm_str, "\": \""); + strcat(hm_str, e->value); + strcat(hm_str, "\"]"); + if (e->next != NULL && e->next->key != NULL) { + strcat(hm_str, ","); + } + strcat(hm_str, "\n"); + e = e->next; + } + + strcat(hm_str, " ]"); + if (i < hm->length - 1) { + strcat(hm_str, ","); + } + strcat(hm_str, "\n"); + } + + strcat(hm_str, "]\n"); + return hm_str; } void hm_print(const hm *const hm) { - return NULL; + char *str = hm_to_str(hm); + printf("%s\n", str); + free(str); } diff --git a/main.c b/main.c index 09ae288928dd80d4db07b75589fe999f4b0ccdad..7a4af81ce300ddccc7eeb8deb94d5e7d87c4e0a4 100644 --- a/main.c +++ b/main.c @@ -9,6 +9,37 @@ int main() { hm *hashmap = hm_create(10); + hm_set(hashmap, "Key1", "Value1"); + hm_set(hashmap, "Key2", "Value1"); + hm_set(hashmap, "Key1", "Value2"); + hm_set(hashmap, "Key3", "Value1"); + hm_set(hashmap, "Key4", "FOUR"); + hm_set(hashmap, "Key1", "Value3"); + hm_set(hashmap, "Key5", "I think it's good now"); + hm_set(hashmap, "Key6", "6"); + hm_set(hashmap, "Key7", "7"); + hm_set(hashmap, "Key8", "8"); + hm_set(hashmap, "Key9", "9"); + hm_set(hashmap, "Key27", "MORE ?"); + hm_set(hashmap, "Key10", "Is this the end ?"); + + printf("Value of %s : %s\n", "Key1", hm_get(hashmap, "Key1")); + printf("Value of %s : %s\n", "Key2", hm_get(hashmap, "Key2")); + printf("Value of %s : %s\n", "Key3", hm_get(hashmap, "Key3")); + printf("Value of %s : %s\n", "Key4", hm_get(hashmap, "Key4")); + printf("Value of %s : %s\n", "Key5", hm_get(hashmap, "Key5")); + printf("Value of %s : %s\n", "Key6", hm_get(hashmap, "Key6")); + printf("Value of %s : %s\n", "Key7", hm_get(hashmap, "Key7")); + printf("Value of %s : %s\n", "Key8", hm_get(hashmap, "Key8")); + printf("Value of %s : %s\n", "Key9", hm_get(hashmap, "Key9")); + printf("Value of %s : %s\n", "Key10", hm_get(hashmap, "Key10")); + + hm_print(hashmap); + hm_rm(hashmap, "Key1"); + hm_print(hashmap); + hm_rm(hashmap, "Key10"); + hm_print(hashmap); + hm_destroy(&hashmap); return EXIT_SUCCESS;