From 02c7492f744167fddf7f036404d3a0b27455c8bc Mon Sep 17 00:00:00 2001 From: natjms Date: Fri, 20 Jan 2023 16:11:19 -0800 Subject: [PATCH] Expand the hash table implementation Our implementation now resizes automatically and supports hashing by open addressing. --- calathea.c | 89 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 27 deletions(-) diff --git a/calathea.c b/calathea.c index 8cb05d7..ccd1a7d 100644 --- a/calathea.c +++ b/calathea.c @@ -50,6 +50,12 @@ char * read_file(char *filename) { } /*** Hash map implementation ***/ +struct PageMap { + struct Page **pages; + int capacity; + int size; +}; + int helper_hash_polynomial( char string[], int i, @@ -65,33 +71,69 @@ int helper_hash_polynomial( } } -int hash_polynomial(int mapSize, char key[]) { - return helper_hash_polynomial(key, 0, strlen(key), mapSize, 0); +int hash_polynomial(int capacity, char key[]) { + return helper_hash_polynomial(key, 0, strlen(key), capacity, 0); } -void to_lower_case(char dest[], char str[]) { +char * to_lower_case(char str[]) { + char * lower = malloc((strlen(str) + 1) * sizeof(char)); int i = 0; for (; str[i] != '\0'; i++) { - dest[i] = tolower(str[i]); + lower[i] = tolower(str[i]); } - dest[i] = 0; + lower[i] = 0; + + return lower; } -void map_put(struct Page **map, int mapSize, char title[], struct Page *page) { - char lowercased[80]; - to_lower_case(lowercased, title); - - int index = hash_polynomial(mapSize, lowercased); - map[index] = page; +struct PageMap * map(int capacity) { + struct PageMap *map = malloc(sizeof(struct PageMap)); + map->pages = calloc(capacity, sizeof(struct Page *)); + map->capacity = capacity; + map->size = 0; + return map; } -struct Page * map_get(struct Page **map, int mapSize, char title[]) { - char lowercased[80]; - to_lower_case(lowercased, title); +void map_free(struct PageMap *map) { + free(map->pages); + free(map); +} - int index = hash_polynomial(mapSize, lowercased); - struct Page *page = map[index]; +void map_put(struct PageMap *map, char title[], struct Page *page) { + char *lowercased = to_lower_case(title); + int index = hash_polynomial(map->capacity, lowercased); + while (map->pages[index] != NULL) index++; + map->pages[index] = page; + map->size++; + + // Resize the map if we're running low on space + if (map->size/map->capacity > 0.75) { + map->pages = realloc(map->pages, map->capacity * 2); + for (int i = map->capacity; i < map->capacity * 2; i++) { + map->pages[i] = 0; + } + map->capacity *= 2; + } + + free(lowercased); +} + +struct Page * map_get(struct PageMap *map, char title[]) { + char *lowercased = to_lower_case(title); + + int index = hash_polynomial(map->capacity, lowercased); + struct Page *page = map->pages[index]; + + char *lowercasedFoundTitle = to_lower_case(page->title); + while (strcmp(lowercasedFoundTitle, lowercased) != 0) { + page = map->pages[++index]; + free(lowercasedFoundTitle); + lowercasedFoundTitle = to_lower_case(page->title); + } + + free(lowercased); + free(lowercasedFoundTitle); return page; } @@ -176,7 +218,6 @@ char * substitute_string(char dest[], char sub[], char *start, char *end) { int main(int argc, char *argv[]) { char pagesLocation[256] = "./pages"; - int mapSize = 1000; int initialInboundCapacity = 2; char templateFileName[256] = "./template.html"; char outputDirectoryName[256] = "./build"; @@ -189,11 +230,6 @@ int main(int argc, char *argv[]) { i++; strcpy(pagesLocation, argv[i]); } - } else if (strcmp(argv[i], "--table-size") == 0) { - if (i + 1 < argc) { - i++; - mapSize = atoi(argv[i]); - } } else if (strcmp(argv[i], "--template") == 0) { if (i + 1 < argc) { i++; @@ -230,8 +266,7 @@ int main(int argc, char *argv[]) { return 1; } - struct Page ** pageMap = malloc(mapSize * sizeof(struct Page *)); - memset(pageMap, 0, mapSize * sizeof(struct Page *)); + struct PageMap *pageMap = map(100); // Contains some information about the current file picked from pagesDir struct dirent *fileEntry = readdir(pagesDir); @@ -310,7 +345,7 @@ int main(int argc, char *argv[]) { currentPage->title[min(titleLength, 80)] = 0; // Insert it into the hash map for lookup later - map_put(pageMap, mapSize, currentPage->title, currentPage); + map_put(pageMap, currentPage->title, currentPage); // Get ready to process the next page fileEntry = readdir(pagesDir); @@ -360,14 +395,13 @@ int main(int argc, char *argv[]) { strncpy(linkTitle, nextLinkStart + 2, (nextVerticalBar - 1) - (nextLinkStart + 1)); linkPageTitle = calloc((nextLinkEnd - 2) - nextVerticalBar, sizeof(char)); strncpy(linkPageTitle, nextVerticalBar + 1, (nextLinkEnd - 1) - nextVerticalBar); - puts(linkPageTitle); } else { // The link is of the form [[page title]] linkPageTitle = linkTitle; strncpy(linkTitle, nextLinkStart + 2, (linkLength - 2)*sizeof(char)); } - struct Page *linkedPage = map_get(pageMap, mapSize, linkPageTitle); + struct Page *linkedPage = map_get(pageMap, linkPageTitle); char *compiledLink = NULL; @@ -499,6 +533,7 @@ int main(int argc, char *argv[]) { } closedir(pagesDir); free(templateContent); + map_free(pageMap); // Deallocate all the pages