Last active
April 5, 2020 16:14
-
-
Save zelark/e40be0d4de9f852328d34aa9e0ceaa5a to your computer and use it in GitHub Desktop.
You can find the original example here https://youtu.be/wg8hZxMRwcw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#define HASHMAP_SIZE 16 | |
typedef struct entry_t { | |
char *key; | |
char *value; | |
struct entry_t *next; | |
} entry_t, *entry_p; | |
typedef struct { | |
entry_t **entries; | |
} hmap_t, *hmap_p; | |
unsigned int hash(char *key) { | |
unsigned long int value = 0; | |
unsigned int key_len = strlen(key); | |
/* Do several rounds of multiplication. */ | |
for (int i = 0; i < key_len; ++i) { | |
value = value * 37 + key[i]; | |
} | |
/* Make sure value is 0 <= value < HASHMAP_SIZE. */ | |
value = value % HASHMAP_SIZE; | |
return value; | |
} | |
entry_p hmap_create_entry(char *key, char *value) { | |
/* Allocate the entry. */ | |
entry_t *entry = malloc(sizeof(entry_t)); | |
entry->key = malloc(strlen(key) + 1); | |
entry->value = malloc(strlen(value) + 1); | |
/* Copy the key and value in place. */ | |
strcpy(entry->key, key); | |
strcpy(entry->value, value); | |
/* Next starts out null but may be set later on. */ | |
entry->next = NULL; | |
return entry; | |
} | |
void hmap_delete_entry(entry_t *entry) { | |
free(entry->key); | |
free(entry->value); | |
free(entry); | |
} | |
hmap_p hmap_create(void) { | |
hmap_t *hmap = malloc(sizeof(hmap_t)); | |
hmap->entries = malloc(sizeof(entry_p) * HASHMAP_SIZE); | |
/* Set each entry to null (needed for proper operation). */ | |
for (int i = 0; i < HASHMAP_SIZE; ++i) { | |
hmap->entries[i] = NULL; | |
} | |
return hmap; | |
} | |
void hmap_delete(hmap_t *hmap) { | |
for (int i = 0; i < HASHMAP_SIZE; ++i) { | |
entry_t *entry = hmap->entries[i]; | |
while (entry) { | |
entry_t *next = entry->next; | |
hmap_delete_entry(entry); | |
entry = next; | |
} | |
} | |
free(hmap->entries); | |
free(hmap); | |
} | |
void hmap_put(hmap_t *hmap, char *key, char *value) { | |
unsigned int slot = hash(key); | |
/* Try to look up an entry set. */ | |
entry_t *entry = hmap->entries[slot]; | |
/* No entry means slot empty, insert immediately. */ | |
if (entry == NULL) { | |
hmap->entries[slot] = hmap_create_entry(key, value); | |
return; | |
} | |
entry_t *prev; | |
/* Walk through each entry until either the end is */ | |
/* reached or a matching key is found. */ | |
while (entry != NULL) { | |
/* Check key. */ | |
if (strcmp(entry->key, key) == 0) { | |
/* Match found, replace value. */ | |
free(entry->value); | |
entry->value = malloc(strlen(value) + 1); | |
strcpy(entry->value, value); | |
return; | |
} | |
/* Walk to next. */ | |
prev = entry; | |
entry = prev->next; | |
} | |
// End of chain reached without a match, add new. | |
prev->next = hmap_create_entry(key, value); | |
} | |
char* hmap_get(hmap_t *hmap, char *key) { | |
unsigned int slot = hash(key); | |
/* Try to find a valid slot. */ | |
entry_t *entry = hmap->entries[slot]; | |
/* No slot means no entry. */ | |
if (entry == NULL) { | |
return NULL; | |
} | |
/* Walk through each entry in the slot, */ | |
/* which could just be a single thing. */ | |
while (entry != NULL) { | |
/* Return value if found. */ | |
if (strcmp(entry->key, key) == 0) { | |
return entry->value; | |
} | |
/* Proceed to next key if available. */ | |
entry = entry->next; | |
} | |
/* Reaching here means there were >= 1 entries but no key match. */ | |
return NULL; | |
} | |
void hmap_del(hmap_t *hmap, char *key) { | |
unsigned int slot = hash(key); | |
/* Try to find a valid slot. */ | |
entry_t *entry = hmap->entries[slot]; | |
/* No bucket means no entry. */ | |
if (entry == NULL) { | |
return; | |
} | |
entry_t *prev; | |
int idx = 0; | |
/* Walk through each entry until either the end is reached */ | |
/* or a matching key is found. */ | |
while (entry != NULL) { | |
if (strcmp(entry->key, key) == 0) { | |
/* If first item and no next entry. */ | |
if (entry->next == NULL && idx == 0) { | |
hmap->entries[slot] = NULL; | |
} | |
/* If first item with a next entry. */ | |
if (entry->next != NULL && idx == 0) { | |
hmap->entries[slot] = entry->next; | |
} | |
/* If last item. */ | |
if (entry->next == NULL && idx != 0) { | |
prev->next = NULL; | |
} | |
/* If middle item. */ | |
if (entry->next != NULL && idx != 0) { | |
prev->next = entry->next; | |
} | |
/* Free the deleted entry. */ | |
hmap_delete_entry(entry); | |
return; | |
} | |
/* Walk to next. */ | |
prev = entry; | |
entry = prev->next; | |
++idx; | |
} | |
} | |
void hmap_dump(hmap_t *hmap) { | |
for (int i = 0; i < HASHMAP_SIZE; ++i) { | |
entry_t *entry = hmap->entries[i]; | |
if (entry == NULL) { | |
continue; | |
} | |
printf("slot[%04d]: ", i); | |
while (1) { | |
printf("%s=%s ", entry->key, entry->value); | |
if (entry->next == NULL) { | |
break; | |
} | |
entry = entry->next; | |
} | |
printf("\n"); | |
} | |
} | |
int main(int argc, char **argv) { | |
hmap_t *hmap = hmap_create(); | |
hmap_put(hmap, "name1", "em"); | |
hmap_put(hmap, "name2", "russian"); | |
hmap_put(hmap, "name3", "pizza"); | |
hmap_put(hmap, "name4", "doge"); | |
hmap_put(hmap, "name5", "pyro"); | |
hmap_put(hmap, "name6", "joost"); | |
hmap_put(hmap, "name7", "kalix"); | |
hmap_dump(hmap); | |
hmap_delete(hmap); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment