Expand the hash table implementation

Our implementation now resizes automatically and supports hashing by
open addressing.
This commit is contained in:
Nat 2023-01-20 16:11:19 -08:00
parent f4e04b0dfd
commit 02c7492f74
Signed by: nat
GPG Key ID: B53AB05285D710D6
1 changed files with 62 additions and 27 deletions

View File

@ -50,6 +50,12 @@ char * read_file(char *filename) {
} }
/*** Hash map implementation ***/ /*** Hash map implementation ***/
struct PageMap {
struct Page **pages;
int capacity;
int size;
};
int helper_hash_polynomial( int helper_hash_polynomial(
char string[], char string[],
int i, int i,
@ -65,33 +71,69 @@ int helper_hash_polynomial(
} }
} }
int hash_polynomial(int mapSize, char key[]) { int hash_polynomial(int capacity, char key[]) {
return helper_hash_polynomial(key, 0, strlen(key), mapSize, 0); 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; int i = 0;
for (; str[i] != '\0'; i++) { 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) { struct PageMap * map(int capacity) {
char lowercased[80]; struct PageMap *map = malloc(sizeof(struct PageMap));
to_lower_case(lowercased, title); map->pages = calloc(capacity, sizeof(struct Page *));
map->capacity = capacity;
int index = hash_polynomial(mapSize, lowercased); map->size = 0;
map[index] = page; return map;
} }
struct Page * map_get(struct Page **map, int mapSize, char title[]) { void map_free(struct PageMap *map) {
char lowercased[80]; free(map->pages);
to_lower_case(lowercased, title); free(map);
}
int index = hash_polynomial(mapSize, lowercased); void map_put(struct PageMap *map, char title[], struct Page *page) {
struct Page *page = map[index]; 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; return page;
} }
@ -176,7 +218,6 @@ char * substitute_string(char dest[], char sub[], char *start, char *end) {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
char pagesLocation[256] = "./pages"; char pagesLocation[256] = "./pages";
int mapSize = 1000;
int initialInboundCapacity = 2; int initialInboundCapacity = 2;
char templateFileName[256] = "./template.html"; char templateFileName[256] = "./template.html";
char outputDirectoryName[256] = "./build"; char outputDirectoryName[256] = "./build";
@ -189,11 +230,6 @@ int main(int argc, char *argv[]) {
i++; i++;
strcpy(pagesLocation, 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) { } else if (strcmp(argv[i], "--template") == 0) {
if (i + 1 < argc) { if (i + 1 < argc) {
i++; i++;
@ -230,8 +266,7 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
struct Page ** pageMap = malloc(mapSize * sizeof(struct Page *)); struct PageMap *pageMap = map(100);
memset(pageMap, 0, mapSize * sizeof(struct Page *));
// Contains some information about the current file picked from pagesDir // Contains some information about the current file picked from pagesDir
struct dirent *fileEntry = readdir(pagesDir); struct dirent *fileEntry = readdir(pagesDir);
@ -310,7 +345,7 @@ int main(int argc, char *argv[]) {
currentPage->title[min(titleLength, 80)] = 0; currentPage->title[min(titleLength, 80)] = 0;
// Insert it into the hash map for lookup later // 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 // Get ready to process the next page
fileEntry = readdir(pagesDir); fileEntry = readdir(pagesDir);
@ -360,14 +395,13 @@ int main(int argc, char *argv[]) {
strncpy(linkTitle, nextLinkStart + 2, (nextVerticalBar - 1) - (nextLinkStart + 1)); strncpy(linkTitle, nextLinkStart + 2, (nextVerticalBar - 1) - (nextLinkStart + 1));
linkPageTitle = calloc((nextLinkEnd - 2) - nextVerticalBar, sizeof(char)); linkPageTitle = calloc((nextLinkEnd - 2) - nextVerticalBar, sizeof(char));
strncpy(linkPageTitle, nextVerticalBar + 1, (nextLinkEnd - 1) - nextVerticalBar); strncpy(linkPageTitle, nextVerticalBar + 1, (nextLinkEnd - 1) - nextVerticalBar);
puts(linkPageTitle);
} else { } else {
// The link is of the form [[page title]] // The link is of the form [[page title]]
linkPageTitle = linkTitle; linkPageTitle = linkTitle;
strncpy(linkTitle, nextLinkStart + 2, (linkLength - 2)*sizeof(char)); 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; char *compiledLink = NULL;
@ -499,6 +533,7 @@ int main(int argc, char *argv[]) {
} }
closedir(pagesDir); closedir(pagesDir);
free(templateContent); free(templateContent);
map_free(pageMap);
// Deallocate all the pages // Deallocate all the pages